eventmachine 0.5.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/RELEASE_NOTES CHANGED
@@ -1,7 +1,20 @@
1
- $Id: RELEASE_NOTES 64 2006-05-17 07:00:16Z blackhedd $
1
+ $Id: RELEASE_NOTES 223 2006-08-08 20:30:41Z blackhedd $
2
2
 
3
3
  RUBY/EventMachine RELEASE NOTES
4
4
 
5
+ --------------------------------------------------
6
+ Version: 0.7.0, released xxAug06
7
+ Added a fix in em.cpp/ConnectToServer to fix a fatal exception that
8
+ occurred in FreeBSD when connecting successfully to a remote server.
9
+
10
+ --------------------------------------------------
11
+ Version: 0.6.0, released xxJul06
12
+ Added deferred operations, suggested by Don Stocks, amillionhitpoints@yahoo.com.
13
+
14
+ --------------------------------------------------
15
+ Version: 0.5.4, released xxJun06
16
+ Added get_peername support for streams and datagrams.
17
+
5
18
  --------------------------------------------------
6
19
  Version: 0.5.3, released 17May06
7
20
  Fixed bugs in extconf.rb, thanks to Daniel Harple, dharple@generalconsumption.org.
data/TODO ADDED
@@ -0,0 +1,10 @@
1
+ $Id: TODO 231 2006-08-13 17:15:53Z blackhedd $
2
+
3
+ TODO List:
4
+
5
+ 12Aug06: Noticed by Don Stocks. A TCP connect-request that results
6
+ in a failed DNS resolution fires a fatal error back to user code.
7
+ Uuuuuugly. We should probably cause an unbind event to get fired
8
+ instead, and add some parameterization so the caller can detect
9
+ the nature of the failure.
10
+
data/ext/cmain.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: cmain.cpp 47 2006-05-15 21:42:38Z blackhedd $
3
+ $Id: cmain.cpp 265 2006-10-05 19:07:45Z blackhedd $
4
4
 
5
5
  File: libmain.cpp
6
6
  Date: 06Apr06
@@ -105,6 +105,17 @@ extern "C" const char *evma_create_tcp_server (const char *address, int port)
105
105
  return EventMachine->CreateTcpServer (address, port);
106
106
  }
107
107
 
108
+ /******************************
109
+ evma_create_unix_domain_server
110
+ ******************************/
111
+
112
+ extern "C" const char *evma_create_unix_domain_server (const char *filename)
113
+ {
114
+ if (!EventMachine)
115
+ throw std::runtime_error ("not initialized");
116
+ return EventMachine->CreateUnixDomainServer (filename);
117
+ }
118
+
108
119
  /*************************
109
120
  evma_open_datagram_socket
110
121
  *************************/
@@ -173,10 +184,95 @@ extern "C" void evma_start_tls (const char *binding)
173
184
  {
174
185
  if (!EventMachine)
175
186
  throw std::runtime_error ("not initialized");
176
- EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
177
- if (ed)
178
- ed->StartTls();
187
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
188
+ if (ed)
189
+ ed->StartTls();
190
+ }
191
+
192
+
193
+ /*****************
194
+ evma_get_peername
195
+ *****************/
196
+
197
+ extern "C" int evma_get_peername (const char *binding, struct sockaddr *sa)
198
+ {
199
+ if (!EventMachine)
200
+ throw std::runtime_error ("not initialized");
201
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
202
+ if (ed) {
203
+ return ed->GetPeername (sa) ? 1 : 0;
204
+ }
205
+ else
206
+ return 0;
207
+ }
208
+
209
+
210
+ /*********************
211
+ evma_signal_loopbreak
212
+ *********************/
213
+
214
+ extern "C" void evma_signal_loopbreak()
215
+ {
216
+ if (!EventMachine)
217
+ throw std::runtime_error ("not initialized");
218
+ EventMachine->SignalLoopBreaker();
219
+ }
220
+
221
+
222
+
223
+ /****************
224
+ evma__write_file
225
+ ****************/
226
+
227
+ extern "C" const char *evma__write_file (const char *filename)
228
+ {
229
+ if (!EventMachine)
230
+ throw std::runtime_error ("not initialized");
231
+ return EventMachine->_OpenFileForWriting (filename);
232
+ }
233
+
234
+
235
+ /********************************
236
+ evma_get_comm_inactivity_timeout
237
+ ********************************/
238
+
239
+ extern "C" int evma_get_comm_inactivity_timeout (const char *binding, int *value)
240
+ {
241
+ if (!EventMachine)
242
+ throw std::runtime_error ("not initialized");
243
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
244
+ if (ed) {
245
+ return ed->GetCommInactivityTimeout (value);
246
+ }
247
+ else
248
+ return 0; //Perhaps this should be an exception. Access to an unknown binding.
179
249
  }
