~ubuntu-branches/ubuntu/precise/nodejs/precise

« back to all changes in this revision

Viewing changes to src/node_net.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jérémy Lal
  • Date: 2010-08-20 11:49:04 UTC
  • mfrom: (7.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100820114904-lz22w6fkth7yh179
Tags: 0.2.0-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
#include <fcntl.h>
15
15
#include <arpa/inet.h> /* inet_pton */
16
16
 
 
17
#include <netdb.h>
 
18
 
17
19
#include <netinet/in.h>
18
20
#include <netinet/tcp.h>
19
21
 
33
35
#include <sys/uio.h>
34
36
#endif
35
37
 
 
38
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
39
 
36
40
 
37
41
namespace node {
38
42
 
42
46
static Persistent<String> syscall_symbol;
43
47
 
44
48
static Persistent<String> fd_symbol;
 
49
static Persistent<String> size_symbol;
45
50
static Persistent<String> address_symbol;
46
51
static Persistent<String> port_symbol;
47
52
static Persistent<String> type_symbol;
58
63
          String::New("Bad file descriptor argument"))); \
59
64
  }
60
65
 
61
 
 
62
 
 
63
66
static inline bool SetCloseOnExec(int fd) {
64
67
  return (fcntl(fd, F_SETFD, FD_CLOEXEC) != -1);
65
68
}
71
74
 
72
75
 
73
76
static inline bool SetSockFlags(int fd) {
 
77
  int flags = 1;
 
78
  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
74
79
  return SetNonBlock(fd) && SetCloseOnExec(fd);
75
80
}
76
81
 
131
136
  // default to TCP
132
137
  int domain = PF_INET;
133
138
  int type = SOCK_STREAM;
 
139
#ifdef SO_REUSEPORT
 
140
  bool set_reuseport = false;
 
141
#endif
134
142
 
135
143
  if (args[0]->IsString()) {
136
144
    String::Utf8Value t(args[0]->ToString());
147
155
    } else if (0 == strcasecmp(*t, "UNIX")) {
148
156
      domain = PF_UNIX;
149
157
      type = SOCK_STREAM;
 
158
    } else if (0 == strcasecmp(*t, "UNIX_DGRAM")) {
 
159
      domain = PF_UNIX;
 
160
      type = SOCK_DGRAM;
150
161
    } else if (0 == strcasecmp(*t, "UDP")) {
 
162
      domain = PF_INET;
 
163
      type = SOCK_DGRAM;
 
164
#ifdef SO_REUSEPORT
 
165
      set_reuseport = true;
 
166
#endif
 
167
    } else if (0 == strcasecmp(*t, "UDP4")) {
 
168
      domain = PF_INET;
 
169
      type = SOCK_DGRAM;
 
170
#ifdef SO_REUSEPORT
 
171
      set_reuseport = true;
 
172
#endif
 
173
    } else if (0 == strcasecmp(*t, "UDP6")) {
151
174
      domain = PF_INET6;
152
175
      type = SOCK_DGRAM;
 
176
#ifdef SO_REUSEPORT
 
177
      set_reuseport = true;
 
178
#endif
153
179
    } else {
154
180
      return ThrowException(Exception::Error(
155
181
            String::New("Unknown socket type.")));
166
192
    return ThrowException(ErrnoException(fcntl_errno, "fcntl"));
167
193
  }
168
194
 
 
195
#ifdef SO_REUSEPORT
 
196
  // needed for datagrams to be able to have multiple processes listening to
 
197
  // e.g. broadcasted datagrams.
 
198
  if (set_reuseport) {
 
199
    int flags = 1;
 
200
    setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const char *)&flags,
 
201
               sizeof(flags));
 
202
  }
 
203
#endif
 
204
 
169
205
  return scope.Close(Integer::New(fd));
170
206
}
171
207
 
185
221
    // UNIX
186
222
    String::Utf8Value path(first->ToString());
187
223
 
