eventmachine 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/ed.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ed.h 447 2007-07-20 16:42:06Z blackhedd $
3
+ $Id: ed.h 502 2007-08-24 09:29:53Z blackhedd $
4
4
 
5
5
  File: ed.h
6
6
  Date: 06Apr06
@@ -65,6 +65,7 @@ class EventableDescriptor: public Bindable_t
65
65
  virtual bool GetSubprocessPid (pid_t*) {return false;}
66
66
 
67
67
  virtual void StartTls() {}
68
+ virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename) {}
68
69
 
69
70
  // Properties: return 0/1 to signify T/F, and handle the values
70
71
  // through arguments.
@@ -148,6 +149,7 @@ class ConnectionDescriptor: public EventableDescriptor
148
149
  virtual int GetOutboundDataSize() {return OutboundDataSize;}
149
150
 
150
151
  virtual void StartTls();
152
+ virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename);
151
153
  void SetServerMode() {bIsServer = true;}
152
154
 
153
155
  virtual bool GetPeername (struct sockaddr*);
@@ -174,6 +176,8 @@ class ConnectionDescriptor: public EventableDescriptor
174
176
 
175
177
  #ifdef WITH_SSL
176
178
  SslBox_t *SslBox;
179
+ std::string CertChainFilename;
180
+ std::string PrivateKeyFilename;
177
181
  #endif
178
182
  bool bIsServer;
179
183
 
@@ -268,7 +272,7 @@ class PipeDescriptor
268
272
  class PipeDescriptor: public EventableDescriptor