180
250
 
251
+ /********************************
252
+ evma_set_comm_inactivity_timeout
253
+ ********************************/
181
254
 
255
+ extern "C" int evma_set_comm_inactivity_timeout (const char *binding, int *value)
256
+ {
257
+ if (!EventMachine)
258
+ throw std::runtime_error ("not initialized");
259
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
260
+ if (ed) {
261
+ return ed->SetCommInactivityTimeout (value);
262
+ }
263
+ else
264
+ return 0; //Perhaps this should be an exception. Access to an unknown binding.
265
+ }
266
+
267
+
268
+ /**********************
269
+ evma_set_timer_quantum
270
+ **********************/
271
+
272
+ extern "C" void evma_set_timer_quantum (int interval)
273
+ {
274
+ if (!EventMachine)
275
+ throw std::runtime_error ("not initialized");
276
+ EventMachine->SetTimerQuantum (interval);
277
+ }
182
278
 
data/ext/ed.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.cpp 47 2006-05-15 21:42:38Z blackhedd $
3
+ $Id: ed.cpp 255 2006-09-15 11:21:15Z blackhedd $
4
4
 
5
5
  File: ed.cpp
6
6
  Date: 06Apr06
@@ -159,13 +159,16 @@ ConnectionDescriptor::ConnectionDescriptor
159
159
  ******************************************/
160
160
 
161
161
  ConnectionDescriptor::ConnectionDescriptor (int sd):
162
- EventableDescriptor (sd),
163
- bConnectPending (false),
164
- OutboundDataSize (0),
162
+ EventableDescriptor (sd),
163
+ bConnectPending (false),
164
+ bReadAttemptedAfterClose (false),
165
+ OutboundDataSize (0),
165
166
  #ifdef WITH_SSL
166
167
  SslBox (NULL),
167
168
  #endif
168
- bIsServer (false)
169
+ bIsServer (false),
170
+ LastIo (gCurrentLoopTime),
171
+ InactivityTimeout (0)
169
172
  {
170
173
  }
171
174
 
@@ -333,10 +336,33 @@ void ConnectionDescriptor::Read()
333
336
  * a socket that has already been scheduled for closing or close-after-writing.
334
337
  * In those cases, we'll leave it up the to protocol handler to "do the
335
338
  * right thing" (which probably means to ignore the incoming data).
339
+ *
340
+ * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come
341
+ * here with the socket already closed, after the process receives
342
+ * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application
343
+ * was one in which network connections were doing a lot of interleaved reads
344
+ * and writes.
345
+ * Since we always write before reading (in order to keep the outbound queues
346
+ * as light as possible), I think what happened is that an interrupt caused
347
+ * the socket to be closed in ConnectionDescriptor::Write. We'll then
348
+ * come here in the same pass through the main event loop, and won't get
349
+ * cleaned up until immediately after.
350
+ * We originally asserted that the socket was valid when we got here.
351
+ * To deal properly with the possibility that we are closed when we get here,
352
+ * I removed the assert. HOWEVER, the potential for an infinite loop scares me,
353
+ * so even though this is really clunky, I added a flag to assert that we never
354
+ * come here more than once after being closed. (FCianfrocca)
336
355
  */
337
356
 
338
357
  int sd = GetSocket();
339
- assert (sd != INVALID_SOCKET);
358
+ //assert (sd != INVALID_SOCKET); (original, removed 22Aug06)
359
+ if (sd == INVALID_SOCKET) {
360
+ assert (!bReadAttemptedAfterClose);
361
+ bReadAttemptedAfterClose = true;
362
+ return;
363
+ }
364
+
365
+ LastIo = gCurrentLoopTime;
340
366
 
