eventmachine 0.4.5 → 0.5.1

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.
@@ -1,7 +1,23 @@
1
- $Id: RELEASE_NOTES 2326 2006-04-19 16:16:16Z francis $
1
+ $Id: RELEASE_NOTES 2459 2006-05-05 17:11:04Z francis $
2
2
 
3
3
  RUBY/EventMachine RELEASE NOTES
4
4
 
5
+ --------------------------------------------------
6
+ Version: 0.5.1, released 05May06
7
+ Made it possible to pass a Class rather than a Module
8
+ to a protocol handler.
9
+ Added Windows port.
10
+
11
+ --------------------------------------------------
12
+ Version: 0.5.0, released 30Apr06
13
+ Added a preliminary SSL/TLS extension. This will probably
14
+ change over the next few releases.
15
+
16
+ --------------------------------------------------
17
+ Version: 0.4.5, released 29Apr06
18
+ Changed ext files so the ruby.h is installed after unistd.h
19
+ otherwise it doesn't compile on gcc 4.1
20
+
5
21
  --------------------------------------------------
6
22
  Version: 0.4.2, released 19Apr06
7
23
  Changed the Ruby-glue so the extension will play nicer
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: binder.cpp 2381 2006-04-24 13:33:03Z francis $
3
+ $Id: binder.cpp 2451 2006-05-05 03:16:31Z francis $
4
4
 
5
5
  File: binder.cpp
6
6
  Date: 07Apr06
@@ -42,6 +42,7 @@ string Bindable_t::CreateBinding()
42
42
  static string seed;
43
43
 
44
44
  if ((index >= 1000000) || (seed.length() == 0)) {
45
+ #ifdef OS_UNIX
45
46
  int fd = open (DEV_URANDOM, O_RDONLY);
46
47
  if (fd < 0)
47
48
  throw std::runtime_error ("No entropy device");
@@ -58,6 +59,21 @@ string Bindable_t::CreateBinding()
58
59
  sprintf (u2 + (i * 2), "%02x", u1[i]);
59
60
 
60
61
  seed = string (u2);
62
+ #endif
63
+
64
+
65
+ #ifdef OS_WIN32
66
+ UUID uuid;
67
+ UuidCreate (&uuid);
68
+ unsigned char *uuidstring = NULL;
69
+ UuidToString (&uuid, &uuidstring);
70
+ if (!uuidstring)
71
+ throw std::runtime_error ("Unable to read uuid");
72
+ seed = string ((const char*)uuidstring);
73
+
74
+ RpcStringFree (&uuidstring);
75
+ #endif
76
+
61
77
  index = 0;
62
78
 
63
79
 
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: binder.h 2291 2006-04-14 03:56:18Z francis $
3
+ $Id: binder.h 2412 2006-04-29 01:18:59Z francis $
4
4
 
5
5
  File: binder.h
6
6
  Date: 07Apr06
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: libmain.cpp 2291 2006-04-14 03:56:18Z francis $
3
+ $Id: cmain.cpp 2416 2006-04-29 02:02:16Z francis $
4
4
 
5
5
  File: libmain.cpp
6
6
  Date: 06Apr06
@@ -165,4 +165,18 @@ extern "C" void evma_stop_machine()
165
165
  }
166
166
 
167
167
 
168
+ /**************
169
+ evma_start_tls
170
+ **************/
171
+
172
+ extern "C" void evma_start_tls (const char *binding)
173
+ {
174
+ if (!EventMachine)
175
+ throw std::runtime_error ("not initialized");
176
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
177
+ if (ed)
178
+ ed->StartTls();
179
+ }
180
+
181
+
168
182
 
data/ext/ed.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.cpp 2382 2006-04-25 03:03:53Z francis $
3
+ $Id: ed.cpp 2457 2006-05-05 14:57:21Z francis $
4
4
 
5
5
  File: ed.cpp
6
6
  Date: 06Apr06
@@ -27,6 +27,25 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
27
  #include "project.h"
28
28
 
29
29
 
30
+
31
+ /********************
32
+ SetSocketNonblocking
33
+ ********************/
34
+
35
+ bool SetSocketNonblocking (SOCKET sd)
36
+ {
37
+ #ifdef OS_UNIX
38
+ int val = fcntl (sd, F_GETFL, 0);
39
+ return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false;
40
+ #endif
41
+
42
+ #ifdef OS_WIN32
43
+ unsigned long one = 1;
44
+ return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false;
45
+ #endif
46
+ }
47
+
48
+
30
49
  /****************************************
31
50
  EventableDescriptor::EventableDescriptor
32
51
  ****************************************/
@@ -60,7 +79,7 @@ EventableDescriptor::EventableDescriptor (int sd):
60
79
  * effect of discarding outbound data.