269
273
  {
270
274
  public:
271
- PipeDescriptor (FILE*, pid_t, EventMachine_t*);
275
+ PipeDescriptor (int, pid_t, EventMachine_t*);
272
276
  virtual ~PipeDescriptor();
273
277
 
274
278
  virtual void Read();
@@ -296,7 +300,6 @@ class PipeDescriptor: public EventableDescriptor
296
300
  bool bReadAttemptedAfterClose;
297
301
  time_t LastIo;
298
302
  int InactivityTimeout;
299
- //FILE *MyStream;
300
303
 
301
304
  deque<OutboundPage> OutboundPages;
302
305
  int OutboundDataSize;
@@ -309,6 +312,34 @@ class PipeDescriptor: public EventableDescriptor
309
312
  #endif // OS_UNIX
310
313
 
311
314
 
315
+ /************************
316
+ class KeyboardDescriptor
317
+ ************************/
318
+
319
+ class KeyboardDescriptor: public EventableDescriptor
320
+ {
321
+ public:
322
+ KeyboardDescriptor (EventMachine_t*);
323
+ virtual ~KeyboardDescriptor();
324
+
325
+ virtual void Read();
326
+ virtual void Write();
327
+ virtual void Heartbeat();
328
+
329
+ virtual bool SelectForRead() {return true;}
330
+ virtual bool SelectForWrite() {return false;}
331
+
332
+ protected:
333
+ bool bReadAttemptedAfterClose;
334
+ time_t LastIo;
335
+ int InactivityTimeout;
336
+
337
+ private:
338
+ void _DispatchInboundData (const char *buffer, int size);
339
+ };
340
+
341
+
342
+
312
343
  #endif // __EventableDescriptor__H_
313
344
 
314
345
 
data/ext/eee ADDED
@@ -0,0 +1,173 @@
1
+ # $Id: extconf.rb 501 2007-08-18 18:32:16Z blackhedd $
2
+ #
3
+ #----------------------------------------------------------------------------
4
+ #
5
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
6
+ # Gmail: blackhedd
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of either: 1) the GNU General Public License
10
+ # as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version; or 2) Ruby's License.
12
+ #
13
+ # See the file COPYING for complete licensing information.
14
+ #
15
+ #---------------------------------------------------------------------------
16
+ #
17
+ # extconf.rb for Ruby/EventMachine
18
+ # We have to munge LDSHARED because this code needs a C++ link.
19
+ #
20
+
21
+ require 'mkmf'
22
+
23
+ flags = []
24
+
25
+ case RUBY_PLATFORM.split('-',2)[1]
26
+ when 'mswin32', 'mingw32', 'bccwin32'
27
+ unless have_header('windows.h') and
28
+ have_header('winsock.h') and
29
+ have_library('kernel32') and
30
+ have_library('rpcrt4') and
31
+ have_library('gdi32')
32
+ exit
33
+ end
34
+
35
+ flags << "-D OS_WIN32"
36
+ flags << '-D BUILD_FOR_RUBY'
37
+ flags << "-EHs"
38
+ flags << "-GR"
39
+
40
+ dir_config('ssl')
41
+ if have_library('ssleay32') and
42
+ have_library('libeay32') and
43
+ have_header('openssl/ssl.h') and
44
+ have_header('openssl/err.h')
45
+ flags << '-D WITH_SSL'
46
+ else
47
+ flags << '-D WITHOUT_SSL'
48
+ end
49
+
50
+ when /solaris/
51
+ unless have_library('pthread') and
52
+ have_library('nsl') and
53
+ have_library('socket')
54
+ exit
55
+ end
56
+
57
+ flags << '-D OS_UNIX'
58
+ flags << '-D OS_SOLARIS8'
59
+ flags << '-D BUILD_FOR_RUBY'
60
+
61
+ dir_config('ssl')
62
+ if have_library('ssl') and
63
+ have_library('crypto') and
64
+ have_header('openssl/ssl.h') and
65
+ have_header('openssl/err.h')
66
+ flags << '-D WITH_SSL'
67
+ else
68
+ flags << '-D WITHOUT_SSL'
69
+ end
70
+
71
+ # on Unix we need a g++ link, not gcc.
72
+ CONFIG['LDSHARED'] = "$(CXX) -shared"
73
+
74
+ # Patch by Tim Pease, fixes SUNWspro compile problems.
75
+ if CONFIG['CC'] == 'cc'
76
+ $CFLAGS = CONFIG['CFLAGS'] = "-g -O2 -fPIC"
77
+ CONFIG['CCDLFLAGS'] = "-fPIC"
78
+ end
79
+
80
+ when /darwin/
81
+ flags << '-DOS_UNIX'
82
+ flags << '-DBUILD_FOR_RUBY'
83
+
84
+ dir_config('ssl')
85
+ if have_library('ssl') and
86
+ have_library('crypto') and
87
+ have_library('C') and
88
+ have_header('openssl/ssl.h') and
89
+ have_header('openssl/err.h')
90
+ flags << '-DWITH_SSL'
91
+ else
92
+ flags << '-DWITHOUT_SSL'
93
+ end
94
+ # on Unix we need a g++ link, not gcc.
95
+ # Ff line contributed by Daniel Harple.
96
+ CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
97
+
98
+ when /linux/
99
+ unless have_library('pthread')
100
+ exit
101
+ end
102
+
103
+ flags << '-DOS_UNIX'
104
+ flags << '-DBUILD_FOR_RUBY'
105
+
106
+ # Original epoll test is inadequate because 2.4 kernels have the header
107
+ # but not the code.
108
+ #flags << '-DHAVE_EPOLL' if have_header('sys/epoll.h')
109
+ if have_header('sys/epoll.h')
110
+ File.open("hasEpollTest.c", "w") {|f|
111
+ f.puts "#include <sys/epoll.h>"
112
+ f.puts "int main() { epoll_create(1024); return 0;}"
113
+ }
114
+ (e = system( "gcc hasEpollTest.c -o hasEpollTest " )) and (e = $?.to_i)
115
+ `rm -f hasEpollTest.c hasEpollTest`
116
+ flags << '-DHAVE_EPOLL' if e == 0
117
+ end
118
+
119
+ dir_config('ssl', "#{ENV['OPENSSL']}/include", ENV['OPENSSL'])
120
+ # Check for libcrypto twice, before and after ssl. That's because on some platforms
121
+ # and openssl versions, libssl will emit unresolved externals from crypto. It
122
+ # would be cleaner to simply check crypto first, but that doesn't always work in
123
+ # Ruby. The order we check them doesn't seem to control the order in which they're
124
+ # emitted into the link command. This is pretty weird, I have to admit.
125
+ if have_library('crypto') and
126
+ have_library('ssl') and
127
+ have_library('crypto') and
128
+ have_header('openssl/ssl.h') and
129
+ have_header('openssl/err.h')
130
+ flags << '-DWITH_SSL'
131
+ else
132
+ flags << '-DWITHOUT_SSL'
133
+ end
134
+ # on Unix we need a g++ link, not gcc.
135
+ CONFIG['LDSHARED'] = "$(CXX) -shared"
136
+
137
+ # Modify the mkmf constant LINK_SO so the generated shared object is stripped.
138
+ # You might think modifying CONFIG['LINK_SO'] would be a better way to do this,
139
+ # but it doesn't work because mkmf doesn't look at CONFIG['LINK_SO'] again after
140
+ # it initializes.
141
+ linkso = Object.send :remove_const, "LINK_SO"
142
+ LINK_SO = linkso + "; strip $@"
143
+
144
+ else
145
+ unless have_library('pthread')
146
+ exit
147
+ end
148
+
149
+ flags << '-DOS_UNIX'
150
+ flags << '-DBUILD_FOR_RUBY'
151
+
152
+ dir_config('ssl')
153
+ if have_library('ssl') and
154
+ have_library('crypto') and
155
+ have_header('openssl/ssl.h') and
156
+ have_header('openssl/err.h')
157
+ flags << '-DWITH_SSL'
158
+ else
159
+ flags << '-DWITHOUT_SSL'
160
+ end
161
+ # on Unix we need a g++ link, not gcc.
162
+ CONFIG['LDSHARED'] = "$(CXX) -shared"
163
+
164
+ end
165
+
166
+ if $CPPFLAGS
167
+ $CPPFLAGS += ' ' + flags.join(' ')
168
+ else
169
+ $CFLAGS += ' ' + flags.join(' ')
170
+ end
171
+
172
+
173
+ create_makefile "rubyeventmachine"
data/ext/em.cpp CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: em.cpp 386 2007-06-20 00:08:19Z blackhedd $
3
+ $Id: em.cpp 533 2007-09-14 17:36:04Z blackhedd $
4
4
 
