eventmachine 0.12.6-x86-mswin32-60 → 0.12.8-x86-mswin32-60

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 (116) hide show
  1. data/{docs/README → README} +21 -13
  2. data/Rakefile +14 -4
  3. data/docs/DEFERRABLES +0 -5
  4. data/docs/INSTALL +2 -4
  5. data/docs/LEGAL +1 -1
  6. data/docs/LIGHTWEIGHT_CONCURRENCY +0 -2
  7. data/docs/PURE_RUBY +0 -2
  8. data/docs/RELEASE_NOTES +0 -2
  9. data/docs/SMTP +0 -7
  10. data/docs/SPAWNED_PROCESSES +0 -4
  11. data/docs/TODO +0 -2
  12. data/eventmachine.gemspec +41 -32
  13. data/examples/ex_channel.rb +43 -0
  14. data/examples/ex_queue.rb +2 -0
  15. data/examples/helper.rb +2 -0
  16. data/ext/cmain.cpp +685 -586
  17. data/ext/cplusplus.cpp +15 -6
  18. data/ext/ed.cpp +1732 -1522
  19. data/ext/ed.h +407 -380
  20. data/ext/em.cpp +2263 -1937
  21. data/ext/em.h +223 -186
  22. data/ext/eventmachine.h +111 -98
  23. data/ext/eventmachine_cpp.h +1 -0
  24. data/ext/extconf.rb +4 -0
  25. data/ext/kb.cpp +81 -82
  26. data/ext/pipe.cpp +349 -351
  27. data/ext/project.h +21 -0
  28. data/ext/rubymain.cpp +1047 -847
  29. data/ext/ssl.cpp +38 -1
  30. data/ext/ssl.h +5 -1
  31. data/java/src/com/rubyeventmachine/Application.java +7 -3
  32. data/java/src/com/rubyeventmachine/EmReactor.java +16 -1
  33. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +25 -3
  34. data/lib/{protocols → em}/buftok.rb +16 -5
  35. data/lib/em/callback.rb +26 -0
  36. data/lib/em/channel.rb +57 -0
  37. data/lib/em/connection.rb +505 -0
  38. data/lib/em/deferrable.rb +144 -165
  39. data/lib/em/file_watch.rb +54 -0
  40. data/lib/em/future.rb +24 -25
  41. data/lib/em/messages.rb +1 -1
  42. data/lib/em/process_watch.rb +44 -0
  43. data/lib/em/processes.rb +119 -113
  44. data/lib/em/protocols.rb +35 -0
  45. data/lib/em/protocols/header_and_content.rb +138 -0
  46. data/lib/em/protocols/httpclient.rb +263 -0
  47. data/lib/em/protocols/httpclient2.rb +582 -0
  48. data/lib/{protocols → em/protocols}/line_and_text.rb +2 -2
  49. data/lib/em/protocols/linetext2.rb +160 -0
  50. data/lib/{protocols → em/protocols}/memcache.rb +37 -7
  51. data/lib/em/protocols/object_protocol.rb +39 -0
  52. data/lib/em/protocols/postgres3.rb +247 -0
  53. data/lib/em/protocols/saslauth.rb +175 -0
  54. data/lib/em/protocols/smtpclient.rb +331 -0
  55. data/lib/em/protocols/smtpserver.rb +547 -0
  56. data/lib/em/protocols/stomp.rb +200 -0
  57. data/lib/{protocols → em/protocols}/tcptest.rb +21 -25
  58. data/lib/em/queue.rb +61 -0
  59. data/lib/em/spawnable.rb +53 -56
  60. data/lib/em/streamer.rb +92 -74
  61. data/lib/em/timers.rb +55 -0
  62. data/lib/em/version.rb +3 -0
  63. data/lib/eventmachine.rb +1636 -1926
  64. data/lib/evma.rb +1 -1
  65. data/lib/jeventmachine.rb +106 -101
  66. data/lib/pr_eventmachine.rb +47 -36
  67. data/tasks/project.rake +2 -1
  68. data/tests/client.crt +31 -0
  69. data/tests/client.key +51 -0
  70. data/tests/test_attach.rb +18 -0
  71. data/tests/test_basic.rb +285 -231
  72. data/tests/test_channel.rb +63 -0
  73. data/tests/test_connection_count.rb +2 -2
  74. data/tests/test_epoll.rb +162 -163
  75. data/tests/test_errors.rb +36 -36
  76. data/tests/test_exc.rb +22 -25
  77. data/tests/test_file_watch.rb +49 -0
  78. data/tests/test_futures.rb +77 -93
  79. data/tests/test_hc.rb +2 -2
  80. data/tests/test_httpclient.rb +55 -52
  81. data/tests/test_httpclient2.rb +153 -155
  82. data/tests/test_inactivity_timeout.rb +30 -0
  83. data/tests/test_kb.rb +8 -9
  84. data/tests/test_ltp2.rb +274 -277
  85. data/tests/test_next_tick.rb +135 -109
  86. data/tests/test_object_protocol.rb +37 -0
  87. data/tests/test_process_watch.rb +48 -0
  88. data/tests/test_processes.rb +128 -95
  89. data/tests/test_proxy_connection.rb +92 -0
  90. data/tests/test_pure.rb +1 -5
  91. data/tests/test_queue.rb +44 -0
  92. data/tests/test_running.rb +9 -14
  93. data/tests/test_sasl.rb +32 -34
  94. data/tests/test_send_file.rb +175 -176
  95. data/tests/test_servers.rb +37 -41
  96. data/tests/test_smtpserver.rb +47 -55
  97. data/tests/test_spawn.rb +284 -291
  98. data/tests/test_ssl_args.rb +1 -1
  99. data/tests/test_ssl_methods.rb +1 -1
  100. data/tests/test_ssl_verify.rb +82 -0
  101. data/tests/test_timers.rb +81 -88
  102. data/tests/test_ud.rb +0 -7
  103. data/tests/testem.rb +1 -1
  104. metadata +52 -36
  105. data/lib/em/eventable.rb +0 -39
  106. data/lib/eventmachine_version.rb +0 -31
  107. data/lib/protocols/header_and_content.rb +0 -129
  108. data/lib/protocols/httpcli2.rb +0 -803
  109. data/lib/protocols/httpclient.rb +0 -270
  110. data/lib/protocols/linetext2.rb +0 -161
  111. data/lib/protocols/postgres.rb +0 -261
  112. data/lib/protocols/saslauth.rb +0 -179
  113. data/lib/protocols/smtpclient.rb +0 -308
  114. data/lib/protocols/smtpserver.rb +0 -556
  115. data/lib/protocols/stomp.rb +0 -153
  116. data/tests/test_eventables.rb +0 -77
data/ext/cplusplus.cpp CHANGED
@@ -33,7 +33,7 @@ EM::Run
33
33
 
34
34
  void EM::Run (void (*start_func)())
35
35
  {
36
- evma__epoll();
36
+ evma_set_epoll (1);
37
37
  evma_initialize_library (EM::Callback);
38
38
  if (start_func)
39
39
  AddTimer (0, start_func);
@@ -115,13 +115,13 @@ void EM::Connection::Close (bool afterWriting)
115
115
  }
116
116
 
117
117
 
118
- /***********************
119
- EM::Connection::Connect
120
- ***********************/
118
+ /***************************
119
+ EM::Connection::BindConnect
120
+ ***************************/
121
121
 
122
- void EM::Connection::Connect (const char *host, int port)
122
+ void EM::Connection::BindConnect (const char *bind_addr, int bind_port, const char *host, int port)
123
123
  {
124
- Signature = evma_connect_to_server (host, port);
124
+ Signature = evma_connect_to_server (bind_addr, bind_port, host, port);
125
125
  #ifdef OS_SOLARIS8
126
126
  Eventables.insert( std::map<std::string,EM::Eventable*>::value_type (Signature, this));
127
127
  #else
@@ -129,6 +129,15 @@ void EM::Connection::Connect (const char *host, int port)
129
129
  #endif
130
130
  }
131
131
 
132
+ /***********************
133
+ EM::Connection::Connect
134
+ ***********************/
135
+
136
+ void EM::Connection::Connect (const char *host, int port)
137
+ {
138
+ this->BindConnect(NULL, 0, host, port);
139
+ }
140
+
132
141
  /*******************
133
142
  EM::Acceptor::Start
134
143
  *******************/