61
80
  */
62
81
 
63
- if (sd == -1)
82
+ if (sd == INVALID_SOCKET)
64
83
  throw std::runtime_error ("bad eventable descriptor");
65
84
  CreatedAt = gCurrentLoopTime;
66
85
  }
@@ -95,10 +114,10 @@ EventableDescriptor::Close
95
114
  void EventableDescriptor::Close()
96
115
  {
97
116
  // Close the socket right now. Intended for emergencies.
98
- if (MySocket != -1) {
117
+ if (MySocket != INVALID_SOCKET) {
99
118
  shutdown (MySocket, 1);
100
- close (MySocket);
101
- MySocket = -1;
119
+ closesocket (MySocket);
120
+ MySocket = INVALID_SOCKET;
102
121
  }
103
122
  }
104
123
 
@@ -118,7 +137,7 @@ bool EventableDescriptor::ShouldDelete()
118
137
  * if there is outbound data to write, and only request a close if there is none.
119
138
  */
120
139
 
121
- return ((MySocket == -1) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
140
+ return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
122
141
  }
123
142
 
124
143
 
@@ -142,7 +161,9 @@ ConnectionDescriptor::ConnectionDescriptor
142
161
  ConnectionDescriptor::ConnectionDescriptor (int sd):
143
162
  EventableDescriptor (sd),
144
163
  bConnectPending (false),
145
- OutboundDataSize (0)
164
+ OutboundDataSize (0),
165
+ SslBox (NULL),
166
+ bIsServer (false)
146
167
  {
147
168
  }
148
169
 
@@ -156,6 +177,9 @@ ConnectionDescriptor::~ConnectionDescriptor()
156
177
  // Run down any stranded outbound data.
157
178
  for (size_t i=0; i < OutboundPages.size(); i++)
158
179
  OutboundPages[i].Free();
180
+
181
+ if (SslBox)
182
+ delete SslBox;
159
183
  }
160
184
 
161
185
 
@@ -196,6 +220,36 @@ ConnectionDescriptor::SendOutboundData
196
220
 
197
221
  int ConnectionDescriptor::SendOutboundData (const char *data, int length)
198
222
  {
223
+ if (SslBox) {
224
+ if (length > 0) {
225
+ int w = SslBox->PutPlaintext (data, length);
226
+ if (w < 0)
227
+ ScheduleClose (false);
228
+ else
229
+ _DispatchCiphertext();
230
+ }
231
+ // TODO: What's the correct return value?
232
+ return 1; // That's a wild guess, almost certainly wrong.
233
+ }
234
+ else
235
+ return _SendRawOutboundData (data, length);
236
+ }
237
+
238
+
239
+
240
+ /******************************************
241
+ ConnectionDescriptor::_SendRawOutboundData
242
+ ******************************************/
243
+
244
+ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
245
+ {
246
+ /* This internal method is called to schedule bytes that
247
+ * will be sent out to the remote peer.
248
+ * It's not directly accessed by the caller, who hits ::SendOutboundData,
249
+ * which may or may not filter or encrypt the caller's data before
250
+ * sending it here.
251
+ */
252
+
199
253
  // Highly naive and incomplete implementation.
200
254
  // There's no throttle for runaways (which should abort only this connection
201
255
  // and not the whole process), and no coalescing of small pages.
@@ -276,7 +330,7 @@ void ConnectionDescriptor::Read()
276
330
  */
277
331
 
278
332
  int sd = GetSocket();
279
- assert (sd != -1);
333
+ assert (sd != INVALID_SOCKET);
280
334
 
281
335
  int total_bytes_read = 0;
282
336
  char readbuffer [16 * 1024];
@@ -299,10 +353,7 @@ void ConnectionDescriptor::Read()
299
353
  // to be able to depend on this behavior, so they will have
300
354
  // the option to do some things faster.
301
355
  readbuffer [r] = 0;
302
-
303
- if (EventCallback)
304
- (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, readbuffer, r);
305
-
356
+ _DispatchInboundData (readbuffer, r);
306
357
  }
307
358
  else if (r == 0) {
308
359
  break;
@@ -324,6 +375,36 @@ void ConnectionDescriptor::Read()
324
375
  }
325
376
 
326
377
 
