blob: db63b829ea181d87e44dcfbeadacb0bf477bb0c0 [file] [log] [blame]
Alexander Afanasyev181a8b92013-02-28 13:28:53 -08001#!/usr/bin/env node
2
Wentao Shangc05dc532012-11-19 12:00:33 -08003/*
4 * @author: Wentao Shang
5 * See COPYING for copyright and distribution information.
6 * Implement WebSocket proxy between ccnd and javascript stack.
7 */
8
Jeff Thompson287a3182012-11-11 18:12:20 -08009var WebSocketServer = require('ws').Server;
10var dgram = require('dgram');
11
Wentao Shangc05dc532012-11-19 12:00:33 -080012var opt = require('node-getopt').create([
13 ['c' , 'ccnd=ARG', 'host name or ip of ccnd router'],
Wentao Shang7eb8c402012-11-19 13:30:44 -080014 ['p' , 'port=ARG', 'port number on which the proxy will listen'],
Wentao Shangc05dc532012-11-19 12:00:33 -080015 ['m' , 'maxclient=ARG', 'maximum number of concurrent client'],
16 ['L' , 'LOG=ARG', 'level of log message display'],
17 ['h' , 'help', 'display this help']
18]) // create Getopt instance
19.bindHelp() // bind option 'help' to default action
20.parseSystem(); // parse command line
Jeff Thompson287a3182012-11-11 18:12:20 -080021
Wentao Shangc05dc532012-11-19 12:00:33 -080022var ccndhost = opt.options.ccnd || 'localhost';
Wentao Shang7eb8c402012-11-19 13:30:44 -080023var wsport = opt.options.port || 9696;
Jeff Thompson287a3182012-11-11 18:12:20 -080024
Wentao Shang7eb8c402012-11-19 13:30:44 -080025var wss = new WebSocketServer({port:wsport, host:'0.0.0.0'}); // Set host to '0.0.0.0' so that we can accept connections from anywhere
26 // This host has nothing to do with ccndhost.
Wentao Shangc05dc532012-11-19 12:00:33 -080027
28var MaxNumOfClients = opt.options.maxclient || 40;
29
30var LOG = opt.options.LOG || 1;
31
32if (LOG > 0) console.log('WebSocketServer started...');
Jeff Thompson287a3182012-11-11 18:12:20 -080033
34wss.on('connection', function(ws) {
Wentao Shangc05dc532012-11-19 12:00:33 -080035 if (LOG > 0) console.log('wss.onconnection: WebSocket client connection received.');
36 if (LOG > 0) console.log('wss.onconnection: Number of clients now is ' + wss.clients.length);
Jeff Thompson287a3182012-11-11 18:12:20 -080037
38 if (wss.clients.length > MaxNumOfClients) {
Wentao Shangc05dc532012-11-19 12:00:33 -080039 if (LOG > 0) console.log('wss.onconnection: Max num of clients exceeded. Close WS connection now.');
Jeff Thompson287a3182012-11-11 18:12:20 -080040 ws.terminate();
41 return;
42 }
43
44 var udp = dgram.createSocket("udp4");
45
46 /*
47 * According to the email discussion with Michael, when we use
48 * UDP to connect to ccnd, we MUST first send a 'heartbeat'
49 * UDP packet with 1-byte payload (content of this byte can
50 * be random). The purpose of this packet is to let ccnd
51 * mark the incoming FACE as 'friendly' (with CCN_FACE_GG
52 * flag set). We also need to periodically send this 'heartbeat'
53 * packet every few seconds to keep ccnd from recycling the UDP
54 * face. Michael recomended 8 seconds interval.
55 * --Wentao
56 */
57 // Send 'heartbeat' packet now
58 var heartbeat = new Buffer(1);
59 heartbeat[0] = 0x21;
60 udp.send(heartbeat, 0, 1, 9695, ccndhost, null);
61
62 // Schedule a timer to send 'heartbeat' periodically
63 var timerID = setInterval(function() {
64 if (udp == null || udp == undefined)
65 return;
66
67 var hb = new Buffer(1);
68 hb[0] = 0x21;
69 udp.send(hb, 0, 1, 9695, ccndhost, null);
Wentao Shangc05dc532012-11-19 12:00:33 -080070 if (LOG > 1) console.log('UDP heartbeat fired at ccnd.');
Jeff Thompson287a3182012-11-11 18:12:20 -080071 },
72 8000 // 8000 ms delay
73 );
74
75 ws.on('message', function(message) {
Wentao Shangc05dc532012-11-19 12:00:33 -080076 if (typeof message == 'string') {
77 if (LOG > 2) console.log("ws.onmessage: Message from clinet: " + message);
78 }
Jeff Thompson287a3182012-11-11 18:12:20 -080079 else if (typeof message == 'object') {
80 // From JS array to Buffer
81 var buffer = new Buffer(message);
82
Wentao Shangc05dc532012-11-19 12:00:33 -080083 if (LOG > 2) {
84 var logMsg = 'ws.onmessage: Byte array from client: ';
85 for (var i = 0; i < buffer.length; i++)
86 logMsg += String.fromCharCode(buffer[i]);
87 console.log(logMsg);
88 }
Jeff Thompson287a3182012-11-11 18:12:20 -080089
90 udp.send(buffer, 0, buffer.length, 9695, ccndhost, null);
Jeff Thompson287a3182012-11-11 18:12:20 -080091 }
92 });
93
94 ws.on('close', function() {
Wentao Shangc05dc532012-11-19 12:00:33 -080095 if (LOG > 0) console.log('ws.onclose: WebSocket connection closed. Close UDP connection to ccnd and stop "heartbeat" timer.');
Jeff Thompson287a3182012-11-11 18:12:20 -080096 clearInterval(timerID);
97 udp.close();
98 udp = null;
99 });
100
101 udp.on('message', function(msg, rinfo) {
102 if (typeof msg == 'object') {
103 // From Buffer to ArrayBuffer
104 var bytesView = new Uint8Array(msg);
105
Wentao Shangc05dc532012-11-19 12:00:33 -0800106 if (LOG > 2) {
107 console.log('udp.onmessage: Byte array from server: ');
108 console.log('udp.onmessage: bytesView.length ' + bytesView.length);
109 var logMsg = "";
110 for (var i = 0; i < bytesView.length; i++)
111 logMsg += String.fromCharCode(bytesView[i]);
112 console.log(logMsg);
113 }
Jeff Thompson287a3182012-11-11 18:12:20 -0800114
115 ws.send(bytesView.buffer, {binary: true, mask: false});
Jeff Thompson287a3182012-11-11 18:12:20 -0800116 }
117 });
118
119 // Actually the socket close by ccnd will not cause the 'close' event to raise.
120 // So this event handle is only called when the client browser shuts down the WS
121 // connection, causing ws 'close' event to raise. In that event handle, we explicitly
122 // call udp.close(). So in this function we can do nothing. Anyway, here we clear the
123 // timer and terminate ws for a second time since that will not throw exception. 'ws'
124 // will check the 'readyState' before closing, therefore avoids 'close' event loop.
125 // --Wentao
126 udp.on('close', function() {
Wentao Shangc05dc532012-11-19 12:00:33 -0800127 if (LOG > 0) console.log('udp.onclose: UDP connection to ccnd terminated. Shut down WS connection to client and stop "heartbeat" timer.');
Jeff Thompson287a3182012-11-11 18:12:20 -0800128 clearInterval(timerID);
129 ws.terminate();
130 });
131
132 udp.on('error', function() {
Wentao Shangc05dc532012-11-19 12:00:33 -0800133 if (LOG > 0) console.log('udp.onerror: Error on UDP connection to ccnd. Shut down WS connection to client and stop "heartbeat" timer.');
Jeff Thompson287a3182012-11-11 18:12:20 -0800134 clearInterval(timerID);
135 ws.terminate();
136 });
137});