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 @ 63a9cd38

History | View | Annotate | Download (10.2 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 <sys/types.h>
9
#include <sys/socket.h>
10
#include <netdb.h>
11
#include <strings.h>
12

    
13
using namespace v8;
14

    
15
static Persistent<String> readyState_str; 
16

    
17
static Persistent<Integer> readyStateCONNECTING; 
18
static Persistent<Integer> readyStateOPEN; 
19
static Persistent<Integer> readyStateCLOSED; 
20

    
21
enum encoding {UTF8, RAW};
22

    
23
class Socket {
24
public:
25
  Socket (Handle<Object> obj, double timeout);
26
  ~Socket ();
27

    
28
  int ConnectTCP (char *port, char *host);
29
  void Write (Handle<Value> arg);
30
  void Disconnect ();
31

    
32
  void SetEncoding (enum encoding);
33
  void SetTimeout (double);
34

    
35
  void OnConnect ();
36
  void OnRead (const void *buf, size_t count);
37
  void OnDrain ();
38
  void OnError (oi_error e);
39
  void OnClose ();
40

    
41
private:
42
  oi_socket socket_;
43
  struct addrinfo *address_;
44
  Persistent<Object> js_object_;
45
};
46

    
47
static void
48
on_connect (oi_socket *socket)
49
{
50
  Socket *s = static_cast<Socket*> (socket->data);
51
  s->OnConnect();
52
}
53

    
54
static void
55
on_read (oi_socket *socket, const void *buf, size_t count)
56
{
57
  Socket *s = static_cast<Socket*> (socket->data);
58
  s->OnRead(buf, count);
59
}
60

    
61
static void
62
on_drain (oi_socket *socket)
63
{
64
  Socket *s = static_cast<Socket*> (socket->data);
65
  s->OnDrain();
66
}
67

    
68
static void
69
on_error (oi_socket *socket, oi_error e)
70
{
71
  Socket *s = static_cast<Socket*> (socket->data);
72
  s->OnError(e);
73
}
74

    
75
static void
76
on_timeout (oi_socket *socket)
77
{
78
  Socket *s = static_cast<Socket*> (socket->data);
79
  s->OnTimeout(e);
80
}
81

    
82
static void
83
on_close (oi_socket *socket)
84
{
85
  Socket *s = static_cast<Socket*> (socket->data);
86
  s->OnClose();
87
}
88

    
89

    
90
static Handle<Value>
91
NewSocket (const Arguments& args)
92
{
93
  if (args.Length() > 1)
94
    return Undefined();
95

    
96
  HandleScope scope;
97

    
98
  // Default options 
99
  double timeout = 60.0; // in seconds
100
  enum {RAW, UTF8} encoding = RAW;
101

    
102
  // Set options from argument.
103
  if (args.Length() == 1 && args[0]->IsObject()) {
104
    Local<Object> options = args[0]->ToObject();
105
    Local<Value> timeout_value = options->Get(String::NewSymbol("timeout"));
106
    Local<Value> encoding_value = options->Get(String::NewSymbol("encoding"));
107

    
108
    if (timeout_value->IsNumber()) {
109
      // timeout is specified in milliseconds like other time
110
      // values in javascript
111
      timeout = timeout_value->NumberValue() / 1000;
112
    }
113

    
114
    if (encoding_value->IsString()) {
115
      Local<String> encoding_string = encoding_value->ToString();
116
      char buf[5]; // need enough room for "utf8" or "raw"
117
      encoding_string->WriteAscii(buf, 0, 4);
118
      buf[4] = '\0';
119
      if(strcasecmp(buf, "utf8") == 0) encoding = UTF8;
120
    }
121
  }
122

    
123
  Socket *s = new Socket(args.This(), timeout);
124
  if(s == NULL)
125
    return Undefined(); // XXX raise error?
126

    
127
  return args.This();
128
}
129

    
130
static Socket*
131
Unwrapsocket (Handle<Object> obj) 
132
{
133
  HandleScope scope;
134
  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
135
  Socket* socket = static_cast<Socket*>(field->Value());
136
  return socket;
137
}
138

    
139
static Handle<Value>
140
SocketConnectTCPCallback (const Arguments& args)
141
{
142
  if (args.Length() < 1)
143
    return Undefined();
144

    
145
  HandleScope scope;
146
  Socket *socket = Unwrapsocket(args.Holder());
147

    
148
  String::AsciiValue port(args[0]);
149

    
150
  char *host = NULL; 
151
  String::AsciiValue host_v(args[1]->ToString());
152
  if(args[1]->IsString()) {
153
    host = *host_v;
154
  }
155

    
156
  int r = socket->ConnectTCP(*port, host);
157
  // TODO raise error if r != 0
158
    
159
  return Undefined(); 
160
}
161

    
162
static Handle<Value>
163
SocketWriteCallback (const Arguments& args) 
164
{
165
  HandleScope scope;
166
  Socket *socket = Unwrapsocket(args.Holder());
167
  socket->Write(args[0]);
168
  return Undefined();
169
}
170

    
171
static Handle<Value>
172
SocketCloseCallback (const Arguments& args) 
173
{
174
  HandleScope scope;
175
  Socket *socket = Unwrapsocket(args.Holder());
176
  socket->Disconnect();
177
  return Undefined();
178
}
179

    
180
static void
181
DestroySocket (Persistent<Value> _, void *data)
182
{
183
  Socket *s = static_cast<Socket*> (data);
184
  delete s;
185
}
186

    
187
Socket::Socket(Handle<Object> js_object, double timeout)
188
{
189
  oi_socket_init(&socket_, timeout);
190
  socket_.on_connect = on_connect;
191
  socket_.on_read    = on_read;
192
  socket_.on_drain   = on_drain;
193
  socket_.on_error   = on_error;
194
  socket_.on_close   = on_close;
195
  socket_.on_timeout = on_timeout;
196
  socket_.data = this;
197

    
198
  HandleScope scope;
199
  js_object_ = Persistent<Object>::New(js_object);
200
  js_object_->SetInternalField (0, External::New(this));
201
  js_object_.MakeWeak (this, DestroySocket);
202
}
203

    
204
Socket::~Socket ()
205
{
206
  Disconnect();
207
  oi_socket_detach(&socket_);
208
  js_object_.Dispose();
209
  js_object_.Clear(); // necessary? 
210
}
211

    
212
static struct addrinfo tcp_hints = 
213
/* ai_flags      */ { AI_PASSIVE
214
/* ai_family     */ , AF_UNSPEC
215
/* ai_socktype   */ , SOCK_STREAM
216
/* ai_protocol   */ , 0
217
/* ai_addrlen    */ , 0
218
/* ai_addr       */ , 0
219
/* ai_canonname  */ , 0
220
/* ai_next       */ , 0
221
                    };
222

    
223
int
224
Socket::ConnectTCP(char *port, char *host)
225
{
226
  int r;
227

    
228
  HandleScope scope;
229

    
230
  js_object_->Set(readyState_str, readyStateCONNECTING);
231

    
232
  /* FIXME Blocking DNS resolution. */
233
  printf("resolving host: %s, port: %s\n", host, port);
234
  r = getaddrinfo (host, port, &tcp_hints, &address);
235
  if(r != 0)  {
236
    perror("getaddrinfo");
237
    return r;
238
  }
239

    
240
  r = oi_socket_connect (&socket, address);
241
  if(r != 0)  {
242
    perror("oi_socket_connect");
243
    return r;
244
  }
245
  oi_socket_attach (&socket, node_loop());
246

    
247
  freeaddrinfo(address);
248
  address = NULL;
249
}
250

    
251
void Socket::Write (Handle<Value> arg)
252
{
253
  HandleScope scope;
254
 
255
  if (arg == Null()) {
256

    
257
    oi_socket_write_eof(&socket);
258

    
259
  } else if (arg->IsString()) {
260
    Local<String> s = arg->ToString();
261

    
262
    size_t l1 = s->Utf8Length(), l2;
263
    oi_buf *buf = oi_buf_new2(l1);
264
    l2 = s->WriteUtf8(buf->base, l1);
265
    assert(l1 == l2);
266

    
267
    oi_socket_write(&socket, buf);
268

    
269
  } else if (arg->IsArray()) {
270
    size_t length = array->Length();
271
    Handle<Array> array = Handle<Array>::Cast(arg);
272
    oi_buf *buf = oi_buf_new2(length);
273
    for (int i = 0; i < length; i++) {
274
      Local<Value> int_value = array->Get(Integer::New(i));
275
      buf[i] = int_value->Int32Value();
276
    }
277

    
278
    oi_socket_write(&socket, buf);
279

    
280
  } else {
281
    // raise error bad argument.
282
    assert(0);
283
  }
284
}
285
 
286
void
287
Socket::Disconnect()
288
{
289
  oi_socket_close(&socket);
290
}
291

    
292
void
293
Socket::OnConnect()
294
{
295
  HandleScope scope;
296

    
297
  assert(READY_STATE_CONNECTING == ReadyState());
298
  js_object_->Set(readyState_str, readyStateOPEN);
299

    
300
  Handle<Value> on_connect_value = js_object_->Get( String::NewSymbol("on_connect") );
301
  if (!on_connect_value->IsFunction())
302
    return; 
303
  Handle<Function> on_connect = Handle<Function>::Cast(on_connect_value);
304

    
305
  TryCatch try_catch;
306

    
307
  Handle<Value> r = on_connect->Call(js_object_, 0, NULL);
308

    
309
  if(try_catch.HasCaught())
310
    node_fatal_exception(try_catch);
311
}
312

    
313
void
314
Socket::OnRead (const void *buf, size_t count)
315
{
316
  HandleScope scope;
317

    
318
  assert(READY_STATE_OPEN == ReadyState());
319

    
320
  Handle<Value> onread_value = js_object_->Get( String::NewSymbol("on_read") );
321
  if (!onread_value->IsFunction()) return; 
322
  Handle<Function> onread = Handle<Function>::Cast(onread_value);
323

    
324
  const int argc = 1;
325
  Handle<Value> argv[argc];
326

    
327
  if(count) {
328
    Handle<String> chunk = String::New((const char*)buf, count); // TODO binary data?
329
    argv[0] = chunk;
330
  } else {
331
    // TODO eof? delete write method?
332
    argv[0] = Null();
333
  }
334

    
335
  TryCatch try_catch;
336

    
337
  Handle<Value> r = onread->Call(js_object_, argc, argv);
338

    
339
  if(try_catch.HasCaught())
340
    node_fatal_exception(try_catch);
341
}
342

    
343
void
344
Socket::OnClose ()
345
{
346
  HandleScope scope;
347

    
348
  printf("onclose readyState %d\n", ReadyState());
349

    
350
  assert(READY_STATE_OPEN == ReadyState());
351
  js_object_->Set(readyState_str, readyStateCLOSED);
352

    
353
  Handle<Value> onclose_value = js_object_->Get( String::NewSymbol("on_close") );
354
  if (!onclose_value->IsFunction()) return; 
355
  Handle<Function> onclose = Handle<Function>::Cast(onclose_value);
356

    
357
  TryCatch try_catch;
358

    
359
  Handle<Value> r = onclose->Call(js_object_, 0, NULL);
360

    
361
  if(try_catch.HasCaught())
362
    node_fatal_exception(try_catch);
363
}
364

    
365
void
366
NodeInit_net (Handle<Object> target)
367
{
368
  HandleScope scope;
369

    
370
  //
371
  // Socket
372
  //
373
  Local<FunctionTemplate> socket_template = FunctionTemplate::New(NewSocket);
374
  target->Set(String::NewSymbol("Socket"), socket_template->GetFunction());
375
  socket_template->InstanceTemplate()->SetInternalFieldCount(1);
376

    
377
  // socket.connectTCP()
378
  Local<FunctionTemplate> socket_connect_tcp = 
379
      FunctionTemplate::New(SocketConnectTCPCallback);
380
  socket_template->InstanceTemplate()->Set(String::NewSymbol("connectTCP"), 
381
                                           socket_connect_tcp->GetFunction());
382

    
383
  // socket.connectUNIX()
384
  Local<FunctionTemplate> socket_connect_unix = 
385
      FunctionTemplate::New(SocketConnectUNIXCallback);
386
  socket_template->InstanceTemplate()->Set(String::NewSymbol("connectUNIX"), 
387
                                           socket_connect_unix->GetFunction());
388

    
389
  // socket.write()
390
  Local<FunctionTemplate> socket_write =
391
      FunctionTemplate::New(SocketWriteCallback);
392
  socket_template->InstanceTemplate()->Set(String::NewSymbol("write"), 
393
                                           socket_write->GetFunction());
394

    
395
  // socket.close()
396
  Local<FunctionTemplate> socket_close = 
397
      FunctionTemplate::New(SocketCloseCallback);
398
  socket_template->InstanceTemplate()->Set(String::NewSymbol("close"), 
399
                                           socket_close->GetFunction());
400

    
401
  //
402
  // Server
403
  //
404
  Local<FunctionTemplate> server_template = FunctionTemplate::New(NewServer);
405
  target->Set(String::NewSymbol("Server"), server_template->GetFunction());
406
  server_template->InstanceTemplate()->SetInternalFieldCount(1);
407

    
408
  // server.listenTCP()
409
  Local<FunctionTemplate> server_listenTCP =
410
      FunctionTemplate::New(ServerListenTCPCallback);
411
  server_template->InstanceTemplate()->Set(String::NewSymbol("listenTCP"), 
412
                                           server_listenTCP->GetFunction());
413

    
414
  // server.listenUNIX()
415
  Local<FunctionTemplate> server_listenUNIX =
416
      FunctionTemplate::New(ServerListenUNIXCallback);
417
  server_template->InstanceTemplate()->Set(String::NewSymbol("listenUNIX"), 
418
                                           server_listenTCP->GetFunction());
419

    
420
  // server.close()
421
  Local<FunctionTemplate> server_close = FunctionTemplate::New(ServerCloseCallback);
422
  server_template->InstanceTemplate()->Set(String::NewSymbol("close"), 
423
                                           server_close->GetFunction());
424
}
425