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.
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 |
|