188
 
    if (path.length() > sizeof un.sun_path) {
 
224
    if ((size_t) path.length() >= ARRAY_SIZE(un.sun_path)) {
189
225
      return Exception::Error(String::New("Socket path too long"));
190
226
    }
191
227
 
192
228
    memset(&un, 0, sizeof un);
193
229
    un.sun_family = AF_UNIX;
194
 
    strcpy(un.sun_path, *path);
 
230
    memcpy(un.sun_path, *path, path.length());
195
231
 
196
232
    addr = (struct sockaddr*)&un;
197
 
    addrlen = path.length() + sizeof(un.sun_family) + 1;
 
233
    addrlen = sizeof(un) - sizeof(un.sun_path) + path.length() + 1;
198
234
 
199
235
  } else {
200
236
    // TCP or UDP
202
238
    memset(&in6, 0, sizeof in6);
203
239
 
204
240
    int port = first->Int32Value();
205
 
    in.sin_port = in6.sin6_port = htons(port);  
 
241
    in.sin_port = in6.sin6_port = htons(port);
206
242
    in.sin_family = AF_INET;
207
243
    in6.sin6_family = AF_INET6;
208
244
 
229
265
}
230
266
 
231
267
 
232
 
// Bind with UNIX 
 
268
// Bind with UNIX
233
269
//   t.bind(fd, "/tmp/socket")
234
270
// Bind with TCP
235
271
//   t.bind(fd, 80, "192.168.11.2")
336
372
  return Undefined();
337
373
}
338
374
 
339
 
 
340
375
#define ADDRESS_TO_JS(info, address_storage) \
341
376
do { \
342
377
  char ip[INET6_ADDRSTRLEN]; \
343
378
  int port; \
344
379
  struct sockaddr_in *a4; \
345
380
  struct sockaddr_in6 *a6; \
 
381
  struct sockaddr_un *au; \
346
382
  switch ((address_storage).ss_family) { \
347
383
    case AF_INET6: \
348
384
      a6 = (struct sockaddr_in6*)&(address_storage); \
358
394
      (info)->Set(address_symbol, String::New(ip)); \
359
395
      (info)->Set(port_symbol, Integer::New(port)); \
360
396
      break; \
 
397
    case AF_UNIX: \
 
398
      au = (struct sockaddr_un*)&(address_storage); \
 
399
      (info)->Set(address_symbol, String::New(au->sun_path)); \
 
400
      break; \
 
401
    default: \
 
402
      (info)->Set(address_symbol, String::Empty()); \
361
403
  } \
362
404
} while (0)
363
405
 
474
516
    return ThrowException(ErrnoException(errno, "getsockopt"));
475
517
  }
476
518
 
477
 
  return scope.Close(Integer::New(error)); 
 
519
  return scope.Close(Integer::New(error));
478
520
}
479
521
 
480
522
 
520
562
  return scope.Close(Integer::New(bytes_read));
521
563
}
522
564
 
 
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) {
 
572
  HandleScope scope;
 
573
 
 
574
  if (args.Length() < 5) {
 
575
    return ThrowException(Exception::TypeError(
 
576
          String::New("Takes 5 parameters")));
 
577
  }
 
578
 
 
579
  FD_ARG(args[0])
 
580
 
 
581
  if (!Buffer::HasInstance(args[1])) {
 
582
    return ThrowException(Exception::TypeError(
 
583
          String::New("Second argument should be a buffer")));
 
584
  }
 
585
 
 
586
  Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
 
587
 
 
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")));
 
592
  }
 
593
 
 
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")));
 
598
  }
 
599
 
 
600
  int flags = args[4]->Int32Value();
 
601
 
 
602
  struct sockaddr_storage address_storage;
 
603
  socklen_t addrlen = sizeof(struct sockaddr_storage);
 
604
 
 
605
  ssize_t bytes_read = recvfrom(fd, (char*)buffer->data() + off, len, flags,
 
606
                                (struct sockaddr*) &address_storage, &addrlen);
 
607
 
 
608
  if (bytes_read < 0) {
 
609
    if (errno == EAGAIN || errno == EINTR) return Null();
 
610
    return ThrowException(ErrnoException(errno, "read"));
 
611
  }
 
612
 
 
613
  Local<Object> info = Object::New();
 
614
 
 
615
  info->Set(size_symbol, Integer::New(bytes_read));
 
616
 
 
617
  ADDRESS_TO_JS(info, address_storage);
 
618
 
 
619
  return scope.Close(info);
 
620
}
 
621
 
523
622
 
524
623
// bytesRead = t.recvMsg(fd, buffer, offset, length)
525
624
// if (recvMsg.fd) {
554
653
          String::New("Length is extends beyond buffer")));
555
654
  }
556
655
 
557
 
  int received_fd;
558
 
 
559
656
  struct iovec iov[1];
560
657
  iov[0].iov_base = (char*)buffer->data() + off;
561
658
  iov[0].iov_len = len;
562
659
 
