eventmachine 1.0.9.1 → 1.2.0.dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/cmain.cpp +77 -5
  4. data/ext/ed.cpp +100 -39
  5. data/ext/ed.h +27 -13
  6. data/ext/em.cpp +105 -163
  7. data/ext/em.h +10 -7
  8. data/ext/eventmachine.h +13 -1
  9. data/ext/extconf.rb +22 -13
  10. data/ext/fastfilereader/rubymain.cpp +6 -6
  11. data/ext/project.h +9 -4
  12. data/ext/rubymain.cpp +155 -36
  13. data/ext/ssl.cpp +157 -13
  14. data/ext/ssl.h +7 -2
  15. data/lib/em/channel.rb +5 -0
  16. data/lib/em/completion.rb +2 -2
  17. data/lib/em/connection.rb +61 -3
  18. data/lib/em/iterator.rb +26 -5
  19. data/lib/em/pool.rb +1 -1
  20. data/lib/em/protocols/line_and_text.rb +1 -1
  21. data/lib/em/pure_ruby.rb +6 -1
  22. data/lib/em/queue.rb +16 -7
  23. data/lib/em/resolver.rb +46 -23
  24. data/lib/em/threaded_resource.rb +2 -2
  25. data/lib/em/version.rb +1 -1
  26. data/lib/eventmachine.rb +59 -42
  27. data/rakelib/package.rake +23 -1
  28. data/tests/dhparam.pem +13 -0
  29. data/tests/em_test_helper.rb +79 -0
  30. data/tests/test_basic.rb +17 -26
  31. data/tests/test_channel.rb +14 -1
  32. data/tests/test_connection_write.rb +2 -2
  33. data/tests/test_defer.rb +17 -0
  34. data/tests/test_epoll.rb +1 -1
  35. data/tests/test_fork.rb +75 -0
  36. data/tests/test_ipv4.rb +125 -0
  37. data/tests/test_ipv6.rb +131 -0
  38. data/tests/test_iterator.rb +18 -0
  39. data/tests/test_many_fds.rb +1 -1
  40. data/tests/test_queue.rb +14 -0
  41. data/tests/test_resolver.rb +23 -0
  42. data/tests/test_set_sock_opt.rb +2 -0
  43. data/tests/test_ssl_dhparam.rb +83 -0
  44. data/tests/test_ssl_ecdh_curve.rb +79 -0
  45. data/tests/test_ssl_extensions.rb +49 -0
  46. data/tests/test_ssl_methods.rb +19 -0
  47. data/tests/test_ssl_protocols.rb +246 -0
  48. data/tests/test_ssl_verify.rb +44 -0
  49. data/tests/test_system.rb +4 -0
  50. data/tests/test_unbind_reason.rb +5 -1
  51. metadata +116 -49
  52. data/.gitignore +0 -21
  53. data/.travis.yml +0 -22
  54. data/.yardopts +0 -7
  55. data/Gemfile +0 -2
  56. data/Rakefile +0 -20
  57. data/eventmachine.gemspec +0 -38
  58. data/rakelib/cpp.rake_example +0 -77
data/ext/em.cpp CHANGED
@@ -32,22 +32,15 @@ static unsigned int MaxOutstandingTimers = 100000;
32
32
  */
33
33
  static unsigned int SimultaneousAcceptCount = 10;
34
34
 
35
-
36
- /* Internal helper to convert strings to internet addresses. IPv6-aware.
37
- * Not reentrant or threadsafe, optimized for speed.
38
- */
39
- static struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size);
40
-
41
35
  /* Internal helper to create a socket with SOCK_CLOEXEC set, and fall
42
36
  * back to fcntl'ing it if the headers/runtime don't support it.
43
37
  */
