520
562
return scope.Close(Integer::New(bytes_read));
565
// var info = t.recvfrom(fd, buffer, offset, length, flags);
566
// info.size // bytes read
567
// info.port // from port
568
// info.address // from address
569
// returns null on EAGAIN or EINTR, raises an exception on all other errors
570
// returns object otherwise
571
static Handle<Value> RecvFrom(const Arguments& args) {
574
if (args.Length() < 5) {
575
return ThrowException(Exception::TypeError(
576
String::New("Takes 5 parameters")));
581
if (!Buffer::HasInstance(args[1])) {
582
return ThrowException(Exception::TypeError(
583
String::New("Second argument should be a buffer")));
586
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
588
size_t off = args[2]->Int32Value();
589
if (off >= buffer->length()) {
590
return ThrowException(Exception::Error(
591
String::New("Offset is out of bounds")));
594
size_t len = args[3]->Int32Value();
595
if (off + len > buffer->length()) {
596
return ThrowException(Exception::Error(
597
String::New("Length is extends beyond buffer")));
600
int flags = args[4]->Int32Value();
602
struct sockaddr_storage address_storage;
603
socklen_t addrlen = sizeof(struct sockaddr_storage);
605
ssize_t bytes_read = recvfrom(fd, (char*)buffer->data() + off, len, flags,
606
(struct sockaddr*) &address_storage, &addrlen);
608
if (bytes_read < 0) {
609
if (errno == EAGAIN || errno == EINTR) return Null();
610
return ThrowException(ErrnoException(errno, "read"));
613
Local<Object> info = Object::New();
615
info->Set(size_symbol, Integer::New(bytes_read));
617
ADDRESS_TO_JS(info, address_storage);
619
return scope.Close(info);
524
623
// bytesRead = t.recvMsg(fd, buffer, offset, length)
525
624
// if (recvMsg.fd) {
583
681
// that the wrapper can pick up. Since we're single threaded, this is not
584
682
// a problem - just make sure to copy out that variable before the next
585
683
// call to recvmsg().
587
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
588
if (cmsg && cmsg->cmsg_type == SCM_RIGHTS) {
589
received_fd = *(int *) CMSG_DATA(cmsg);
590
recv_msg_template->GetFunction()->Set(fd_symbol, Integer::New(received_fd));
592
recv_msg_template->GetFunction()->Set(fd_symbol, Null());
685
// XXX: Some implementations can send multiple file descriptors in a
686
// single message. We should be using CMSG_NXTHDR() to walk the
687
// chain to get at them all. This would require changing the
688
// API to hand these back up the caller, is a pain.
690
int received_fd = -1;
691
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
692
msg.msg_controllen > 0 && cmsg != NULL;
693
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
694
if (cmsg->cmsg_type == SCM_RIGHTS) {
695
if (received_fd != -1) {
696
fprintf(stderr, "ignoring extra FD received: %d\n", received_fd);
699
received_fd = *(int *) CMSG_DATA(cmsg);
701
fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
707
recv_msg_template->GetFunction()->Set(
709
(received_fd != -1) ?
710
Integer::New(received_fd) :
595
714
return scope.Close(Integer::New(bytes_read));
643
// var bytesWritten = t.sendFD(self.fd)
644
// returns null on EAGAIN or EINTR, raises an exception on all other errors
645
static Handle<Value> SendFD(const Arguments& args) {
762
// var bytes = sendmsg(fd, buf, off, len, fd, flags);
764
// Write a buffer with optional offset and length to the given file
765
// descriptor. Note that we refuse to send 0 bytes.
767
// The 'fd' parameter is a numerical file descriptor, or the undefined value
770
// The 'flags' parameter is a number representing a bitmask of MSG_* values.
771
// This is passed directly to sendmsg().
773
// Returns null on EAGAIN or EINTR, raises an exception on all other errors
774
static Handle<Value> SendMsg(const Arguments& args) {
646
775
HandleScope scope;
648
779
if (args.Length() < 2) {
649
780
return ThrowException(Exception::TypeError(
650
781
String::New("Takes 2 parameters")));
784
// The first argument should be a file descriptor
655
// TODO: make sure fd is a unix domain socket?
657
if (!args[1]->IsInt32()) {
787
// Grab the actul data to be written, stuffing it into iov
788
if (!Buffer::HasInstance(args[1])) {
658
789
return ThrowException(Exception::TypeError(
659
String::New("FD to send is not an integer")));
662
int fd_to_send = args[1]->Int32Value();
790
String::New("Expected either a string or a buffer")));
793
Buffer *buf = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
796
if (args.Length() >= 3 && !args[2]->IsUndefined()) {
797
if (!args[2]->IsUint32()) {
798
return ThrowException(Exception::TypeError(
799
String::New("Expected unsigned integer for offset")));
802
offset = args[2]->Uint32Value();
803
if (offset >= buf->length()) {
804
return ThrowException(Exception::Error(
805
String::New("Offset into buffer too large")));
809
size_t length = buf->length() - offset;
810
if (args.Length() >= 4 && !args[3]->IsUndefined()) {
811
if (!args[3]->IsUint32()) {
812
return ThrowException(Exception::TypeError(
813
String::New("Expected unsigned integer for length")));
816
length = args[3]->Uint32Value();
817
if (offset + length > buf->length()) {
818
return ThrowException(Exception::Error(
819
String::New("offset + length beyond buffer length")));
823
iov.iov_base = buf->data() + offset;
824
iov.iov_len = length;
827
if (args.Length() >= 5 && !args[4]->IsUndefined()) {
828
if (!args[4]->IsUint32()) {
829
return ThrowException(Exception::TypeError(
830
String::New("Expected unsigned integer for a file descriptor")));
833
fd_to_send = args[4]->Uint32Value();
837
if (args.Length() >= 6 && !args[5]->IsUndefined()) {
838
if (!args[5]->IsUint32()) {
839
return ThrowException(Exception::TypeError(
840
String::New("Expected unsigned integer for a flags argument")));
843
flags = args[5]->Uint32Value();
664
846
struct msghdr msg;
666
char control_msg[CMSG_SPACE(sizeof(fd_to_send))];
667
struct cmsghdr *cmsg;
668
static char dummy = 'd'; // Need to send at least a byte of data in the message
670
iov[0].iov_base = &dummy;
673
850
msg.msg_iovlen = 1;
674
851
msg.msg_name = NULL;
675
852
msg.msg_namelen = 0;
676
853
msg.msg_flags = 0;
677
msg.msg_control = (void *) control_msg;
678
msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send));
679
cmsg = CMSG_FIRSTHDR(&msg);
680
cmsg->cmsg_level = SOL_SOCKET;
681
cmsg->cmsg_type = SCM_RIGHTS;
682
cmsg->cmsg_len = msg.msg_controllen;
683
*(int*) CMSG_DATA(cmsg) = fd_to_send;
685
ssize_t written = sendmsg(fd, &msg, 0);
854
msg.msg_control = NULL;
855
msg.msg_controllen = 0;
857
if (fd_to_send >= 0) {
858
struct cmsghdr *cmsg;
860
msg.msg_control = (void *) scratch;
861
msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send));
863
cmsg = CMSG_FIRSTHDR(&msg);
864
cmsg->cmsg_level = SOL_SOCKET;
865
cmsg->cmsg_type = SCM_RIGHTS;
866
cmsg->cmsg_len = msg.msg_controllen;
867
*(int*) CMSG_DATA(cmsg) = fd_to_send;
870
ssize_t written = sendmsg(fd, &msg, flags);
873
if (errno == EAGAIN || errno == EINTR) return Null();
874
return ThrowException(ErrnoException(errno, "sendmsg"));
877
/* Note that the FD isn't explicitly closed here, this
878
* happens in the JS */
880
return scope.Close(Integer::New(written));
883
// var bytes = sendto(fd, buf, off, len, flags, destination port, desitnation address);
885
// Write a buffer with optional offset and length to the given file
886
// descriptor. Note that we refuse to send 0 bytes.
888
// The 'fd' parameter is a numerical file descriptor, or the undefined value
891
// The 'flags' parameter is a number representing a bitmask of MSG_* values.
892
// This is passed directly to sendmsg().
894
// The destination port can either be an int port, or a path.
896
// Returns null on EAGAIN or EINTR, raises an exception on all other errors
897
static Handle<Value> SendTo(const Arguments& args) {
900
if (args.Length() < 5) {
901
return ThrowException(Exception::TypeError(
902
String::New("Takes 5 or 6 parameters")));
905
// The first argument should be a file descriptor
908
// Grab the actul data to be written
909
if (!Buffer::HasInstance(args[1])) {
910
return ThrowException(Exception::TypeError(
911
String::New("Expected either a string or a buffer")));
914
Buffer *buf = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
917
if (args.Length() >= 3 && !args[2]->IsUndefined()) {
918
if (!args[2]->IsUint32()) {
919
return ThrowException(Exception::TypeError(
920
String::New("Expected unsigned integer for offset")));
923
offset = args[2]->Uint32Value();
924
if (offset >= buf->length()) {
925
return ThrowException(Exception::Error(
926
String::New("Offset into buffer too large")));
930
size_t length = buf->length() - offset;
931
if (args.Length() >= 4 && !args[3]->IsUndefined()) {
932
if (!args[3]->IsUint32()) {
933
return ThrowException(Exception::TypeError(
934
String::New("Expected unsigned integer for length")));
937
length = args[3]->Uint32Value();
938
if (offset + length > buf->length()) {
939
return ThrowException(Exception::Error(
940
String::New("offset + length beyond buffer length")));
945
if (args.Length() >= 5 && !args[4]->IsUndefined()) {
946
if (!args[4]->IsUint32()) {
947
return ThrowException(Exception::TypeError(
948
String::New("Expected unsigned integer for a flags argument")));
951
flags = args[4]->Uint32Value();
954
Handle<Value> error = ParseAddressArgs(args[5], args[6], false);
955
if (!error.IsEmpty()) return ThrowException(error);
957
ssize_t written = sendto(fd, buf->data() + offset, length, flags, addr, addrlen);
687
959
if (written < 0) {
688
960
if (errno == EAGAIN || errno == EINTR) return Null();
761
1032
return Undefined();
1035
static Handle<Value> SetBroadcast(const Arguments& args) {
1041
flags = args[1]->IsFalse() ? 0 : 1;
1042
r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void *)&flags, sizeof(flags));
1045
return ThrowException(ErrnoException(errno, "setsockopt"));
1047
return scope.Close(Integer::New(flags));
1051
static Handle<Value> SetTTL(const Arguments& args) {
1054
if (args.Length() != 2) {
1055
return ThrowException(Exception::TypeError(
1056
String::New("Takes exactly two arguments: fd, new TTL")));
1061
if (! args[1]->IsInt32()) {
1062
return ThrowException(Exception::TypeError(
1063
String::New("Argument must be a number")));
1066
int newttl = args[1]->Int32Value();
1067
if (newttl < 1 || newttl > 255) {
1068
return ThrowException(Exception::TypeError(
1069
String::New("new TTL must be between 1 and 255")));
1072
int r = setsockopt(fd, IPPROTO_IP, IP_TTL, (void *)&newttl, sizeof(newttl));
1075
return ThrowException(ErrnoException(errno, "setsockopt"));
1077
return scope.Close(Integer::New(newttl));
1083
// G E T A D D R I N F O
1087
struct resolve_request {
1088
Persistent<Function> cb;
1089
struct addrinfo *address_list;
1090
int ai_family; // AF_INET or AF_INET6
1094
#ifndef EAI_NODATA // EAI_NODATA is deprecated, FreeBSD already thrown it away in favor of EAI_NONAME
1095
#define EAI_NODATA EAI_NONAME
1098
static int AfterResolve(eio_req *req) {
1099
ev_unref(EV_DEFAULT_UC);
1101
struct resolve_request * rreq = (struct resolve_request *)(req->data);
1104
Local<Value> argv[2];
1106
if (req->result != 0) {
1107
argv[1] = Array::New();
1108
if (req->result == EAI_NODATA) {
1109
argv[0] = Local<Value>::New(Null());
1111
argv[0] = ErrnoException(req->result,
1113
gai_strerror(req->result));
1116
struct addrinfo *address;
1119
for (address = rreq->address_list; address; address = address->ai_next) { n++; }
1121
Local<Array> results = Array::New(n);
1123
char ip[INET6_ADDRSTRLEN];
1127
address = rreq->address_list;
1129
assert(address->ai_socktype == SOCK_STREAM);
1130
assert(address->ai_family == AF_INET || address->ai_family == AF_INET6);
1131
addr = ( address->ai_family == AF_INET
1132
? (char *) &((struct sockaddr_in *) address->ai_addr)->sin_addr
1133
: (char *) &((struct sockaddr_in6 *) address->ai_addr)->sin6_addr
1135
const char *c = inet_ntop(address->ai_family, addr, ip, INET6_ADDRSTRLEN);
1136
Local<String> s = String::New(c);
1137
results->Set(Integer::New(n), s);
1140
address = address->ai_next;
1143
argv[0] = Local<Value>::New(Null());
1149
rreq->cb->Call(Context::GetCurrent()->Global(), 2, argv);
1151
if (try_catch.HasCaught()) {
1152
FatalException(try_catch);
1155
if (rreq->address_list) freeaddrinfo(rreq->address_list);
1156
rreq->cb.Dispose(); // Dispose of the persistent handle
1163
static int Resolve(eio_req *req) {
1164
// Note: this function is executed in the thread pool! CAREFUL
1165
struct resolve_request * rreq = (struct resolve_request *) req->data;
1167
struct addrinfo hints;
1168
memset(&hints, 0, sizeof(struct addrinfo));
1169
hints.ai_family = rreq->ai_family;
1170
hints.ai_socktype = SOCK_STREAM;
1172
req->result = getaddrinfo((char*)rreq->hostname,
1175
&(rreq->address_list));
1180
static Handle<Value> GetAddrInfo(const Arguments& args) {
1183
String::Utf8Value hostname(args[0]->ToString());
1185
int type = args[1]->Int32Value();
1195
return ThrowException(Exception::TypeError(
1196
String::New("Second argument must be an integer 4 or 6")));
1199
if (!args[2]->IsFunction()) {
1200
return ThrowException(Exception::TypeError(
1201
String::New("Thrid argument must be a callback")));
1204
Local<Function> cb = Local<Function>::Cast(args[2]);
1206
struct resolve_request *rreq = (struct resolve_request *)
1207
calloc(1, sizeof(struct resolve_request) + hostname.length() + 1);
1210
V8::LowMemoryNotification();
1211
return ThrowException(Exception::Error(
1212
String::New("Could not allocate enough memory")));
1215
strncpy(rreq->hostname, *hostname, hostname.length() + 1);
1216
rreq->cb = Persistent<Function>::New(cb);
1217
rreq->ai_family = fam;
1219
// For the moment I will do DNS lookups in the eio thread pool. This is
1220
// sub-optimal and cannot handle massive numbers of requests.
1222
// (One particularly annoying problem is that the pthread stack size needs
1223
// to be increased dramatically to handle getaddrinfo() see X_STACKSIZE in
1226
// In the future I will move to a system using c-ares:
1227
// http://lists.schmorp.de/pipermail/libev/2009q1/000632.html
1228
eio_custom(Resolve, EIO_PRI_DEFAULT, AfterResolve, rreq);
1230
// There will not be any active watchers from this object on the event
1231
// loop while getaddrinfo() runs. If the only thing happening in the
1232
// script was this hostname resolution, then the event loop would drop
1233
// out. Thus we need to add ev_ref() until AfterResolve().
1234
ev_ref(EV_DEFAULT_UC);
765
1240
static Handle<Value> IsIP(const Arguments& args) {
766
1241
HandleScope scope;
768
1243
if (!args[0]->IsString()) {
769
1244
return scope.Close(Integer::New(4));