5
5
  File: em.cpp
6
6
  Date: 06Apr06
@@ -414,6 +414,23 @@ bool EventMachine_t::_RunEpollOnce()
414
414
  }
415
415
 
416
416
  // TODO, heartbeats.
417
+ // Added 14Sep07, its absence was noted by Brian Candler. But the comment was here, indicated
418
+ // that this got thought about and not done when EPOLL was originally written. Was there a reason
419
+ // not to do it, or was it an oversight? Certainly, running a heartbeat on 50,000 connections every
420
+ // two seconds can get to be a real bear, especially if all we're doing is timing out dead ones.
421
+ // Maybe there's a better way to do this. (Or maybe it's not that expensive after all.)
422
+ //
423
+ { // dispatch heartbeats
424
+ if (gCurrentLoopTime >= NextHeartbeatTime) {
425
+ NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
426
+
427
+ for (int i=0; i < Descriptors.size(); i++) {
428
+ EventableDescriptor *ed = Descriptors[i];
429
+ assert (ed);
430
+ ed->Heartbeat();
431
+ }
432
+ }
433
+ }
417
434
 
418
435
  timeval tv = {0,0};
419
436
  EmSelect (0, NULL, NULL, NULL, &tv);
@@ -1375,7 +1392,7 @@ const char *EventMachine_t::Socketpair (char * const*cmd_strings)
1375
1392
  pid_t f = fork();