44
-
45
- int EmSocket (int domain, int type, int protocol)
38
+ SOCKET EmSocket (int domain, int type, int protocol)
46
39
  {
47
- int sd;
40
+ SOCKET sd;
48
41
  #ifdef HAVE_SOCKET_CLOEXEC
49
42
  sd = socket (domain, type | SOCK_CLOEXEC, protocol);
50
- if (sd < 0) {
43
+ if (sd == INVALID_SOCKET) {
51
44
  sd = socket (domain, type, protocol);
52
45
  if (sd < 0) {
53
46
  return sd;
@@ -56,7 +49,7 @@ int EmSocket (int domain, int type, int protocol)
56
49
  }
57
50
  #else
58
51
  sd = socket (domain, type, protocol);
59
- if (sd < 0) {
52
+ if (sd == INVALID_SOCKET) {
60
53
  return sd;
61
54
  }
62
55
  SetFdCloexec(sd);
@@ -114,8 +107,8 @@ EventMachine_t::EventMachine_t (EMCallback event_callback, Poller_t poller):
114
107
  NumCloseScheduled (0),
115
108
  HeartbeatInterval(2000000),
116
109
  EventCallback (event_callback),
117
- LoopBreakerReader (-1),
118
- LoopBreakerWriter (-1),
110
+ LoopBreakerReader (INVALID_SOCKET),
111
+ LoopBreakerWriter (INVALID_SOCKET),
119
112
  bTerminateSignalReceived (false),
120
113
  Poller (poller),
121
114
  epfd (-1),
@@ -138,6 +131,11 @@ EventMachine_t::EventMachine_t (EMCallback event_callback, Poller_t poller):
138
131
  (void) mach_timebase_info(&mach_timebase);
139
132
  #endif
140
133
 
134
+ #ifdef OS_WIN32
135
+ TickCountTickover = 0;
136
+ LastTickCount = 0;
137
+ #endif
138
+
141
139
  // Make sure the current loop time is sane, in case we do any initializations of
142
140
  // objects before we start running.
143
141
  _UpdateTime();
@@ -217,7 +215,10 @@ void EventMachine_t::ScheduleHalt()
217
215
  SignalLoopBreaker();
218
216
  }
219
217
 
220
-
218
+ bool EventMachine_t::Stopping()
219
+ {
220
+ return bTerminateSignalReceived;
221
+ }
221
222
 
222
223
  /*******************************
223
224
  EventMachine_t::SetTimerQuantum
@@ -240,6 +241,7 @@ void EventMachine_t::SetTimerQuantum (int interval)
240
241
  (STATIC) EventMachine_t::SetuidString
241
242
  *************************************/
242
243
 
244
+ #ifdef OS_UNIX
243
245
  void EventMachine_t::SetuidString (const char *username)
244
246
  {
245
247
  /* This method takes a caller-supplied username and tries to setuid
@@ -256,7 +258,6 @@ void EventMachine_t::SetuidString (const char *username)
256
258
  * A setuid failure here would be in the latter category.
257
259
  */
258
260
 
259
- #ifdef OS_UNIX
260
261
  if (!username || !*username)
261
262
  throw std::runtime_error ("setuid_string failed: no username specified");
262
263
 
@@ -276,17 +277,18 @@ void EventMachine_t::SetuidString (const char *username)
276
277
  throw std::runtime_error ("setuid_string failed: no setuid");
277
278
 
278
279
  // Success.
279
- #endif
280
280
  }
281
-
281
+ #else
282
+ void EventMachine_t::SetuidString (const char *username UNUSED) { }
283
+ #endif
282
284
 
283
285
  /****************************************
284
286
  (STATIC) EventMachine_t::SetRlimitNofile
285
287
  ****************************************/
286
288
 
289
+ #ifdef OS_UNIX
287
290
  int EventMachine_t::SetRlimitNofile (int nofiles)
288
291
  {
289
- #ifdef OS_UNIX
290
292
  struct rlimit rlim;
291
293
  getrlimit (RLIMIT_NOFILE, &rlim);
292
294
  if (nofiles >= 0) {
@@ -299,14 +301,10 @@ int EventMachine_t::SetRlimitNofile (int nofiles)
299
301
  }
300
302
  getrlimit (RLIMIT_NOFILE, &rlim);
301
303
  return rlim.rlim_cur;
302
- #endif
303
-
304
- #ifdef OS_WIN32
305
- // No meaningful implementation on Windows.
306
- return 0;
307
- #endif
308
304
  }
309
-
305
+ #else
306
+ int EventMachine_t::SetRlimitNofile (int nofiles UNUSED) { return 0; }
307
+ #endif
310
308
 
311
309
  /*********************************
312
310
  EventMachine_t::SignalLoopBreaker
@@ -361,7 +359,7 @@ void EventMachine_t::_InitializeLoopBreaker()
361
359
  #endif
362
360
 
363
361
  #ifdef OS_WIN32
364
- int sd = EmSocket (AF_INET, SOCK_DGRAM, 0);
362
+ SOCKET sd = EmSocket (AF_INET, SOCK_DGRAM, 0);
365
363
  if (sd == INVALID_SOCKET)
366
364
  throw std::runtime_error ("no loop breaker socket");
367
365
  SetSocketNonblocking (sd);
@@ -914,7 +912,7 @@ SelectData_t::~SelectData_t()
914
912
  _SelectDataSelect
915
913
  *****************/
916
914
 
917
- #if defined(HAVE_TBR) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
915
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
918
916
  static VALUE _SelectDataSelect (void *v)
919
917
  {
920
918
  SelectData_t *sd = (SelectData_t*)v;
@@ -983,7 +981,7 @@ void EventMachine_t::_RunSelectOnce()
983
981
  for (i = 0; i < Descriptors.size(); i++) {
984
982
  EventableDescriptor *ed = Descriptors[i];
985
983
  assert (ed);
986
- int sd = ed->GetSocket();
984
+ SOCKET sd = ed->GetSocket();
987
985
  if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
988
986
  continue;
989
987
  assert (sd != INVALID_SOCKET);
@@ -1028,7 +1026,7 @@ void EventMachine_t::_RunSelectOnce()
1028
1026
  for (i=0; i < Descriptors.size(); i++) {
1029
1027
  EventableDescriptor *ed = Descriptors[i];
1030
1028
  assert (ed);
1031
- int sd = ed->GetSocket();
1029
+ SOCKET sd = ed->GetSocket();
1032
1030
  if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
1033
1031
  continue;
1034
1032
  assert (sd != INVALID_SOCKET);
@@ -1077,7 +1075,7 @@ void EventMachine_t::_CleanBadDescriptors()
1077
1075
  if (ed->ShouldDelete())
1078
1076
  continue;
1079
1077
 
1080
- int sd = ed->GetSocket();
1078
+ SOCKET sd = ed->GetSocket();
1081
1079
 
1082
1080
  struct timeval tv;
1083
1081
  tv.tv_sec = 0;
@@ -1194,16 +1192,15 @@ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind
1194
1192
  if (!server || !*server || !port)
1195
1193
  throw std::runtime_error ("invalid server or port");
1196
1194
 
1197
- int family, bind_size;
1198
- struct sockaddr_storage bind_as, *bind_as_ptr = (struct sockaddr_storage*)name2address (server, port, &family, &bind_size);
1199
- if (!bind_as_ptr) {
1195
+ struct sockaddr_storage bind_as;
1196
+ size_t bind_as_len = sizeof bind_as;
1197
+ if (!name2address (server, port, (struct sockaddr *)&bind_as, &bind_as_len)) {
1200
1198
  char buf [200];
1201
1199
  snprintf (buf, sizeof(buf)-1, "unable to resolve server address: %s", strerror(errno));
1202
1200
  throw std::runtime_error (buf);
1203
1201
  }
1204
- bind_as = *bind_as_ptr; // copy because name2address points to a static
1205
1202
 
1206
- int sd = EmSocket (family, SOCK_STREAM, 0);
1203
+ SOCKET sd = EmSocket (bind_as.ss_family, SOCK_STREAM, 0);
1207
1204
  if (sd == INVALID_SOCKET) {
1208
1205
  char buf [200];
1209
1206
  snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno));
@@ -1223,23 +1220,23 @@ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind
1223
1220
  setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
1224
1221
 
1225
1222
  if (bind_addr) {
1226
- int bind_to_size, bind_to_family;
1227
- struct sockaddr *bind_to = name2address (bind_addr, bind_port, &bind_to_family, &bind_to_size);
1228
- if (!bind_to) {
1223
+ struct sockaddr_storage bind_to;
1224
+ size_t bind_to_len = sizeof bind_to;
1225
+ if (!name2address (bind_addr, bind_port, (struct sockaddr *)&bind_to, &bind_to_len)) {
1229
1226
  close (sd);
1230
1227
  throw std::runtime_error ("invalid bind address");
1231
1228
  }
1232
- if (bind (sd, bind_to, bind_to_size) < 0) {
1229
+ if (bind (sd, (struct sockaddr *)&bind_to, bind_to_len) < 0) {
1233
1230
  close (sd);
1234
1231
  throw std::runtime_error ("couldn't bind to address");
1235
1232
  }
1236
1233
  }
1237
1234
 
1238
1235
  uintptr_t out = 0;
1239
- int e = 0;
1240
1236
 
1241
1237
  #ifdef OS_UNIX
1242
- if (connect (sd, (struct sockaddr*)&bind_as, bind_size) == 0) {
1238
+ int e_reason = 0;
1239
+ if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) {
1243
1240
  // This is a connect success, which Linux appears
1244
1241
  // never to give when the socket is nonblocking,
1245
1242
  // even if the connection is intramachine or to
@@ -1285,13 +1282,13 @@ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind
1285
1282
  out = cd->GetBinding();
1286
1283
  } else {
1287
1284
  // Fall through to the !out case below.
1288
- e = error;
1285
+ e_reason = error;
1289
1286
  }
1290
1287
  }
1291
1288
  else {
1292
1289
  // The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
1293
1290
  // Fall through to the !out case below
1294
- e = errno;
1291
+ e_reason = errno;
1295
1292
  }
1296
1293
 
1297
1294
  if (!out) {
@@ -1310,7 +1307,7 @@ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind
1310
1307
  ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1311
1308
  if (!cd)
1312
1309
  throw std::runtime_error ("no connection allocated");
1313
- cd->SetUnbindReasonCode(e);
1310
+ cd->SetUnbindReasonCode (e_reason);
1314
1311
  cd->ScheduleClose (false);
1315
1312
  Add (cd);
1316
1313
  out = cd->GetBinding();
@@ -1318,7 +1315,7 @@ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind
1318
1315
  #endif
1319
1316
 
1320
1317
  #ifdef OS_WIN32
1321
- if (connect (sd, (struct sockaddr*)&bind_as, bind_size) == 0) {
1318
+ if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) {
1322
1319
  // This is a connect success, which Windows appears
1323
1320
  // never to give when the socket is nonblocking,
1324
1321
  // even if the connection is intramachine or to
@@ -1353,6 +1350,7 @@ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind
1353
1350
  EventMachine_t::ConnectToUnixServer
1354
1351
  ***********************************/
1355
1352
 
1353
+ #ifdef OS_UNIX
1356
1354
  const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server)
1357
1355
  {
1358
1356
  /* Connect to a Unix-domain server, which by definition is running
@@ -1362,14 +1360,6 @@ const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server)
1362
1360
  * is always local and can always be fulfilled immediately.
1363
1361
  */
1364
1362
 
1365
- #ifdef OS_WIN32
1366
- throw std::runtime_error ("unix-domain connection unavailable on this platform");
1367
- return 0;
1368
- #endif
1369
-
1370
- // The whole rest of this function is only compiled on Unix systems.
1371
- #ifdef OS_UNIX
1372
-
1373
1363
  uintptr_t out = 0;
1374
1364
 
1375
1365
  if (!server || !*server)
@@ -1387,7 +1377,7 @@ const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server)
1387
1377
 
1388
1378
  strcpy (pun.sun_path, server);
1389
1379
 
1390
- int fd = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
1380
+ SOCKET fd = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
1391
1381
  if (fd == INVALID_SOCKET)
1392
1382
  return 0;
1393
1383
 
@@ -1419,14 +1409,19 @@ const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server)
1419
1409
  close (fd);
1420
1410
 
1421
1411
  return out;
1422
- #endif
1423
1412
  }
1413
+ #else
1414
+ const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server UNUSED)
1415
+ {
1416
+ throw std::runtime_error ("unix-domain connection unavailable on this platform");
1417
+ }
1418
+ #endif
1424
1419
 
1425
1420
  /************************
1426
1421
  EventMachine_t::AttachFD
1427
1422
  ************************/
1428
1423
 
1429
- const uintptr_t EventMachine_t::AttachFD (int fd, bool watch_mode)
1424
+ const uintptr_t EventMachine_t::AttachFD (SOCKET fd, bool watch_mode)
1430
1425
  {
1431
1426
  #ifdef OS_UNIX
1432
1427
  if (fcntl(fd, F_GETFL, 0) < 0) {
@@ -1487,7 +1482,7 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1487
1482
  if (!ed)
1488
1483
  throw std::runtime_error ("detaching bad descriptor");
1489
1484
 
1490
- int fd = ed->GetSocket();
1485
+ SOCKET fd = ed->GetSocket();
1491
1486
 
1492
1487
  #ifdef HAVE_EPOLL
1493
1488
  if (Poller == Poller_Epoll) {
@@ -1544,66 +1539,30 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1544
1539
  name2address
1545
1540
  ************/
1546
1541
 
1547
- struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size)
1542
+ bool EventMachine_t::name2address (const char *server, int port, struct sockaddr *addr, size_t *addr_len)
1548
1543
  {
1549
- // THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed.
1550
- // Check the more-common cases first.
1551
- // Return NULL if no resolution.
1552
-
1553
- static struct sockaddr_in in4;
1554
- #ifndef __CYGWIN__
1555
- static struct sockaddr_in6 in6;
1556
- #endif
1557
- struct hostent *hp;
1558
-
1559
1544
  if (!server || !*server)
1560
1545
  server = "0.0.0.0";
1561
1546
 
1562
- memset (&in4, 0, sizeof(in4));
1563
- if ( (in4.sin_addr.s_addr = inet_addr (server)) != INADDR_NONE) {
1564
- if (family)
1565
- *family = AF_INET;
1566
- if (bind_size)
1567
- *bind_size = sizeof(in4);
1568
- in4.sin_family = AF_INET;
1569
- in4.sin_port = htons (port);
1570
- return (struct sockaddr*)&in4;
1571
- }
1572
-
1573
- #if defined(OS_UNIX) && !defined(__CYGWIN__)
1574
- memset (&in6, 0, sizeof(in6));
1575
- if (inet_pton (AF_INET6, server, in6.sin6_addr.s6_addr) > 0) {
1576
- if (family)
1577
- *family = AF_INET6;
1578
- if (bind_size)
1579
- *bind_size = sizeof(in6);
1580
- in6.sin6_family = AF_INET6;
1581
- in6.sin6_port = htons (port);
1582
- return (struct sockaddr*)&in6;
1583
- }
1584
- #endif
1547
+ struct addrinfo *ai;
1548
+ struct addrinfo hints;
1549
+ memset (&hints, 0, sizeof(hints));
1550
+ hints.ai_family = AF_UNSPEC;
1551
+ hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
1585
1552
 
1586
- #ifdef OS_WIN32
1587
- // TODO, must complete this branch. Windows doesn't have inet_pton.
1588
- // A possible approach is to make a getaddrinfo call with the supplied
1589
- // server address, constraining the hints to ipv6 and seeing if we
1590
- // get any addresses.
1591
- // For the time being, Ipv6 addresses aren't supported on Windows.
1592
- #endif
1553
+ char portstr[12];
1554
+ snprintf(portstr, sizeof(portstr), "%u", port);
1555
+
1556
+ if (getaddrinfo (server, portstr, &hints, &ai) == 0) {
1557
+ assert (ai->ai_addrlen <= *addr_len);
1558
+ memcpy (addr, ai->ai_addr, ai->ai_addrlen);
1559
+ *addr_len = ai->ai_addrlen;
1593
1560
 
1594
- hp = gethostbyname ((char*)server); // Windows requires the cast.
1595
- if (hp) {
1596
- in4.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1597
- if (family)
1598
- *family = AF_INET;
1599
- if (bind_size)
1600
- *bind_size = sizeof(in4);
1601
- in4.sin_family = AF_INET;
1602
- in4.sin_port = htons (port);
1603
- return (struct sockaddr*)&in4;
1561
+ freeaddrinfo(ai);
1562
+ return true;
1604
1563
  }
1605
1564
 
1606
- return NULL;
1565
+ return false;
1607
1566
  }
1608
1567
 
1609
1568
 
@@ -1620,14 +1579,12 @@ const uintptr_t EventMachine_t::CreateTcpServer (const char *server, int port)
1620
1579
  */
1621
1580
 
1622
1581
 
1623
- int family, bind_size;
1624
- struct sockaddr *bind_here = name2address (server, port, &family, &bind_size);
1625
- if (!bind_here)
1582
+ struct sockaddr_storage bind_here;
1583
+ size_t bind_here_len = sizeof bind_here;
1584
+ if (!name2address (server, port, (struct sockaddr *)&bind_here, &bind_here_len))
1626
1585
  return 0;
1627
1586
 
1628
- //struct sockaddr_in sin;
1629
-
1630
- int sd_accept = EmSocket (family, SOCK_STREAM, 0);
1587
+ SOCKET sd_accept = EmSocket (bind_here.ss_family, SOCK_STREAM, 0);
1631
1588
  if (sd_accept == INVALID_SOCKET) {
1632
1589
  goto fail;
1633
1590
  }
@@ -1650,8 +1607,7 @@ const uintptr_t EventMachine_t::CreateTcpServer (const char *server, int port)
1650
1607
  }
1651
1608
 
1652
1609
 
1653
- //if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) {
1654
- if (bind (sd_accept, bind_here, bind_size)) {
1610
+ if (bind (sd_accept, (struct sockaddr *)&bind_here, bind_here_len)) {
1655
1611
  //__warning ("binding failed");
1656
1612
  goto fail;
1657
1613
  }
@@ -1678,40 +1634,27 @@ const uintptr_t EventMachine_t::OpenDatagramSocket (const char *address, int por
1678
1634
  {
1679
1635
  uintptr_t output_binding = 0;
1680
1636
 
1681
- int sd = EmSocket (AF_INET, SOCK_DGRAM, 0);
1637
+ struct sockaddr_storage bind_here;
1638
+ size_t bind_here_len = sizeof bind_here;
1639
+ if (!name2address (address, port, (struct sockaddr *)&bind_here, &bind_here_len))
1640
+ return 0;
1641
+
1642
+ // from here on, early returns must close the socket!
1643
+ SOCKET sd = EmSocket (bind_here.ss_family, SOCK_DGRAM, 0);
1682
1644
  if (sd == INVALID_SOCKET)
1683
1645
  goto fail;
1684
- // from here on, early returns must close the socket!
1685
-
1686
-
1687
- struct sockaddr_in sin;
1688
- memset (&sin, 0, sizeof(sin));
1689
- sin.sin_family = AF_INET;
1690
- sin.sin_port = htons (port);
1691
-
1692
1646
 
1693
- if (address && *address) {
1694
- sin.sin_addr.s_addr = inet_addr (address);
1695
- if (sin.sin_addr.s_addr == INADDR_NONE) {
1696
- hostent *hp = gethostbyname ((char*)address); // Windows requires the cast.
1697
- if (hp == NULL)
1698
- goto fail;
1699
- sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1700
- }
1647
+ { // set the SO_REUSEADDR on the socket before we bind, otherwise it won't work for a second one
1648
+ int oval = 1;
1649
+ if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0)
1650
+ goto fail;
1701
1651
  }
1702
- else
1703
- sin.sin_addr.s_addr = htonl (INADDR_ANY);
1704
-
1705
1652
 
1706
1653
  // Set the new socket nonblocking.
1707
- {
1708
- if (!SetSocketNonblocking (sd))
1709
- //int val = fcntl (sd, F_GETFL, 0);
1710
- //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1)
1711
- goto fail;
1712
- }
1654
+ if (!SetSocketNonblocking (sd))
1655
+ goto fail;
1713
1656
 
1714
- if (bind (sd, (struct sockaddr*)&sin, sizeof(sin)) != 0)
1657
+ if (bind (sd, (struct sockaddr *)&bind_here, bind_here_len) != 0)
1715
1658
  goto fail;
1716
1659
 
1717
1660
  { // Looking good.
@@ -1953,6 +1896,7 @@ void EventMachine_t::Deregister (EventableDescriptor *ed)
1953
1896
  EventMachine_t::CreateUnixDomainServer
1954
1897
  **************************************/
1955
1898
 
1899
+ #ifdef OS_UNIX
1956
1900
  const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename)
1957
1901
  {
1958
1902
  /* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
@@ -1962,16 +1906,9 @@ const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename)
1962
1906
  * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
1963
1907
  */
1964
1908
 
1965
- #ifdef OS_WIN32
1966
- throw std::runtime_error ("unix-domain server unavailable on this platform");
1967
- #endif
1968
-
1969
- // The whole rest of this function is only compiled on Unix systems.
1970
- #ifdef OS_UNIX
1971
-
1972
1909
  struct sockaddr_un s_sun;
1973
1910
 
1974
- int sd_accept = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
1911
+ SOCKET sd_accept = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
1975
1912
  if (sd_accept == INVALID_SOCKET) {
1976
1913
  goto fail;
1977
1914
  }
@@ -2011,15 +1948,20 @@ const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename)
2011
1948
  if (sd_accept != INVALID_SOCKET)
2012
1949
  close (sd_accept);
2013
1950
  return 0;
2014
- #endif // OS_UNIX
2015
1951
  }
1952
+ #else
1953
+ const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename UNUSED)
1954
+ {
1955
+ throw std::runtime_error ("unix-domain server unavailable on this platform");
1956
+ }
1957
+ #endif
2016
1958
 
2017
1959
 
2018
1960
  /**************************************
2019
1961
  EventMachine_t::AttachSD
2020
1962
  **************************************/
2021
1963
 
2022
- const uintptr_t EventMachine_t::AttachSD (int sd_accept)
1964
+ const uintptr_t EventMachine_t::AttachSD (SOCKET sd_accept)
2023
1965
  {
2024
1966
  uintptr_t output_binding = 0;
2025
1967
 
@@ -2054,15 +1996,9 @@ const uintptr_t EventMachine_t::AttachSD (int sd_accept)
2054
1996
  EventMachine_t::Socketpair
2055
1997
  **************************/
2056
1998
 
2057
- const uintptr_t EventMachine_t::Socketpair (char * const*cmd_strings)
1999
+ #ifdef OS_UNIX
2000
+ const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings)
2058
2001
  {
2059
- #ifdef OS_WIN32
2060
- throw std::runtime_error ("socketpair is currently unavailable on this platform");
2061
- #endif
2062
-
2063
- // The whole rest of this function is only compiled on Unix systems.
2064
- // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
2065
- #ifdef OS_UNIX
2066
2002
  // Make sure the incoming array of command strings is sane.
2067
2003
  if (!cmd_strings)
2068
2004
  return 0;
@@ -2110,8 +2046,14 @@ const uintptr_t EventMachine_t::Socketpair (char * const*cmd_strings)
2110
2046
  throw std::runtime_error ("no fork");
2111
2047
 
2112
2048
  return output_binding;
2113
- #endif
2114
2049
  }
2050
+ #else
2051
+ const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings UNUSED)
2052
+ {
2053
+ throw std::runtime_error ("socketpair is currently unavailable on this platform");
2054
+ }
2055
+ #endif
2056
+
2115
2057
 
2116
2058
 
2117
2059
  /****************************