378
+
379
+ /******************************************
380
+ ConnectionDescriptor::_DispatchInboundData
381
+ ******************************************/
382
+
383
+ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
384
+ {
385
+ if (SslBox) {
386
+ SslBox->PutCiphertext (buffer, size);
387
+
388
+ int s;
389
+ char B [2048];
390
+ while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
391
+ B [s] = 0;
392
+ if (EventCallback)
393
+ (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, B, s);
394
+ }
395
+ // INCOMPLETE, s may indicate an SSL error that would force the connection down.
396
+ _DispatchCiphertext();
397
+ }
398
+ else {
399
+ if (EventCallback)
400
+ (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, buffer, size);
401
+ }
402
+ }
403
+
404
+
405
+
406
+
407
+
327
408
  /***************************
328
409
  ConnectionDescriptor::Write
329
410
  ***************************/
@@ -335,13 +416,23 @@ void ConnectionDescriptor::Write()
335
416
  * At that point, check to be sure there are no errors,
336
417
  * and if none, then promote the socket out of the pending
337
418
  * state.
419
+ * TODO: I haven't figured out how Windows signals errors on
420
+ * unconnected sockets. Maybe it does the untraditional but
421
+ * logical thing and makes the socket selectable for error.
422
+ * If so, it's unsupported here for the time being, and connect
423
+ * errors will have to be caught by the timeout mechanism.
338
424
  */
339
425
 
340
426
  if (bConnectPending) {
341
427
  int error;
342
428
  socklen_t len;
343
429
  len = sizeof(error);
430
+ #ifdef OS_UNIX
344
431
  int o = getsockopt (MySocket, SOL_SOCKET, SO_ERROR, &error, &len);
432
+ #endif
433
+ #ifdef OS_WIN32
434
+ int o = getsockopt (MySocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
435
+ #endif
345
436
  if ((o == 0) && (error == 0))
346
437
  bConnectPending = false;
347
438
  else
@@ -367,7 +458,7 @@ void ConnectionDescriptor::_WriteOutboundData()
367
458
  */
368
459
 
369
460
  int sd = GetSocket();
370
- assert (sd != -1);
461
+ assert (sd != INVALID_SOCKET);
371
462
 
372
463
  char output_buffer [16 * 1024];
373
464
  size_t nbytes = 0;
@@ -394,7 +485,7 @@ void ConnectionDescriptor::_WriteOutboundData()
394
485
  // if it were we probably would have crashed already.
395
486
  assert (nbytes > 0);
396
487
 
397
- assert (GetSocket() != -1);
488
+ assert (GetSocket() != INVALID_SOCKET);
398
489
  int bytes_written = send (GetSocket(), output_buffer, nbytes, 0);
399
490
 
400
491
  if (bytes_written > 0) {
@@ -410,13 +501,97 @@ void ConnectionDescriptor::_WriteOutboundData()
410
501
  }
411
502
  }
412
503
  else {
504
+ #ifdef OS_UNIX
413
505
  if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
506
+ #endif
507
+ #ifdef OS_WIN32
508
+ if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
509
+ #endif
414
510
  Close();
415
511
  }
416
512
  }
417
513
 
418
514
 
419
515
 
516
+ /******************************
517
+ ConnectionDescriptor::StartTls
518
+ ******************************/
519
+
520
+ void ConnectionDescriptor::StartTls()
521
+ {
522
+ if (SslBox)
523
+ throw std::runtime_error ("SSL/TLS already running on connection");
524
+
525
+ SslBox = new SslBox_t (bIsServer);
526
+ _DispatchCiphertext();
527
+ }
528
+
529
+
530
+
531
+ /*****************************************
532
+ ConnectionDescriptor::_DispatchCiphertext
533
+ *****************************************/
534
+
535
+ void ConnectionDescriptor::_DispatchCiphertext()
536
+ {
537
+ assert (SslBox);
538
+
539
+
540
+ char BigBuf [2048];
541
+ bool did_work;
542
+
543
+ do {
544
+ did_work = false;
545
+
546
+ // try to drain ciphertext
547
+ while (SslBox->CanGetCiphertext()) {
548
+ int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf));
549
+ assert (r > 0);
550
+ _SendRawOutboundData (BigBuf, r);
551
+ did_work = true;
552
+ }
553
+
554
+ // Pump the SslBox, in case it has queued outgoing plaintext
555
+ // This will return >0 if data was written,
556
+ // 0 if no data was written, and <0 if there was a fatal error.
557
+ bool pump;
558
+ do {
559
+ pump = false;
560
+ int w = SslBox->PutPlaintext (NULL, 0);
561
+ if (w > 0) {
562
+ did_work = true;
563
+ pump = true;
564
+ }
565
+ else if (w < 0)
566
+ ScheduleClose (false);
567
+ } while (pump);
568
+
569
+ // try to put plaintext. INCOMPLETE, doesn't belong here?
570
+ // In SendOutboundData, we're spooling plaintext directly
571
+ // into SslBox. That may be wrong, we may need to buffer it
572
+ // up here!
573
+ /*
574
+ const char *ptr;
575
+ int ptr_length;
576
+ while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) {
577
+ assert (ptr && (ptr_length > 0));
578
+ int w = SslMachine.PutPlaintext (ptr, ptr_length);
579
+ if (w > 0) {
580
+ OutboundPlaintext.DiscardBytes (w);
581
+ did_work = true;
582
+ }
583
+ else
584
+ break;
585
+ }
586
+ */
587
+
588
+ } while (did_work);
589
+
590
+ }
591
+
592
+
593
+
594
+
420
595
  /*******************************
421
596
  ConnectionDescriptor::Heartbeat
422
597
  *******************************/