1376
1393
  if (f > 0) {
1377
1394
  close (sv[1]);
1378
- PipeDescriptor *pd = new PipeDescriptor (fdopen(sv[0], "r+"), f, this);
1395
+ PipeDescriptor *pd = new PipeDescriptor (sv[0], f, this);
1379
1396
  if (!pd)
1380
1397
  throw std::runtime_error ("unable to allocate pipe");
1381
1398
  Add (pd);
@@ -1397,6 +1414,29 @@ const char *EventMachine_t::Socketpair (char * const*cmd_strings)
1397
1414
  }
1398
1415
 
1399
1416
 
1417
+ /****************************
1418
+ EventMachine_t::OpenKeyboard
1419
+ ****************************/
1420
+
1421
+ const char *EventMachine_t::OpenKeyboard()
1422
+ {
1423
+ #ifdef OS_UNIX
1424
+ KeyboardDescriptor *kd = new KeyboardDescriptor (this);
1425
+ if (!kd)
1426
+ throw std::runtime_error ("no keyboard-object allocated");
1427
+ Add (kd);
1428
+ return kd->GetBinding().c_str();
1429
+ #endif
1430
+
1431
+ #ifdef OS_WIN32
1432
+ throw std::runtime_error ("open-keyboard is currently unavailable on this platform");
1433
+ return NULL;
1434
+ #endif
1435
+ }
1436
+
1437
+
1438
+
1439
+
1400
1440
 
1401
1441
  //#endif // OS_UNIX
1402
1442
 
data/ext/em.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: em.h 377 2007-06-13 01:05:56Z blackhedd $
3
+ $Id: em.h 502 2007-08-24 09:29:53Z blackhedd $
4
4
 
5
5
  File: em.h
6
6
  Date: 06Apr06
@@ -70,6 +70,7 @@ class EventMachine_t
70
70
  const char *OpenDatagramSocket (const char *, int);
71
71
  const char *CreateUnixDomainServer (const char*);
72
72
  const char *_OpenFileForWriting (const char*);
73
+ const char *OpenKeyboard();
73
74
  //const char *Popen (const char*, const char*);
74
75
  const char *Socketpair (char* const*);
75
76
 
data/ext/eventmachine.h CHANGED
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: eventmachine.h 426 2007-07-17 16:54:08Z blackhedd $
3
+ $Id: eventmachine.h 502 2007-08-24 09:29:53Z blackhedd $
4
4
 
5
5
  File: eventmachine.h
6
6
  Date: 15Apr06
