root/trunk/ext/cmain.cpp

Revision 785, 12.8 kB (checked in by francis, 9 months ago)

Applied a patch from Aman Gupta (tmm1) with contributions from
Riham Aldakkak, adds file-descriptor attach/detach and two new
event notifications, to support file descriptors not generated
internally by the reactor.

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