root/trunk/ext/cmain.cpp

Revision 788, 12.6 kB (checked in by raggi, 8 months ago)

Merge of branches/raggi
Most notable work and patches by Aman Gupta, Roger Pack, and James Tucker.
Patches / Tickets also submitted by: Jeremy Evans, aanand, darix, mmmurf,
danielaquino, macournoyer.

  • Moved docs into docs/ dir
  • Major refactor of rakefile, added generic rakefile helpers in tasks
  • Added example CPP build rakefile in tasks/cpp.rake
  • Moved rake tests out to tasks/tests.rake
  • Added svn ignores where appropriate
  • Fixed jruby build on older java platforms
  • Gem now builds from Rakefile rather than directly via extconf
  • Gem unified for jruby, C++ and pure ruby.
  • Correction for pure C++ build, removing ruby dependency
  • Fix for CYGWIN builds on ipv6
  • Major refactor for extconf.rb
  • Working mingw builds
  • extconf optionally uses pkg_config over manual configuration
  • extconf builds for 1.9 on any system that has 1.9
  • extconf no longer links pthread explicitly
  • looks for kqueue on all *nix systems
  • better error output on std::runtime_error, now says where it came from
  • Fixed some tests on jruby
  • Added test for general send_data flaw, required for a bugfix in jruby build
  • Added timeout to epoll tests
  • Added fixes for java reactor ruby api
  • Small addition of some docs in httpclient.rb and httpcli2.rb
  • Some refactor and fixes in smtpserver.rb
  • Added parenthesis where possible to avoid excess ruby warnings
  • Refactor of $eventmachine_library logic for accuracy and maintenance, jruby
  • EM::start_server now supports unix sockets
  • EM::connect now supports unix sockets
  • EM::defer @threadqueue now handled more gracefully
  • Added better messages on exceptions raised
  • Fix edge case in timer fires
  • Explicitly require buftok.rb
  • Add protocols to autoload, rather than require them all immediately
  • Fix a bug in pr_eventmachine for outbound_q
  • Refactors to take some of the use of defer out of tests.
  • Fixes in EM.defer under start/stop conditions. Reduced scope of threads.
  • Property svn:keywords set to Id
