eventmachine 0.4.5 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-