563
660
  struct msghdr msg;
 
661
  msg.msg_flags = 0;
564
662
  msg.msg_iov = iov;
565
663
  msg.msg_iovlen = 1;
566
664
  msg.msg_name = NULL;
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().
586
 
 
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));
591
 
  } else {
592
 
    recv_msg_template->GetFunction()->Set(fd_symbol, Null());
 
684
  //
 
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.
 
689
 
 
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);
 
697
      }
 
698
 
 
699
      received_fd = *(int *) CMSG_DATA(cmsg);
 
700
    } else {
 
701
      fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
 
702
        cmsg->cmsg_type
 
703
      );
 
704
    }
593
705
  }
594
706
 
 
707
  recv_msg_template->GetFunction()->Set(
 
708
    fd_symbol,
 
709
    (received_fd != -1) ?
 
710
      Integer::New(received_fd) :
 
711
      Null()
 
712
  );
 
713
 
595
714
  return scope.Close(Integer::New(bytes_read));
596
715
}
597
716
 
608
727
 
609
728
  FD_ARG(args[0])
610
729
 
611
 
  if (!Buffer::HasInstance(args[1])) { 
 
730
  if (!Buffer::HasInstance(args[1])) {
612
731
    return ThrowException(Exception::TypeError(
613
732
          String::New("Second argument should be a buffer")));
614
733
  }
640
759
}
641
760
 
642
761
 
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);
 
763
//
 
764
// Write a buffer with optional offset and length to the given file
 
765
// descriptor. Note that we refuse to send 0 bytes.
 
766
//
 
767
// The 'fd' parameter is a numerical file descriptor, or the undefined value
 
768
// to send none.
 
769
//
 
770
// The 'flags' parameter is a number representing a bitmask of MSG_* values.
 
771
// This is passed directly to sendmsg().
 
772
//
 
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;
647
776
 
 
777
  struct iovec iov;
 
778
 
648
779
  if (args.Length() < 2) {
649
780
    return ThrowException(Exception::TypeError(
650
781
          String::New("Takes 2 parameters")));
651
782
  }
652
783
 
 
784
  // The first argument should be a file descriptor
653
785
  FD_ARG(args[0])
654
786
 
655
 
  // TODO: make sure fd is a unix domain socket?
656
 
 
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")));
660
 
  }
661
 
 
662
 
  int fd_to_send = args[1]->Int32Value();
 
790
      String::New("Expected either a string or a buffer")));
 
791
  }
 
792
 
 
793
  Buffer *buf = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
 
794
 
 
795
  size_t offset = 0;
 
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")));
 
800
    }
 
801
 
 
802
    offset = args[2]->Uint32Value();
 
803
    if (offset >= buf->length()) {
 
804
      return ThrowException(Exception::Error(
 
805
        String::New("Offset into buffer too large")));
 
806
    }
 
807
  }
 
808
 
 
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")));
 
814
    }
 
815
 
 
816
    length = args[3]->Uint32Value();
 
817
    if (offset + length > buf->length()) {
 
818
      return ThrowException(Exception::Error(
 
819
        String::New("offset + length beyond buffer length")));
 
820
    }
 
821
  }
 
822
 
 
823
  iov.iov_base = buf->data() + offset;
 
824
  iov.iov_len = length;
 
825
 
 
826
  int fd_to_send = -1;
 
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")));
 
831
    }
 
832
 
 
833
    fd_to_send = args[4]->Uint32Value();
 
834
  }
 
835
 
 
836
  int flags = 0;
 
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")));
 
841
    }
 
842
 
 
843
    flags = args[5]->Uint32Value();
 
844
  }
663
845
 
664
846
  struct msghdr msg;
665
 
  struct iovec iov[1];
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
 
847
  char scratch[64];
669
848
 
670
 
  iov[0].iov_base = &dummy;
671
 
  iov[0].iov_len = 1;
672
 
  msg.msg_iov = iov;
 
849
  msg.msg_iov = &iov;
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;
684
 
 
685
 
  ssize_t written = sendmsg(fd, &msg, 0);
 
854
  msg.msg_control = NULL;
 
855
  msg.msg_controllen = 0;
 
856
 
 
857
  if (fd_to_send >= 0) {
 
858
    struct cmsghdr *cmsg;
 
859
 
 
860
    msg.msg_control = (void *) scratch;
 
861
    msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send));
 
862
 
 
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;
 
868
  }
 
