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.
- data/RELEASE_NOTES +17 -1
- data/ext/binder.cpp +17 -1
- data/ext/binder.h +1 -1
- data/ext/cmain.cpp +15 -1
- data/ext/ed.cpp +206 -28
- data/ext/ed.h +18 -1
- data/ext/em.cpp +65 -19
- data/ext/em.h +1 -1
- data/ext/eventmachine.h +2 -1
- data/ext/extconf.rb +52 -3
- data/ext/page.cpp +114 -0
- data/ext/page.h +58 -0
- data/ext/project.h +30 -1
- data/ext/rubymain.cpp +89 -2
- data/ext/sigs.cpp +44 -8
- data/ext/sigs.h +5 -1
- data/ext/ssl.cpp +377 -0
- data/ext/ssl.h +92 -0
- data/lib/eventmachine.rb +39 -7
- metadata +6 -2
data/RELEASE_NOTES
CHANGED
@@ -1,7 +1,23 @@
|
|
1
|
-
$Id: RELEASE_NOTES
|
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
|
data/ext/binder.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: binder.cpp
|
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
|
|
data/ext/binder.h
CHANGED
data/ext/cmain.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id:
|
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
|
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 ==
|
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 !=
|
117
|
+
if (MySocket != INVALID_SOCKET) {
|
99
118
|
shutdown (MySocket, 1);
|
100
|
-
|
101
|
-
MySocket =
|
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 ==
|
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 !=
|
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 !=
|
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() !=
|
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 ==
|
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
|
-
|
501
|
-
|
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
|
-
|
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
|
-
|
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 !=
|
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
|
-
|
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
|
-
|
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 !=
|
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 ==
|
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
|
-
|