Search code examples
node.jssocketswebsocketmasking

NodeJS Write a Masked WebSocket frame?


im need help, please.

im making small chat app and server using node.js

masked and unmasked data read eveything ok. write unmasked data ok no problem. now im need sending masked data.

need small revision unmasked data sending script. please help.

my script :

  this.send = function(data) {
    var dataLength = Buffer.byteLength(data),
      dataBuffer, rawBytesSend = 2;
    if(dataLength > 65535) {
      dataBuffer = new Buffer(10 + dataLength);
      dataBuffer[1] = 127;
      var low = dataLength | 0,
        hi = (dataLength - low) / 4294967296;
      dataBuffer[2] = (hi >> 24) & 255;
      dataBuffer[3] = (hi >> 16) & 255;
      dataBuffer[4] = (hi >> 8) & 255;
      dataBuffer[5] = hi & 255;
      dataBuffer[6] = (low >> 24) & 255;
      dataBuffer[7] = (low >> 16) & 255;
      dataBuffer[8] = (low >> 8) & 255;
      dataBuffer[9] = low & 255;
      rawBytesSend += 8
    } else if(dataLength > 125) {
      dataBuffer = new Buffer(4 + dataLength);
      dataBuffer[1] = 126;
      dataBuffer[2] = (dataLength >> 8) & 255;
      dataBuffer[3] = dataLength & 255;
      rawBytesSend += 2
    } else {
      dataBuffer = new Buffer(2 + dataLength);
      dataBuffer[1] = dataLength
    }
    dataBuffer[0] = 128 + (binary ? 2 : 1);
    dataBuffer[1] &= ~128;


    /* NOT WOKING THIS CODE BLOCK <<<<------
    mask = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256),
            Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)];

    for (var i = 0, n = dataBuffer.length - rawBytesSend ; i < n; i++) {
      dataBuffer[rawBytesSend + i] = dataBuffer[rawBytesSend + i] ^ mask[i % 4];
    }
    */ //NOT WOKING THIS CODE BLOCK HOW TO FIX THIS PROBLEM !!!!!!!!!!!!!


    if(that.socket.writable) {
      dataBuffer.write(data, rawBytesSend);
      this.socket.write(dataBuffer);
      that.rawBytesSend += rawBytesSend + dataLength;
      that.bytesSend += dataLength
    } else {
      this.__end(true)
    }
    return rawBytesSend
  };

Solution

  • im found a fix sharing...

    this.mask = function(payload, mask, offset) {
    if (!mask || mask.length === 0) return payload;
    offset = offset || 0;
    for (var i = 0, n = payload.length - offset; i < n; i++) {
      payload[offset + i] = payload[offset + i] ^ mask[i % 4];
    }
    return payload;
    };
    
    this.send = function(data) {
    if (data instanceof Array) data = new Buffer(data);
    var code,
        type    ='text',
        _masking=this._mask, 
        OPCODES ={continuation:0,text:1,binary:2,close:8,ping:9,pong:10},
    
        isText = (typeof data === 'string'),
        opcode = OPCODES[type || (isText ? 'text' : 'binary')],
        buffer = isText ? new Buffer(data, 'utf8') : data,
        insert = code ? 2 : 0,
        length = buffer.length + insert,
        header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10),
        offset = header + (_masking ? 4 : 0),
        masked = _masking ? 128 : 0,
        frame  = new Buffer(length + offset),
        BYTE   = 255,
        mask, i;
    
    frame[0] = 128 | opcode;
    
    if (length <= 125) {
      frame[1] = masked | length;
    } else if (length <= 65535) {
      frame[1] = masked | 126;
      frame[2] = Math.floor(length / 256);
      frame[3] = length & BYTE;
    } else {
      frame[1] = masked | 127;
      frame[2] = Math.floor(length / Math.pow(2,56)) & BYTE;
      frame[3] = Math.floor(length / Math.pow(2,48)) & BYTE;
      frame[4] = Math.floor(length / Math.pow(2,40)) & BYTE;
      frame[5] = Math.floor(length / Math.pow(2,32)) & BYTE;
      frame[6] = Math.floor(length / Math.pow(2,24)) & BYTE;
      frame[7] = Math.floor(length / Math.pow(2,16)) & BYTE;
      frame[8] = Math.floor(length / Math.pow(2,8))  & BYTE;
      frame[9] = length & BYTE;
    }
    if (code) {
      frame[offset]   = Math.floor(code / 256) & BYTE;
      frame[offset+1] = code & BYTE;
    }
    buffer.copy(frame, offset + insert);
    if (_masking) {
      mask = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256),
              Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)];
      new Buffer(mask).copy(frame, header);
      this.mask(frame, mask, offset);
    }
    if(that.socket.writable) {
      //dataBuffer.write(data, rawBytesSend);
      this.socket.write(frame);
      //that.rawBytesSend += rawBytesSend + dataLength;
      //that.bytesSend += dataLength
    } else {
      this.__end(true)
    }
    return true;
    };