869
 
 
870
  ssize_t written = sendmsg(fd, &msg, flags);
 
871
 
 
872
  if (written < 0) {
 
873
    if (errno == EAGAIN || errno == EINTR) return Null();
 
874
    return ThrowException(ErrnoException(errno, "sendmsg"));
 
875
  }
 
876
 
 
877
  /* Note that the FD isn't explicitly closed here, this
 
878
   * happens in the JS */
 
879
 
 
880
  return scope.Close(Integer::New(written));
 
881
}
 
882
 
 
883
// var bytes = sendto(fd, buf, off, len, flags, destination port, desitnation address);
 
884
//
 
885
// Write a buffer with optional offset and length to the given file
 
886
// descriptor. Note that we refuse to send 0 bytes.
 
887
//
 
888
// The 'fd' parameter is a numerical file descriptor, or the undefined value
 
889
// to send none.
 
890
//
 
891
// The 'flags' parameter is a number representing a bitmask of MSG_* values.
 
892
// This is passed directly to sendmsg().
 
893
//
 
894
// The destination port can either be an int port, or a path.
 
895
//
 
896
// Returns null on EAGAIN or EINTR, raises an exception on all other errors
 
897
static Handle<Value> SendTo(const Arguments& args) {
 
898
  HandleScope scope;
 
899
 
 
900
  if (args.Length() < 5) {
 
901
    return ThrowException(Exception::TypeError(
 
902
          String::New("Takes 5 or 6 parameters")));
 
903
  }
 
904
 
 
905
  // The first argument should be a file descriptor
 
906
  FD_ARG(args[0])
 
907
 
 
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")));
 
912
  }
 
913
 
 
914
  Buffer *buf = ObjectWrap::Unwrap<Buffer>(args[1]->ToObject());
 
915
 
 
916
  size_t offset = 0;
 
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")));
 
921
    }
 
922
 
 
923
    offset = args[2]->Uint32Value();
 
924
    if (offset >= buf->length()) {
 
925
      return ThrowException(Exception::Error(
 
926
        String::New("Offset into buffer too large")));
 
927
    }
 
928
  }
 
929
 
 
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")));
 
935
    }
 
936
 
 
937
    length = args[3]->Uint32Value();
 
938
    if (offset + length > buf->length()) {
 
939
      return ThrowException(Exception::Error(
 
940
        String::New("offset + length beyond buffer length")));
 
941
    }
 
942
  }
 
943
 
 
944
  int flags = 0;
 
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")));
 
949
    }
 
950
 
 
951
    flags = args[4]->Uint32Value();
 
952
  }
 
953
 
 
954
  Handle<Value> error = ParseAddressArgs(args[5], args[6], false);
 
955
  if (!error.IsEmpty()) return ThrowException(error);
 
956
 
 
957
  ssize_t written = sendto(fd, buf->data() + offset, length, flags, addr, addrlen);
686
958
 
687
959
  if (written < 0) {
688
960
    if (errno == EAGAIN || errno == EINTR) return Null();
729
1001
  return Undefined();
730
1002
}
731
1003
 
732
 
 
733
1004
static Handle<Value> SetKeepAlive(const Arguments& args) {
734
1005
  int r;
735
1006
  HandleScope scope;
761
1032
  return Undefined();
762
1033
}
763
1034
 
 
1035
static Handle<Value> SetBroadcast(const Arguments& args) {
 
1036
  int flags, r;
 
1037
  HandleScope scope;
 
1038
 
 
1039
  FD_ARG(args[0])
 
1040
 
 
1041
  flags = args[1]->IsFalse() ? 0 : 1;
 
1042
  r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void *)&flags, sizeof(flags));
 
1043
 
 
1044
  if (r < 0) {
 
1045
    return ThrowException(ErrnoException(errno, "setsockopt"));
 
1046
  } else {
 
1047
    return scope.Close(Integer::New(flags));
 
1048
  }
 
1049
}
 
1050
 
 
1051
static Handle<Value> SetTTL(const Arguments& args) {
 
1052
  HandleScope scope;
 
1053
 
 
1054
  if (args.Length() != 2) {
 
1055
    return ThrowException(Exception::TypeError(
 
1056
      String::New("Takes exactly two arguments: fd, new TTL")));
 
1057
  }
 
1058
 
 
1059
  FD_ARG(args[0]);
 
1060
 
 
1061
  if (! args[1]->IsInt32()) {
 
1062
    return ThrowException(Exception::TypeError(
 
1063
      String::New("Argument must be a number")));
 
1064
  }
 
1065
  
 
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")));
 
1070
  }
 