data/ext/ed.cpp CHANGED
@@ -1,1522 +1,1732 @@
1
- /*****************************************************************************
2
-
3
- $Id$
4
-
5
- File: ed.cpp
6
- Date: 06Apr06
7
-
8
- Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
- Gmail: blackhedd
10
-
11
- This program is free software; you can redistribute it and/or modify
12
- it under the terms of either: 1) the GNU General Public License
13
- as published by the Free Software Foundation; either version 2 of the
14
- License, or (at your option) any later version; or 2) Ruby's License.
15
-
16
- See the file COPYING for complete licensing information.
17
-
18
- *****************************************************************************/
19
-
20
- #include "project.h"
21
-
22
-
23
-
24
- /********************
25
- SetSocketNonblocking
26
- ********************/
27
-
28
- bool SetSocketNonblocking (SOCKET sd)
29
- {
30
- #ifdef OS_UNIX
31
- int val = fcntl (sd, F_GETFL, 0);
32
- return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false;
33
- #endif
34
-
35
- #ifdef OS_WIN32
36
- unsigned long one = 1;
37
- return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false;
38
- #endif
39
- }
40
-
41
-
42
- /****************************************
43
- EventableDescriptor::EventableDescriptor
44
- ****************************************/
45
-
46
- EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
47
- bCloseNow (false),
48
- bCloseAfterWriting (false),
49
- MySocket (sd),
50
- EventCallback (NULL),
51
- LastRead (0),
52
- LastWritten (0),
53
- bCallbackUnbind (true),
54
- UnbindReasonCode (0),
55
- MyEventMachine (em)
56
- {
57
- /* There are three ways to close a socket, all of which should
58
- * automatically signal to the event machine that this object
59
- * should be removed from the polling scheduler.
60
- * First is a hard close, intended for bad errors or possible
61
- * security violations. It immediately closes the connection
62
- * and puts this object into an error state.
63
- * Second is to set bCloseNow, which will cause the event machine
64
- * to delete this object (and thus close the connection in our
65
- * destructor) the next chance it gets. bCloseNow also inhibits
66
- * the writing of new data on the socket (but not necessarily
67
- * the reading of new data).
68
- * The third way is to set bCloseAfterWriting, which inhibits
69
- * the writing of new data and converts to bCloseNow as soon
70
- * as everything in the outbound queue has been written.
71
- * bCloseAfterWriting is really for use only by protocol handlers
72
- * (for example, HTTP writes an HTML page and then closes the
73
- * connection). All of the error states we generate internally
74
- * cause an immediate close to be scheduled, which may have the
75
- * effect of discarding outbound data.
76
- */
77
-
78
- if (sd == INVALID_SOCKET)
79
- throw std::runtime_error ("bad eventable descriptor");
80
- if (MyEventMachine == NULL)
81
- throw std::runtime_error ("bad em in eventable descriptor");
82
- CreatedAt = gCurrentLoopTime;
83
-
84
- #ifdef HAVE_EPOLL
85
- EpollEvent.data.ptr = this;
86
- #endif
87
- }
88
-
89
-
90
- /*****************************************
91
- EventableDescriptor::~EventableDescriptor
92
- *****************************************/
93
-
94
- EventableDescriptor::~EventableDescriptor()
95
- {
96
- if (EventCallback && bCallbackUnbind)
97
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
98
- Close();
99
- }
100
-
101
-
102
- /*************************************
103
- EventableDescriptor::SetEventCallback
104
- *************************************/
105
-
106
- void EventableDescriptor::SetEventCallback (void(*cb)(const char*, int, const char*, int))
107
- {
108
- EventCallback = cb;
109
- }
110
-
111
-
112
- /**************************
113
- EventableDescriptor::Close
114
- **************************/
115
-
116
- void EventableDescriptor::Close()
117
- {
118
- // Close the socket right now. Intended for emergencies.
119
- if (MySocket != INVALID_SOCKET) {
120
- shutdown (MySocket, 1);
121
- closesocket (MySocket);
122
- MySocket = INVALID_SOCKET;
123
- }
124
- }
125
-
126
-
127
- /*********************************
128
- EventableDescriptor::ShouldDelete
129
- *********************************/
130
-
131
- bool EventableDescriptor::ShouldDelete()
132
- {
133
- /* For use by a socket manager, which needs to know if this object
134
- * should be removed from scheduling events and deleted.
135
- * Has an immediate close been scheduled, or are we already closed?
136
- * If either of these are the case, return true. In theory, the manager will
137
- * then delete us, which in turn will make sure the socket is closed.
138
- * Note, if bCloseAfterWriting is true, we check a virtual method to see
139
- * if there is outbound data to write, and only request a close if there is none.
140
- */
141
-
142
- return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
143
- }
144
-
145
-
146
- /**********************************
147
- EventableDescriptor::ScheduleClose
148
- **********************************/
149
-
150
- void EventableDescriptor::ScheduleClose (bool after_writing)
151
- {
152
- // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
153
- if (after_writing)
154
- bCloseAfterWriting = true;
155
- else
156
- bCloseNow = true;
157
- }
158
-
159
-
160
- /*************************************
161
- EventableDescriptor::IsCloseScheduled
162
- *************************************/
163
-
164
- bool EventableDescriptor::IsCloseScheduled()
165
- {
166
- // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose.
167
- return (bCloseNow || bCloseAfterWriting);
168
- }
169
-
170
-
171
- /******************************************
172
- ConnectionDescriptor::ConnectionDescriptor
173
- ******************************************/
174
-
175
- ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
176
- EventableDescriptor (sd, em),
177
- bConnectPending (false),
178
- bNotifyReadable (false),
179
- bNotifyWritable (false),
180
- bReadAttemptedAfterClose (false),
181
- bWriteAttemptedAfterClose (false),
182
- OutboundDataSize (0),
183
- #ifdef WITH_SSL
184
- SslBox (NULL),
185
- bHandshakeSignaled (false),
186
- #endif
187
- bIsServer (false),
188
- LastIo (gCurrentLoopTime),
189
- InactivityTimeout (0)
190
- {
191
- #ifdef HAVE_EPOLL
192
- EpollEvent.events = EPOLLOUT;
193
- #endif
194
- // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData()
195
- }
196
-
197
-
198
- /*******************************************
199
- ConnectionDescriptor::~ConnectionDescriptor
200
- *******************************************/
201
-
202
- ConnectionDescriptor::~ConnectionDescriptor()
203
- {
204
- // Run down any stranded outbound data.
205
- for (size_t i=0; i < OutboundPages.size(); i++)
206
- OutboundPages[i].Free();
207
-
208
- #ifdef WITH_SSL
209
- if (SslBox)
210
- delete SslBox;
211
- #endif
212
- }
213
-
214
-
215
- /**************************************************
216
- STATIC: ConnectionDescriptor::SendDataToConnection
217
- **************************************************/
218
-
219
- int ConnectionDescriptor::SendDataToConnection (const char *binding, const char *data, int data_length)
220
- {
221
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
222
- // TODO: Poor polymorphism here. We should be calling one virtual method
223
- // instead of hacking out the runtime information of the target object.
224
- ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
225
- if (cd)
226
- return cd->SendOutboundData (data, data_length);
227
- DatagramDescriptor *ds = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
228
- if (ds)
229
- return ds->SendOutboundData (data, data_length);
230
- #ifdef OS_UNIX
231
- PipeDescriptor *ps = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
232
- if (ps)
233
- return ps->SendOutboundData (data, data_length);
234
- #endif
235
- return -1;
236
- }
237
-
238
-
239
- /*********************************************
240
- STATIC: ConnectionDescriptor::CloseConnection
241
- *********************************************/
242
-
243
- void ConnectionDescriptor::CloseConnection (const char *binding, bool after_writing)
244
- {
245
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
246
- EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
247
- if (ed)
248
- ed->ScheduleClose (after_writing);
249
- }
250
-
251
- /***********************************************
252
- STATIC: ConnectionDescriptor::ReportErrorStatus
253
- ***********************************************/
254
-
255
- int ConnectionDescriptor::ReportErrorStatus (const char *binding)
256
- {
257
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
258
- // TODO: Poor polymorphism here. We should be calling one virtual method
259
- // instead of hacking out the runtime information of the target object.
260
- ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
261
- if (cd)
262
- return cd->_ReportErrorStatus();
263
- return -1;
264
- }
265
-
266
- /***************************************
267
- ConnectionDescriptor::SetConnectPending
268
- ****************************************/
269
-
270
- void ConnectionDescriptor::SetConnectPending(bool f)
271
- {
272
- bConnectPending = f;
273
- #ifdef HAVE_KQUEUE
274
- MyEventMachine->ArmKqueueWriter (this);
275
- #endif
276
- }
277
-
278
-
279
- /**************************************
280
- ConnectionDescriptor::SendOutboundData
281
- **************************************/
282
-
283
- int ConnectionDescriptor::SendOutboundData (const char *data, int length)
284
- {
285
- #ifdef WITH_SSL
286
- if (SslBox) {
287
- if (length > 0) {
288
- int w = SslBox->PutPlaintext (data, length);
289
- if (w < 0)
290
- ScheduleClose (false);
291
- else
292
- _DispatchCiphertext();
293
- }
294
- // TODO: What's the correct return value?
295
- return 1; // That's a wild guess, almost certainly wrong.
296
- }
297
- else
298
- #endif
299
- return _SendRawOutboundData (data, length);
300
- }
301
-
302
-
303
-
304
- /******************************************
305
- ConnectionDescriptor::_SendRawOutboundData
306
- ******************************************/
307
-
308
- int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
309
- {
310
- /* This internal method is called to schedule bytes that
311
- * will be sent out to the remote peer.
312
- * It's not directly accessed by the caller, who hits ::SendOutboundData,
313
- * which may or may not filter or encrypt the caller's data before
314
- * sending it here.
315
- */
316
-
317
- // Highly naive and incomplete implementation.
318
- // There's no throttle for runaways (which should abort only this connection
319
- // and not the whole process), and no coalescing of small pages.
320
- // (Well, not so bad, small pages are coalesced in ::Write)
321
-
322
- if (IsCloseScheduled())
323
- //if (bCloseNow || bCloseAfterWriting)
324
- return 0;
325
-
326
- if (!data && (length > 0))
327
- throw std::runtime_error ("bad outbound data");
328
- char *buffer = (char *) malloc (length + 1);
329
- if (!buffer)
330
- throw std::runtime_error ("no allocation for outbound data");
331
- memcpy (buffer, data, length);
332
- buffer [length] = 0;
333
- OutboundPages.push_back (OutboundPage (buffer, length));
334
- OutboundDataSize += length;
335
- #ifdef HAVE_EPOLL
336
- EpollEvent.events = (EPOLLIN | EPOLLOUT);
337
- assert (MyEventMachine);
338
- MyEventMachine->Modify (this);
339
- #endif
340
- #ifdef HAVE_KQUEUE
341
- MyEventMachine->ArmKqueueWriter (this);
342
- #endif
343
- return length;
344
- }
345
-
346
-
347
-
348
- /***********************************
349
- ConnectionDescriptor::SelectForRead
350
- ***********************************/
351
-
352
- bool ConnectionDescriptor::SelectForRead()
353
- {
354
- /* A connection descriptor is always scheduled for read,
355
- * UNLESS it's in a pending-connect state.
356
- * On Linux, unlike Unix, a nonblocking socket on which
357
- * connect has been called, does NOT necessarily select
358
- * both readable and writable in case of error.
359
- * The socket will select writable when the disposition
360
- * of the connect is known. On the other hand, a socket
361
- * which successfully connects and selects writable may
362
- * indeed have some data available on it, so it will
363
- * select readable in that case, violating expectations!
364
- * So we will not poll for readability until the socket
365
- * is known to be in a connected state.
366
- */
367
-
368
- return bConnectPending ? false : true;
369
- }
370
-
371
-
372
- /************************************
373
- ConnectionDescriptor::SelectForWrite
374
- ************************************/
375
-
376
- bool ConnectionDescriptor::SelectForWrite()
377
- {
378
- /* Cf the notes under SelectForRead.
379
- * In a pending-connect state, we ALWAYS select for writable.
380
- * In a normal state, we only select for writable when we
381
- * have outgoing data to send.
382
- */
383
-
384
- if (bConnectPending || bNotifyWritable)
385
- return true;
386
- else {
387
- return (GetOutboundDataSize() > 0);
388
- }
389
- }
390
-
391
-
392
- /**************************
393
- ConnectionDescriptor::Read
394
- **************************/
395
-
396
- void ConnectionDescriptor::Read()
397
- {
398
- /* Read and dispatch data on a socket that has selected readable.
399
- * It's theoretically possible to get and dispatch incoming data on
400
- * a socket that has already been scheduled for closing or close-after-writing.
401
- * In those cases, we'll leave it up the to protocol handler to "do the
402
- * right thing" (which probably means to ignore the incoming data).
403
- *
404
- * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come
405
- * here with the socket already closed, after the process receives
406
- * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application
407
- * was one in which network connections were doing a lot of interleaved reads
408
- * and writes.
409
- * Since we always write before reading (in order to keep the outbound queues
410
- * as light as possible), I think what happened is that an interrupt caused
411
- * the socket to be closed in ConnectionDescriptor::Write. We'll then
412
- * come here in the same pass through the main event loop, and won't get
413
- * cleaned up until immediately after.
414
- * We originally asserted that the socket was valid when we got here.
415
- * To deal properly with the possibility that we are closed when we get here,
416
- * I removed the assert. HOWEVER, the potential for an infinite loop scares me,
417
- * so even though this is really clunky, I added a flag to assert that we never
418
- * come here more than once after being closed. (FCianfrocca)
419
- */
420
-
421
- int sd = GetSocket();
422
- //assert (sd != INVALID_SOCKET); (original, removed 22Aug06)
423
- if (sd == INVALID_SOCKET) {
424
- assert (!bReadAttemptedAfterClose);
425
- bReadAttemptedAfterClose = true;
426
- return;
427
- }
428
-
429
- if (bNotifyReadable) {
430
- if (EventCallback)
431
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
432
- return;
433
- }
434
-
435
- LastIo = gCurrentLoopTime;
436
-
437
- int total_bytes_read = 0;
438
- char readbuffer [16 * 1024 + 1];
439
-
440
- for (int i=0; i < 10; i++) {
441
- // Don't read just one buffer and then move on. This is faster
442
- // if there is a lot of incoming.
443
- // But don't read indefinitely. Give other sockets a chance to run.
444
- // NOTICE, we're reading one less than the buffer size.
445
- // That's so we can put a guard byte at the end of what we send
446
- // to user code.
447
-
448
-
449
- int r = recv (sd, readbuffer, sizeof(readbuffer) - 1, 0);
450
- //cerr << "<R:" << r << ">";
451
-
452
- if (r > 0) {
453
- total_bytes_read += r;
454
- LastRead = gCurrentLoopTime;
455
-
456
- // Add a null-terminator at the the end of the buffer
457
- // that we will send to the callback.
458
- // DO NOT EVER CHANGE THIS. We want to explicitly allow users
459
- // to be able to depend on this behavior, so they will have
460
- // the option to do some things faster. Additionally it's
461
- // a security guard against buffer overflows.
462
- readbuffer [r] = 0;
463
- _DispatchInboundData (readbuffer, r);
464
- }
465
- else if (r == 0) {
466
- break;
467
- }
468
- else {
469
- // Basically a would-block, meaning we've read everything there is to read.
470
- break;
471
- }
472
-
473
- }
474
-
475
-
476
- if (total_bytes_read == 0) {
477
- // If we read no data on a socket that selected readable,
478
- // it generally means the other end closed the connection gracefully.
479
- ScheduleClose (false);
480
- //bCloseNow = true;
481
- }
482
-
483
- }
484
-
485
-
486
-
487
- /******************************************
488
- ConnectionDescriptor::_DispatchInboundData
489
- ******************************************/
490
-
491
- void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
492
- {
493
- #ifdef WITH_SSL
494
- if (SslBox) {
495
- SslBox->PutCiphertext (buffer, size);
496
-
497
- int s;
498
- char B [2048];
499
- while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
500
- _CheckHandshakeStatus();
501
- B [s] = 0;
502
- if (EventCallback)
503
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, B, s);
504
- }
505
- _CheckHandshakeStatus();
506
- // INCOMPLETE, s may indicate an SSL error that would force the connection down.
507
- _DispatchCiphertext();
508
- }
509
- else {
510
- if (EventCallback)
511
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buffer, size);
512
- }
513
- #endif
514
-
515
- #ifdef WITHOUT_SSL
516
- if (EventCallback)
517
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buffer, size);
518
- #endif
519
- }
520
-
521
-
522
-
523
- /*******************************************
524
- ConnectionDescriptor::_CheckHandshakeStatus
525
- *******************************************/
526
-
527
- void ConnectionDescriptor::_CheckHandshakeStatus()
528
- {
529
- #ifdef WITH_SSL
530
- if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) {
531
- bHandshakeSignaled = true;
532
- if (EventCallback)
533
- (*EventCallback)(GetBinding().c_str(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
534
- }
535
- #endif
536
- }
537
-
538
-
539
-
540
- /***************************
541
- ConnectionDescriptor::Write
542
- ***************************/
543
-
544
- void ConnectionDescriptor::Write()
545
- {
546
- /* A socket which is in a pending-connect state will select
547
- * writable when the disposition of the connect is known.
548
- * At that point, check to be sure there are no errors,
549
- * and if none, then promote the socket out of the pending
550
- * state.
551
- * TODO: I haven't figured out how Windows signals errors on
552
- * unconnected sockets. Maybe it does the untraditional but
553
- * logical thing and makes the socket selectable for error.
554
- * If so, it's unsupported here for the time being, and connect
555
- * errors will have to be caught by the timeout mechanism.
556
- */
557
-
558
- if (bConnectPending) {
559
- int error;
560
- socklen_t len;
561
- len = sizeof(error);
562
- #ifdef OS_UNIX
563
- int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
564
- #endif
565
- #ifdef OS_WIN32
566
- int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
567
- #endif
568
- if ((o == 0) && (error == 0)) {
569
- if (EventCallback)
570
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_COMPLETED, "", 0);
571
- bConnectPending = false;
572
- #ifdef HAVE_EPOLL
573
- // The callback may have scheduled outbound data.
574
- EpollEvent.events = EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0);
575
- #endif
576
- #ifdef HAVE_KQUEUE
577
- MyEventMachine->ArmKqueueReader (this);
578
- // The callback may have scheduled outbound data.
579
- if (SelectForWrite())
580
- MyEventMachine->ArmKqueueWriter (this);
581
- #endif
582
- }
583
- else
584
- ScheduleClose (false);
585
- //bCloseNow = true;
586
- }
587
- else {
588
-
589
- if (bNotifyWritable) {
590
- if (EventCallback)
591
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
592
- return;
593
- }
594
-
595
- _WriteOutboundData();
596
- }
597
- }
598
-
599
-
600
- /****************************************
601
- ConnectionDescriptor::_WriteOutboundData
602
- ****************************************/
603
-
604
- void ConnectionDescriptor::_WriteOutboundData()
605
- {
606
- /* This is a helper function called by ::Write.
607
- * It's possible for a socket to select writable and then no longer
608
- * be writable by the time we get around to writing. The kernel might
609
- * have used up its available output buffers between the select call
610
- * and when we get here. So this condition is not an error.
611
- *
612
- * 20Jul07, added the same kind of protection against an invalid socket
613
- * that is at the top of ::Read. Not entirely how this could happen in
614
- * real life (connection-reset from the remote peer, perhaps?), but I'm
615
- * doing it to address some reports of crashing under heavy loads.
616
- */
617
-
618
- int sd = GetSocket();
619
- //assert (sd != INVALID_SOCKET);
620
- if (sd == INVALID_SOCKET) {
621
- assert (!bWriteAttemptedAfterClose);
622
- bWriteAttemptedAfterClose = true;
623
- return;
624
- }
625
-
626
- LastIo = gCurrentLoopTime;
627
- char output_buffer [16 * 1024];
628
- size_t nbytes = 0;
629
-
630
- while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
631
- OutboundPage *op = &(OutboundPages[0]);
632
- if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
633
- memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
634
- nbytes += (op->Length - op->Offset);
635
- op->Free();
636
- OutboundPages.pop_front();
637
- }
638
- else {
639
- int len = sizeof(output_buffer) - nbytes;
640
- memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
641
- op->Offset += len;
642
- nbytes += len;
643
- }
644
- }
645
-
646
- // We should never have gotten here if there were no data to write,
647
- // so assert that as a sanity check.
648
- // Don't bother to make sure nbytes is less than output_buffer because
649
- // if it were we probably would have crashed already.
650
- assert (nbytes > 0);
651
-
652
- assert (GetSocket() != INVALID_SOCKET);
653
- int bytes_written = send (GetSocket(), output_buffer, nbytes, 0);
654
-
655
- bool err = false;
656
- if (bytes_written < 0) {
657
- err = true;
658
- bytes_written = 0;
659
- }
660
-
661
- assert (bytes_written >= 0);
662
- OutboundDataSize -= bytes_written;
663
- if ((size_t)bytes_written < nbytes) {
664
- int len = nbytes - bytes_written;
665
- char *buffer = (char*) malloc (len + 1);
666
- if (!buffer)
667
- throw std::runtime_error ("bad alloc throwing back data");
668
- memcpy (buffer, output_buffer + bytes_written, len);
669
- buffer [len] = 0;
670
- OutboundPages.push_front (OutboundPage (buffer, len));
671
- }
672
-
673
- #ifdef HAVE_EPOLL
674
- EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
675
- assert (MyEventMachine);
676
- MyEventMachine->Modify (this);
677
- #endif
678
- #ifdef HAVE_KQUEUE
679
- if (SelectForWrite())
680
- MyEventMachine->ArmKqueueWriter (this);
681
- #endif
682
-
683
-
684
- if (err) {
685
- #ifdef OS_UNIX
686
- if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
687
- #endif
688
- #ifdef OS_WIN32
689
- if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
690
- #endif
691
- Close();
692
- }
693
- }
694
-
695
-
696
- /****************************************
697
- ConnectionDescriptor::_ReportErrorStatus
698
- ****************************************/
699
-
700
- int ConnectionDescriptor::_ReportErrorStatus()
701
- {
702
- int error;
703
- socklen_t len;
704
- len = sizeof(error);
705
- #ifdef OS_UNIX
706
- int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
707
- #endif
708
- #ifdef OS_WIN32
709
- int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
710
- #endif
711
- if ((o == 0) && (error == 0))
712
- return 0;
713
- else
714
- return 1;
715
- }
716
-
717
-
718
- /******************************
719
- ConnectionDescriptor::StartTls
720
- ******************************/
721
-
722
- void ConnectionDescriptor::StartTls()
723
- {
724
- #ifdef WITH_SSL
725
- if (SslBox)
726
- throw std::runtime_error ("SSL/TLS already running on connection");
727
-
728
- SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename);
729
- _DispatchCiphertext();
730
- #endif
731
-
732
- #ifdef WITHOUT_SSL
733
- throw std::runtime_error ("Encryption not available on this event-machine");
734
- #endif
735
- }
736
-
737
-
738
- /*********************************
739
- ConnectionDescriptor::SetTlsParms
740
- *********************************/
741
-
742
- void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename)
743
- {
744
- #ifdef WITH_SSL
745
- if (SslBox)
746
- throw std::runtime_error ("call SetTlsParms before calling StartTls");
747
- if (privkey_filename && *privkey_filename)
748
- PrivateKeyFilename = privkey_filename;
749
- if (certchain_filename && *certchain_filename)
750
- CertChainFilename = certchain_filename;
751
- #endif
752
-
753
- #ifdef WITHOUT_SSL
754
- throw std::runtime_error ("Encryption not available on this event-machine");
755
- #endif
756
- }
757
-
758
-
759
- /*********************************
760
- ConnectionDescriptor::GetPeerCert
761
- *********************************/
762
-
763
- #ifdef WITH_SSL
764
- X509 *ConnectionDescriptor::GetPeerCert()
765
- {
766
- if (!SslBox)
767
- throw std::runtime_error ("SSL/TLS not running on this connection");
768
- return SslBox->GetPeerCert();
769
- }
770
- #endif
771
-
772
-
773
- /*****************************************
774
- ConnectionDescriptor::_DispatchCiphertext
775
- *****************************************/
776
-
777
- #ifdef WITH_SSL
778
- void ConnectionDescriptor::_DispatchCiphertext()
779
- {
780
- assert (SslBox);
781
-
782
-
783
- char BigBuf [2048];
784
- bool did_work;
785
-
786
- do {
787
- did_work = false;
788
-
789
- // try to drain ciphertext
790
- while (SslBox->CanGetCiphertext()) {
791
- int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf));
792
- assert (r > 0);
793
- _SendRawOutboundData (BigBuf, r);
794
- did_work = true;
795
- }
796
-
797
- // Pump the SslBox, in case it has queued outgoing plaintext
798
- // This will return >0 if data was written,
799
- // 0 if no data was written, and <0 if there was a fatal error.
800
- bool pump;
801
- do {
802
- pump = false;
803
- int w = SslBox->PutPlaintext (NULL, 0);
804
- if (w > 0) {
805
- did_work = true;
806
- pump = true;
807
- }
808
- else if (w < 0)
809
- ScheduleClose (false);
810
- } while (pump);
811
-
812
- // try to put plaintext. INCOMPLETE, doesn't belong here?
813
- // In SendOutboundData, we're spooling plaintext directly
814
- // into SslBox. That may be wrong, we may need to buffer it
815
- // up here!
816
- /*
817
- const char *ptr;
818
- int ptr_length;
819
- while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) {
820
- assert (ptr && (ptr_length > 0));
821
- int w = SslMachine.PutPlaintext (ptr, ptr_length);
822
- if (w > 0) {
823
- OutboundPlaintext.DiscardBytes (w);
824
- did_work = true;
825
- }
826
- else
827
- break;
828
- }
829
- */
830
-
831
- } while (did_work);
832
-
833
- }
834
- #endif
835
-
836
-
837
-
838
- /*******************************
839
- ConnectionDescriptor::Heartbeat
840
- *******************************/
841
-
842
- void ConnectionDescriptor::Heartbeat()
843
- {
844
- /* Only allow a certain amount of time to go by while waiting
845
- * for a pending connect. If it expires, then kill the socket.
846
- * For a connected socket, close it if its inactivity timer
847
- * has expired.
848
- */
849
-
850
- if (bConnectPending) {
851
- if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
852
- ScheduleClose (false);
853
- //bCloseNow = true;
854
- }
855
- else {
856
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
857
- ScheduleClose (false);
858
- //bCloseNow = true;
859
- }
860
- }
861
-
862
-
863
- /****************************************
864
- LoopbreakDescriptor::LoopbreakDescriptor
865
- ****************************************/
866
-
867
- LoopbreakDescriptor::LoopbreakDescriptor (int sd, EventMachine_t *parent_em):
868
- EventableDescriptor (sd, parent_em)
869
- {
870
- /* This is really bad and ugly. Change someday if possible.
871
- * We have to know about an event-machine (probably the one that owns us),
872
- * so we can pass newly-created connections to it.
873
- */
874
-
875
- bCallbackUnbind = false;
876
-
877
- #ifdef HAVE_EPOLL
878
- EpollEvent.events = EPOLLIN;
879
- #endif
880
- #ifdef HAVE_KQUEUE
881
- MyEventMachine->ArmKqueueReader (this);
882
- #endif
883
- }
884
-
885
-
886
-
887
-
888
- /*************************
889
- LoopbreakDescriptor::Read
890
- *************************/
891
-
892
- void LoopbreakDescriptor::Read()
893
- {
894
- // TODO, refactor, this code is probably in the wrong place.
895
- assert (MyEventMachine);
896
- MyEventMachine->_ReadLoopBreaker();
897
- }
898
-
899
-
900
- /**************************
901
- LoopbreakDescriptor::Write
902
- **************************/
903
-
904
- void LoopbreakDescriptor::Write()
905
- {
906
- // Why are we here?
907
- throw std::runtime_error ("bad code path in loopbreak");
908
- }
909
-
910
- /**************************************
911
- AcceptorDescriptor::AcceptorDescriptor
912
- **************************************/
913
-
914
- AcceptorDescriptor::AcceptorDescriptor (int sd, EventMachine_t *parent_em):
915
- EventableDescriptor (sd, parent_em)
916
- {
917
- #ifdef HAVE_EPOLL
918
- EpollEvent.events = EPOLLIN;
919
- #endif
920
- #ifdef HAVE_KQUEUE
921
- MyEventMachine->ArmKqueueReader (this);
922
- #endif
923
- }
924
-
925
-
926
- /***************************************
927
- AcceptorDescriptor::~AcceptorDescriptor
928
- ***************************************/
929
-
930
- AcceptorDescriptor::~AcceptorDescriptor()
931
- {
932
- }
933
-
934
- /****************************************
935
- STATIC: AcceptorDescriptor::StopAcceptor
936
- ****************************************/
937
-
938
- void AcceptorDescriptor::StopAcceptor (const char *binding)
939
- {
940
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
941
- AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding));
942
- if (ad)
943
- ad->ScheduleClose (false);
944
- else
945
- throw std::runtime_error ("failed to close nonexistent acceptor");
946
- }
947
-
948
-
949
- /************************
950
- AcceptorDescriptor::Read
951
- ************************/
952
-
953
- void AcceptorDescriptor::Read()
954
- {
955
- /* Accept up to a certain number of sockets on the listening connection.
956
- * Don't try to accept all that are present, because this would allow a DoS attack
957
- * in which no data were ever read or written. We should accept more than one,
958
- * if available, to keep the partially accepted sockets from backing up in the kernel.
959
- */
960
-
961
- /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it
962
- * for readability. According to Stevens UNP, it's possible for an acceptor to select readable
963
- * and then block when we call accept. For example, the other end resets the connection after
964
- * the socket selects readable and before we call accept. The kernel will remove the dead
965
- * socket from the accept queue. If the accept queue is now empty, accept will block.
966
- */
967
-
968
-
969
- struct sockaddr_in pin;
970
- socklen_t addrlen = sizeof (pin);
971
-
972
- for (int i=0; i < 10; i++) {
973
- int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
974
- if (sd == INVALID_SOCKET) {
975
- // This breaks the loop when we've accepted everything on the kernel queue,
976
- // up to 10 new connections. But what if the *first* accept fails?
977
- // Does that mean anything serious is happening, beyond the situation
978
- // described in the note above?
979
- break;
980
- }
981
-
982
- // Set the newly-accepted socket non-blocking.
983
- // On Windows, this may fail because, weirdly, Windows inherits the non-blocking
984
- // attribute that we applied to the acceptor socket into the accepted one.
985
- if (!SetSocketNonblocking (sd)) {
986
- //int val = fcntl (sd, F_GETFL, 0);
987
- //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
988
- shutdown (sd, 1);
989
- closesocket (sd);
990
- continue;
991
- }
992
-
993
-
994
- // Disable slow-start (Nagle algorithm). Eventually make this configurable.
995
- int one = 1;
996
- setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
997
-
998
-
999
- ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine);
1000
- if (!cd)
1001
- throw std::runtime_error ("no newly accepted connection");
1002
- cd->SetServerMode();
1003
- if (EventCallback) {
1004
- (*EventCallback) (GetBinding().c_str(), EM_CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
1005
- }
1006
- #ifdef HAVE_EPOLL
1007
- cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0);
1008
- #endif
1009
- assert (MyEventMachine);
1010
- MyEventMachine->Add (cd);
1011
- #ifdef HAVE_KQUEUE
1012
- if (cd->SelectForWrite())
1013
- MyEventMachine->ArmKqueueWriter (cd);
1014
- MyEventMachine->ArmKqueueReader (cd);
1015
- #endif
1016
- }
1017
-
1018
- }
1019
-
1020
-
1021
- /*************************
1022
- AcceptorDescriptor::Write
1023
- *************************/
1024
-
1025
- void AcceptorDescriptor::Write()
1026
- {
1027
- // Why are we here?
1028
- throw std::runtime_error ("bad code path in acceptor");
1029
- }
1030
-
1031
-
1032
- /*****************************
1033
- AcceptorDescriptor::Heartbeat
1034
- *****************************/
1035
-
1036
- void AcceptorDescriptor::Heartbeat()
1037
- {
1038
- // No-op
1039
- }
1040
-
1041
-
1042
- /*******************************
1043
- AcceptorDescriptor::GetSockname
1044
- *******************************/
1045
-
1046
- bool AcceptorDescriptor::GetSockname (struct sockaddr *s)
1047
- {
1048
- bool ok = false;
1049
- if (s) {
1050
- socklen_t len = sizeof(*s);
1051
- int gp = getsockname (GetSocket(), s, &len);
1052
- if (gp == 0)
1053
- ok = true;
1054
- }
1055
- return ok;
1056
- }
1057
-
1058
-
1059
-
1060
- /**************************************
1061
- DatagramDescriptor::DatagramDescriptor
1062
- **************************************/
1063
-
1064
- DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
1065
- EventableDescriptor (sd, parent_em),
1066
- OutboundDataSize (0),
1067
- LastIo (gCurrentLoopTime),
1068
- InactivityTimeout (0)
1069
- {
1070
- memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1071
-
1072
- /* Provisionally added 19Oct07. All datagram sockets support broadcasting.
1073
- * Until now, sending to a broadcast address would give EACCES (permission denied)
1074
- * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order
1075
- * to accept a packet to a broadcast address. Solaris doesn't require it. I think
1076
- * Windows DOES require it but I'm not sure.
1077
- *
1078
- * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST
1079
- * on a UDP socket in order to enable broadcasting. The reason for requiring the option
1080
- * in the first place is so that applications don't send broadcast datagrams by mistake.
1081
- * I imagine that could happen if a user of an application typed in an address that happened
1082
- * to be a broadcast address on that particular subnet.
1083
- *
1084
- * This is provisional because someone may eventually come up with a good reason not to
1085
- * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API
1086
- * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T
1087
- * EXPLICITLY SET THE OPTION.
1088
- */
1089
-
1090
- int oval = 1;
1091
- int sob = setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval));
1092
-
1093
- #ifdef HAVE_EPOLL
1094
- EpollEvent.events = EPOLLIN;
1095
- #endif
1096
- #ifdef HAVE_KQUEUE
1097
- MyEventMachine->ArmKqueueReader (this);
1098
- #endif
1099
- }
1100
-
1101
-
1102
- /***************************************
1103
- DatagramDescriptor::~DatagramDescriptor
1104
- ***************************************/
1105
-
1106
- DatagramDescriptor::~DatagramDescriptor()
1107
- {
1108
- // Run down any stranded outbound data.
1109
- for (size_t i=0; i < OutboundPages.size(); i++)
1110
- OutboundPages[i].Free();
1111
- }
1112
-
1113
-
1114
- /*****************************
1115
- DatagramDescriptor::Heartbeat
1116
- *****************************/
1117
-
1118
- void DatagramDescriptor::Heartbeat()
1119
- {
1120
- // Close it if its inactivity timer has expired.
1121
-
1122
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1123
- ScheduleClose (false);
1124
- //bCloseNow = true;
1125
- }
1126
-
1127
-
1128
- /************************
1129
- DatagramDescriptor::Read
1130
- ************************/
1131
-
1132
- void DatagramDescriptor::Read()
1133
- {
1134
- int sd = GetSocket();
1135
- assert (sd != INVALID_SOCKET);
1136
- LastIo = gCurrentLoopTime;
1137
-
1138
- // This is an extremely large read buffer.
1139
- // In many cases you wouldn't expect to get any more than 4K.
1140
- char readbuffer [16 * 1024];
1141
-
1142
- for (int i=0; i < 10; i++) {
1143
- // Don't read just one buffer and then move on. This is faster
1144
- // if there is a lot of incoming.
1145
- // But don't read indefinitely. Give other sockets a chance to run.
1146
- // NOTICE, we're reading one less than the buffer size.
1147
- // That's so we can put a guard byte at the end of what we send
1148
- // to user code.
1149
-
1150
- struct sockaddr_in sin;
1151
- socklen_t slen = sizeof (sin);
1152
- memset (&sin, 0, slen);
1153
-
1154
- int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen);
1155
- //cerr << "<R:" << r << ">";
1156
-
1157
- // In UDP, a zero-length packet is perfectly legal.
1158
- if (r >= 0) {
1159
- LastRead = gCurrentLoopTime;
1160
-
1161
- // Add a null-terminator at the the end of the buffer
1162
- // that we will send to the callback.
1163
- // DO NOT EVER CHANGE THIS. We want to explicitly allow users
1164
- // to be able to depend on this behavior, so they will have
1165
- // the option to do some things faster. Additionally it's
1166
- // a security guard against buffer overflows.
1167
- readbuffer [r] = 0;
1168
-
1169
-
1170
- // Set up a "temporary" return address so that callers can "reply" to us
1171
- // from within the callback we are about to invoke. That means that ordinary
1172
- // calls to "send_data_to_connection" (which is of course misnamed in this
1173
- // case) will result in packets being sent back to the same place that sent
1174
- // us this one.
1175
- // There is a different call (evma_send_datagram) for cases where the caller
1176
- // actually wants to send a packet somewhere else.
1177
-
1178
- memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1179
- memcpy (&ReturnAddress, &sin, slen);
1180
-
1181
- if (EventCallback)
1182
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r);
1183
-
1184
- }
1185
- else {
1186
- // Basically a would-block, meaning we've read everything there is to read.
1187
- break;
1188
- }
1189
-
1190
- }
1191
-
1192
-
1193
- }
1194
-
1195
-
1196
- /*************************
1197
- DatagramDescriptor::Write
1198
- *************************/
1199
-
1200
- void DatagramDescriptor::Write()
1201
- {
1202
- /* It's possible for a socket to select writable and then no longer
1203
- * be writable by the time we get around to writing. The kernel might
1204
- * have used up its available output buffers between the select call
1205
- * and when we get here. So this condition is not an error.
1206
- * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData,
1207
- * but differs in the that the outbound data pages (received from the
1208
- * user) are _message-structured._ That is, we send each of them out
1209
- * one message at a time.
1210
- * TODO, we are currently suppressing the EMSGSIZE error!!!
1211
- */
1212
-
1213
- int sd = GetSocket();
1214
- assert (sd != INVALID_SOCKET);
1215
- LastIo = gCurrentLoopTime;
1216
-
1217
- assert (OutboundPages.size() > 0);
1218
-
1219
- // Send out up to 10 packets, then cycle the machine.
1220
- for (int i = 0; i < 10; i++) {
1221
- if (OutboundPages.size() <= 0)
1222
- break;
1223
- OutboundPage *op = &(OutboundPages[0]);
1224
-
1225
- // The nasty cast to (char*) is needed because Windows is brain-dead.
1226
- int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
1227
- int e = errno;
1228
-
1229
- OutboundDataSize -= op->Length;
1230
- op->Free();
1231
- OutboundPages.pop_front();
1232
-
1233
- if (s == SOCKET_ERROR) {
1234
- #ifdef OS_UNIX
1235
- if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
1236
- #endif
1237
- #ifdef OS_WIN32
1238
- if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1239
- #endif
1240
- Close();
1241
- break;
1242
- }
1243
- }
1244
- }
1245
-
1246
- #ifdef HAVE_EPOLL
1247
- EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
1248
- assert (MyEventMachine);
1249
- MyEventMachine->Modify (this);
1250
- #endif
1251
- }
1252
-
1253
-
1254
- /**********************************
1255
- DatagramDescriptor::SelectForWrite
1256
- **********************************/
1257
-
1258
- bool DatagramDescriptor::SelectForWrite()
1259
- {
1260
- /* Changed 15Nov07, per bug report by Mark Zvillius.
1261
- * The outbound data size will be zero if there are zero-length outbound packets,
1262
- * so we now select writable in case the outbound page buffer is not empty.
1263
- * Note that the superclass ShouldDelete method still checks for outbound data size,
1264
- * which may be wrong.
1265
- */
1266
- //return (GetOutboundDataSize() > 0); (Original)
1267
- return (OutboundPages.size() > 0);
1268
- }
1269
-
1270
-
1271
- /************************************
1272
- DatagramDescriptor::SendOutboundData
1273
- ************************************/
1274
-
1275
- int DatagramDescriptor::SendOutboundData (const char *data, int length)
1276
- {
1277
- // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1278
- // That means it needs to move to a common ancestor.
1279
-
1280
- if (IsCloseScheduled())
1281
- //if (bCloseNow || bCloseAfterWriting)
1282
- return 0;
1283
-
1284
- if (!data && (length > 0))
1285
- throw std::runtime_error ("bad outbound data");
1286
- char *buffer = (char *) malloc (length + 1);
1287
- if (!buffer)
1288
- throw std::runtime_error ("no allocation for outbound data");
1289
- memcpy (buffer, data, length);
1290
- buffer [length] = 0;
1291
- OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress));
1292
- OutboundDataSize += length;
1293
- #ifdef HAVE_EPOLL
1294
- EpollEvent.events = (EPOLLIN | EPOLLOUT);
1295
- assert (MyEventMachine);
1296
- MyEventMachine->Modify (this);
1297
- #endif
1298
- return length;
1299
- }
1300
-
1301
-
1302
- /****************************************
1303
- DatagramDescriptor::SendOutboundDatagram
1304
- ****************************************/
1305
-
1306
- int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, const char *address, int port)
1307
- {
1308
- // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1309
- // That means it needs to move to a common ancestor.
1310
- // TODO: Refactor this so there's no overlap with SendOutboundData.
1311
-
1312
- if (IsCloseScheduled())
1313
- //if (bCloseNow || bCloseAfterWriting)
1314
- return 0;
1315
-
1316
- if (!address || !*address || !port)
1317
- return 0;
1318
-
1319
- sockaddr_in pin;
1320
- unsigned long HostAddr;
1321
-
1322
- HostAddr = inet_addr (address);
1323
- if (HostAddr == INADDR_NONE) {
1324
- // The nasty cast to (char*) is because Windows is brain-dead.
1325
- hostent *hp = gethostbyname ((char*)address);
1326
- if (!hp)
1327
- return 0;
1328
- HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
1329
- }
1330
-
1331
- memset (&pin, 0, sizeof(pin));
1332
- pin.sin_family = AF_INET;
1333
- pin.sin_addr.s_addr = HostAddr;
1334
- pin.sin_port = htons (port);
1335
-
1336
-
1337
-
1338
- if (!data && (length > 0))
1339
- throw std::runtime_error ("bad outbound data");
1340
- char *buffer = (char *) malloc (length + 1);
1341
- if (!buffer)
1342
- throw std::runtime_error ("no allocation for outbound data");
1343
- memcpy (buffer, data, length);
1344
- buffer [length] = 0;
1345
- OutboundPages.push_back (OutboundPage (buffer, length, pin));
1346
- OutboundDataSize += length;
1347
- #ifdef HAVE_EPOLL
1348
- EpollEvent.events = (EPOLLIN | EPOLLOUT);
1349
- assert (MyEventMachine);
1350
- MyEventMachine->Modify (this);
1351
- #endif
1352
- return length;
1353
- }
1354
-
1355
-
1356
- /****************************************
1357
- STATIC: DatagramDescriptor::SendDatagram
1358
- ****************************************/
1359
-
1360
- int DatagramDescriptor::SendDatagram (const char *binding, const char *data, int length, const char *address, int port)
1361
- {
1362
- DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
1363
- if (dd)
1364
- return dd->SendOutboundDatagram (data, length, address, port);
1365
- else
1366
- return -1;
1367
- }
1368
-
1369
-
1370
- /*********************************
1371
- ConnectionDescriptor::GetPeername
1372
- *********************************/
1373
-
1374
- bool ConnectionDescriptor::GetPeername (struct sockaddr *s)
1375
- {
1376
- bool ok = false;
1377
- if (s) {
1378
- socklen_t len = sizeof(*s);
1379
- int gp = getpeername (GetSocket(), s, &len);
1380
- if (gp == 0)
1381
- ok = true;
1382
- }
1383
- return ok;
1384
- }
1385
-
1386
- /*********************************
1387
- ConnectionDescriptor::GetSockname
1388
- *********************************/
1389
-
1390
- bool ConnectionDescriptor::GetSockname (struct sockaddr *s)
1391
- {
1392
- bool ok = false;
1393
- if (s) {
1394
- socklen_t len = sizeof(*s);
1395
- int gp = getsockname (GetSocket(), s, &len);
1396
- if (gp == 0)
1397
- ok = true;
1398
- }
1399
- return ok;
1400
- }
1401
-
1402
-
1403
- /**********************************************
1404
- ConnectionDescriptor::GetCommInactivityTimeout
1405
- **********************************************/
1406
-
1407
- int ConnectionDescriptor::GetCommInactivityTimeout (int *value)
1408
- {
1409
- if (value) {
1410
- *value = InactivityTimeout;
1411
- return 1;
1412
- }
1413
- else {
1414
- // TODO, extended logging, got bad parameter.
1415
- return 0;
1416
- }
1417
- }
1418
-
1419
-
1420
- /**********************************************
1421
- ConnectionDescriptor::SetCommInactivityTimeout
1422
- **********************************************/
1423
-
1424
- int ConnectionDescriptor::SetCommInactivityTimeout (int *value)
1425
- {
1426
- int out = 0;
1427
-
1428
- if (value) {
1429
- if ((*value==0) || (*value >= 2)) {
1430
- // Replace the value and send the old one back to the caller.
1431
- int v = *value;
1432
- *value = InactivityTimeout;
1433
- InactivityTimeout = v;
1434
- out = 1;
1435
- }
1436
- else {
1437
- // TODO, extended logging, got bad value.
1438
- }
1439
- }
1440
- else {
1441
- // TODO, extended logging, got bad parameter.
1442
- }
1443
-
1444
- return out;
1445
- }
1446
-
1447
- /*******************************
1448
- DatagramDescriptor::GetPeername
1449
- *******************************/
1450
-
1451
- bool DatagramDescriptor::GetPeername (struct sockaddr *s)
1452
- {
1453
- bool ok = false;
1454
- if (s) {
1455
- memset (s, 0, sizeof(struct sockaddr));
1456
- memcpy (s, &ReturnAddress, sizeof(ReturnAddress));
1457
- ok = true;
1458
- }
1459
- return ok;
1460
- }
1461
-
1462
- /*******************************
1463
- DatagramDescriptor::GetSockname
1464
- *******************************/
1465
-
1466
- bool DatagramDescriptor::GetSockname (struct sockaddr *s)
1467
- {
1468
- bool ok = false;
1469
- if (s) {
1470
- socklen_t len = sizeof(*s);
1471
- int gp = getsockname (GetSocket(), s, &len);
1472
- if (gp == 0)
1473
- ok = true;
1474
- }
1475
- return ok;
1476
- }
1477
-
1478
-
1479
-
1480
- /********************************************
1481
- DatagramDescriptor::GetCommInactivityTimeout
1482
- ********************************************/
1483
-
1484
- int DatagramDescriptor::GetCommInactivityTimeout (int *value)
1485
- {
1486
- if (value) {
1487
- *value = InactivityTimeout;
1488
- return 1;
1489
- }
1490
- else {
1491
- // TODO, extended logging, got bad parameter.
1492
- return 0;
1493
- }
1494
- }
1495
-
1496
- /********************************************
1497
- DatagramDescriptor::SetCommInactivityTimeout
1498
- ********************************************/
1499
-
1500
- int DatagramDescriptor::SetCommInactivityTimeout (int *value)
1501
- {
1502
- int out = 0;
1503
-
1504
- if (value) {
1505
- if ((*value==0) || (*value >= 2)) {
1506
- // Replace the value and send the old one back to the caller.
1507
- int v = *value;
1508
- *value = InactivityTimeout;
1509
- InactivityTimeout = v;
1510
- out = 1;
1511
- }
1512
- else {
1513
- // TODO, extended logging, got bad value.
1514
- }
1515
- }
1516
- else {
1517
- // TODO, extended logging, got bad parameter.
1518
- }
1519
-
1520
- return out;
1521
- }
1522
-
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: ed.cpp
6
+ Date: 06Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ #include "project.h"
21
+
22
+
23
+
24
+ /********************
25
+ SetSocketNonblocking
26
+ ********************/
27
+
28
+ bool SetSocketNonblocking (SOCKET sd)
29
+ {
30
+ #ifdef OS_UNIX
31
+ int val = fcntl (sd, F_GETFL, 0);
32
+ return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false;
33
+ #endif
34
+
35
+ #ifdef OS_WIN32
36
+ unsigned long one = 1;
37
+ return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false;
38
+ #endif
39
+ }
40
+
41
+
42
+ /****************************************
43
+ EventableDescriptor::EventableDescriptor
44
+ ****************************************/
45
+
46
+ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
47
+ bCloseNow (false),
48
+ bCloseAfterWriting (false),
49
+ MySocket (sd),
50
+ EventCallback (NULL),
51
+ bCallbackUnbind (true),
52
+ UnbindReasonCode (0),
53
+ ProxyTarget(NULL),
54
+ MyEventMachine (em)
55
+ {
56
+ /* There are three ways to close a socket, all of which should
57
+ * automatically signal to the event machine that this object
58
+ * should be removed from the polling scheduler.
59
+ * First is a hard close, intended for bad errors or possible
60
+ * security violations. It immediately closes the connection
61
+ * and puts this object into an error state.
62
+ * Second is to set bCloseNow, which will cause the event machine
63
+ * to delete this object (and thus close the connection in our
64
+ * destructor) the next chance it gets. bCloseNow also inhibits
65
+ * the writing of new data on the socket (but not necessarily
66
+ * the reading of new data).
67
+ * The third way is to set bCloseAfterWriting, which inhibits
68
+ * the writing of new data and converts to bCloseNow as soon
69
+ * as everything in the outbound queue has been written.
70
+ * bCloseAfterWriting is really for use only by protocol handlers
71
+ * (for example, HTTP writes an HTML page and then closes the
72
+ * connection). All of the error states we generate internally
73
+ * cause an immediate close to be scheduled, which may have the
74
+ * effect of discarding outbound data.
75
+ */
76
+
77
+ if (sd == INVALID_SOCKET)
78
+ throw std::runtime_error ("bad eventable descriptor");
79
+ if (MyEventMachine == NULL)
80
+ throw std::runtime_error ("bad em in eventable descriptor");
81
+ CreatedAt = gCurrentLoopTime;
82
+
83
+ #ifdef HAVE_EPOLL
84
+ EpollEvent.data.ptr = this;
85
+ #endif
86
+ }
87
+
88
+
89
+ /*****************************************
90
+ EventableDescriptor::~EventableDescriptor
91
+ *****************************************/
92
+
93
+ EventableDescriptor::~EventableDescriptor()
94
+ {
95
+ if (EventCallback && bCallbackUnbind)
96
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
97
+ StopProxy();
98
+ Close();
99
+ }
100
+
101
+
102
+ /*************************************
103
+ EventableDescriptor::SetEventCallback
104
+ *************************************/
105
+
106
+ void EventableDescriptor::SetEventCallback (void(*cb)(const char*, int, const char*, int))
107
+ {
108
+ EventCallback = cb;
109
+ }
110
+
111
+
112
+ /**************************
113
+ EventableDescriptor::Close
114
+ **************************/
115
+
116
+ void EventableDescriptor::Close()
117
+ {
118
+ // Close the socket right now. Intended for emergencies.
119
+ if (MySocket != INVALID_SOCKET) {
120
+ shutdown (MySocket, 1);
121
+ closesocket (MySocket);
122
+ MySocket = INVALID_SOCKET;
123
+ }
124
+ }
125
+
126
+
127
+ /*********************************
128
+ EventableDescriptor::ShouldDelete
129
+ *********************************/
130
+
131
+ bool EventableDescriptor::ShouldDelete()
132
+ {
133
+ /* For use by a socket manager, which needs to know if this object
134
+ * should be removed from scheduling events and deleted.
135
+ * Has an immediate close been scheduled, or are we already closed?
136
+ * If either of these are the case, return true. In theory, the manager will
137
+ * then delete us, which in turn will make sure the socket is closed.
138
+ * Note, if bCloseAfterWriting is true, we check a virtual method to see
139
+ * if there is outbound data to write, and only request a close if there is none.
140
+ */
141
+
142
+ return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
143
+ }
144
+
145
+
146
+ /**********************************
147
+ EventableDescriptor::ScheduleClose
148
+ **********************************/
149
+
150
+ void EventableDescriptor::ScheduleClose (bool after_writing)
151
+ {
152
+ // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
153
+ if (after_writing)
154
+ bCloseAfterWriting = true;
155
+ else
156
+ bCloseNow = true;
157
+ }
158
+
159
+
160
+ /*************************************
161
+ EventableDescriptor::IsCloseScheduled
162
+ *************************************/
163
+
164
+ bool EventableDescriptor::IsCloseScheduled()
165
+ {
166
+ // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose.
167
+ return (bCloseNow || bCloseAfterWriting);
168
+ }
169
+
170
+
171
+ /*******************************
172
+ EventableDescriptor::StartProxy
173
+ *******************************/
174
+
175
+ void EventableDescriptor::StartProxy(const char *to)
176
+ {
177
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (to));
178
+ if (ed) {
179
+ StopProxy();
180
+ ProxyTarget = strdup(to);
181
+ return;
182
+ }
183
+ throw std::runtime_error ("Tried to proxy to an invalid descriptor");
184
+ }
185
+
186
+
187
+ /******************************
188
+ EventableDescriptor::StopProxy
189
+ ******************************/
190
+
191
+ void EventableDescriptor::StopProxy()
192
+ {
193
+ if (ProxyTarget) {
194
+ free(ProxyTarget);
195
+ ProxyTarget = NULL;
196
+ }
197
+ }
198
+
199
+
200
+ /********************************************
201
+ EventableDescriptor::_GenericInboundDispatch
202
+ ********************************************/
203
+
204
+ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
205
+ {
206
+ assert(EventCallback);
207
+
208
+ if (!ProxyTarget)
209
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buf, size);
210
+ else if (ConnectionDescriptor::SendDataToConnection(ProxyTarget, buf, size) == -1) {
211
+ (*EventCallback)(GetBinding().c_str(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
212
+ StopProxy();
213
+ }
214
+ }
215
+
216
+
217
+ /******************************************
218
+ ConnectionDescriptor::ConnectionDescriptor
219
+ ******************************************/
220
+
221
+ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
222
+ EventableDescriptor (sd, em),
223
+ bConnectPending (false),
224
+ bNotifyReadable (false),
225
+ bNotifyWritable (false),
226
+ bReadAttemptedAfterClose (false),
227
+ bWriteAttemptedAfterClose (false),
228
+ OutboundDataSize (0),
229
+ #ifdef WITH_SSL
230
+ SslBox (NULL),
231
+ bHandshakeSignaled (false),
232
+ bSslVerifyPeer (false),
233
+ bSslPeerAccepted(false),
234
+ #endif
235
+ #ifdef HAVE_KQUEUE
236
+ bGotExtraKqueueEvent(false),
237
+ #endif
238
+ bIsServer (false),
239
+ LastIo (gCurrentLoopTime),
240
+ InactivityTimeout (0)
241
+ {
242
+ // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData()
243
+ // 5May09: Moved EPOLLOUT into SetConnectPending() so it doesn't happen for attached read pipes
244
+ }
245
+
246
+
247
+ /*******************************************
248
+ ConnectionDescriptor::~ConnectionDescriptor
249
+ *******************************************/
250
+
251
+ ConnectionDescriptor::~ConnectionDescriptor()
252
+ {
253
+ // Run down any stranded outbound data.
254
+ for (size_t i=0; i < OutboundPages.size(); i++)
255
+ OutboundPages[i].Free();
256
+
257
+ #ifdef WITH_SSL
258
+ if (SslBox)
259
+ delete SslBox;
260
+ #endif
261
+ }
262
+
263
+
264
+ /**************************************************
265
+ STATIC: ConnectionDescriptor::SendDataToConnection
266
+ **************************************************/
267
+
268
+ int ConnectionDescriptor::SendDataToConnection (const char *binding, const char *data, int data_length)
269
+ {
270
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
271
+ // TODO: Poor polymorphism here. We should be calling one virtual method
272
+ // instead of hacking out the runtime information of the target object.
273
+ ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
274
+ if (cd)
275
+ return cd->SendOutboundData (data, data_length);
276
+ DatagramDescriptor *ds = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
277
+ if (ds)
278
+ return ds->SendOutboundData (data, data_length);
279
+ #ifdef OS_UNIX
280
+ PipeDescriptor *ps = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
281
+ if (ps)
282
+ return ps->SendOutboundData (data, data_length);
283
+ #endif
284
+ return -1;
285
+ }
286
+
287
+
288
+ /*********************************************
289
+ STATIC: ConnectionDescriptor::CloseConnection
290
+ *********************************************/
291
+
292
+ void ConnectionDescriptor::CloseConnection (const char *binding, bool after_writing)
293
+ {
294
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
295
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
296
+ if (ed)
297
+ ed->ScheduleClose (after_writing);
298
+ }
299
+
300
+ /***********************************************
301
+ STATIC: ConnectionDescriptor::ReportErrorStatus
302
+ ***********************************************/
303
+
304
+ int ConnectionDescriptor::ReportErrorStatus (const char *binding)
305
+ {
306
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
307
+ // TODO: Poor polymorphism here. We should be calling one virtual method
308
+ // instead of hacking out the runtime information of the target object.
309
+ ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
310
+ if (cd)
311
+ return cd->_ReportErrorStatus();
312
+ return -1;
313
+ }
314
+
315
+ /***************************************
316
+ ConnectionDescriptor::SetConnectPending
317
+ ****************************************/
318
+
319
+ void ConnectionDescriptor::SetConnectPending(bool f)
320
+ {
321
+ bConnectPending = f;
322
+
323
+ if (bConnectPending) { // not yet connected, select for writability
324
+ #ifdef HAVE_EPOLL
325
+ EpollEvent.events = EPOLLOUT;
326
+ #endif
327
+ #ifdef HAVE_KQUEUE
328
+ MyEventMachine->ArmKqueueWriter (this);
329
+ #endif
330
+ } else { // connected, wait for incoming data and write out any pending outgoing data
331
+ #ifdef HAVE_EPOLL
332
+ EpollEvent.events = EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0);
333
+ #endif
334
+ #ifdef HAVE_KQUEUE
335
+ MyEventMachine->ArmKqueueReader (this);
336
+ if (SelectForWrite())
337
+ MyEventMachine->ArmKqueueWriter (this);
338
+ #endif
339
+ }
340
+ }
341
+
342
+
343
+ /***************************************
344
+ ConnectionDescriptor::SetNotifyReadable
345
+ ****************************************/
346
+
347
+ void ConnectionDescriptor::SetNotifyReadable(bool readable)
348
+ {
349
+ bNotifyReadable = readable;
350
+ if (bNotifyReadable) {
351
+ #ifdef HAVE_EPOLL
352
+ EpollEvent.events |= EPOLLIN;
353
+ #endif
354
+ #ifdef HAVE_KQUEUE
355
+ MyEventMachine->ArmKqueueReader (this);
356
+ #endif
357
+ }
358
+ }
359
+
360
+
361
+ /***************************************
362
+ ConnectionDescriptor::SetNotifyWritable
363
+ ****************************************/
364
+
365
+ void ConnectionDescriptor::SetNotifyWritable(bool writable)
366
+ {
367
+ bNotifyWritable = writable;
368
+ if (bNotifyWritable) {
369
+ #ifdef HAVE_EPOLL
370
+ EpollEvent.events |= EPOLLOUT;
371
+ #endif
372
+ #ifdef HAVE_KQUEUE
373
+ MyEventMachine->ArmKqueueWriter (this);
374
+ #endif
375
+ }
376
+ }
377
+
378
+
379
+ /**************************************
380
+ ConnectionDescriptor::SendOutboundData
381
+ **************************************/
382
+
383
+ int ConnectionDescriptor::SendOutboundData (const char *data, int length)
384
+ {
385
+ #ifdef WITH_SSL
386
+ if (SslBox) {
387
+ if (length > 0) {
388
+ int w = SslBox->PutPlaintext (data, length);
389
+ if (w < 0)
390
+ ScheduleClose (false);
391
+ else
392
+ _DispatchCiphertext();
393
+ }
394
+ // TODO: What's the correct return value?
395
+ return 1; // That's a wild guess, almost certainly wrong.
396
+ }
397
+ else
398
+ #endif
399
+ return _SendRawOutboundData (data, length);
400
+ }
401
+
402
+
403
+
404
+ /******************************************
405
+ ConnectionDescriptor::_SendRawOutboundData
406
+ ******************************************/
407
+
408
+ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
409
+ {
410
+ /* This internal method is called to schedule bytes that
411
+ * will be sent out to the remote peer.
412
+ * It's not directly accessed by the caller, who hits ::SendOutboundData,
413
+ * which may or may not filter or encrypt the caller's data before
414
+ * sending it here.
415
+ */
416
+
417
+ // Highly naive and incomplete implementation.
418
+ // There's no throttle for runaways (which should abort only this connection
419
+ // and not the whole process), and no coalescing of small pages.
420
+ // (Well, not so bad, small pages are coalesced in ::Write)
421
+
422
+ if (IsCloseScheduled())
423
+ //if (bCloseNow || bCloseAfterWriting)
424
+ return 0;
425
+
426
+ if (!data && (length > 0))
427
+ throw std::runtime_error ("bad outbound data");
428
+ char *buffer = (char *) malloc (length + 1);
429
+ if (!buffer)
430
+ throw std::runtime_error ("no allocation for outbound data");
431
+
432
+ memcpy (buffer, data, length);
433
+ buffer [length] = 0;
434
+ OutboundPages.push_back (OutboundPage (buffer, length));
435
+ OutboundDataSize += length;
436
+
437
+ #ifdef HAVE_EPOLL
438
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
439
+ assert (MyEventMachine);
440
+ MyEventMachine->Modify (this);
441
+ #endif
442
+ #ifdef HAVE_KQUEUE
443
+ MyEventMachine->ArmKqueueWriter (this);
444
+ #endif
445
+
446
+ return length;
447
+ }
448
+
449
+
450
+
451
+ /***********************************
452
+ ConnectionDescriptor::SelectForRead
453
+ ***********************************/
454
+
455
+ bool ConnectionDescriptor::SelectForRead()
456
+ {
457
+ /* A connection descriptor is always scheduled for read,
458
+ * UNLESS it's in a pending-connect state.
459
+ * On Linux, unlike Unix, a nonblocking socket on which
460
+ * connect has been called, does NOT necessarily select
461
+ * both readable and writable in case of error.
462
+ * The socket will select writable when the disposition
463
+ * of the connect is known. On the other hand, a socket
464
+ * which successfully connects and selects writable may
465
+ * indeed have some data available on it, so it will
466
+ * select readable in that case, violating expectations!
467
+ * So we will not poll for readability until the socket
468
+ * is known to be in a connected state.
469
+ */
470
+
471
+ return bConnectPending ? false : true;
472
+ }
473
+
474
+
475
+ /************************************
476
+ ConnectionDescriptor::SelectForWrite
477
+ ************************************/
478
+
479
+ bool ConnectionDescriptor::SelectForWrite()
480
+ {
481
+ /* Cf the notes under SelectForRead.
482
+ * In a pending-connect state, we ALWAYS select for writable.
483
+ * In a normal state, we only select for writable when we
484
+ * have outgoing data to send.
485
+ */
486
+
487
+ if (bConnectPending || bNotifyWritable)
488
+ return true;
489
+ else {
490
+ return (GetOutboundDataSize() > 0);
491
+ }
492
+ }
493
+
494
+
495
+ /**************************
496
+ ConnectionDescriptor::Read
497
+ **************************/
498
+
499
+ void ConnectionDescriptor::Read()
500
+ {
501
+ /* Read and dispatch data on a socket that has selected readable.
502
+ * It's theoretically possible to get and dispatch incoming data on
503
+ * a socket that has already been scheduled for closing or close-after-writing.
504
+ * In those cases, we'll leave it up the to protocol handler to "do the
505
+ * right thing" (which probably means to ignore the incoming data).
506
+ *
507
+ * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come
508
+ * here with the socket already closed, after the process receives
509
+ * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application
510
+ * was one in which network connections were doing a lot of interleaved reads
511
+ * and writes.
512
+ * Since we always write before reading (in order to keep the outbound queues
513
+ * as light as possible), I think what happened is that an interrupt caused
514
+ * the socket to be closed in ConnectionDescriptor::Write. We'll then
515
+ * come here in the same pass through the main event loop, and won't get
516
+ * cleaned up until immediately after.
517
+ * We originally asserted that the socket was valid when we got here.
518
+ * To deal properly with the possibility that we are closed when we get here,
519
+ * I removed the assert. HOWEVER, the potential for an infinite loop scares me,
520
+ * so even though this is really clunky, I added a flag to assert that we never
521
+ * come here more than once after being closed. (FCianfrocca)
522
+ */
523
+
524
+ int sd = GetSocket();
525
+ //assert (sd != INVALID_SOCKET); (original, removed 22Aug06)
526
+ if (sd == INVALID_SOCKET) {
527
+ assert (!bReadAttemptedAfterClose);
528
+ bReadAttemptedAfterClose = true;
529
+ return;
530
+ }
531
+
532
+ if (bNotifyReadable) {
533
+ if (EventCallback)
534
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
535
+ return;
536
+ }
537
+
538
+ LastIo = gCurrentLoopTime;
539
+
540
+ int total_bytes_read = 0;
541
+ char readbuffer [16 * 1024 + 1];
542
+
543
+ for (int i=0; i < 10; i++) {
544
+ // Don't read just one buffer and then move on. This is faster
545
+ // if there is a lot of incoming.
546
+ // But don't read indefinitely. Give other sockets a chance to run.
547
+ // NOTICE, we're reading one less than the buffer size.
548
+ // That's so we can put a guard byte at the end of what we send
549
+ // to user code.
550
+
551
+
552
+ int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
553
+ //cerr << "<R:" << r << ">";
554
+
555
+ if (r > 0) {
556
+ total_bytes_read += r;
557
+
558
+ // Add a null-terminator at the the end of the buffer
559
+ // that we will send to the callback.
560
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
561
+ // to be able to depend on this behavior, so they will have
562
+ // the option to do some things faster. Additionally it's
563
+ // a security guard against buffer overflows.
564
+ readbuffer [r] = 0;
565
+ _DispatchInboundData (readbuffer, r);
566
+ }
567
+ else if (r == 0) {
568
+ break;
569
+ }
570
+ else {
571
+ // Basically a would-block, meaning we've read everything there is to read.
572
+ break;
573
+ }
574
+
575
+ }
576
+
577
+
578
+ if (total_bytes_read == 0) {
579
+ // If we read no data on a socket that selected readable,
580
+ // it generally means the other end closed the connection gracefully.
581
+ ScheduleClose (false);
582
+ //bCloseNow = true;
583
+ }
584
+
585
+ }
586
+
587
+
588
+
589
+ /******************************************
590
+ ConnectionDescriptor::_DispatchInboundData
591
+ ******************************************/
592
+
593
+ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
594
+ {
595
+ #ifdef WITH_SSL
596
+ if (SslBox) {
597
+ SslBox->PutCiphertext (buffer, size);
598
+
599
+ int s;
600
+ char B [2048];
601
+ while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
602
+ _CheckHandshakeStatus();
603
+ B [s] = 0;
604
+ _GenericInboundDispatch(B, s);
605
+ }
606
+
607
+ // If our SSL handshake had a problem, shut down the connection.
608
+ if (s == -2) {
609
+ ScheduleClose(false);
610
+ return;
611
+ }
612
+
613
+ _CheckHandshakeStatus();
614
+ _DispatchCiphertext();
615
+ }
616
+ else {
617
+ _GenericInboundDispatch(buffer, size);
618
+ }
619
+ #endif
620
+
621
+ #ifdef WITHOUT_SSL
622
+ _GenericInboundDispatch(buffer, size);
623
+ #endif
624
+ }
625
+
626
+
627
+
628
+ /*******************************************
629
+ ConnectionDescriptor::_CheckHandshakeStatus
630
+ *******************************************/
631
+
632
+ void ConnectionDescriptor::_CheckHandshakeStatus()
633
+ {
634
+ #ifdef WITH_SSL
635
+ if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) {
636
+ bHandshakeSignaled = true;
637
+ if (EventCallback)
638
+ (*EventCallback)(GetBinding().c_str(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
639
+ }
640
+ #endif
641
+ }
642
+
643
+
644
+
645
+ /***************************
646
+ ConnectionDescriptor::Write
647
+ ***************************/
648
+
649
+ void ConnectionDescriptor::Write()
650
+ {
651
+ /* A socket which is in a pending-connect state will select
652
+ * writable when the disposition of the connect is known.
653
+ * At that point, check to be sure there are no errors,
654
+ * and if none, then promote the socket out of the pending
655
+ * state.
656
+ * TODO: I haven't figured out how Windows signals errors on
657
+ * unconnected sockets. Maybe it does the untraditional but
658
+ * logical thing and makes the socket selectable for error.
659
+ * If so, it's unsupported here for the time being, and connect
660
+ * errors will have to be caught by the timeout mechanism.
661
+ */
662
+
663
+ if (bConnectPending) {
664
+ int error;
665
+ socklen_t len;
666
+ len = sizeof(error);
667
+ #ifdef OS_UNIX
668
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
669
+ #endif
670
+ #ifdef OS_WIN32
671
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
672
+ #endif
673
+ if ((o == 0) && (error == 0)) {
674
+ if (EventCallback)
675
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_COMPLETED, "", 0);
676
+
677
+ // 5May09: Moved epoll/kqueue read/write arming into SetConnectPending, so it can be called
678
+ // from EventMachine_t::AttachFD as well.
679
+ SetConnectPending (false);
680
+ }
681
+ else
682
+ ScheduleClose (false);
683
+ //bCloseNow = true;
684
+ }
685
+ else {
686
+
687
+ if (bNotifyWritable) {
688
+ if (EventCallback)
689
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
690
+ return;
691
+ }
692
+
693
+ /* 5May09: Kqueue bugs on OSX cause one extra writable event to fire even though we're using
694
+ EV_ONESHOT. We ignore this extra event once, but only the first time. If it happens again,
695
+ we should fall through to the assert(nbytes>0) failure to catch any EM bugs which might cause
696
+ ::Write to be called in a busy-loop.
697
+ */
698
+ #ifdef HAVE_KQUEUE
699
+ if (MyEventMachine->UsingKqueue()) {
700
+ if (OutboundDataSize == 0 && !bGotExtraKqueueEvent) {
701
+ bGotExtraKqueueEvent = true;
702
+ return;
703
+ } else if (OutboundDataSize > 0) {
704
+ bGotExtraKqueueEvent = false;
705
+ }
706
+ }
707
+ #endif
708
+
709
+ _WriteOutboundData();
710
+ }
711
+ }
712
+
713
+
714
+ /****************************************
715
+ ConnectionDescriptor::_WriteOutboundData
716
+ ****************************************/
717
+
718
+ void ConnectionDescriptor::_WriteOutboundData()
719
+ {
720
+ /* This is a helper function called by ::Write.
721
+ * It's possible for a socket to select writable and then no longer
722
+ * be writable by the time we get around to writing. The kernel might
723
+ * have used up its available output buffers between the select call
724
+ * and when we get here. So this condition is not an error.
725
+ *
726
+ * 20Jul07, added the same kind of protection against an invalid socket
727
+ * that is at the top of ::Read. Not entirely how this could happen in
728
+ * real life (connection-reset from the remote peer, perhaps?), but I'm
729
+ * doing it to address some reports of crashing under heavy loads.
730
+ */
731
+
732
+ int sd = GetSocket();
733
+ //assert (sd != INVALID_SOCKET);
734
+ if (sd == INVALID_SOCKET) {
735
+ assert (!bWriteAttemptedAfterClose);
736
+ bWriteAttemptedAfterClose = true;
737
+ return;
738
+ }
739
+
740
+ LastIo = gCurrentLoopTime;
741
+ size_t nbytes = 0;
742
+
743
+ #ifdef HAVE_WRITEV
744
+ int iovcnt = OutboundPages.size();
745
+ // Max of 16 outbound pages at a time
746
+ if (iovcnt > 16) iovcnt = 16;
747
+
748
+ struct iovec iov[ iovcnt ];
749
+
750
+ for(int i = 0; i < iovcnt; i++){
751
+ OutboundPage *op = &(OutboundPages[i]);
752
+ iov[i].iov_base = (void *)(op->Buffer + op->Offset);
753
+ iov[i].iov_len = op->Length - op->Offset;
754
+
755
+ nbytes += iov[i].iov_len;
756
+ }
757
+ #else
758
+ char output_buffer [16 * 1024];
759
+
760
+ while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
761
+ OutboundPage *op = &(OutboundPages[0]);
762
+ if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
763
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
764
+ nbytes += (op->Length - op->Offset);
765
+ op->Free();
766
+ OutboundPages.pop_front();
767
+ }
768
+ else {
769
+ int len = sizeof(output_buffer) - nbytes;
770
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
771
+ op->Offset += len;
772
+ nbytes += len;
773
+ }
774
+ }
775
+ #endif
776
+
777
+ // We should never have gotten here if there were no data to write,
778
+ // so assert that as a sanity check.
779
+ // Don't bother to make sure nbytes is less than output_buffer because
780
+ // if it were we probably would have crashed already.
781
+ assert (nbytes > 0);
782
+
783
+ assert (GetSocket() != INVALID_SOCKET);
784
+ #ifdef HAVE_WRITEV
785
+ int bytes_written = writev (GetSocket(), iov, iovcnt);
786
+ #else
787
+ int bytes_written = write (GetSocket(), output_buffer, nbytes);
788
+ #endif
789
+
790
+ bool err = false;
791
+ if (bytes_written < 0) {
792
+ err = true;
793
+ bytes_written = 0;
794
+ }
795
+
796
+ assert (bytes_written >= 0);
797
+ OutboundDataSize -= bytes_written;
798
+
799
+ #ifdef HAVE_WRITEV
800
+ if (!err) {
801
+ int sent = bytes_written;
802
+ deque<OutboundPage>::iterator op = OutboundPages.begin();
803
+
804
+ for (int i = 0; i < iovcnt; i++) {
805
+ if (iov[i].iov_len <= sent) {
806
+ // Sent this page in full, free it.
807
+ op->Free();
808
+ OutboundPages.pop_front();
809
+
810
+ sent -= iov[i].iov_len;
811
+ } else {
812
+ // Sent part (or none) of this page, increment offset to send the remainder
813
+ op->Offset += sent;
814
+ break;
815
+ }
816
+
817
+ // Shouldn't be possible run out of pages before the loop ends
818
+ assert(op != OutboundPages.end());
819
+ *op++;
820
+ }
821
+ }
822
+ #else
823
+ if ((size_t)bytes_written < nbytes) {
824
+ int len = nbytes - bytes_written;
825
+ char *buffer = (char*) malloc (len + 1);
826
+ if (!buffer)
827
+ throw std::runtime_error ("bad alloc throwing back data");
828
+ memcpy (buffer, output_buffer + bytes_written, len);
829
+ buffer [len] = 0;
830
+ OutboundPages.push_front (OutboundPage (buffer, len));
831
+ }
832
+ #endif
833
+
834
+ #ifdef HAVE_EPOLL
835
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
836
+ assert (MyEventMachine);
837
+ MyEventMachine->Modify (this);
838
+ #endif
839
+ #ifdef HAVE_KQUEUE
840
+ if (SelectForWrite())
841
+ MyEventMachine->ArmKqueueWriter (this);
842
+ #endif
843
+
844
+
845
+ if (err) {
846
+ #ifdef OS_UNIX
847
+ if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
848
+ #endif
849
+ #ifdef OS_WIN32
850
+ if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
851
+ #endif
852
+ Close();
853
+ }
854
+ }
855
+
856
+
857
+ /****************************************
858
+ ConnectionDescriptor::_ReportErrorStatus
859
+ ****************************************/
860
+
861
+ int ConnectionDescriptor::_ReportErrorStatus()
862
+ {
863
+ int error;
864
+ socklen_t len;
865
+ len = sizeof(error);
866
+ #ifdef OS_UNIX
867
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
868
+ #endif
869
+ #ifdef OS_WIN32
870
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
871
+ #endif
872
+ if ((o == 0) && (error == 0))
873
+ return 0;
874
+ else
875
+ return 1;
876
+ }
877
+
878
+
879
+ /******************************
880
+ ConnectionDescriptor::StartTls
881
+ ******************************/
882
+
883
+ void ConnectionDescriptor::StartTls()
884
+ {
885
+ #ifdef WITH_SSL
886
+ if (SslBox)
887
+ throw std::runtime_error ("SSL/TLS already running on connection");
888
+
889
+ SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding().c_str());
890
+ _DispatchCiphertext();
891
+ #endif
892
+
893
+ #ifdef WITHOUT_SSL
894
+ throw std::runtime_error ("Encryption not available on this event-machine");
895
+ #endif
896
+ }
897
+
898
+
899
+ /*********************************
900
+ ConnectionDescriptor::SetTlsParms
901
+ *********************************/
902
+
903
+ void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer)
904
+ {
905
+ #ifdef WITH_SSL
906
+ if (SslBox)
907
+ throw std::runtime_error ("call SetTlsParms before calling StartTls");
908
+ if (privkey_filename && *privkey_filename)
909
+ PrivateKeyFilename = privkey_filename;
910
+ if (certchain_filename && *certchain_filename)
911
+ CertChainFilename = certchain_filename;
912
+ bSslVerifyPeer = verify_peer;
913
+ #endif
914
+
915
+ #ifdef WITHOUT_SSL
916
+ throw std::runtime_error ("Encryption not available on this event-machine");
917
+ #endif
918
+ }
919
+
920
+
921
+ /*********************************
922
+ ConnectionDescriptor::GetPeerCert
923
+ *********************************/
924
+
925
+ #ifdef WITH_SSL
926
+ X509 *ConnectionDescriptor::GetPeerCert()
927
+ {
928
+ if (!SslBox)
929
+ throw std::runtime_error ("SSL/TLS not running on this connection");
930
+ return SslBox->GetPeerCert();
931
+ }
932
+ #endif
933
+
934
+
935
+ /***********************************
936
+ ConnectionDescriptor::VerifySslPeer
937
+ ***********************************/
938
+
939
+ #ifdef WITH_SSL
940
+ bool ConnectionDescriptor::VerifySslPeer(const char *cert)
941
+ {
942
+ bSslPeerAccepted = false;
943
+
944
+ if (EventCallback)
945
+ (*EventCallback)(GetBinding().c_str(), EM_SSL_VERIFY, cert, strlen(cert));
946
+
947
+ return bSslPeerAccepted;
948
+ }
949
+ #endif
950
+
951
+
952
+ /***********************************
953
+ ConnectionDescriptor::AcceptSslPeer
954
+ ***********************************/
955
+
956
+ #ifdef WITH_SSL
957
+ void ConnectionDescriptor::AcceptSslPeer()
958
+ {
959
+ bSslPeerAccepted = true;
960
+ }
961
+ #endif
962
+
963
+
964
+ /*****************************************
965
+ ConnectionDescriptor::_DispatchCiphertext
966
+ *****************************************/
967
+
968
+ #ifdef WITH_SSL
969
+ void ConnectionDescriptor::_DispatchCiphertext()
970
+ {
971
+ assert (SslBox);
972
+
973
+
974
+ char BigBuf [2048];
975
+ bool did_work;
976
+
977
+ do {
978
+ did_work = false;
979
+
980
+ // try to drain ciphertext
981
+ while (SslBox->CanGetCiphertext()) {
982
+ int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf));
983
+ assert (r > 0);
984
+ _SendRawOutboundData (BigBuf, r);
985
+ did_work = true;
986
+ }
987
+
988
+ // Pump the SslBox, in case it has queued outgoing plaintext
989
+ // This will return >0 if data was written,
990
+ // 0 if no data was written, and <0 if there was a fatal error.
991
+ bool pump;
992
+ do {
993
+ pump = false;
994
+ int w = SslBox->PutPlaintext (NULL, 0);
995
+ if (w > 0) {
996
+ did_work = true;
997
+ pump = true;
998
+ }
999
+ else if (w < 0)
1000
+ ScheduleClose (false);
1001
+ } while (pump);
1002
+
1003
+ // try to put plaintext. INCOMPLETE, doesn't belong here?
1004
+ // In SendOutboundData, we're spooling plaintext directly
1005
+ // into SslBox. That may be wrong, we may need to buffer it
1006
+ // up here!
1007
+ /*
1008
+ const char *ptr;
1009
+ int ptr_length;
1010
+ while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) {
1011
+ assert (ptr && (ptr_length > 0));
1012
+ int w = SslMachine.PutPlaintext (ptr, ptr_length);
1013
+ if (w > 0) {
1014
+ OutboundPlaintext.DiscardBytes (w);
1015
+ did_work = true;
1016
+ }
1017
+ else
1018
+ break;
1019
+ }
1020
+ */
1021
+
1022
+ } while (did_work);
1023
+
1024
+ }
1025
+ #endif
1026
+
1027
+
1028
+
1029
+ /*******************************
1030
+ ConnectionDescriptor::Heartbeat
1031
+ *******************************/
1032
+
1033
+ void ConnectionDescriptor::Heartbeat()
1034
+ {
1035
+ /* Only allow a certain amount of time to go by while waiting
1036
+ * for a pending connect. If it expires, then kill the socket.
1037
+ * For a connected socket, close it if its inactivity timer
1038
+ * has expired.
1039
+ */
1040
+
1041
+ if (bConnectPending) {
1042
+ if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
1043
+ ScheduleClose (false);
1044
+ //bCloseNow = true;
1045
+ }
1046
+ else {
1047
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1048
+ ScheduleClose (false);
1049
+ //bCloseNow = true;
1050
+ }
1051
+ }
1052
+
1053
+
1054
+ /****************************************
1055
+ LoopbreakDescriptor::LoopbreakDescriptor
1056
+ ****************************************/
1057
+
1058
+ LoopbreakDescriptor::LoopbreakDescriptor (int sd, EventMachine_t *parent_em):
1059
+ EventableDescriptor (sd, parent_em)
1060
+ {
1061
+ /* This is really bad and ugly. Change someday if possible.
1062
+ * We have to know about an event-machine (probably the one that owns us),
1063
+ * so we can pass newly-created connections to it.
1064
+ */
1065
+
1066
+ bCallbackUnbind = false;
1067
+
1068
+ #ifdef HAVE_EPOLL
1069
+ EpollEvent.events = EPOLLIN;
1070
+ #endif
1071
+ #ifdef HAVE_KQUEUE
1072
+ MyEventMachine->ArmKqueueReader (this);
1073
+ #endif
1074
+ }
1075
+
1076
+
1077
+
1078
+
1079
+ /*************************
1080
+ LoopbreakDescriptor::Read
1081
+ *************************/
1082
+
1083
+ void LoopbreakDescriptor::Read()
1084
+ {
1085
+ // TODO, refactor, this code is probably in the wrong place.
1086
+ assert (MyEventMachine);
1087
+ MyEventMachine->_ReadLoopBreaker();
1088
+ }
1089
+
1090
+
1091
+ /**************************
1092
+ LoopbreakDescriptor::Write
1093
+ **************************/
1094
+
1095
+ void LoopbreakDescriptor::Write()
1096
+ {
1097
+ // Why are we here?
1098
+ throw std::runtime_error ("bad code path in loopbreak");
1099
+ }
1100
+
1101
+ /**************************************
1102
+ AcceptorDescriptor::AcceptorDescriptor
1103
+ **************************************/
1104
+
1105
+ AcceptorDescriptor::AcceptorDescriptor (int sd, EventMachine_t *parent_em):
1106
+ EventableDescriptor (sd, parent_em)
1107
+ {
1108
+ #ifdef HAVE_EPOLL
1109
+ EpollEvent.events = EPOLLIN;
1110
+ #endif
1111
+ #ifdef HAVE_KQUEUE
1112
+ MyEventMachine->ArmKqueueReader (this);
1113
+ #endif
1114
+ }
1115
+
1116
+
1117
+ /***************************************
1118
+ AcceptorDescriptor::~AcceptorDescriptor
1119
+ ***************************************/
1120
+
1121
+ AcceptorDescriptor::~AcceptorDescriptor()
1122
+ {
1123
+ }
1124
+
1125
+ /****************************************
1126
+ STATIC: AcceptorDescriptor::StopAcceptor
1127
+ ****************************************/
1128
+
1129
+ void AcceptorDescriptor::StopAcceptor (const char *binding)
1130
+ {
1131
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
1132
+ AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding));
1133
+ if (ad)
1134
+ ad->ScheduleClose (false);
1135
+ else
1136
+ throw std::runtime_error ("failed to close nonexistent acceptor");
1137
+ }
1138
+
1139
+
1140
+ /************************
1141
+ AcceptorDescriptor::Read
1142
+ ************************/
1143
+
1144
+ void AcceptorDescriptor::Read()
1145
+ {
1146
+ /* Accept up to a certain number of sockets on the listening connection.
1147
+ * Don't try to accept all that are present, because this would allow a DoS attack
1148
+ * in which no data were ever read or written. We should accept more than one,
1149
+ * if available, to keep the partially accepted sockets from backing up in the kernel.
1150
+ */
1151
+
1152
+ /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it
1153
+ * for readability. According to Stevens UNP, it's possible for an acceptor to select readable
1154
+ * and then block when we call accept. For example, the other end resets the connection after
1155
+ * the socket selects readable and before we call accept. The kernel will remove the dead
1156
+ * socket from the accept queue. If the accept queue is now empty, accept will block.
1157
+ */
1158
+
1159
+
1160
+ struct sockaddr_in pin;
1161
+ socklen_t addrlen = sizeof (pin);
1162
+
1163
+ for (int i=0; i < 10; i++) {
1164
+ int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
1165
+ if (sd == INVALID_SOCKET) {
1166
+ // This breaks the loop when we've accepted everything on the kernel queue,
1167
+ // up to 10 new connections. But what if the *first* accept fails?
1168
+ // Does that mean anything serious is happening, beyond the situation
1169
+ // described in the note above?
1170
+ break;
1171
+ }
1172
+
1173
+ // Set the newly-accepted socket non-blocking.
1174
+ // On Windows, this may fail because, weirdly, Windows inherits the non-blocking
1175
+ // attribute that we applied to the acceptor socket into the accepted one.
1176
+ if (!SetSocketNonblocking (sd)) {
1177
+ //int val = fcntl (sd, F_GETFL, 0);
1178
+ //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
1179
+ shutdown (sd, 1);
1180
+ closesocket (sd);
1181
+ continue;
1182
+ }
1183
+
1184
+
1185
+ // Disable slow-start (Nagle algorithm). Eventually make this configurable.
1186
+ int one = 1;
1187
+ setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
1188
+
1189
+
1190
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine);
1191
+ if (!cd)
1192
+ throw std::runtime_error ("no newly accepted connection");
1193
+ cd->SetServerMode();
1194
+ if (EventCallback) {
1195
+ (*EventCallback) (GetBinding().c_str(), EM_CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
1196
+ }
1197
+ #ifdef HAVE_EPOLL
1198
+ cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0);
1199
+ #endif
1200
+ assert (MyEventMachine);
1201
+ MyEventMachine->Add (cd);
1202
+ #ifdef HAVE_KQUEUE
1203
+ if (cd->SelectForWrite())
1204
+ MyEventMachine->ArmKqueueWriter (cd);
1205
+ MyEventMachine->ArmKqueueReader (cd);
1206
+ #endif
1207
+ }
1208
+
1209
+ }
1210
+
1211
+
1212
+ /*************************
1213
+ AcceptorDescriptor::Write
1214
+ *************************/
1215
+
1216
+ void AcceptorDescriptor::Write()
1217
+ {
1218
+ // Why are we here?
1219
+ throw std::runtime_error ("bad code path in acceptor");
1220
+ }
1221
+
1222
+
1223
+ /*****************************
1224
+ AcceptorDescriptor::Heartbeat
1225
+ *****************************/
1226
+
1227
+ void AcceptorDescriptor::Heartbeat()
1228
+ {
1229
+ // No-op
1230
+ }
1231
+
1232
+
1233
+ /*******************************
1234
+ AcceptorDescriptor::GetSockname
1235
+ *******************************/
1236
+
1237
+ bool AcceptorDescriptor::GetSockname (struct sockaddr *s)
1238
+ {
1239
+ bool ok = false;
1240
+ if (s) {
1241
+ socklen_t len = sizeof(*s);
1242
+ int gp = getsockname (GetSocket(), s, &len);
1243
+ if (gp == 0)
1244
+ ok = true;
1245
+ }
1246
+ return ok;
1247
+ }
1248
+
1249
+
1250
+
1251
+ /**************************************
1252
+ DatagramDescriptor::DatagramDescriptor
1253
+ **************************************/
1254
+
1255
+ DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
1256
+ EventableDescriptor (sd, parent_em),
1257
+ OutboundDataSize (0),
1258
+ LastIo (gCurrentLoopTime),
1259
+ InactivityTimeout (0)
1260
+ {
1261
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1262
+
1263
+ /* Provisionally added 19Oct07. All datagram sockets support broadcasting.
1264
+ * Until now, sending to a broadcast address would give EACCES (permission denied)
1265
+ * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order
1266
+ * to accept a packet to a broadcast address. Solaris doesn't require it. I think
1267
+ * Windows DOES require it but I'm not sure.
1268
+ *
1269
+ * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST
1270
+ * on a UDP socket in order to enable broadcasting. The reason for requiring the option
1271
+ * in the first place is so that applications don't send broadcast datagrams by mistake.
1272
+ * I imagine that could happen if a user of an application typed in an address that happened
1273
+ * to be a broadcast address on that particular subnet.
1274
+ *
1275
+ * This is provisional because someone may eventually come up with a good reason not to
1276
+ * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API
1277
+ * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T
1278
+ * EXPLICITLY SET THE OPTION.
1279
+ */
1280
+
1281
+ int oval = 1;
1282
+ int sob = setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval));
1283
+
1284
+ #ifdef HAVE_EPOLL
1285
+ EpollEvent.events = EPOLLIN;
1286
+ #endif
1287
+ #ifdef HAVE_KQUEUE
1288
+ MyEventMachine->ArmKqueueReader (this);
1289
+ #endif
1290
+ }
1291
+
1292
+
1293
+ /***************************************
1294
+ DatagramDescriptor::~DatagramDescriptor
1295
+ ***************************************/
1296
+
1297
+ DatagramDescriptor::~DatagramDescriptor()
1298
+ {
1299
+ // Run down any stranded outbound data.
1300
+ for (size_t i=0; i < OutboundPages.size(); i++)
1301
+ OutboundPages[i].Free();
1302
+ }
1303
+
1304
+
1305
+ /*****************************
1306
+ DatagramDescriptor::Heartbeat
1307
+ *****************************/
1308
+
1309
+ void DatagramDescriptor::Heartbeat()
1310
+ {
1311
+ // Close it if its inactivity timer has expired.
1312
+
1313
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1314
+ ScheduleClose (false);
1315
+ //bCloseNow = true;
1316
+ }
1317
+
1318
+
1319
+ /************************
1320
+ DatagramDescriptor::Read
1321
+ ************************/
1322
+
1323
+ void DatagramDescriptor::Read()
1324
+ {
1325
+ int sd = GetSocket();
1326
+ assert (sd != INVALID_SOCKET);
1327
+ LastIo = gCurrentLoopTime;
1328
+
1329
+ // This is an extremely large read buffer.
1330
+ // In many cases you wouldn't expect to get any more than 4K.
1331
+ char readbuffer [16 * 1024];
1332
+
1333
+ for (int i=0; i < 10; i++) {
1334
+ // Don't read just one buffer and then move on. This is faster
1335
+ // if there is a lot of incoming.
1336
+ // But don't read indefinitely. Give other sockets a chance to run.
1337
+ // NOTICE, we're reading one less than the buffer size.
1338
+ // That's so we can put a guard byte at the end of what we send
1339
+ // to user code.
1340
+
1341
+ struct sockaddr_in sin;
1342
+ socklen_t slen = sizeof (sin);
1343
+ memset (&sin, 0, slen);
1344
+
1345
+ int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen);
1346
+ //cerr << "<R:" << r << ">";
1347
+
1348
+ // In UDP, a zero-length packet is perfectly legal.
1349
+ if (r >= 0) {
1350
+
1351
+ // Add a null-terminator at the the end of the buffer
1352
+ // that we will send to the callback.
1353
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
1354
+ // to be able to depend on this behavior, so they will have
1355
+ // the option to do some things faster. Additionally it's
1356
+ // a security guard against buffer overflows.
1357
+ readbuffer [r] = 0;
1358
+
1359
+
1360
+ // Set up a "temporary" return address so that callers can "reply" to us
1361
+ // from within the callback we are about to invoke. That means that ordinary
1362
+ // calls to "send_data_to_connection" (which is of course misnamed in this
1363
+ // case) will result in packets being sent back to the same place that sent
1364
+ // us this one.
1365
+ // There is a different call (evma_send_datagram) for cases where the caller
1366
+ // actually wants to send a packet somewhere else.
1367
+
1368
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1369
+ memcpy (&ReturnAddress, &sin, slen);
1370
+
1371
+ _GenericInboundDispatch(readbuffer, r);
1372
+
1373
+ }
1374
+ else {
1375
+ // Basically a would-block, meaning we've read everything there is to read.
1376
+ break;
1377
+ }
1378
+
1379
+ }
1380
+
1381
+
1382
+ }
1383
+
1384
+
1385
+ /*************************
1386
+ DatagramDescriptor::Write
1387
+ *************************/
1388
+
1389
+ void DatagramDescriptor::Write()
1390
+ {
1391
+ /* It's possible for a socket to select writable and then no longer
1392
+ * be writable by the time we get around to writing. The kernel might
1393
+ * have used up its available output buffers between the select call
1394
+ * and when we get here. So this condition is not an error.
1395
+ * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData,
1396
+ * but differs in the that the outbound data pages (received from the
1397
+ * user) are _message-structured._ That is, we send each of them out
1398
+ * one message at a time.
1399
+ * TODO, we are currently suppressing the EMSGSIZE error!!!
1400
+ */
1401
+
1402
+ int sd = GetSocket();
1403
+ assert (sd != INVALID_SOCKET);
1404
+ LastIo = gCurrentLoopTime;
1405
+
1406
+ assert (OutboundPages.size() > 0);
1407
+
1408
+ // Send out up to 10 packets, then cycle the machine.
1409
+ for (int i = 0; i < 10; i++) {
1410
+ if (OutboundPages.size() <= 0)
1411
+ break;
1412
+ OutboundPage *op = &(OutboundPages[0]);
1413
+
1414
+ // The nasty cast to (char*) is needed because Windows is brain-dead.
1415
+ int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
1416
+ int e = errno;
1417
+
1418
+ OutboundDataSize -= op->Length;
1419
+ op->Free();
1420
+ OutboundPages.pop_front();
1421
+
1422
+ if (s == SOCKET_ERROR) {
1423
+ #ifdef OS_UNIX
1424
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
1425
+ #endif
1426
+ #ifdef OS_WIN32
1427
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1428
+ #endif
1429
+ Close();
1430
+ break;
1431
+ }
1432
+ }
1433
+ }
1434
+
1435
+ #ifdef HAVE_EPOLL
1436
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
1437
+ assert (MyEventMachine);
1438
+ MyEventMachine->Modify (this);
1439
+ #endif
1440
+ }
1441
+
1442
+
1443
+ /**********************************
1444
+ DatagramDescriptor::SelectForWrite
1445
+ **********************************/
1446
+
1447
+ bool DatagramDescriptor::SelectForWrite()
1448
+ {
1449
+ /* Changed 15Nov07, per bug report by Mark Zvillius.
1450
+ * The outbound data size will be zero if there are zero-length outbound packets,
1451
+ * so we now select writable in case the outbound page buffer is not empty.
1452
+ * Note that the superclass ShouldDelete method still checks for outbound data size,
1453
+ * which may be wrong.
1454
+ */
1455
+ //return (GetOutboundDataSize() > 0); (Original)
1456
+ return (OutboundPages.size() > 0);
1457
+ }
1458
+
1459
+
1460
+ /************************************
1461
+ DatagramDescriptor::SendOutboundData
1462
+ ************************************/
1463
+
1464
+ int DatagramDescriptor::SendOutboundData (const char *data, int length)
1465
+ {
1466
+ // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1467
+ // That means it needs to move to a common ancestor.
1468
+
1469
+ if (IsCloseScheduled())
1470
+ //if (bCloseNow || bCloseAfterWriting)
1471
+ return 0;
1472
+
1473
+ if (!data && (length > 0))
1474
+ throw std::runtime_error ("bad outbound data");
1475
+ char *buffer = (char *) malloc (length + 1);
1476
+ if (!buffer)
1477
+ throw std::runtime_error ("no allocation for outbound data");
1478
+ memcpy (buffer, data, length);
1479
+ buffer [length] = 0;
1480
+ OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress));
1481
+ OutboundDataSize += length;
1482
+
1483
+ #ifdef HAVE_EPOLL
1484
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1485
+ assert (MyEventMachine);
1486
+ MyEventMachine->Modify (this);
1487
+ #endif
1488
+
1489
+ return length;
1490
+ }
1491
+
1492
+
1493
+ /****************************************
1494
+ DatagramDescriptor::SendOutboundDatagram
1495
+ ****************************************/
1496
+
1497
+ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, const char *address, int port)
1498
+ {
1499
+ // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1500
+ // That means it needs to move to a common ancestor.
1501
+ // TODO: Refactor this so there's no overlap with SendOutboundData.
1502
+
1503
+ if (IsCloseScheduled())
1504
+ //if (bCloseNow || bCloseAfterWriting)
1505
+ return 0;
1506
+
1507
+ if (!address || !*address || !port)
1508
+ return 0;
1509
+
1510
+ sockaddr_in pin;
1511
+ unsigned long HostAddr;
1512
+
1513
+ HostAddr = inet_addr (address);
1514
+ if (HostAddr == INADDR_NONE) {
1515
+ // The nasty cast to (char*) is because Windows is brain-dead.
1516
+ hostent *hp = gethostbyname ((char*)address);
1517
+ if (!hp)
1518
+ return 0;
1519
+ HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
1520
+ }
1521
+
1522
+ memset (&pin, 0, sizeof(pin));
1523
+ pin.sin_family = AF_INET;
1524
+ pin.sin_addr.s_addr = HostAddr;
1525
+ pin.sin_port = htons (port);
1526
+
1527
+
1528
+ if (!data && (length > 0))
1529
+ throw std::runtime_error ("bad outbound data");
1530
+ char *buffer = (char *) malloc (length + 1);
1531
+ if (!buffer)
1532
+ throw std::runtime_error ("no allocation for outbound data");
1533
+ memcpy (buffer, data, length);
1534
+ buffer [length] = 0;
1535
+ OutboundPages.push_back (OutboundPage (buffer, length, pin));
1536
+ OutboundDataSize += length;
1537
+
1538
+ #ifdef HAVE_EPOLL
1539
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1540
+ assert (MyEventMachine);
1541
+ MyEventMachine->Modify (this);
1542
+ #endif
1543
+
1544
+ return length;
1545
+ }
1546
+
1547
+
1548
+ /****************************************
1549
+ STATIC: DatagramDescriptor::SendDatagram
1550
+ ****************************************/
1551
+
1552
+ int DatagramDescriptor::SendDatagram (const char *binding, const char *data, int length, const char *address, int port)
1553
+ {
1554
+ DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
1555
+ if (dd)
1556
+ return dd->SendOutboundDatagram (data, length, address, port);
1557
+ else
1558
+ return -1;
1559
+ }
1560
+
1561
+
1562
+ /*********************************
1563
+ ConnectionDescriptor::GetPeername
1564
+ *********************************/
1565
+
1566
+ bool ConnectionDescriptor::GetPeername (struct sockaddr *s)
1567
+ {
1568
+ bool ok = false;
1569
+ if (s) {
1570
+ socklen_t len = sizeof(*s);
1571
+ int gp = getpeername (GetSocket(), s, &len);
1572
+ if (gp == 0)
1573
+ ok = true;
1574
+ }
1575
+ return ok;
1576
+ }
1577
+
1578
+ /*********************************
1579
+ ConnectionDescriptor::GetSockname
1580
+ *********************************/
1581
+
1582
+ bool ConnectionDescriptor::GetSockname (struct sockaddr *s)
1583
+ {
1584
+ bool ok = false;
1585
+ if (s) {
1586
+ socklen_t len = sizeof(*s);
1587
+ int gp = getsockname (GetSocket(), s, &len);
1588
+ if (gp == 0)
1589
+ ok = true;
1590
+ }
1591
+ return ok;
1592
+ }
1593
+
1594
+
1595
+ /**********************************************
1596
+ ConnectionDescriptor::GetCommInactivityTimeout
1597
+ **********************************************/
1598
+
1599
+ float ConnectionDescriptor::GetCommInactivityTimeout()
1600
+ {
1601
+ return ((float)InactivityTimeout / 1000000);
1602
+ }
1603
+
1604
+
1605
+ /**********************************************
1606
+ ConnectionDescriptor::SetCommInactivityTimeout
1607
+ **********************************************/
1608
+
1609
+ int ConnectionDescriptor::SetCommInactivityTimeout (float value)
1610
+ {
1611
+ if (value > 0) {
1612
+ InactivityTimeout = (Int64)(value * 1000000);
1613
+ return 1;
1614
+ }
1615
+ return 0;
1616
+ }
1617
+
1618
+ /*******************************
1619
+ DatagramDescriptor::GetPeername
1620
+ *******************************/
1621
+
1622
+ bool DatagramDescriptor::GetPeername (struct sockaddr *s)
1623
+ {
1624
+ bool ok = false;
1625
+ if (s) {
1626
+ memset (s, 0, sizeof(struct sockaddr));
1627
+ memcpy (s, &ReturnAddress, sizeof(ReturnAddress));
1628
+ ok = true;
1629
+ }
1630
+ return ok;
1631
+ }
1632
+
1633
+ /*******************************
1634
+ DatagramDescriptor::GetSockname
1635
+ *******************************/
1636
+
1637
+ bool DatagramDescriptor::GetSockname (struct sockaddr *s)
1638
+ {
1639
+ bool ok = false;
1640
+ if (s) {
1641
+ socklen_t len = sizeof(*s);
1642
+ int gp = getsockname (GetSocket(), s, &len);
1643
+ if (gp == 0)
1644
+ ok = true;
1645
+ }
1646
+ return ok;
1647
+ }
1648
+
1649
+
1650
+
1651
+ /********************************************
1652
+ DatagramDescriptor::GetCommInactivityTimeout
1653
+ ********************************************/
1654
+
1655
+ float DatagramDescriptor::GetCommInactivityTimeout()
1656
+ {
1657
+ return ((float)InactivityTimeout / 1000000);
1658
+ }
1659
+
1660
+ /********************************************
1661
+ DatagramDescriptor::SetCommInactivityTimeout
1662
+ ********************************************/
1663
+
1664
+ int DatagramDescriptor::SetCommInactivityTimeout (float value)
1665
+ {
1666
+ if (value > 0) {
1667
+ InactivityTimeout = (Int64)(value * 1000000);
1668
+ return 1;
1669
+ }
1670
+ return 0;
1671
+ }
1672
+
1673
+
1674
+ /************************************
1675
+ InotifyDescriptor::InotifyDescriptor
1676
+ *************************************/
1677
+
1678
+ InotifyDescriptor::InotifyDescriptor (EventMachine_t *em):
1679
+ EventableDescriptor(0, em)
1680
+ {
1681
+ bCallbackUnbind = false;
1682
+
1683
+ #ifndef HAVE_INOTIFY
1684
+ throw std::runtime_error("no inotify support on this system");
1685
+ #else
1686
+
1687
+ int fd = inotify_init();
1688
+ if (fd == -1) {
1689
+ char buf[200];
1690
+ snprintf (buf, sizeof(buf)-1, "unable to create inotify descriptor: %s", strerror(errno));
1691
+ throw std::runtime_error (buf);
1692
+ }
1693
+
1694
+ MySocket = fd;
1695
+ SetSocketNonblocking(MySocket);
1696
+ #ifdef HAVE_EPOLL
1697
+ EpollEvent.events = EPOLLIN;
1698
+ #endif
1699
+
1700
+ #endif
1701
+ }
1702
+
1703
+
1704
+ /*************************************
1705
+ InotifyDescriptor::~InotifyDescriptor
1706
+ **************************************/
1707
+
1708
+ InotifyDescriptor::~InotifyDescriptor()
1709
+ {
1710
+ close(MySocket);
1711
+ MySocket = INVALID_SOCKET;
1712
+ }
1713
+
1714
+ /***********************
1715
+ InotifyDescriptor::Read
1716
+ ************************/
1717
+
1718
+ void InotifyDescriptor::Read()
1719
+ {
1720
+ assert (MyEventMachine);
1721
+ MyEventMachine->_ReadInotifyEvents();
1722
+ }
1723
+
1724
+
1725
+ /************************
1726
+ InotifyDescriptor::Write
1727
+ *************************/
1728
+
1729
+ void InotifyDescriptor::Write()
1730
+ {
1731
+ throw std::runtime_error("bad code path in inotify");
1732
+ }