The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / src / net.cc @ 822d7fa2

History | View | Annotate | Download (13.7 KB)

1
#include "net.h"
2
#include "node.h"
3

    
4
#include <oi_socket.h>
5
#include <oi_buf.h>
6

    
7
#include <assert.h>
8
#include <stdlib.h>
9
#include <string.h>
10
#include <strings.h>
11

    
12
#include <sys/types.h>
13
#include <sys/socket.h>
14
#include <netdb.h>
15

    
16
using namespace v8;
17

    
18
#define ON_CONNECT_SYMBOL String::NewSymbol("onConnect")
19
#define ON_READ_SYMBOL String::NewSymbol("onRead")
20

    
21
static const struct addrinfo tcp_hints = 
22
/* ai_flags      */ { AI_PASSIVE
23
/* ai_family     */ , AF_UNSPEC
24
/* ai_socktype   */ , SOCK_STREAM
25
/* ai_protocol   */ , 0
26
/* ai_addrlen    */ , 0
27
/* ai_addr       */ , NULL
28
/* ai_canonname  */ , NULL
29
/* ai_next       */ , NULL
30
                    };
31

    
32
class Server {
33
public:
34
  Server (Handle<Object> handle, int backlog);
35
  ~Server ();
36

    
37
  static Handle<Value> New (const Arguments& args);
38
  static Handle<Value> ListenTCP (const Arguments& args);
39
  static Handle<Value> Close (const Arguments& args);
40

    
41
private:
42
  static oi_socket* OnConnection (oi_server *, struct sockaddr *, socklen_t);
43
  static Server* Unwrap (Handle<Object> handle);
44
  static void MakeWeak (Persistent<Value> _, void *data);
45
  oi_server server_;
46
  Persistent<Object> handle_;
47
};
48

    
49
class Socket {
50
public:
51
  Socket (Handle<Object> handle, double timeout);
52
  ~Socket ();
53

    
54
  void SetEncoding (Handle<Value>);
55
  void SetTimeout (double);
56

    
57
  static Handle<Value> New (const Arguments& args);
58
  static Handle<Value> Write (const Arguments& args);
59
  static Handle<Value> Close (const Arguments& args);
60
  static Handle<Value> ConnectTCP (const Arguments& args);
61
  static Handle<Value> SetEncoding (const Arguments& args);
62

    
63
private:
64
  static void OnConnect (oi_socket *socket);
65
  static void OnRead (oi_socket *s, const void *buf, size_t count);
66
  static void OnDrain (oi_socket *s);
67
  static void OnError (oi_socket *s, oi_error e);
68
  static void OnClose (oi_socket *s);
69
  static void OnTimeout (oi_socket *s);
70

    
71
  static int Resolve (eio_req *req);
72
  static int AfterResolve (eio_req *req);
73

    
74
  static Socket* Unwrap (Handle<Object> handle);
75
  static void MakeWeak (Persistent<Value> _, void *data);
76

    
77
  enum {UTF8, RAW} encoding_;
78
  oi_socket socket_;
79
  Persistent<Object> handle_;
80

    
81
  char *host_;
82
  char *port_;
83
};
84

    
85
Server::Server (Handle<Object> handle, int backlog)
86
{
87
  oi_server_init(&server_, backlog);
88
  server_.on_connection = Server::OnConnection;
89
//  server_.on_error      = Server::OnError;
90
  server_.data = this;
91

    
92
  HandleScope scope;
93
  handle_ = Persistent<Object>::New(handle);
94
  handle_->SetInternalField(0, External::New(this));
95
  handle_.MakeWeak(this, Server::MakeWeak);
96
}
97

    
98
Server::~Server ()
99
{
100
  oi_server_close(&server_);
101
  oi_server_detach(&server_);
102
  handle_.Dispose();
103
  handle_.Clear(); // necessary? 
104
}
105

    
106
Handle<Value>
107
Server::New (const Arguments& args)
108
{
109
  ;
110
}
111

    
112
Handle<Value>
113
Server::ListenTCP (const Arguments& args)
114
{
115
  ;
116
}
117

    
118
Handle<Value>
119
Server::Close (const Arguments& args)
120
{
121
  ;
122
}
123

    
124
oi_socket*
125
Server::OnConnection (oi_server *, struct sockaddr *remote_addr, socklen_t remote_addr_len)
126
{
127
  ; 
128
}
129

    
130
Server*
131
Server::Unwrap (Handle<Object> handle)
132
{
133
  HandleScope scope;
134
  Handle<External> field = Handle<External>::Cast(handle->GetInternalField(0));
135
  Server* server = static_cast<Server*>(field->Value());
136
  return server;
137
}
138

    
139
void
140
Server::MakeWeak (Persistent<Value> _, void *data)
141
{
142
  Server *s = static_cast<Server*> (data);
143
  delete s;
144
}
145

    
146
Handle<Value>
147
Socket::New(const Arguments& args)
148
{
149
  if (args.Length() > 1)
150
    return Undefined();
151

    
152
  HandleScope scope;
153

    
154
  // Default options 
155
  double timeout = 60.0; // in seconds
156
  enum {UTF8, RAW} encoding ;
157

    
158
  // Set options from argument.
159
  if (args.Length() == 1 && args[0]->IsObject()) {
160
    Local<Object> options = args[0]->ToObject();
161
    Local<Value> timeout_value = options->Get(String::NewSymbol("timeout"));
162
    Local<Value> encoding_value = options->Get(String::NewSymbol("encoding"));
163

    
164
    if (timeout_value->IsNumber()) {
165
      // timeout is specified in milliseconds like other time
166
      // values in javascript
167
      timeout = timeout_value->NumberValue() / 1000;
168
    }
169

    
170
    if (encoding_value->IsString()) {
171
      Local<String> encoding_string = encoding_value->ToString();
172
      char buf[5]; // need enough room for "utf8" or "raw"
173
      encoding_string->WriteAscii(buf, 0, 4);
174
      buf[4] = '\0';
175
      if(strcasecmp(buf, "utf8") == 0) encoding = UTF8;
176
    }
177
  }
178

    
179
  Socket *s = new Socket(args.Holder(), timeout);
180
  if(s == NULL)
181
    return Undefined(); // XXX raise error?
182

    
183
  return args.This();
184
}
185

    
186
void
187
Socket::SetEncoding (Handle<Value> encoding_value)
188
{
189
  if (encoding_value->IsString()) {
190
    HandleScope scope;
191
    Local<String> encoding_string = encoding_value->ToString();
192
    char buf[5]; // need enough room for "utf8" or "raw"
193
    encoding_string->WriteAscii(buf, 0, 4);
194
    buf[4] = '\0';
195
    if(strcasecmp(buf, "utf8") == 0)
196
      encoding_ = UTF8;
197
    else
198
      encoding_ = RAW;
199
  }
200
}
201

    
202
Socket*
203
Socket::Unwrap (Handle<Object> handle) 
204
{
205
  HandleScope scope;
206
  Handle<External> field = Handle<External>::Cast(handle->GetInternalField(0));
207
  Socket* socket = static_cast<Socket*>(field->Value());
208
  return socket;
209
}
210

    
211
Handle<Value>
212
Socket::ConnectTCP (const Arguments& args)
213
{
214
  if (args.Length() < 1)
215
    return Undefined();
216

    
217
  HandleScope scope;
218
  Socket *socket = Socket::Unwrap(args.Holder());
219

    
220
  String::AsciiValue port(args[0]);
221
  socket->port_ = strdup(*port);
222

    
223
  char *host = NULL; 
224
  String::AsciiValue host_v(args[1]->ToString());
225
  if(args[1]->IsString()) {
226
    socket->host_ = strdup(*host_v);
227
  }
228

    
229
  if(args[2]->IsFunction()) {
230
    socket->handle_->Set(ON_CONNECT_SYMBOL , args[2]);
231
  }
232

    
233
  /* For the moment I will do DNS lookups in the thread pool. This is
234
   * sub-optimal and cannot handle massive numbers of requests but it is 
235
   * quite portable. 
236
   * In the future I will move to a system using adns or udns: 
237
   * http://lists.schmorp.de/pipermail/libev/2009q1/000632.html
238
   */
239
  node_eio_warmup();
240
  eio_req *req = eio_custom (Socket::Resolve, EIO_PRI_DEFAULT, Socket::AfterResolve, socket);
241
}
242

    
243
/* This function is executed in the thread pool. It cannot touch anything! */
244
int
245
Socket::Resolve (eio_req *req) 
246
{
247
  Socket *socket = static_cast<Socket*> (req->data);
248
  struct addrinfo *address = NULL;
249

    
250
  req->result = getaddrinfo(socket->host_, socket->port_, &tcp_hints, &address);
251

    
252
  req->ptr2 = address;
253

    
254
  free(socket->host_);
255
  socket->host_ = NULL;
256

    
257
  free(socket->port_);
258
  socket->port_ = NULL;
259

    
260
  return 0;
261
}
262

    
263
int
264
Socket::AfterResolve (eio_req *req) 
265
{
266
  Socket *socket = static_cast<Socket*> (req->data);
267
  struct addrinfo *address = static_cast<struct addrinfo *>(req->ptr2);
268
  req->ptr2 = NULL;
269

    
270
  int r = 0;
271
  if (req->result == 0) {
272
    r = oi_socket_connect (&socket->socket_, address);
273
  }
274
  if (address)
275
    freeaddrinfo(address); 
276

    
277
  // no error. return.
278
  if(r == 0 && req->result == 0) {
279
    oi_socket_attach (&socket->socket_, node_loop());
280
    return 0;
281
  }
282

    
283
  HandleScope scope;
284
  Handle<Value> onconnect_value = socket->handle_->Get(ON_CONNECT_SYMBOL);
285
  if (!onconnect_value->IsFunction()) return 0; 
286
  Handle<Function> onconnect = Handle<Function>::Cast(onconnect_value);
287

    
288
  TryCatch try_catch;
289
  const int argc = 1;
290
  Local<Value> argv[argc];
291
  argv[0] = Integer::New(r | req->result); // FIXME very stupid error code.
292

    
293
  onconnect->Call(socket->handle_, argc, argv);
294
  if(try_catch.HasCaught())
295
    node_fatal_exception(try_catch);
296

    
297
  return 0;
298
}
299

    
300
Handle<Value>
301
Socket::Close (const Arguments& args) 
302
{
303
  HandleScope scope;
304
  Socket *socket = Socket::Unwrap(args.Holder());
305
  oi_socket_close(&socket->socket_);
306
  return Undefined();
307
}
308

    
309
void
310
Socket::MakeWeak (Persistent<Value> _, void *data)
311
{
312
  Socket *s = static_cast<Socket*> (data);
313
  delete s;
314
}
315

    
316
Socket::Socket(Handle<Object> handle, double timeout)
317
{
318
  oi_socket_init(&socket_, timeout);
319
  socket_.on_connect = Socket::OnConnect;
320
  socket_.on_read    = Socket::OnRead;
321
  socket_.on_drain   = Socket::OnDrain;
322
  socket_.on_error   = Socket::OnError;
323
  socket_.on_close   = Socket::OnClose;
324
  socket_.on_timeout = Socket::OnTimeout;
325
  socket_.data = this;
326

    
327
  HandleScope scope;
328
  handle_ = Persistent<Object>::New(handle);
329
  handle_->SetInternalField(0, External::New(this));
330
  handle_.MakeWeak(this, Socket::MakeWeak);
331

    
332
  encoding_ = UTF8; // default encoding.
333
  host_ = NULL;
334
  port_ = NULL;
335
}
336

    
337
Socket::~Socket ()
338
{
339
  oi_socket_close(&socket_);
340
  oi_socket_detach(&socket_);
341
  free(host_);
342
  free(port_);
343
  handle_.Dispose();
344
  handle_.Clear(); // necessary? 
345
}
346

    
347
Handle<Value>
348
Socket::SetEncoding (const Arguments& args) 
349
{
350
  Socket *socket = Socket::Unwrap(args.Holder());
351
  socket->SetEncoding(args[0]);
352
  return Undefined();
353
}
354

    
355
Handle<Value>
356
Socket::Write (const Arguments& args) 
357
{
358
  HandleScope scope;
359

    
360
  Socket *socket = Socket::Unwrap(args.Holder());
361
 
362
  if (args[0] == Null()) {
363
    oi_socket_write_eof(&socket->socket_);
364

    
365
  } else if (args[0]->IsString()) {
366
    // utf8 encoding
367
    Local<String> s = args[0]->ToString();
368
    size_t length = s->Utf8Length();
369
    oi_buf *buf = oi_buf_new2(length);
370
    s->WriteUtf8(buf->base, length);
371
    oi_socket_write(&socket->socket_, buf);
372

    
373
  } else if (args[0]->IsArray()) {
374
    // raw encoding
375
    Handle<Array> array = Handle<Array>::Cast(args[0]);
376
    size_t length = array->Length();
377
    oi_buf *buf = oi_buf_new2(length);
378
    for (int i = 0; i < length; i++) {
379
      Local<Value> int_value = array->Get(Integer::New(i));
380
      buf->base[i] = int_value->Int32Value();
381
    }
382
    oi_socket_write(&socket->socket_, buf);
383

    
384
  } else {
385
    // raise error bad argument.
386
    assert(0);
387
  }
388

    
389
  return Undefined();
390
}
391

    
392
void
393
Socket::OnConnect (oi_socket *s)
394
{
395
  Socket *socket = static_cast<Socket*> (s->data);
396

    
397
  HandleScope scope;
398

    
399
  Handle<Value> on_connect_value = socket->handle_->Get(ON_CONNECT_SYMBOL);
400
  if (!on_connect_value->IsFunction())
401
    return; 
402
  Handle<Function> on_connect = Handle<Function>::Cast(on_connect_value);
403

    
404
  TryCatch try_catch;
405
  const int argc = 1;
406
  Local<Value> argv[argc];
407
  argv[0] = Integer::New(0); 
408

    
409
  Handle<Value> r = on_connect->Call(socket->handle_, argc, argv);
410

    
411
  if(try_catch.HasCaught())
412
    node_fatal_exception(try_catch);
413
}
414

    
415
void
416
Socket::OnRead (oi_socket *s, const void *buf, size_t count)
417
{
418
  Socket *socket = static_cast<Socket*> (s->data);
419
  HandleScope scope;
420

    
421
  Handle<Value> onread_value = socket->handle_->Get(ON_READ_SYMBOL);
422
  if (!onread_value->IsFunction()) return; 
423
  Handle<Function> onread = Handle<Function>::Cast(onread_value);
424

    
425
  const int argc = 1;
426
  Handle<Value> argv[argc];
427

    
428
  if(count) {
429
    if(socket->encoding_ == UTF8) {
430
      // utf8 encoding
431
      Handle<String> chunk = String::New((const char*)buf, count);
432
      argv[0] = chunk;
433
    } else {
434
      // raw encoding
435
      Local<Array> array = Array::New(count);
436
      for (int i = 0; i < count; i++) {
437
        int val = static_cast<const int*>(buf)[i];
438
        array->Set(Integer::New(i), Integer::New(val));
439
      }
440
      argv[0] = array;
441
    }
442
  } else {
443
    argv[0] = Local<Value>::New(Null());
444
  }
445

    
446
  TryCatch try_catch;
447

    
448
  Handle<Value> r = onread->Call(socket->handle_, argc, argv);
449

    
450
  if(try_catch.HasCaught())
451
    node_fatal_exception(try_catch);
452
}
453

    
454
void
455
Socket::OnClose (oi_socket *s)
456
{
457
  Socket *socket = static_cast<Socket*> (s->data);
458
  HandleScope scope;
459

    
460
  Handle<Value> onclose_value = socket->handle_->Get( String::NewSymbol("onClose") );
461
  if (!onclose_value->IsFunction()) return; 
462
  Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
463

    
464
  TryCatch try_catch;
465

    
466
  Handle<Value> r = onclose->Call(socket->handle_, 0, NULL);
467

    
468
  if(try_catch.HasCaught())
469
    node_fatal_exception(try_catch);
470
}
471

    
472
void
473
Socket::OnDrain (oi_socket *s)
474
{
475
  Socket *socket = static_cast<Socket*> (s->data);
476
  HandleScope scope;
477

    
478
  Handle<Value> ondrain_value = socket->handle_->Get( String::NewSymbol("onDrain") );
479
  if (!ondrain_value->IsFunction()) return; 
480
  Handle<Function> ondrain = Handle<Function>::Cast(ondrain_value);
481

    
482
  TryCatch try_catch;
483

    
484
  Handle<Value> r = ondrain->Call(socket->handle_, 0, NULL);
485

    
486
  if(try_catch.HasCaught())
487
    node_fatal_exception(try_catch);
488
}
489

    
490

    
491
void
492
Socket::OnError (oi_socket *s, oi_error e)
493
{
494
  Socket *socket = static_cast<Socket*> (s->data);
495
  HandleScope scope;
496

    
497
  Handle<Value> onerror_value = socket->handle_->Get( String::NewSymbol("onError") );
498
  if (!onerror_value->IsFunction()) return; 
499
  Handle<Function> onerror = Handle<Function>::Cast(onerror_value);
500

    
501
  TryCatch try_catch;
502

    
503
  Handle<Value> r = onerror->Call(socket->handle_, 0, NULL);
504

    
505
  if(try_catch.HasCaught())
506
    node_fatal_exception(try_catch);
507
}
508

    
509
void
510
Socket::OnTimeout (oi_socket *s)
511
{
512
  Socket *socket = static_cast<Socket*> (s->data);
513
  HandleScope scope;
514

    
515
  Handle<Value> ontimeout_value = socket->handle_->Get( String::NewSymbol("onTimeout") );
516
  if (!ontimeout_value->IsFunction()) return; 
517
  Handle<Function> ontimeout = Handle<Function>::Cast(ontimeout_value);
518

    
519
  TryCatch try_catch;
520

    
521
  Handle<Value> r = ontimeout->Call(socket->handle_, 0, NULL);
522

    
523
  if(try_catch.HasCaught())
524
    node_fatal_exception(try_catch);
525
}
526

    
527

    
528
void
529
NodeInit_net (Handle<Object> target)
530
{
531
  HandleScope scope;
532

    
533
  Local<FunctionTemplate> socket_template = FunctionTemplate::New(Socket::New);
534
  socket_template->InstanceTemplate()->SetInternalFieldCount(1);
535
  target->Set(String::NewSymbol("Socket"), socket_template->GetFunction());
536

    
537
  NODE_SET_METHOD(socket_template->InstanceTemplate(), "connectTCP", Socket::ConnectTCP);
538
  //NODE_SET_METHOD(socket_template->InstanceTemplate(), "connectUNIX", Socket::ConnectUNIX);
539
  NODE_SET_METHOD(socket_template->InstanceTemplate(), "write", Socket::Write);
540
  NODE_SET_METHOD(socket_template->InstanceTemplate(), "close", Socket::Close);
541
  NODE_SET_METHOD(socket_template->InstanceTemplate(), "setEncoding", Socket::SetEncoding);
542

    
543
  Local<FunctionTemplate> server_template = FunctionTemplate::New(Server::New);
544
  server_template->InstanceTemplate()->SetInternalFieldCount(1);
545
  target->Set(String::NewSymbol("Server"), server_template->GetFunction());
546

    
547
  NODE_SET_METHOD(server_template->InstanceTemplate(), "listenTCP", Server::ListenTCP);
548
}
549