341
367
  int total_bytes_read = 0;
342
368
  char readbuffer [16 * 1024];
@@ -345,6 +371,10 @@ void ConnectionDescriptor::Read()
345
371
  // Don't read just one buffer and then move on. This is faster
346
372
  // if there is a lot of incoming.
347
373
  // But don't read indefinitely. Give other sockets a chance to run.
374
+ // NOTICE, we're reading one less than the buffer size.
375
+ // That's so we can put a guard byte at the end of what we send
376
+ // to user code.
377
+
348
378
 
349
379
  int r = recv (sd, readbuffer, sizeof(readbuffer) - 1, 0);
350
380
  //cerr << "<R:" << r << ">";
@@ -355,17 +385,18 @@ void ConnectionDescriptor::Read()
355
385
 
356
386
  // Add a null-terminator at the the end of the buffer
357
387
  // that we will send to the callback.
358
- // DO NOT CHANGE THIS. We want to explicitly allow users
388
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
359
389
  // to be able to depend on this behavior, so they will have
360
- // the option to do some things faster.
390
+ // the option to do some things faster. Additionally it's
391
+ // a security guard against buffer overflows.
361
392
  readbuffer [r] = 0;
362
- _DispatchInboundData (readbuffer, r);
393
+ _DispatchInboundData (readbuffer, r);
363
394
  }
364
395
  else if (r == 0) {
365
396
  break;
366
397
  }
367
398
  else {
368
- // Basically a would-block, meaning we've everything there is to read.
399
+ // Basically a would-block, meaning we've read everything there is to read.
369
400
  break;
370
401
  }
371
402
 
@@ -424,19 +455,19 @@ ConnectionDescriptor::Write
424
455
 
425
456
  void ConnectionDescriptor::Write()
426
457
  {
427
- /* A socket which is in a pending-connect state will select
428
- * writable when the disposition of the connect is known.
429
- * At that point, check to be sure there are no errors,
430
- * and if none, then promote the socket out of the pending
431
- * state.
432
- * TODO: I haven't figured out how Windows signals errors on
433
- * unconnected sockets. Maybe it does the untraditional but
434
- * logical thing and makes the socket selectable for error.
435
- * If so, it's unsupported here for the time being, and connect
436
- * errors will have to be caught by the timeout mechanism.
437
- */
458
+ /* A socket which is in a pending-connect state will select
459
+ * writable when the disposition of the connect is known.
460
+ * At that point, check to be sure there are no errors,
461
+ * and if none, then promote the socket out of the pending
462
+ * state.
463
+ * TODO: I haven't figured out how Windows signals errors on
464
+ * unconnected sockets. Maybe it does the untraditional but
465
+ * logical thing and makes the socket selectable for error.
466
+ * If so, it's unsupported here for the time being, and connect
467
+ * errors will have to be caught by the timeout mechanism.
468
+ */
438
469
 
439
- if (bConnectPending) {
470
+ if (bConnectPending) {
440
471
  int error;
441
472
  socklen_t len;
442
473
  len = sizeof(error);
@@ -446,14 +477,17 @@ void ConnectionDescriptor::Write()
446
477
  #ifdef OS_WIN32
447
478
  int o = getsockopt (MySocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
448
479
  #endif
449
- if ((o == 0) && (error == 0))
450
- bConnectPending = false;
451
- else
452
- bCloseNow = true;
453
- }
454
- else {
455
- _WriteOutboundData();
456
- }
480
+ if ((o == 0) && (error == 0)) {
481
+ if (EventCallback)
482
+ (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_COMPLETED, "", 0);
483
+ bConnectPending = false;
484
+ }
485
+ else
486
+ bCloseNow = true;
487
+ }
488
+ else {
489
+ _WriteOutboundData();
490
+ }
457
491
  }
458
492
 
459
493
 
@@ -473,6 +507,7 @@ void ConnectionDescriptor::_WriteOutboundData()
473
507
  int sd = GetSocket();
474
508
  assert (sd != INVALID_SOCKET);
475
509
 
510
+ LastIo = gCurrentLoopTime;
476
511
  char output_buffer [16 * 1024];
477
512
  size_t nbytes = 0;
478
513
 
@@ -617,14 +652,20 @@ ConnectionDescriptor::Heartbeat
617
652
 
618
653
  void ConnectionDescriptor::Heartbeat()
619
654
  {
620
- /* Only allow a certain amount of time to go by while waiting
621
- * for a pending connect. If it expires, then kill the socket.
622
- */
655
+ /* Only allow a certain amount of time to go by while waiting
656
+ * for a pending connect. If it expires, then kill the socket.
657
+ * For a connected socket, close it if its inactivity timer
658
+ * has expired.
659
+ */
623
660
 
624
- if (bConnectPending) {
625
- if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
626
- bCloseNow = true;
627
- }
661
+ if (bConnectPending) {
662
+ if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
663
+ bCloseNow = true;
664
+ }
665
+ else {
666
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
667
+ bCloseNow = true;
668
+ }
628
669
  }
629
670
 
630
671
 
@@ -748,7 +789,9 @@ DatagramDescriptor::DatagramDescriptor
748
789
 
749
790
  DatagramDescriptor::DatagramDescriptor (int sd):
750
791
  EventableDescriptor (sd),
751
- OutboundDataSize (0)
792
+ OutboundDataSize (0),
793
+ LastIo (gCurrentLoopTime),
794
+ InactivityTimeout (0)
752
795
  {
753
796
  memset (&ReturnAddress, 0, sizeof(ReturnAddress));
754
797
  }
@@ -766,6 +809,19 @@ DatagramDescriptor::~DatagramDescriptor()
766
809
  }