1071
 
 
1072
  int r = setsockopt(fd, IPPROTO_IP, IP_TTL, (void *)&newttl, sizeof(newttl));
 
1073
 
 
1074
  if (r < 0) {
 
1075
    return ThrowException(ErrnoException(errno, "setsockopt"));
 
1076
  } else {
 
1077
    return scope.Close(Integer::New(newttl));
 
1078
  }
 
1079
}
 
1080
 
 
1081
 
 
1082
//
 
1083
// G E T A D D R I N F O
 
1084
//
 
1085
 
 
1086
 
 
1087
struct resolve_request {
 
1088
  Persistent<Function> cb;
 
1089
  struct addrinfo *address_list;
 
1090
  int ai_family; // AF_INET or AF_INET6
 
1091
  char hostname[1];
 
1092
};
 
1093
 
 
1094
#ifndef EAI_NODATA // EAI_NODATA is deprecated, FreeBSD already thrown it away in favor of EAI_NONAME
 
1095
#define EAI_NODATA EAI_NONAME
 
1096
#endif
 
1097
 
 
1098
static int AfterResolve(eio_req *req) {
 
1099
  ev_unref(EV_DEFAULT_UC);
 
1100
 
 
1101
  struct resolve_request * rreq = (struct resolve_request *)(req->data);
 
1102
 
 
1103
  HandleScope scope;
 
1104
  Local<Value> argv[2];
 
1105
 
 
1106
  if (req->result != 0) {
 
1107
    argv[1] = Array::New();
 
1108
    if (req->result == EAI_NODATA) {
 
1109
      argv[0] = Local<Value>::New(Null());
 
1110
    } else {
 
1111
      argv[0] = ErrnoException(req->result,
 
1112
                               "getaddrinfo",
 
1113
                               gai_strerror(req->result));
 
1114
    }
 
1115
  } else {
 
1116
    struct addrinfo *address;
 
1117
    int n = 0;
 
1118
 
 
1119
    for (address = rreq->address_list; address; address = address->ai_next) { n++; }
 
1120
 
 
1121
    Local<Array> results = Array::New(n);
 
1122
 
 
1123
    char ip[INET6_ADDRSTRLEN];
 
1124
    const char *addr;
 
1125
 
 
1126
    n = 0;
 
1127
    address = rreq->address_list;
 
1128
    while (address) {
 
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
 
1134
             );
 
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);
 
1138
 
 
1139
      n++;
 
1140
      address = address->ai_next;
 
1141
    }
 
1142
 
 
1143
    argv[0] = Local<Value>::New(Null());
 
1144
    argv[1] = results;
 
1145
  }
 
1146
 
 
1147
  TryCatch try_catch;
 
1148
 
 
1149
  rreq->cb->Call(Context::GetCurrent()->Global(), 2, argv);
 
1150
 
 
1151
  if (try_catch.HasCaught()) {
 
1152
    FatalException(try_catch);
 
1153
  }
 
1154
 
 
1155
  if (rreq->address_list) freeaddrinfo(rreq->address_list);
 
1156
  rreq->cb.Dispose(); // Dispose of the persistent handle
 
1157
  free(rreq);
 
1158
 
 
1159
  return 0;
 
1160
}
 
1161
 
 
1162
 
 
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;
 
1166
 
 
1167
  struct addrinfo hints;
 
1168
  memset(&hints, 0, sizeof(struct addrinfo));
 
1169
  hints.ai_family = rreq->ai_family;
 
1170
  hints.ai_socktype = SOCK_STREAM;
 
1171
 
 
1172
  req->result = getaddrinfo((char*)rreq->hostname,
 
1173
                            NULL,
 
1174
                            &hints,
 
1175
                            &(rreq->address_list));
 
1176
  return 0;
 
1177
}
 