@@ -43,6 +43,8 @@ extern "C" {
43
43
  const char *evma_create_tcp_server (const char *address, int port);
44
44
  const char *evma_create_unix_domain_server (const char *filename);
45
45
  const char *evma_open_datagram_socket (const char *server, int port);
46
+ const char *evma_open_keyboard();
47
+ void evma_set_tls_parms (const char *binding, const char *privatekey_filename, const char *certchain_filenane);
46
48
  void evma_start_tls (const char *binding);
47
49
  int evma_get_peername (const char *binding, struct sockaddr*);
48
50
  int evma_get_subprocess_pid (const char *binding, pid_t*);
data/ext/extconf.rb CHANGED
@@ -1,4 +1,4 @@
1
- # $Id: extconf.rb 404 2007-07-13 01:07:28Z blackhedd $
1
+ # $Id: extconf.rb 526 2007-09-11 17:43:23Z blackhedd $
2
2
  #
3
3
  #----------------------------------------------------------------------------
4
4
  #
@@ -116,8 +116,14 @@ when /linux/
116
116
  flags << '-DHAVE_EPOLL' if e == 0
117
117
  end
118
118
 
119
- dir_config('ssl')
120
- if have_library('ssl') and
119
+ dir_config('ssl', "#{ENV['OPENSSL']}/include", ENV['OPENSSL'])
120
+ # Check for libcrypto twice, before and after ssl. That's because on some platforms
121
+ # and openssl versions, libssl will emit unresolved externals from crypto. It
122
+ # would be cleaner to simply check crypto first, but that doesn't always work in
123
+ # Ruby. The order we check them doesn't seem to control the order in which they're
124
+ # emitted into the link command. This is pretty weird, I have to admit.
125
+ if have_library('crypto') and
126
+ have_library('ssl') and
121
127
  have_library('crypto') and
122
128
  have_header('openssl/ssl.h') and
123
129
  have_header('openssl/err.h')
data/ext/kb.cpp ADDED
@@ -0,0 +1,365 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: kb.cpp 502 2007-08-24 09:29:53Z blackhedd $
4
+
5
+ File: kb.cpp
6
+ Date: 24Aug07
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
+ KeyboardDescriptor::KeyboardDescriptor
25
+ **************************************/
26
+
27
+ KeyboardDescriptor::KeyboardDescriptor (EventMachine_t *parent_em):
28
+ EventableDescriptor (0, parent_em),
29
+ bReadAttemptedAfterClose (false),
30
+ LastIo (gCurrentLoopTime),
31
+ InactivityTimeout (0)
32
+ {
33
+ #ifdef HAVE_EPOLL
34
+ EpollEvent.events = EPOLLIN;
35
+ #endif
36
+ }
37
+
38
+
39
+ /***************************************
40
+ KeyboardDescriptor::~KeyboardDescriptor
41
+ ***************************************/
42
+
43
+ KeyboardDescriptor::~KeyboardDescriptor()
44
+ {
45
+ }
46
+
47
+
48
+ /*************************
49
+ KeyboardDescriptor::Write
50
+ *************************/
51
+
52
+ void KeyboardDescriptor::Write()
53
+ {
54
+ // Why are we here?
55
+ throw std::runtime_error ("bad code path in keyboard handler");
56
+ }
57
+
58
+
59
+ /*****************************
60
+ KeyboardDescriptor::Heartbeat
61
+ *****************************/
62
+
63
+ void KeyboardDescriptor::Heartbeat()
64
+ {
65
+ // no-op
66
+ }
67
+
68
+
69
+ /************************
70
+ KeyboardDescriptor::Read
71
+ ************************/
72
+
73
+ void KeyboardDescriptor::Read()
74
+ {
75
+ char c;
76
+ read (GetSocket(), &c, 1);
77
+ if (EventCallback)
78
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, &c, 1);
79
+ }
80
+
81
+
82
+
83
+
84
+ #if 0
85
+ /******************************
86
+ PipeDescriptor::PipeDescriptor
87
+ ******************************/
88
+
89
+ PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em):
90
+ EventableDescriptor (fd, parent_em),
91
+ bReadAttemptedAfterClose (false),
92
+ LastIo (gCurrentLoopTime),
93
+ InactivityTimeout (0),
94
+ OutboundDataSize (0),
95
+ SubprocessPid (subpid)
96
+ {
97
+ #ifdef HAVE_EPOLL
98
+ EpollEvent.events = EPOLLIN;
99
+ #endif
100
+ }
101
+
102
+
103
+ /*******************************
104
+ PipeDescriptor::~PipeDescriptor
105
+ *******************************/
106
+
107
+ PipeDescriptor::~PipeDescriptor()
108
+ {
109
+ // Run down any stranded outbound data.
110
+ for (size_t i=0; i < OutboundPages.size(); i++)
111
+ OutboundPages[i].Free();
112
+
113
+ /* As a virtual destructor, we come here before the base-class
114
+ * destructor that closes our file-descriptor.
115
+ * We have to make sure the subprocess goes down (if it's not
116
+ * already down) and we have to reap the zombie.
117
+ *
118
+ * This implementation is PROVISIONAL and will surely be improved.
119
+ * The intention here is that we never block, hence the highly
120
+ * undesirable sleeps. But if we can't reap the subprocess even
121
+ * after sending it SIGKILL, then something is wrong and we
122
+ * throw a fatal exception, which is also not something we should
123
+ * be doing.
124
+ *
125
+ * Eventually the right thing to do will be to have the reactor
126
+ * core respond to SIGCHLD by chaining a handler on top of the
127
+ * one Ruby may have installed, and dealing with a list of dead
128
+ * children that are pending cleanup.
129
+ *
130
+ * Since we want to have a signal processor integrated into the
131
+ * client-visible API, let's wait until that is done before cleaning
132
+ * this up.
133
+ */
134
+
135
+ struct timespec req = {0, 10000000};
136
+ kill (SubprocessPid, SIGTERM);
137
+ nanosleep (&req, NULL);
138
+ if (waitpid (SubprocessPid, NULL, WNOHANG) == 0) {
139
+ kill (SubprocessPid, SIGKILL);
140
+ nanosleep (&req, NULL);
141
+ if (waitpid (SubprocessPid, NULL, WNOHANG) == 0)
142
+ throw std::runtime_error ("unable to reap subprocess");
143
+ }
144
+ }
145
+
146
+
147
+
148
+ /********************
149
+ PipeDescriptor::Read
150
+ ********************/
151
+
152
+ void PipeDescriptor::Read()
153
+ {
154
+ int sd = GetSocket();
155
+ if (sd == INVALID_SOCKET) {
156
+ assert (!bReadAttemptedAfterClose);
157
+ bReadAttemptedAfterClose = true;
158
+ return;
159
+ }
160
+
161
+ LastIo = gCurrentLoopTime;
162
+
163
+ int total_bytes_read = 0;
164
+ char readbuffer [16 * 1024];
165
+
166
+ for (int i=0; i < 10; i++) {
167
+ // Don't read just one buffer and then move on. This is faster
168
+ // if there is a lot of incoming.
169
+ // But don't read indefinitely. Give other sockets a chance to run.
170
+ // NOTICE, we're reading one less than the buffer size.
171
+ // That's so we can put a guard byte at the end of what we send
172
+ // to user code.
173
+ // Use read instead of recv, which on Linux gives a "socket operation
174
+ // on nonsocket" error.
175
+
176
+
177
+ int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
178
+ //cerr << "<R:" << r << ">";
179
+
180
+ if (r > 0) {
181
+ total_bytes_read += r;
182
+ LastRead = gCurrentLoopTime;
183
+
184
+ // Add a null-terminator at the the end of the buffer
185
+ // that we will send to the callback.
186
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
187
+ // to be able to depend on this behavior, so they will have
188
+ // the option to do some things faster. Additionally it's
189
+ // a security guard against buffer overflows.
190
+ readbuffer [r] = 0;
191
+ if (EventCallback)
192
+ (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r);
193
+ }
194
+ else if (r == 0) {
195
+ break;
196
+ }
197
+ else {
198
+ // Basically a would-block, meaning we've read everything there is to read.
199
+ break;
200
+ }
201
+
202
+ }
203
+
204
+
205
+ if (total_bytes_read == 0) {
206
+ // If we read no data on a socket that selected readable,
207
+ // it generally means the other end closed the connection gracefully.
208
+ ScheduleClose (false);
209
+ //bCloseNow = true;
210
+ }
211
+
212
+ }
213
+
214
+ /*********************
215
+ PipeDescriptor::Write
216
+ *********************/
217
+
218
+ void PipeDescriptor::Write()
219
+ {
220
+ int sd = GetSocket();
221
+ assert (sd != INVALID_SOCKET);
222
+
223
+ LastIo = gCurrentLoopTime;
224
+ char output_buffer [16 * 1024];
225
+ size_t nbytes = 0;
226
+
227
+ while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
228
+ OutboundPage *op = &(OutboundPages[0]);
229
+ if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
230
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
231
+ nbytes += (op->Length - op->Offset);
232
+ op->Free();
233
+ OutboundPages.pop_front();
234
+ }
235
+ else {
236
+ int len = sizeof(output_buffer) - nbytes;
237
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
238
+ op->Offset += len;
239
+ nbytes += len;
240
+ }
241
+ }
242
+
243
+ // We should never have gotten here if there were no data to write,
244
+ // so assert that as a sanity check.
245
+ // Don't bother to make sure nbytes is less than output_buffer because
246
+ // if it were we probably would have crashed already.
247
+ assert (nbytes > 0);
248
+
249
+ assert (GetSocket() != INVALID_SOCKET);
250
+ int bytes_written = write (GetSocket(), output_buffer, nbytes);
251
+
252
+ if (bytes_written > 0) {
253
+ OutboundDataSize -= bytes_written;
254
+ if ((size_t)bytes_written < nbytes) {
255
+ int len = nbytes - bytes_written;
256
+ char *buffer = (char*) malloc (len + 1);
257
+ if (!buffer)
258
+ throw std::runtime_error ("bad alloc throwing back data");
259
+ memcpy (buffer, output_buffer + bytes_written, len);
260
+ buffer [len] = 0;
261
+ OutboundPages.push_front (OutboundPage (buffer, len));
262
+ }
263
+ #ifdef HAVE_EPOLL
264
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
265
+ assert (MyEventMachine);
266
+ MyEventMachine->Modify (this);
267
+ #endif
268
+ }
269
+ else {
270
+ #ifdef OS_UNIX
271
+ if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
272
+ #endif
273
+ #ifdef OS_WIN32
274
+ if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
275
+ #endif
276
+ Close();
277
+ }
278
+ }
279
+
280
+
281
+ /*************************
282
+ PipeDescriptor::Heartbeat
283
+ *************************/
284
+
285
+ void PipeDescriptor::Heartbeat()
286
+ {
287
+ // If an inactivity timeout is defined, then check for it.
288
+ if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
289
+ ScheduleClose (false);
290
+ //bCloseNow = true;
291
+ }
292
+
293
+
294
+ /*****************************
295
+ PipeDescriptor::SelectForRead
296
+ *****************************/
297
+
298
+ bool PipeDescriptor::SelectForRead()
299
+ {
300
+ /* Pipe descriptors, being local by definition, don't have
301
+ * a pending state, so this is simpler than for the
302
+ * ConnectionDescriptor object.
303
+ */
304
+ return true;
305
+ }
306
+
307
+ /******************************
308
+ PipeDescriptor::SelectForWrite
309
+ ******************************/
310
+
311
+ bool PipeDescriptor::SelectForWrite()
312
+ {
313
+ /* Pipe descriptors, being local by definition, don't have
314
+ * a pending state, so this is simpler than for the
315
+ * ConnectionDescriptor object.
316
+ */
317
+ return (GetOutboundDataSize() > 0);
318
+ }
319
+
320
+
321
+
322
+
323
+ /********************************
324
+ PipeDescriptor::SendOutboundData
325
+ ********************************/
326
+
327
+ int PipeDescriptor::SendOutboundData (const char *data, int length)
328
+ {
329
+ //if (bCloseNow || bCloseAfterWriting)
330
+ if (IsCloseScheduled())
331
+ return 0;
332
+
333
+ if (!data && (length > 0))
334
+ throw std::runtime_error ("bad outbound data");
335
+ char *buffer = (char *) malloc (length + 1);
336
+ if (!buffer)
337
+ throw std::runtime_error ("no allocation for outbound data");
338
+ memcpy (buffer, data, length);
339
+ buffer [length] = 0;
340
+ OutboundPages.push_back (OutboundPage (buffer, length));
341
+ OutboundDataSize += length;
342
+ #ifdef HAVE_EPOLL
343
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
344
+ assert (MyEventMachine);
345
+ MyEventMachine->Modify (this);
346
+ #endif
347
+ return length;
348
+ }
349
+
350
+ /********************************
351
+ PipeDescriptor::GetSubprocessPid
352
+ ********************************/
353
+
354
+ bool PipeDescriptor::GetSubprocessPid (pid_t *pid)
355
+ {
356
+ bool ok = false;
357
+ if (pid && (SubprocessPid > 0)) {
358
+ *pid = SubprocessPid;
359
+ ok = true;
360
+ }
361
+ return ok;
362
+ }
363
+
364
+ #endif
365
+