SocketCluster / socketcluster-client

JavaScript client for SocketCluster
MIT License
292 stars 91 forks source link

Client not connecting in nodejs #19

Closed vnistor closed 9 years ago

vnistor commented 9 years ago

I'm trying to use the client to connect to my server, but can't seem to do that under nodejs, though the same works fine in a browser. Running the latest SocketCluster both client and server side.

var options = {
    protocol: 'wss',
    secure: true,
    hostname: 'localhost',
    port: 443
};

var socketCluster = require('socketcluster-client');
// Initiate the connection to the server
 socket = socketCluster.connect(options);

   socket.on('error', function (err) {
     console.log('Socket error - ' + err);
   });
   socket.on('connect', function () {
     console.log('CONNECTED');
   });

I'm getting: Socket error - Error: Socket hung up

This seems to be triggered by a 1006 code after:

/scc/node_modules/socketcluster-client/lib/scsocket.js:399
      throw err;
            ^
Error: Socket hung up
    at Emitter.SCSocket._onSCClose (/scc/node_modules/socketcluster-client/lib/scsocket.js:462:15)
    at Emitter.<anonymous> (/scc/node_modules/socketcluster-client/lib/scsocket.js:293:12)
    at Emitter.emit (/scc/node_modules/socketcluster-client/node_modules/sc-emitter/node_modules/component-emitter/index.js:131:20)
    at Emitter.SCEmitter.emit (/scc/node_modules/socketcluster-client/node_modules/sc-emitter/index.js:28:26)
    at Emitter.SCTransport._onClose (/scc/node_modules/socketcluster-client/lib/sctransport.js:132:30)
    at WebSocket.wsSocket.onerror (/scc/node_modules/socketcluster-client/lib/sctransport.js:79:12)
    at WebSocket.onError (/scc/node_modules/socketcluster-client/node_modules/sc-ws/lib/WebSocket.js:428:14)
    at WebSocket.emit (events.js:107:17)
    at ClientRequest.onerror (/scc/node_modules/socketcluster-client/node_modules/sc-ws/lib/WebSocket.js:686:10)
    at ClientRequest.emit (events.js:107:17)

Things that have been tried:

  1. Older versions: in 2.3.12 I get the same error in versions older than 2.3.11 the code just exits. It's like nothing got executed. The client does not connect, I have something that tells me when a client connects server-side
  2. secure:false
  3. removing protocol: 'wss'
  4. running on a different machine than the server
vnistor commented 9 years ago

Another user was nice enough to let me try to connect to their server, to test if this was not a server settings issue. The person was running SocketCluster 2.3.6 on their server. I managed to connect to their server but not mine. Downgrading my SC to 2.3.6 didn't help.

Just in case, here is the server config:

var socketCluster = new SocketCluster({
  workers: Number(argv.w),
  brokers: Number(argv.s),
  port:  Number(argv.p) || 443,
  workerController: __dirname + '/worker.js',
  brokerController: __dirname + '/broker.js',
  socketChannelLimit: 1000,
  rebootWorkerOnCrash: argv['auto-reboot'] !== false,
  protocol: 'https',
  protocolOptions: {
    key: fs.readFileSync(__dirname + '/keys/ssl.key', 'utf8'),
    cert: fs.readFileSync(__dirname + '/keys/ssl.cert', 'utf8'),
    passphrase: ''
  },
  authKey: argv.ak,
  brokerOptions: {      
    host: 'localhost',
    port: 6379
  }
});

I've removed some of the things that I thought could interact or were not necessary to run the app, like path, appName, origins, logLevel, allowClientPublish, host.

jondubois commented 9 years ago

@vnistor This server config which you posted, is that the one which works (yours) or the one which fails (Rob's)?

I am able to reproduce the same issue as you when I provide a single pfx file instead of a separate key and cert file - Do you think this could be the issue?

It only happens when running the client in Node.js for me as well.

vnistor commented 9 years ago

@jondubois That is the config that fails (mine). I will ask Rob about the config where I was able to connect. Mine has key+cert config.

jondubois commented 9 years ago

@vnistor What happens if you remove the passphrase field from protocolOptions?

vnistor commented 9 years ago

@jondubois Well I don't think the certficate works without it. There is a passphrase there, I just removed it when pasting. Let me try.

jondubois commented 9 years ago

Ok, I was just trying to check what the difference might be between the two setups.

vnistor commented 9 years ago

Fails. It is required.

1441705058211 - Origin: Master
    [Error] Error: The supplied private key is encrypted and cannot be used without a passphrase - Please provide a valid passphrase as a property to protocolOptions
    at EventEmitter.SocketCluster._init (/node_modules/sc/master/node_modules/socketcluster/index.js:200:17)
    at Domain.<anonymous> (/node_modules/sc/master/node_modules/socketcluster/index.js:39:10)
    at Domain.run (domain.js:197:16)
    at EventEmitter.SocketCluster (/node_modules/sc/master/node_modules/socketcluster/index.js:38:21)
    at Object.<anonymous> (/node_modules/sc/master/localServer.js:9:21)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
jondubois commented 9 years ago

@vnistor Ok, I was able to reproduce the issue when running the client in the browser too. To reproduce:

In the client socketCluster.connect(...) method, set the hostname as '127.0.0.1' then try accessing your app using https://localhost:443/ in Chrome browser (a warning should come up regarding invalid SSL cert, you should click on advanced link and proceed anyway) - The WebSocket connection should fail with a 1006. Now try to access your app using https://127.0.0.1:443/ - This time the connection should be successful.

Basically it looks like if you try to access the app using the ip address, then you need to also provide the ip address to the socketCluster.connect(...) method. If you try to access the app using the name (e.g. 'localhost'), then you also need to provide the host name ('localhost') to the socketCluster.connect(...) method.

Interestingly enough, I noticed that after I clicked on 'proceed with invalid certificate' in Chrome for both the 'localhost' and '127.0.0.1', the error would not happen anymore regardless of host name vs ip address.

jondubois commented 9 years ago

It looks like Chrome is blocking the client until you click on 'proceed anyway'. The weird thing is why this is also happening when running the client in Node.js - As far as I understand Node.js shouldn't care if you're using a valid CA-signed cert vs a self-signed one.

jondubois commented 9 years ago

Actually it looks like Node.js blocks connections if the CA is invalid. See http://stackoverflow.com/questions/10888610/ignore-invalid-self-signed-ssl-certificate-in-node-js-with-https-request and http://stackoverflow.com/questions/19665863/how-do-i-use-a-self-signed-certificate-for-a-https-node-js-server

^ These issues have some workarounds. Maybe they work in our case too. If so, I should update the website to explain this because this is a common use case.

jondubois commented 9 years ago

@vnistor Ok, if you add an rejectUnauthorized: false option to the client's socketCluster.connect(...) options, it works.

I'll update the docs :)

vnistor commented 9 years ago

@jondubois Thanks a lot! I can confirm this fixes the issue. The certificate was issued by https://www.startssl.com/ for the host I was trying to connect to (I used localhost in the example, but it didn't work for the full domain either). I guess not everyone recognizes them, probably because they offer a free service.

There should be some indication that this is the issue though. The docs will love it!

jondubois commented 9 years ago

I updated the docs: http://socketcluster.io/#!/docs/api-socketcluster-client