767
810
 
768
811
 
812
+ /*****************************
813
+ DatagramDescriptor::Heartbeat
814
+ *****************************/
815
+
816
+ void DatagramDescriptor::Heartbeat()
817
+ {
818
+ // Close it if its inactivity timer has expired.
819
+
820
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
821
+ bCloseNow = true;
822
+ }
823
+
824
+
769
825
  /************************
770
826
  DatagramDescriptor::Read
771
827
  ************************/
@@ -774,6 +830,7 @@ void DatagramDescriptor::Read()
774
830
  {
775
831
  int sd = GetSocket();
776
832
  assert (sd != INVALID_SOCKET);
833
+ LastIo = gCurrentLoopTime;
777
834
 
778
835
  // This is an extremely large read buffer.
779
836
  // In many cases you wouldn't expect to get any more than 4K.
@@ -783,6 +840,9 @@ void DatagramDescriptor::Read()
783
840
  // Don't read just one buffer and then move on. This is faster
784
841
  // if there is a lot of incoming.
785
842
  // But don't read indefinitely. Give other sockets a chance to run.
843
+ // NOTICE, we're reading one less than the buffer size.
844
+ // That's so we can put a guard byte at the end of what we send
845
+ // to user code.
786
846
 
787
847
  struct sockaddr_in sin;
788
848
  socklen_t slen = sizeof (sin);
@@ -797,9 +857,10 @@ void DatagramDescriptor::Read()
797
857
 
798
858
  // Add a null-terminator at the the end of the buffer
799
859
  // that we will send to the callback.
800
- // DO NOT CHANGE THIS. We want to explicitly allow users
860
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
801
861
  // to be able to depend on this behavior, so they will have
802
- // the option to do some things faster.
862
+ // the option to do some things faster. Additionally it's
863
+ // a security guard against buffer overflows.
803
864
  readbuffer [r] = 0;
804
865
 
805
866
 
@@ -819,7 +880,7 @@ void DatagramDescriptor::Read()
819
880
 
820
881
  }
821
882
  else {
822
- // Basically a would-block, meaning we've everything there is to read.
883
+ // Basically a would-block, meaning we've read everything there is to read.
823
884
  break;
824
885
  }
825
886
 
@@ -848,6 +909,7 @@ void DatagramDescriptor::Write()
848
909
 
849
910
  int sd = GetSocket();
850
911
  assert (sd != INVALID_SOCKET);
912
+ LastIo = gCurrentLoopTime;
851
913
 