1178
 
 
1179
 
 
1180
static Handle<Value> GetAddrInfo(const Arguments& args) {
 
1181
  HandleScope scope;
 
1182
 
 
1183
  String::Utf8Value hostname(args[0]->ToString());
 
1184
 
 
1185
  int type = args[1]->Int32Value();
 
1186
  int fam = AF_INET;
 
1187
  switch (type) {
 
1188
    case 4:
 
1189
      fam = AF_INET;
 
1190
      break;
 
1191
    case 6:
 
1192
      fam = AF_INET6;
 
1193
      break;
 
1194
    default:
 
1195
      return ThrowException(Exception::TypeError(
 
1196
            String::New("Second argument must be an integer 4 or 6")));
 
1197
  }
 
1198
 
 
1199
  if (!args[2]->IsFunction()) {
 
1200
    return ThrowException(Exception::TypeError(
 
1201
          String::New("Thrid argument must be a callback")));
 
1202
  }
 
1203
 
 
1204
  Local<Function> cb = Local<Function>::Cast(args[2]);
 
1205
 
 
1206
  struct resolve_request *rreq = (struct resolve_request *)
 
1207
    calloc(1, sizeof(struct resolve_request) + hostname.length() + 1);
 
1208
 
 
1209
  if (!rreq) {
 
1210
    V8::LowMemoryNotification();
 
1211
    return ThrowException(Exception::Error(
 
1212
          String::New("Could not allocate enough memory")));
 
1213
  }
 
1214
 
 
1215
  strncpy(rreq->hostname, *hostname, hostname.length() + 1);
 
1216
  rreq->cb = Persistent<Function>::New(cb);
 
1217
  rreq->ai_family = fam;
 
1218
 
 
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.
 
1221
  //
 
1222
  // (One particularly annoying problem is that the pthread stack size needs
 
1223
  // to be increased dramatically to handle getaddrinfo() see X_STACKSIZE in
 
1224
  // wscript ).
 
1225
  //
 
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);
 
1229
 
 
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);
 
1235
 
 
1236
  return Undefined();
 
1237
}
 
1238
 
764
1239
 
765
1240
static Handle<Value> IsIP(const Arguments& args) {
766
1241
  HandleScope scope;
767
 
  
 
1242
 
768
1243
  if (!args[0]->IsString()) {
769
1244
    return scope.Close(Integer::New(4));
770
1245
  }
793
1268
  int errorno = args[0]->Int32Value();
794
1269
  String::Utf8Value syscall(args[1]->ToString());
795
1270
 
796
 
  Local<Value> exception = ErrnoException(errorno, *syscall); 
 
1271
  Local<Value> exception = ErrnoException(errorno, *syscall);
797
1272
 
798
1273
  return scope.Close(exception);
799
1274
}
805
1280
  NODE_SET_METHOD(target, "write", Write);
806
1281
  NODE_SET_METHOD(target, "read", Read);
807
1282
 
808
 
  NODE_SET_METHOD(target, "sendFD", SendFD);
 
1283
  NODE_SET_METHOD(target, "sendMsg", SendMsg);
 
1284
  NODE_SET_METHOD(target, "recvfrom", RecvFrom);
 
1285
  NODE_SET_METHOD(target, "sendto", SendTo);
809
1286
 
810
1287
  recv_msg_template =
811
1288
      Persistent<FunctionTemplate>::New(FunctionTemplate::New(RecvMsg));
824
1301
  NODE_SET_METHOD(target, "socketError", SocketError);
825
1302
  NODE_SET_METHOD(target, "toRead", ToRead);
826
1303
  NODE_SET_METHOD(target, "setNoDelay", SetNoDelay);
 
1304
  NODE_SET_METHOD(target, "setBroadcast", SetBroadcast);
 
1305
  NODE_SET_METHOD(target, "setTTL", SetTTL);
827
1306
  NODE_SET_METHOD(target, "setKeepAlive", SetKeepAlive);
828
1307
  NODE_SET_METHOD(target, "getsockname", GetSockName);
829
1308
  NODE_SET_METHOD(target, "getpeername", GetPeerName);
 
1309
  NODE_SET_METHOD(target, "getaddrinfo", GetAddrInfo);
830
1310
  NODE_SET_METHOD(target, "isIP", IsIP);
831
1311
  NODE_SET_METHOD(target, "errnoException", CreateErrnoException);
832
1312
 
842
1322
  errno_symbol          = NODE_PSYMBOL("errno");
843
1323
  syscall_symbol        = NODE_PSYMBOL("syscall");
844
1324
  fd_symbol             = NODE_PSYMBOL("fd");
 
1325
  size_symbol           = NODE_PSYMBOL("size");
845
1326
  address_symbol        = NODE_PSYMBOL("address");
846
1327
  port_symbol           = NODE_PSYMBOL("port");
847
1328
}
848
1329
 
849
1330
}  // namespace node
 
1331
 
 
1332
NODE_MODULE(node_net, node::InitNet);