@@ -486,7 +661,7 @@ void AcceptorDescriptor::Read()
486
661
 
487
662
  for (int i=0; i < 10; i++) {
488
663
  int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
489
- if (sd == -1) {
664
+ if (sd == INVALID_SOCKET) {
490
665
  // This breaks the loop when we've accepted everything on the kernel queue,
491
666
  // up to 10 new connections. But what if the *first* accept fails?
492
667
  // Does that mean anything serious is happening, beyond the situation
@@ -497,10 +672,11 @@ void AcceptorDescriptor::Read()
497
672
  // Set the newly-accepted socket non-blocking.
498
673
  // On Windows, this may fail because, weirdly, Windows inherits the non-blocking
499
674
  // attribute that we applied to the acceptor socket into the accepted one.
500
- int val = fcntl (sd, F_GETFL, 0);
501
- if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
675
+ if (!SetSocketNonblocking (sd)) {
676
+ //int val = fcntl (sd, F_GETFL, 0);
677
+ //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
502
678
  shutdown (sd, 1);
503
- close (sd);
679
+ closesocket (sd);
504
680
  continue;
505
681
  }
506
682
 
@@ -513,6 +689,7 @@ void AcceptorDescriptor::Read()
513
689
  ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
514
690
  if (!cd)
515
691
  throw std::runtime_error ("no newly accepted connection");
692
+ cd->SetServerMode();
516
693
  if (EventCallback) {
517
694
  (*EventCallback) (GetBinding().c_str(), EventMachine_t::CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
518
695
  }
@@ -554,7 +731,7 @@ DatagramDescriptor::DatagramDescriptor (int sd):
554
731
  EventableDescriptor (sd),
555
732
  OutboundDataSize (0)
556
733
  {
557
- bzero (&ReturnAddress, sizeof(ReturnAddress));
734
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
558
735
  }
559
736
 
560
737
 
@@ -577,7 +754,7 @@ DatagramDescriptor::Read
577
754
  void DatagramDescriptor::Read()
578
755
  {
579
756
  int sd = GetSocket();
580
- assert (sd != -1);
757
+ assert (sd != INVALID_SOCKET);
581
758
 
582
759
  // This is an extremely large read buffer.
583
760
  // In many cases you wouldn't expect to get any more than 4K.
@@ -590,7 +767,7 @@ void DatagramDescriptor::Read()
590
767
 
591
768
  struct sockaddr_in sin;
592
769
  socklen_t slen = sizeof (sin);
593
- bzero (&sin, slen);
770
+ memset (&sin, 0, slen);
594
771
 
595
772
  int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen);
596
773
  //cerr << "<R:" << r << ">";
@@ -615,7 +792,7 @@ void DatagramDescriptor::Read()
615
792
  // There is a different call (evma_send_datagram) for cases where the caller
616
793
  // actually wants to send a packet somewhere else.
617
794
 
618
- bzero (&ReturnAddress, sizeof(ReturnAddress));
795
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
619
796
  memcpy (&ReturnAddress, &sin, slen);
620
797
 
621
798
  if (EventCallback)
@@ -651,7 +828,7 @@ void DatagramDescriptor::Write()
651
828
  */
652
829
 
653
830
  int sd = GetSocket();
654
- assert (sd != -1);
831
+ assert (sd != INVALID_SOCKET);
655
832
 
656
833
  assert (OutboundPages.size() > 0);
657
834
 
@@ -668,8 +845,13 @@ void DatagramDescriptor::Write()
668
845
  op->Free();
669
846
  OutboundPages.pop_front();
670
847
 
671
- if (s == -1) {
848
+ if (s == SOCKET_ERROR) {
849
+ #ifdef OS_UNIX
672
850
  if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
851
+ #endif
852
+ #ifdef OS_WIN32
853
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
854
+ #endif
673
855
  Close();
674
856
  break;
675
857
  }
@@ -773,7 +955,3 @@ int DatagramDescriptor::SendDatagram (const char *binding, const char *data, int
773
955
  return -1;
774
956
  }
775
957
 
776
-
777
-
778
-
779
-