852
914
  assert (OutboundPages.size() > 0);
853
915
 
@@ -923,7 +985,7 @@ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, cons
923
985
  {
924
986
  // This is an exact clone of ConnectionDescriptor::SendOutboundData.
925
987
  // That means it needs to move to a common ancestor.
926
- // TODO: Refactor this so there's no overlap with SendOutboundData.
988
+ // TODO: Refactor this so there's no overlap with SendOutboundData.
927
989
 
928
990
  if (bCloseNow || bCloseAfterWriting)
929
991
  return 0;
@@ -972,7 +1034,129 @@ int DatagramDescriptor::SendDatagram (const char *binding, const char *data, int
972
1034
  DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
973
1035
  if (dd)
974
1036
  return dd->SendOutboundDatagram (data, length, address, port);
975
- else
976
- return -1;
1037
+ else
1038
+ return -1;
1039
+ }
1040
+
1041
+
1042
+ /*********************************
1043
+ ConnectionDescriptor::GetPeername
1044
+ *********************************/
1045
+
1046
+ bool ConnectionDescriptor::GetPeername (struct sockaddr *s)
1047
+ {
1048
+ bool ok = false;
1049
+ if (s) {
1050
+ socklen_t len = sizeof(*s);
1051
+ int gp = getpeername (GetSocket(), s, &len);
1052
+ if (gp == 0)
1053
+ ok = true;
1054
+ }
1055
+ return ok;
1056
+ }
1057
+
1058
+
1059
+ /**********************************************
1060
+ ConnectionDescriptor::GetCommInactivityTimeout
1061
+ **********************************************/
1062
+
1063
+ int ConnectionDescriptor::GetCommInactivityTimeout (int *value)
1064
+ {
1065
+ if (value) {
1066
+ *value = InactivityTimeout;
1067
+ return 1;
1068
+ }
1069
+ else {
1070
+ // TODO, extended logging, got bad parameter.
1071
+ return 0;
1072
+ }
1073
+ }
1074
+
1075
+
1076
+ /**********************************************
1077
+ ConnectionDescriptor::SetCommInactivityTimeout
1078
+ **********************************************/
1079
+
1080
+ int ConnectionDescriptor::SetCommInactivityTimeout (int *value)
1081
+ {
1082
+ int out = 0;
1083
+
1084
+ if (value) {
1085
+ if ((*value==0) || (*value >= 2)) {
1086
+ // Replace the value and send the old one back to the caller.
1087
+ int v = *value;
1088
+ *value = InactivityTimeout;
1089
+ InactivityTimeout = v;
1090
+ out = 1;
1091
+ }
1092
+ else {
1093
+ // TODO, extended logging, got bad value.
1094
+ }
1095
+ }
1096
+ else {
1097
+ // TODO, extended logging, got bad parameter.
1098
+ }
1099
+
1100
+ return out;
1101
+ }
1102
+
1103
+ /*******************************
1104
+ DatagramDescriptor::GetPeername
1105
+ *******************************/
1106
+
1107
+ bool DatagramDescriptor::GetPeername (struct sockaddr *s)
1108
+ {
1109
+ bool ok = false;
1110
+ if (s) {
1111
+ memset (s, 0, sizeof(struct sockaddr));
1112
+ memcpy (s, &ReturnAddress, sizeof(ReturnAddress));
1113
+ ok = true;
1114
+ }
1115
+ return ok;
1116
+ }
1117
+
1118
+
1119
+
1120
+ /********************************************
1121
+ DatagramDescriptor::GetCommInactivityTimeout
1122
+ ********************************************/
1123
+
1124
+ int DatagramDescriptor::GetCommInactivityTimeout (int *value)
1125
+ {
1126
+ if (value) {
1127
+ *value = InactivityTimeout;
1128
+ return 1;
1129
+ }
1130
+ else {
1131
+ // TODO, extended logging, got bad parameter.
1132
+ return 0;
1133
+ }
1134
+ }
1135
+
1136
+ /********************************************
1137
+ DatagramDescriptor::SetCommInactivityTimeout
1138
+ ********************************************/
1139
+
1140
+ int DatagramDescriptor::SetCommInactivityTimeout (int *value)
1141
+ {
1142
+ int out = 0;
1143
+
1144
+ if (value) {
1145
+ if ((*value==0) || (*value >= 2)) {
1146
+ // Replace the value and send the old one back to the caller.
1147
+ int v = *value;
1148
+ *value = InactivityTimeout;
1149
+ InactivityTimeout = v;
1150
+ out = 1;
1151
+ }
1152
+ else {
1153
+ // TODO, extended logging, got bad value.
1154
+ }
1155
+ }
1156
+ else {
1157
+ // TODO, extended logging, got bad parameter.
1158
+ }
1159
+
1160
+ return out;
977
1161
  }
978
1162
 
data/ext/ed.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.h 47 2006-05-15 21:42:38Z blackhedd $
3
+ $Id: ed.h 254 2006-09-15 11:17:01Z blackhedd $
4
4
 
5
5
  File: ed.h
6
6
  Date: 06Apr06
@@ -67,8 +67,15 @@ class EventableDescriptor: public Bindable_t
67
67
 
68
68
  void SetEventCallback (void (*cb)(const char*, int, const char*, int));
69
69
 
70
+ virtual bool GetPeername (struct sockaddr*) {return false;}
71
+
70
72
  virtual void StartTls() {}
71
73
 
74
+ // Properties: return 0/1 to signify T/F, and handle the values
75
+ // through arguments.
76
+ virtual int GetCommInactivityTimeout (int *value) {return 0;}
77
+ virtual int SetCommInactivityTimeout (int *value) {return 0;}
78
+
72
79
  protected:
73
80
  enum {
74
81
  PendingConnectTimeout = 4 // can easily be made an instance variable
@@ -116,6 +123,10 @@ class ConnectionDescriptor: public EventableDescriptor
116
123
  virtual void StartTls();
117
124
  void SetServerMode() {bIsServer = true;}
118
125
 
126
+ virtual bool GetPeername (struct sockaddr*);
127
+
128
+ virtual int GetCommInactivityTimeout (int *value);
129
+ virtual int SetCommInactivityTimeout (int *value);
119
130
 
120
131
  protected:
121
132
  struct OutboundPage {
@@ -128,6 +139,7 @@ class ConnectionDescriptor: public EventableDescriptor
128
139
 
129
140
  protected:
130
141
  bool bConnectPending;
142
+ bool bReadAttemptedAfterClose;
131
143
 
132
144
  deque<OutboundPage> OutboundPages;
133
145
  int OutboundDataSize;
@@ -137,6 +149,9 @@ class ConnectionDescriptor: public EventableDescriptor
137
149
  #endif
138
150
  bool bIsServer;
139
151
 
152
+ time_t LastIo;
153
+ int InactivityTimeout;
154
+
140
155
  private:
141
156
  void _WriteOutboundData();
142
157
  void _DispatchInboundData (const char *buffer, int size);
@@ -158,7 +173,7 @@ class DatagramDescriptor: public EventableDescriptor
158
173
 
159
174
  virtual void Read();
160
175
  virtual void Write();
161
- virtual void Heartbeat() {}
176
+ virtual void Heartbeat();
162
177
 
163
178
  virtual bool SelectForRead() {return true;}
164
179
  virtual bool SelectForWrite();
@@ -169,6 +184,11 @@ class DatagramDescriptor: public EventableDescriptor
169
184
  // Do we have any data to write? This is used by ShouldDelete.
170
185
  virtual int GetOutboundDataSize() {return OutboundDataSize;}
171
186
 
187
+ virtual bool GetPeername (struct sockaddr*);
188
+
189
+ virtual int GetCommInactivityTimeout (int *value);
190
+ virtual int SetCommInactivityTimeout (int *value);
191
+
172
192
  static int SendDatagram (const char*, const char*, int, const char*, int);
173
193
 
174
194
 
@@ -186,6 +206,9 @@ class DatagramDescriptor: public EventableDescriptor
186
206
  int OutboundDataSize;
187
207
 
188
208
  struct sockaddr_in ReturnAddress;
209
+
210
+ time_t LastIo;
211
+ int InactivityTimeout;
189
212
  };
190
213
 
191
214