Make Socket, Bind, Listen, Accept work for windows
authorBert Belder <bertbelder@gmail.com>
Thu, 25 Nov 2010 04:05:35 +0000 (05:05 +0100)
committerBert Belder <bertbelder@gmail.com>
Mon, 20 Dec 2010 22:51:11 +0000 (23:51 +0100)
src/node_net.cc

index bafae4b..b803fd3 100644 (file)
@@ -13,6 +13,7 @@
 
 #ifdef __MINGW32__
 # include <winsock2.h>
+# include <ws2tcpip.h>
 
 #else // __POSIX__
 # include <sys/ioctl.h>
@@ -162,6 +163,8 @@ static Handle<Value> SocketPair(const Arguments& args) {
   return scope.Close(a);
 }
 
+#endif
+
 
 // Creates a new non-blocking socket fd
 // t.socket("TCP");
@@ -219,7 +222,11 @@ static Handle<Value> Socket(const Arguments& args) {
     }
   }
 
+#ifdef __POSIX__
   int fd = socket(domain, type, 0);
+#else // __MINGW32__
+  int fd = _open_osfhandle(socket(domain, type, 0), 0);
+#endif
 
   if (fd < 0) return ThrowException(ErrnoException(errno, "socket"));
 
@@ -250,10 +257,15 @@ static socklen_t addrlen;
 static inline Handle<Value> ParseAddressArgs(Handle<Value> first,
                                              Handle<Value> second,
                                              bool is_bind) {
+#ifdef __POSIX__ // No unix sockets on windows
   static struct sockaddr_un un;
+#endif
   static struct sockaddr_in in;
   static struct sockaddr_in6 in6;
 
+#ifdef __POSIX__ // No unix sockets on windows
+  static struct sockaddr_un un;
+
   if (first->IsString() && !second->IsString()) {
     // UNIX
     String::Utf8Value path(first->ToString());
@@ -270,6 +282,11 @@ static inline Handle<Value> ParseAddressArgs(Handle<Value> first,
     addrlen = sizeof(un) - sizeof(un.sun_path) + path.length() + 1;
 
   } else {
+#else // __MINGW32__
+  if (first->IsString() && !second->IsString()) {
+    return ErrnoException(errno, "ParseAddressArgs", "Unix sockets are not supported on windows");
+  } else {
+#endif
     // TCP or UDP
     memset(&in, 0, sizeof in);
     memset(&in6, 0, sizeof in6);
@@ -321,9 +338,13 @@ static Handle<Value> Bind(const Arguments& args) {
   if (!error.IsEmpty()) return ThrowException(error);
 
   int flags = 1;
+#ifdef __POSIX__
   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
-
   int r = bind(fd, addr, addrlen);
+#else // __MINGW32__
+  setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&flags, sizeof(flags));
+  int r = bind(_get_osfhandle(fd), addr, addrlen);
+#endif
 
   if (r < 0) {
     return ThrowException(ErrnoException(errno, "bind"));
@@ -332,8 +353,6 @@ static Handle<Value> Bind(const Arguments& args) {
   return Undefined();
 }
 
-#endif // __POSIX__
-
 
 static Handle<Value> Close(const Arguments& args) {
   HandleScope scope;
@@ -414,6 +433,11 @@ static Handle<Value> Connect(const Arguments& args) {
   return Undefined();
 }
 
+#endif // __POSIX__
+
+
+#ifdef __POSIX__
+
 #define ADDRESS_TO_JS(info, address_storage) \
 do { \
   char ip[INET6_ADDRSTRLEN]; \
@@ -445,6 +469,37 @@ do { \
   } \
 } while (0)
 
+#else // __MINGW32__
+
+#define ADDRESS_TO_JS(info, address_storage) \
+do { \
+  char ip[INET6_ADDRSTRLEN]; \
+  int port; \
+  struct sockaddr_in *a4; \
+  struct sockaddr_in6 *a6; \
+  switch ((address_storage).ss_family) { \
+    case AF_INET6: \
+      a6 = (struct sockaddr_in6*)&(address_storage); \
+      inet_ntop(AF_INET6, &(a6->sin6_addr), ip, INET6_ADDRSTRLEN); \
+      port = ntohs(a6->sin6_port); \
+      (info)->Set(address_symbol, String::New(ip)); \
+      (info)->Set(port_symbol, Integer::New(port)); \
+      break; \
+    case AF_INET: \
+      a4 = (struct sockaddr_in*)&(address_storage); \
+      inet_ntop(AF_INET, &(a4->sin_addr), ip, INET6_ADDRSTRLEN); \
+      port = ntohs(a4->sin_port); \
+      (info)->Set(address_symbol, String::New(ip)); \
+      (info)->Set(port_symbol, Integer::New(port)); \
+      break; \
+    default: \
+      (info)->Set(address_symbol, String::Empty()); \
+  } \
+} while (0)
+
+#endif // __MINGW32__
+
+#ifdef __POSIX__
 
 static Handle<Value> GetSockName(const Arguments& args) {
   HandleScope scope;
@@ -489,6 +544,8 @@ static Handle<Value> GetPeerName(const Arguments& args) {
   return scope.Close(info);
 }
 
+#endif // __POSIX__
+
 
 static Handle<Value> Listen(const Arguments& args) {
   HandleScope scope;
@@ -496,7 +553,7 @@ static Handle<Value> Listen(const Arguments& args) {
   FD_ARG(args[0])
   int backlog = args[1]->IsInt32() ? args[1]->Int32Value() : 128;
 
-  if (0 > listen(fd, backlog)) {
+  if (0 > listen(_get_osfhandle(fd), backlog)) {
     return ThrowException(ErrnoException(errno, "listen"));
   }
 
@@ -522,12 +579,23 @@ static Handle<Value> Accept(const Arguments& args) {
   struct sockaddr_storage address_storage;
   socklen_t len = sizeof(struct sockaddr_storage);
 
+#ifdef __POSIX__
   int peer_fd = accept(fd, (struct sockaddr*) &address_storage, &len);
 
   if (peer_fd < 0) {
     if (errno == EAGAIN) return scope.Close(Null());
     return ThrowException(ErrnoException(errno, "accept"));
   }
+#else // __MINGW32__
+  int peer_handle = accept(_get_osfhandle(fd), (struct sockaddr*) &address_storage, &len);
+
+  if (peer_handle == INVALID_SOCKET) {
+     if (WSAGetLastError() == WSAEWOULDBLOCK) return scope.Close(Null());
+    return ThrowException(ErrnoException(errno, "accept"));
+  }
+
+  int peer_fd = _open_osfhandle(peer_handle, 0);
+#endif // __MINGW32__
 
   if (!SetSockFlags(peer_fd)) {
     int fcntl_errno = errno;
@@ -545,6 +613,8 @@ static Handle<Value> Accept(const Arguments& args) {
 }
 
 
+#ifdef __POSIX__
+
 static Handle<Value> SocketError(const Arguments& args) {
   HandleScope scope;
 
@@ -1352,10 +1422,9 @@ void InitNet(Handle<Object> target) {
   recv_msg_template =
       Persistent<FunctionTemplate>::New(FunctionTemplate::New(RecvMsg));
   target->Set(String::NewSymbol("recvMsg"), recv_msg_template->GetFunction());
-
-  NODE_SET_METHOD(target, "socket", Socket);
 #endif //__POSIX__
 
+  NODE_SET_METHOD(target, "socket", Socket);
   NODE_SET_METHOD(target, "close", Close);
 
 #ifdef __POSIX__
@@ -1364,9 +1433,13 @@ void InitNet(Handle<Object> target) {
   NODE_SET_METHOD(target, "socketpair", SocketPair);
 
   NODE_SET_METHOD(target, "connect", Connect);
+#endif // __POSIX__
+
   NODE_SET_METHOD(target, "bind", Bind);
   NODE_SET_METHOD(target, "listen", Listen);
   NODE_SET_METHOD(target, "accept", Accept);
+
+#ifdef __POSIX__
   NODE_SET_METHOD(target, "socketError", SocketError);
   NODE_SET_METHOD(target, "toRead", ToRead);
   NODE_SET_METHOD(target, "setNoDelay", SetNoDelay);