Line 
1 /*****************************************************************************
2
3 $Id$
4
5 File:                   cmain.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 static EventMachine_t *EventMachine;
24 static int bUseEpoll = 0;
25 static int bUseKqueue = 0;
26
27 extern "C" void ensure_eventmachine (const char *caller = "unknown caller")
28 {
29         if (!EventMachine) {
30                 int err_size = 128;
31                 char err_string[err_size];
32                 snprintf (err_string, err_size, "eventmachine not initialized: %s", caller);
33                 throw std::runtime_error (err_string);
34         }
35 }
36
37 /***********************
38 evma_initialize_library
39 ***********************/
40
41 extern "C" void evma_initialize_library (void(*cb)(const char*, int, const char*, int))
42 {
43         // Probably a bad idea to mess with the signal mask of a process
44         // we're just being linked into.
45         //InstallSignalHandlers();
46         if (EventMachine)
47                 throw std::runtime_error ("eventmachine already initialized: evma_initialize_library");
48         EventMachine = new EventMachine_t (cb);
49         if (bUseEpoll)
50                 EventMachine->_UseEpoll();
51         if (bUseKqueue)
52                 EventMachine->_UseKqueue();
53 }
54
55
56 /********************
57 evma_release_library
58 ********************/
59
60 extern "C" void evma_release_library()
61 {
62         ensure_eventmachine("evma_release_library");
63         delete EventMachine;
64         EventMachine = NULL;
65 }
66
67
68 /****************
69 evma_run_machine
70 ****************/
71
72 extern "C" void evma_run_machine()
73 {
74         ensure_eventmachine("evma_run_machine");
75         EventMachine->Run();
76 }
77
78
79 /**************************
80 evma_install_oneshot_timer
81 **************************/
82
83 extern "C" const char *evma_install_oneshot_timer (int seconds)
84 {
85         ensure_eventmachine("evma_install_oneshot_timer");
86         return EventMachine->InstallOneshotTimer (seconds);
87 }
88
89
90 /**********************
91 evma_connect_to_server
92 **********************/
93
94 extern "C" const char *evma_connect_to_server (const char *server, int port)
95 {
96         ensure_eventmachine("evma_connect_to_server");
97         return EventMachine->ConnectToServer (server, port);
98 }
99
100 /***************************
101 evma_connect_to_unix_server
102 ***************************/
103
104 extern "C" const char *evma_connect_to_unix_server (const char *server)
105 {
106         ensure_eventmachine("evma_connect_to_unix_server");
107         return EventMachine->ConnectToUnixServer (server);
108 }
109
110 /**************
111 evma_attach_fd
112 **************/
113
114 extern "C" const char *evma_attach_fd (int file_descriptor, int notify_readable, int notify_writable)
115 {
116         if (!EventMachine)
117                 throw std::runtime_error ("not initialized");
118         return EventMachine->AttachFD (file_descriptor, (notify_readable ? true : false), (notify_writable ? true : false));
119 }
120
121 /**************
122 evma_detach_fd
123 **************/
124
125 extern "C" int evma_detach_fd (const char *binding)
126 {
127         if (!EventMachine)
128                 throw std::runtime_error ("not initialized");
129
130         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
131         if (ed)
132                 return EventMachine->DetachFD (ed);
133         else
134                 throw std::runtime_error ("invalid binding to detach");
135 }
136
137 /**********************
138 evma_create_tcp_server
139 **********************/
140
141 extern "C" const char *evma_create_tcp_server (const char *address, int port)
142 {
143         ensure_eventmachine("evma_create_tcp_server");
144         return EventMachine->CreateTcpServer (address, port);
145 }
146
147 /******************************
148 evma_create_unix_domain_server
149 ******************************/
150
151 extern "C" const char *evma_create_unix_domain_server (const char *filename)
152 {
153         ensure_eventmachine("evma_create_unix_domain_server");
154         return EventMachine->CreateUnixDomainServer (filename);
155 }
156
157 /*************************
158 evma_open_datagram_socket
159 *************************/
160
161 extern "C" const char *evma_open_datagram_socket (const char *address, int port)
162 {
163         ensure_eventmachine("evma_open_datagram_socket");
164         return EventMachine->OpenDatagramSocket (address, port);
165 }
166
167 /******************
168 evma_open_keyboard
169 ******************/
170
171 extern "C" const char *evma_open_keyboard()
172 {
173         ensure_eventmachine("evma_open_keyboard");
174         return EventMachine->OpenKeyboard();
175 }
176
177
178
179 /****************************
180 evma_send_data_to_connection
181 ****************************/
182
183 extern "C" int evma_send_data_to_connection (const char *binding, const char *data, int data_length)
184 {
185         ensure_eventmachine("evma_send_data_to_connection");
186         return ConnectionDescriptor::SendDataToConnection (binding, data, data_length);
187 }
188
189 /******************
190 evma_send_datagram
191 ******************/
192
193 extern "C" int evma_send_datagram (const char *binding, const char *data, int data_length, const char *address, int port)
194 {
195         ensure_eventmachine("evma_send_datagram");
196         return DatagramDescriptor::SendDatagram (binding, data, data_length, address, port);
197 }
198
199
200 /*********************
201 evma_close_connection
202 *********************/
203
204 extern "C" void evma_close_connection (const char *binding, int after_writing)
205 {
206         ensure_eventmachine("evma_close_connection");
207         ConnectionDescriptor::CloseConnection (binding, (after_writing ? true : false));
208 }
209
210 /***********************************
211 evma_report_connection_error_status
212 ***********************************/
213
214 extern "C" int evma_report_connection_error_status (const char *binding)
215 {
216         ensure_eventmachine("evma_report_connection_error_status");
217         return ConnectionDescriptor::ReportErrorStatus (binding);
218 }
219
220 /********************
221 evma_stop_tcp_server
222 ********************/
223
224 extern "C" void evma_stop_tcp_server (const char *binding)
225 {
226         ensure_eventmachine("evma_stop_tcp_server");
227         AcceptorDescriptor::StopAcceptor (binding);
228 }
229
230
231 /*****************
232 evma_stop_machine
233 *****************/
234
235 extern "C" void evma_stop_machine()
236 {
237         ensure_eventmachine("evma_stop_machine");
238         EventMachine->ScheduleHalt();
239 }
240
241
242 /**************
243 evma_start_tls
244 **************/
245
246 extern "C" void evma_start_tls (const char *binding)
247 {
248         ensure_eventmachine("evma_start_tls");
249         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
250         if (ed)
251                 ed->StartTls();
252 }
253
254 /******************
255 evma_set_tls_parms
256 ******************/
257
258 extern "C" void evma_set_tls_parms (const char *binding, const char *privatekey_filename, const char *certchain_filename)
259 {
260         ensure_eventmachine("evma_set_tls_parms");
261         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
262         if (ed)
263                 ed->SetTlsParms (privatekey_filename, certchain_filename);
264 }
265
266
267 /*****************
268 evma_get_peername
269 *****************/
270
271 extern "C" int evma_get_peername (const char *binding, struct sockaddr *sa)
272 {
273         ensure_eventmachine("evma_get_peername");
274         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
275         if (ed) {
276                 return ed->GetPeername (sa) ? 1 : 0;
277         }
278         else
279                 return 0;
280 }
281
282 /*****************
283 evma_get_sockname
284 *****************/
285
286 extern "C" int evma_get_sockname (const char *binding, struct sockaddr *sa)
287 {
288         ensure_eventmachine("evma_get_sockname");
289         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
290         if (ed) {
291                 return ed->GetSockname (sa) ? 1 : 0;
292         }
293         else
294                 return 0;
295 }
296
297 /***********************
298 evma_get_subprocess_pid
299 ***********************/
300
301 extern "C" int evma_get_subprocess_pid (const char *binding, pid_t *pid)
302 {
303         ensure_eventmachine("evma_get_subprocess_pid");
304         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
305         if (ed) {
306                 return ed->GetSubprocessPid (pid) ? 1 : 0;
307         }
308         else
309                 return 0;
310 }
311
312 /**************************
313 evma_get_subprocess_status
314 **************************/
315
316 extern "C" int evma_get_subprocess_status (const char *binding, int *status)
317 {
318         ensure_eventmachine("evma_get_subprocess_status");
319         if (status) {
320                 *status = EventMachine->SubprocessExitStatus;
321                 return 1;
322         }
323         else
324                 return 0;
325 }
326
327
328 /*********************
329 evma_signal_loopbreak
330 *********************/
331
332 extern "C" void evma_signal_loopbreak()
333 {
334         ensure_eventmachine("evma_signal_loopbreak");
335         EventMachine->SignalLoopBreaker();
336 }
337
338
339
340 /****************
341 evma__write_file
342 ****************/
343
344 extern "C" const char *evma__write_file (const char *filename)
345 {
346         ensure_eventmachine("evma__write_file");
347         return EventMachine->_OpenFileForWriting (filename);
348 }
349
350
351 /********************************
352 evma_get_comm_inactivity_timeout
353 ********************************/
354
355 extern "C" int evma_get_comm_inactivity_timeout (const char *binding, int *value)
356 {
357         ensure_eventmachine("evma_get_comm_inactivity_timeout");
358         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
359         if (ed) {
360                 return ed->GetCommInactivityTimeout (value);
361         }
362         else
363                 return 0; //Perhaps this should be an exception. Access to an unknown binding.
364 }
365
366 /********************************
367 evma_set_comm_inactivity_timeout
368 ********************************/
369
370 extern "C" int evma_set_comm_inactivity_timeout (const char *binding, int *value)
371 {
372         ensure_eventmachine("evma_set_comm_inactivity_timeout");
373         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
374         if (ed) {
375                 return ed->SetCommInactivityTimeout (value);
376         }
377         else
378                 return 0; //Perhaps this should be an exception. Access to an unknown binding.
379 }
380
381
382 /**********************
383 evma_set_timer_quantum
384 **********************/
385
386 extern "C" void evma_set_timer_quantum (int interval)
387 {
388         ensure_eventmachine("evma_set_timer_quantum");
389         EventMachine->SetTimerQuantum (interval);
390 }
391
392 /************************
393 evma_set_max_timer_count
394 ************************/
395
396 extern "C" void evma_set_max_timer_count (int ct)
397 {
398         // This may only be called if the reactor is not running.
399         if (EventMachine)
400                 throw std::runtime_error ("eventmachine already initialized: evma_set_max_timer_count");
401         EventMachine_t::SetMaxTimerCount (ct);
402 }
403
404 /******************
405 evma_setuid_string
406 ******************/
407
408 extern "C" void evma_setuid_string (const char *username)
409 {
410         // We do NOT need to be running an EM instance because this method is static.
411         EventMachine_t::SetuidString (username);
412 }
413
414
415 /**********
416 evma_popen
417 **********/
418
419 extern "C" const char *evma_popen (char * const*cmd_strings)
420 {
421         ensure_eventmachine("evma_popen");
422         return EventMachine->Socketpair (cmd_strings);
423 }
424
425
426 /***************************
427 evma_get_outbound_data_size
428 ***************************/
429
430 extern "C" int evma_get_outbound_data_size (const char *binding)
431 {
432         ensure_eventmachine("evma_get_outbound_data_size");
433         EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
434         return ed ? ed->GetOutboundDataSize() : 0;
435 }
436
437
438 /***********
439 evma__epoll
440 ***********/
441
442 extern "C" void evma__epoll()
443 {
444         bUseEpoll = 1;
445 }
446
447 /************
448 evma__kqueue
449 ************/
450
451 extern "C" void evma__kqueue()
452 {
453         bUseKqueue = 1;
454 }
455
456
457 /**********************
458 evma_set_rlimit_nofile
459 **********************/
460
461 extern "C" int evma_set_rlimit_nofile (int nofiles)
462 {
463         return EventMachine_t::SetRlimitNofile (nofiles);
464 }
465
466
467 /*********************************
468 evma_send_file_data_to_connection
469 *********************************/
470
471 extern "C" int evma_send_file_data_to_connection (const char *binding, const char *filename)
472 {
473         /* This is a sugaring over send_data_to_connection that reads a file into a
474          * locally-allocated buffer, and sends the file data to the remote peer.
475          * Return the number of bytes written to the caller.
476          * TODO, needs to impose a limit on the file size. This is intended only for
477          * small files. (I don't know, maybe 8K or less.) For larger files, use interleaved
478          * I/O to avoid slowing the rest of the system down.
479          * TODO: we should return a code rather than barf, in case of file-not-found.
480          * TODO, does this compile on Windows?
481          * TODO, given that we want this to work only with small files, how about allocating
482          * the buffer on the stack rather than the heap?
483          *
484          * Modified 25Jul07. This now returns -1 on file-too-large; 0 for success, and a positive
485          * errno in case of other errors.
486          *
487         /* Contributed by Kirk Haines.
488          */
489
490         char data[32*1024];
491         int r;
492
493         ensure_eventmachine("evma_send_file_data_to_connection");
494
495         int Fd = open (filename, O_RDONLY);
496
497         if (Fd < 0)
498                 return errno;
499         // From here on, all early returns MUST close Fd.
500
501         struct stat st;
502         if (fstat (Fd, &st)) {
503                 int e = errno;
504                 close (Fd);
505                 return e;
506         }
507
508         int filesize = st.st_size;
509         if (filesize <= 0) {
510                 close (Fd);
511                 return 0;
512         }
513         else if (filesize > sizeof(data)) {
514                 close (Fd);
515                 return -1;
516         }
517
518
519         r = read (Fd, data, filesize);
520         if (r != filesize) {
521                 int e = errno;
522                 close (Fd);
523                 return e;
524         }
525         evma_send_data_to_connection (binding, data, r);
526         close (Fd);
527
528         return 0;
529 }
530
Note: See TracBrowser for help on using the browser.