diff options
Diffstat (limited to 'test/scanners/cpp')
-rw-r--r-- | test/scanners/cpp/elvis.expected.raydebug | 26 | ||||
-rw-r--r-- | test/scanners/cpp/elvis.in.cpp | 26 | ||||
-rw-r--r-- | test/scanners/cpp/eventmachine.expected.raydebug | 7035 | ||||
-rw-r--r-- | test/scanners/cpp/eventmachine.in.cpp | 7035 | ||||
-rw-r--r-- | test/scanners/cpp/pleac.expected.raydebug | 2041 | ||||
-rw-r--r-- | test/scanners/cpp/pleac.in.cpp | 2041 | ||||
-rw-r--r-- | test/scanners/cpp/suite.rb | 2 | ||||
-rw-r--r-- | test/scanners/cpp/wedekind.expected.raydebug | 12 | ||||
-rw-r--r-- | test/scanners/cpp/wedekind.in.cpp | 12 |
9 files changed, 0 insertions, 18230 deletions
diff --git a/test/scanners/cpp/elvis.expected.raydebug b/test/scanners/cpp/elvis.expected.raydebug deleted file mode 100644 index 81743d0..0000000 --- a/test/scanners/cpp/elvis.expected.raydebug +++ /dev/null @@ -1,26 +0,0 @@ -ident(This)operator(?)ident(is)operator(+)ident(no)operator(:)ident(label)operator(;) - -comment(// This is only one label:) -label(label:) reserved(switch) operator(()ident(TYPE)operator(()ident(v)operator(\)\)) operator({) - reserved(case) ident(T_CLASS)operator(:) reserved(case) ident(T_MODULE)operator(:) - ident(rb_str_append)operator(()ident(s)operator(,) ident(rb_inspect)operator(()ident(v)operator(\)\);) - reserved(break)operator(;) - reserved(default)operator(:) - ident(rb_str_append)operator(()ident(s)operator(,) ident(rb_any_to_s)operator(()ident(v)operator(\)\);) - reserved(break)operator(;) -operator(}) -comment(// These are two labels.) -ident(function)operator(()ident(call)operator(\);) -label(label2:) label(label3:) ident(a) operator(=) ident(b) operator(+) ident(c)operator(;) - -comment(// Another label.) -reserved(if) operator(()integer(1)operator(\)) operator({) - label(label4:) ident(a) operator(=) ident(b) operator(+) ident(c)operator(;) -operator(}) - -comment(// Not a label.) -ident(test)operator(() - ident(a)operator(?) - ident(b)operator(:) - ident(c) -operator(\))
\ No newline at end of file diff --git a/test/scanners/cpp/elvis.in.cpp b/test/scanners/cpp/elvis.in.cpp deleted file mode 100644 index 9cdd574..0000000 --- a/test/scanners/cpp/elvis.in.cpp +++ /dev/null @@ -1,26 +0,0 @@ -This?is+no:label; - -// This is only one label: -label: switch (TYPE(v)) { - case T_CLASS: case T_MODULE: - rb_str_append(s, rb_inspect(v)); - break; - default: - rb_str_append(s, rb_any_to_s(v)); - break; -} -// These are two labels. -function(call); -label2: label3: a = b + c; - -// Another label. -if (1) { - label4: a = b + c; -} - -// Not a label. -test( - a? - b: - c -)
\ No newline at end of file diff --git a/test/scanners/cpp/eventmachine.expected.raydebug b/test/scanners/cpp/eventmachine.expected.raydebug deleted file mode 100644 index 8a3b79b..0000000 --- a/test/scanners/cpp/eventmachine.expected.raydebug +++ /dev/null @@ -1,7035 +0,0 @@ -comment(/***************************************************************************** - -$Id$ - -File: binder.cpp -Date: 07Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - -preprocessor(#define) ident(DEV_URANDOM) string<delimiter(")content(/dev/urandom)delimiter(")> - - -ident(map)operator(<)pre_type(string)operator(,) ident(Bindable_t)operator(*>) ident(Bindable_t)operator(::)ident(BindingBag)operator(;) - - -comment(/******************************** -STATIC Bindable_t::CreateBinding -********************************/) - -pre_type(string) ident(Bindable_t)operator(::)ident(CreateBinding)operator((\)) -operator({) - directive(static) pre_type(int) ident(index) operator(=) integer(0)operator(;) - directive(static) pre_type(string) ident(seed)operator(;) - - reserved(if) operator((()ident(index) operator(>=) integer(1000000)operator(\)) operator(||) operator(()ident(seed)operator(.)ident(length)operator((\)) operator(==) integer(0)operator(\)\)) operator({) - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(fd) operator(=) ident(open) operator(()ident(DEV_URANDOM)operator(,) ident(O_RDONLY)operator(\);) - reserved(if) operator(()ident(fd) operator(<) integer(0)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(No entropy device)delimiter(")>operator(\);) - - pre_type(unsigned) pre_type(char) ident(u)operator([)integer(16)operator(];) - ident(size_t) ident(r) operator(=) ident(read) operator(()ident(fd)operator(,) ident(u)operator(,) reserved(sizeof)operator(()ident(u)operator(\)\);) - reserved(if) operator(()ident(r) operator(<) reserved(sizeof)operator(()ident(u)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(Unable to read entropy device)delimiter(")>operator(\);) - - pre_type(unsigned) pre_type(char) operator(*)ident(u1) operator(=) operator(()pre_type(unsigned) pre_type(char)operator(*\))ident(u)operator(;) - pre_type(char) ident(u2) operator([)reserved(sizeof)operator(()ident(u)operator(\)) operator(*) integer(2) operator(+) integer(1)operator(];) - - reserved(for) operator(()ident(size_t) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) reserved(sizeof)operator(()ident(u)operator(\);) ident(i)operator(++\)) - ident(sprintf) operator(()ident(u2) operator(+) operator(()ident(i) operator(*) integer(2)operator(\),) string<delimiter(")content(%02x)delimiter(")>operator(,) ident(u1)operator([)ident(i)operator(]\);) - - ident(seed) operator(=) pre_type(string) operator(()ident(u2)operator(\);) - preprocessor(#endif) - - - preprocessor(#ifdef) ident(OS_WIN32) - ident(UUID) ident(uuid)operator(;) - ident(UuidCreate) operator((&)ident(uuid)operator(\);) - pre_type(unsigned) pre_type(char) operator(*)ident(uuidstring) operator(=) pre_constant(NULL)operator(;) - ident(UuidToString) operator((&)ident(uuid)operator(,) operator(&)ident(uuidstring)operator(\);) - reserved(if) operator((!)ident(uuidstring)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(Unable to read uuid)delimiter(")>operator(\);) - ident(seed) operator(=) pre_type(string) operator((()directive(const) pre_type(char)operator(*\))ident(uuidstring)operator(\);) - - ident(RpcStringFree) operator((&)ident(uuidstring)operator(\);) - preprocessor(#endif) - - ident(index) operator(=) integer(0)operator(;) - - - operator(}) - - ident(stringstream) ident(ss)operator(;) - ident(ss) operator(<<) ident(seed) operator(<<) operator((++)ident(index)operator(\);) - reserved(return) ident(ss)operator(.)ident(str)operator((\);) -operator(}) - - -comment(/***************************** -STATIC: Bindable_t::GetObject -*****************************/) - -ident(Bindable_t) operator(*)ident(Bindable_t)operator(::)ident(GetObject) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - pre_type(string) ident(s) operator(()ident(binding) operator(?) ident(binding) operator(:) string<delimiter(")delimiter(")>operator(\);) - reserved(return) ident(GetObject) operator(()ident(s)operator(\);) -operator(}) - -comment(/***************************** -STATIC: Bindable_t::GetObject -*****************************/) - -ident(Bindable_t) operator(*)ident(Bindable_t)operator(::)ident(GetObject) operator(()directive(const) pre_type(string) operator(&)ident(binding)operator(\)) -operator({) - ident(map)operator(<)pre_type(string)operator(,) ident(Bindable_t)operator(*>::)ident(const_iterator) ident(i) operator(=) ident(BindingBag)operator(.)ident(find) operator(()ident(binding)operator(\);) - reserved(if) operator(()ident(i) operator(!=) ident(BindingBag)operator(.)ident(end)operator((\)\)) - reserved(return) ident(i)operator(->)ident(second)operator(;) - reserved(else) - reserved(return) pre_constant(NULL)operator(;) -operator(}) - - -comment(/********************** -Bindable_t::Bindable_t -**********************/) - -ident(Bindable_t)operator(::)ident(Bindable_t)operator((\)) -operator({) - ident(Binding) operator(=) ident(Bindable_t)operator(::)ident(CreateBinding)operator((\);) - ident(BindingBag) operator([)ident(Binding)operator(]) operator(=) local_variable(this)operator(;) -operator(}) - - - -comment(/*********************** -Bindable_t::~Bindable_t -***********************/) - -ident(Bindable_t)operator(::~)ident(Bindable_t)operator((\)) -operator({) - ident(BindingBag)operator(.)ident(erase) operator(()ident(Binding)operator(\);) -operator(}) - - -comment(/***************************************************************************** - -$Id$ - -File: cmain.cpp -Date: 06Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - - -directive(static) ident(EventMachine_t) operator(*)ident(EventMachine)operator(;) -directive(static) pre_type(int) ident(bUseEpoll) operator(=) integer(0)operator(;) -directive(static) pre_type(int) ident(bUseKqueue) operator(=) integer(0)operator(;) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(ensure_eventmachine) operator(()directive(const) pre_type(char) operator(*)ident(caller) operator(=) string<delimiter(")content(unknown caller)delimiter(")>operator(\)) -operator({) - reserved(if) operator((!)ident(EventMachine)operator(\)) operator({) - directive(const) pre_type(int) ident(err_size) operator(=) integer(128)operator(;) - pre_type(char) ident(err_string)operator([)ident(err_size)operator(];) - ident(snprintf) operator(()ident(err_string)operator(,) ident(err_size)operator(,) string<delimiter(")content(eventmachine not initialized: %s)delimiter(")>operator(,) ident(caller)operator(\);) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(rb_raise)operator(()ident(rb_eRuntimeError)operator(,) ident(err_string)operator(\);) - preprocessor(#else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(err_string)operator(\);) - preprocessor(#endif) - operator(}) -operator(}) - -comment(/*********************** -evma_initialize_library -***********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_initialize_library) operator(()directive(void)operator((*)ident(cb)operator(\)()directive(const) pre_type(char)operator(*,) pre_type(int)operator(,) directive(const) pre_type(char)operator(*,) pre_type(int)operator(\)\)) -operator({) - comment(// Probably a bad idea to mess with the signal mask of a process) - comment(// we're just being linked into.) - comment(//InstallSignalHandlers(\);) - reserved(if) operator(()ident(EventMachine)operator(\)) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(rb_raise)operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(eventmachine already initialized: evma_initialize_library)delimiter(")>operator(\);) - preprocessor(#else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(eventmachine already initialized: evma_initialize_library)delimiter(")>operator(\);) - preprocessor(#endif) - ident(EventMachine) operator(=) reserved(new) ident(EventMachine_t) operator(()ident(cb)operator(\);) - reserved(if) operator(()ident(bUseEpoll)operator(\)) - ident(EventMachine)operator(->)ident(_UseEpoll)operator((\);) - reserved(if) operator(()ident(bUseKqueue)operator(\)) - ident(EventMachine)operator(->)ident(_UseKqueue)operator((\);) -operator(}) - - -comment(/******************** -evma_release_library -********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_release_library)operator((\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_release_library)delimiter(")>operator(\);) - reserved(delete) ident(EventMachine)operator(;) - ident(EventMachine) operator(=) pre_constant(NULL)operator(;) -operator(}) - - -comment(/**************** -evma_run_machine -****************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_run_machine)operator((\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_run_machine)delimiter(")>operator(\);) - ident(EventMachine)operator(->)ident(Run)operator((\);) -operator(}) - - -comment(/************************** -evma_install_oneshot_timer -**************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_install_oneshot_timer) operator(()pre_type(int) ident(seconds)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_install_oneshot_timer)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(InstallOneshotTimer) operator(()ident(seconds)operator(\);) -operator(}) - - -comment(/********************** -evma_connect_to_server -**********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_connect_to_server) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_connect_to_server)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(ConnectToServer) operator(()ident(server)operator(,) ident(port)operator(\);) -operator(}) - -comment(/*************************** -evma_connect_to_unix_server -***************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_connect_to_unix_server) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_connect_to_unix_server)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(ConnectToUnixServer) operator(()ident(server)operator(\);) -operator(}) - -comment(/************** -evma_attach_fd -**************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_attach_fd) operator(()pre_type(int) ident(file_descriptor)operator(,) pre_type(int) ident(notify_readable)operator(,) pre_type(int) ident(notify_writable)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_attach_fd)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(AttachFD) operator(()ident(file_descriptor)operator(,) operator(()ident(notify_readable) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(\),) operator(()ident(notify_writable) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(\)\);) -operator(}) - -comment(/************** -evma_detach_fd -**************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_detach_fd) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_dettach_fd)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) - reserved(return) ident(EventMachine)operator(->)ident(DetachFD) operator(()ident(ed)operator(\);) - reserved(else) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(rb_raise)operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(invalid binding to detach)delimiter(")>operator(\);) - preprocessor(#else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(invalid binding to detach)delimiter(")>operator(\);) - preprocessor(#endif) -operator(}) - -comment(/********************** -evma_create_tcp_server -**********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_create_tcp_server) operator(()directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_create_tcp_server)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(CreateTcpServer) operator(()ident(address)operator(,) ident(port)operator(\);) -operator(}) - -comment(/****************************** -evma_create_unix_domain_server -******************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_create_unix_domain_server) operator(()directive(const) pre_type(char) operator(*)ident(filename)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_create_unix_domain_server)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(CreateUnixDomainServer) operator(()ident(filename)operator(\);) -operator(}) - -comment(/************************* -evma_open_datagram_socket -*************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_open_datagram_socket) operator(()directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_open_datagram_socket)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(OpenDatagramSocket) operator(()ident(address)operator(,) ident(port)operator(\);) -operator(}) - -comment(/****************** -evma_open_keyboard -******************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_open_keyboard)operator((\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_open_keyboard)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(OpenKeyboard)operator((\);) -operator(}) - - - -comment(/**************************** -evma_send_data_to_connection -****************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_send_data_to_connection) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(data_length)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_send_data_to_connection)delimiter(")>operator(\);) - reserved(return) ident(ConnectionDescriptor)operator(::)ident(SendDataToConnection) operator(()ident(binding)operator(,) ident(data)operator(,) ident(data_length)operator(\);) -operator(}) - -comment(/****************** -evma_send_datagram -******************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_send_datagram) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(data_length)operator(,) directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_send_datagram)delimiter(")>operator(\);) - reserved(return) ident(DatagramDescriptor)operator(::)ident(SendDatagram) operator(()ident(binding)operator(,) ident(data)operator(,) ident(data_length)operator(,) ident(address)operator(,) ident(port)operator(\);) -operator(}) - - -comment(/********************* -evma_close_connection -*********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_close_connection) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) pre_type(int) ident(after_writing)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_close_connection)delimiter(")>operator(\);) - ident(ConnectionDescriptor)operator(::)ident(CloseConnection) operator(()ident(binding)operator(,) operator(()ident(after_writing) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(\)\);) -operator(}) - -comment(/*********************************** -evma_report_connection_error_status -***********************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_report_connection_error_status) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_report_connection_error_status)delimiter(")>operator(\);) - reserved(return) ident(ConnectionDescriptor)operator(::)ident(ReportErrorStatus) operator(()ident(binding)operator(\);) -operator(}) - -comment(/******************** -evma_stop_tcp_server -********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_stop_tcp_server) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_stop_tcp_server)delimiter(")>operator(\);) - ident(AcceptorDescriptor)operator(::)ident(StopAcceptor) operator(()ident(binding)operator(\);) -operator(}) - - -comment(/***************** -evma_stop_machine -*****************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_stop_machine)operator((\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_stop_machine)delimiter(")>operator(\);) - ident(EventMachine)operator(->)ident(ScheduleHalt)operator((\);) -operator(}) - - -comment(/************** -evma_start_tls -**************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_start_tls) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_start_tls)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) - ident(ed)operator(->)ident(StartTls)operator((\);) -operator(}) - -comment(/****************** -evma_set_tls_parms -******************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_set_tls_parms) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) directive(const) pre_type(char) operator(*)ident(privatekey_filename)operator(,) directive(const) pre_type(char) operator(*)ident(certchain_filename)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_set_tls_parms)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) - ident(ed)operator(->)ident(SetTlsParms) operator(()ident(privatekey_filename)operator(,) ident(certchain_filename)operator(\);) -operator(}) - - -comment(/***************** -evma_get_peername -*****************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_get_peername) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) reserved(struct) ident(sockaddr) operator(*)ident(sa)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_get_peername)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) operator({) - reserved(return) ident(ed)operator(->)ident(GetPeername) operator(()ident(sa)operator(\)) operator(?) integer(1) operator(:) integer(0)operator(;) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) -operator(}) - -comment(/***************** -evma_get_sockname -*****************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_get_sockname) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) reserved(struct) ident(sockaddr) operator(*)ident(sa)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_get_sockname)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) operator({) - reserved(return) ident(ed)operator(->)ident(GetSockname) operator(()ident(sa)operator(\)) operator(?) integer(1) operator(:) integer(0)operator(;) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) -operator(}) - -comment(/*********************** -evma_get_subprocess_pid -***********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_get_subprocess_pid) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) ident(pid_t) operator(*)ident(pid)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_get_subprocess_pid)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) operator({) - reserved(return) ident(ed)operator(->)ident(GetSubprocessPid) operator(()ident(pid)operator(\)) operator(?) integer(1) operator(:) integer(0)operator(;) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) -operator(}) - -comment(/************************** -evma_get_subprocess_status -**************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_get_subprocess_status) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) pre_type(int) operator(*)ident(status)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_get_subprocess_status)delimiter(")>operator(\);) - reserved(if) operator(()ident(status)operator(\)) operator({) - operator(*)ident(status) operator(=) ident(EventMachine)operator(->)ident(SubprocessExitStatus)operator(;) - reserved(return) integer(1)operator(;) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) -operator(}) - - -comment(/********************* -evma_signal_loopbreak -*********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_signal_loopbreak)operator((\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_signal_loopbreak)delimiter(")>operator(\);) - ident(EventMachine)operator(->)ident(SignalLoopBreaker)operator((\);) -operator(}) - - - -comment(/**************** -evma__write_file -****************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma__write_file) operator(()directive(const) pre_type(char) operator(*)ident(filename)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma__write_file)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(_OpenFileForWriting) operator(()ident(filename)operator(\);) -operator(}) - - -comment(/******************************** -evma_get_comm_inactivity_timeout -********************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_get_comm_inactivity_timeout) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) pre_type(int) operator(*)ident(value)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_get_comm_inactivity_timeout)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) operator({) - reserved(return) ident(ed)operator(->)ident(GetCommInactivityTimeout) operator(()ident(value)operator(\);) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) comment(//Perhaps this should be an exception. Access to an unknown binding.) -operator(}) - -comment(/******************************** -evma_set_comm_inactivity_timeout -********************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_set_comm_inactivity_timeout) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) pre_type(int) operator(*)ident(value)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_set_comm_inactivity_timeout)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) operator({) - reserved(return) ident(ed)operator(->)ident(SetCommInactivityTimeout) operator(()ident(value)operator(\);) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) comment(//Perhaps this should be an exception. Access to an unknown binding.) -operator(}) - - -comment(/********************** -evma_set_timer_quantum -**********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_set_timer_quantum) operator(()pre_type(int) ident(interval)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_set_timer_quantum)delimiter(")>operator(\);) - ident(EventMachine)operator(->)ident(SetTimerQuantum) operator(()ident(interval)operator(\);) -operator(}) - -comment(/************************ -evma_set_max_timer_count -************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_set_max_timer_count) operator(()pre_type(int) ident(ct)operator(\)) -operator({) - comment(// This may only be called if the reactor is not running.) - - reserved(if) operator(()ident(EventMachine)operator(\)) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(rb_raise)operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(eventmachine already initialized: evma_set_max_timer_count)delimiter(")>operator(\);) - preprocessor(#else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(eventmachine already initialized: evma_set_max_timer_count)delimiter(")>operator(\);) - preprocessor(#endif) - ident(EventMachine_t)operator(::)ident(SetMaxTimerCount) operator(()ident(ct)operator(\);) -operator(}) - -comment(/****************** -evma_setuid_string -******************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma_setuid_string) operator(()directive(const) pre_type(char) operator(*)ident(username)operator(\)) -operator({) - comment(// We do NOT need to be running an EM instance because this method is static.) - ident(EventMachine_t)operator(::)ident(SetuidString) operator(()ident(username)operator(\);) -operator(}) - - -comment(/********** -evma_popen -**********/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(const) pre_type(char) operator(*)ident(evma_popen) operator(()pre_type(char) operator(*) directive(const)operator(*)ident(cmd_strings)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_popen)delimiter(")>operator(\);) - reserved(return) ident(EventMachine)operator(->)ident(Socketpair) operator(()ident(cmd_strings)operator(\);) -operator(}) - - -comment(/*************************** -evma_get_outbound_data_size -***************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_get_outbound_data_size) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_get_outbound_data_size)delimiter(")>operator(\);) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(return) ident(ed) operator(?) ident(ed)operator(->)ident(GetOutboundDataSize)operator((\)) operator(:) integer(0)operator(;) -operator(}) - - -comment(/*********** -evma__epoll -***********/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma__epoll)operator((\)) -operator({) - ident(bUseEpoll) operator(=) integer(1)operator(;) -operator(}) - -comment(/************ -evma__kqueue -************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(evma__kqueue)operator((\)) -operator({) - ident(bUseKqueue) operator(=) integer(1)operator(;) -operator(}) - - -comment(/********************** -evma_set_rlimit_nofile -**********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_set_rlimit_nofile) operator(()pre_type(int) ident(nofiles)operator(\)) -operator({) - reserved(return) ident(EventMachine_t)operator(::)ident(SetRlimitNofile) operator(()ident(nofiles)operator(\);) -operator(}) - - -comment(/********************************* -evma_send_file_data_to_connection -*********************************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(evma_send_file_data_to_connection) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) directive(const) pre_type(char) operator(*)ident(filename)operator(\)) -operator({) - comment(/* This is a sugaring over send_data_to_connection that reads a file into a - * locally-allocated buffer, and sends the file data to the remote peer. - * Return the number of bytes written to the caller. - * TODO, needs to impose a limit on the file size. This is intended only for - * small files. (I don't know, maybe 8K or less.\) For larger files, use interleaved - * I/O to avoid slowing the rest of the system down. - * TODO: we should return a code rather than barf, in case of file-not-found. - * TODO, does this compile on Windows? - * TODO, given that we want this to work only with small files, how about allocating - * the buffer on the stack rather than the heap? - * - * Modified 25Jul07. This now returns -1 on file-too-large; 0 for success, and a positive - * errno in case of other errors. - * - /* Contributed by Kirk Haines. - */) - - pre_type(char) ident(data)operator([)integer(32)operator(*)integer(1024)operator(];) - pre_type(int) ident(r)operator(;) - - ident(ensure_eventmachine)operator(()string<delimiter(")content(evma_send_file_data_to_connection)delimiter(")>operator(\);) - - pre_type(int) ident(Fd) operator(=) ident(open) operator(()ident(filename)operator(,) ident(O_RDONLY)operator(\);) - - reserved(if) operator(()ident(Fd) operator(<) integer(0)operator(\)) - reserved(return) ident(errno)operator(;) - comment(// From here on, all early returns MUST close Fd.) - - reserved(struct) ident(stat) ident(st)operator(;) - reserved(if) operator(()ident(fstat) operator(()ident(Fd)operator(,) operator(&)ident(st)operator(\)\)) operator({) - pre_type(int) ident(e) operator(=) ident(errno)operator(;) - ident(close) operator(()ident(Fd)operator(\);) - reserved(return) ident(e)operator(;) - operator(}) - - pre_type(int) ident(filesize) operator(=) ident(st)operator(.)ident(st_size)operator(;) - reserved(if) operator(()ident(filesize) operator(<=) integer(0)operator(\)) operator({) - ident(close) operator(()ident(Fd)operator(\);) - reserved(return) integer(0)operator(;) - operator(}) - reserved(else) reserved(if) operator(()ident(filesize) operator(>) reserved(sizeof)operator(()ident(data)operator(\)\)) operator({) - ident(close) operator(()ident(Fd)operator(\);) - reserved(return) operator(-)integer(1)operator(;) - operator(}) - - - ident(r) operator(=) ident(read) operator(()ident(Fd)operator(,) ident(data)operator(,) ident(filesize)operator(\);) - reserved(if) operator(()ident(r) operator(!=) ident(filesize)operator(\)) operator({) - pre_type(int) ident(e) operator(=) ident(errno)operator(;) - ident(close) operator(()ident(Fd)operator(\);) - reserved(return) ident(e)operator(;) - operator(}) - ident(evma_send_data_to_connection) operator(()ident(binding)operator(,) ident(data)operator(,) ident(r)operator(\);) - ident(close) operator(()ident(Fd)operator(\);) - - reserved(return) integer(0)operator(;) -operator(}) - -comment(/***************************************************************************** - -$Id$ - -File: cplusplus.cpp -Date: 27Jul07 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - -preprocessor(#include) include("project.h") - - -reserved(namespace) ident(EM) operator({) - directive(static) ident(map)operator(<)pre_type(string)operator(,) ident(Eventable)operator(*>) ident(Eventables)operator(;) - directive(static) ident(map)operator(<)pre_type(string)operator(,) directive(void)operator((*\)(\)>) ident(Timers)operator(;) -operator(}) - - -comment(/******* -EM::Run -*******/) - -directive(void) ident(EM)operator(::)ident(Run) operator(()directive(void) operator((*)ident(start_func)operator(\)(\)\)) -operator({) - ident(evma__epoll)operator((\);) - ident(evma_initialize_library) operator(()ident(EM)operator(::)ident(Callback)operator(\);) - reserved(if) operator(()ident(start_func)operator(\)) - ident(AddTimer) operator(()integer(0)operator(,) ident(start_func)operator(\);) - ident(evma_run_machine)operator((\);) - ident(evma_release_library)operator((\);) -operator(}) - -comment(/************ -EM::AddTimer -************/) - -directive(void) ident(EM)operator(::)ident(AddTimer) operator(()pre_type(int) ident(milliseconds)operator(,) directive(void) operator((*)ident(func)operator(\)(\)\)) -operator({) - reserved(if) operator(()ident(func)operator(\)) operator({) - directive(const) pre_type(char) operator(*)ident(sig) operator(=) ident(evma_install_oneshot_timer) operator(()ident(milliseconds)operator(\);) - ident(Timers)operator(.)ident(insert) operator(()ident(make_pair) operator(()ident(sig)operator(,) ident(func)operator(\)\);) - operator(}) -operator(}) - - -comment(/*************** -EM::StopReactor -***************/) - -directive(void) ident(EM)operator(::)ident(StopReactor)operator((\)) -operator({) - ident(evma_stop_machine)operator((\);) -operator(}) - - -comment(/******************** -EM::Acceptor::Accept -********************/) - -directive(void) ident(EM)operator(::)ident(Acceptor)operator(::)ident(Accept) operator(()directive(const) pre_type(char) operator(*)ident(signature)operator(\)) -operator({) - ident(Connection) operator(*)ident(c) operator(=) ident(MakeConnection)operator((\);) - ident(c)operator(->)ident(Signature) operator(=) ident(signature)operator(;) - ident(Eventables)operator(.)ident(insert) operator(()ident(make_pair) operator(()ident(c)operator(->)ident(Signature)operator(,) ident(c)operator(\)\);) - ident(c)operator(->)ident(PostInit)operator((\);) -operator(}) - -comment(/************************ -EM::Connection::SendData -************************/) - -directive(void) ident(EM)operator(::)ident(Connection)operator(::)ident(SendData) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(\)) -operator({) - reserved(if) operator(()ident(data)operator(\)) - ident(SendData) operator(()ident(data)operator(,) ident(strlen) operator(()ident(data)operator(\)\);) -operator(}) - - -comment(/************************ -EM::Connection::SendData -************************/) - -directive(void) ident(EM)operator(::)ident(Connection)operator(::)ident(SendData) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(\)) -operator({) - ident(evma_send_data_to_connection) operator(()ident(Signature)operator(.)ident(c_str)operator((\),) ident(data)operator(,) ident(length)operator(\);) -operator(}) - - -comment(/********************* -EM::Connection::Close -*********************/) - -directive(void) ident(EM)operator(::)ident(Connection)operator(::)ident(Close) operator(()pre_type(bool) ident(afterWriting)operator(\)) -operator({) - ident(evma_close_connection) operator(()ident(Signature)operator(.)ident(c_str)operator((\),) ident(afterWriting)operator(\);) -operator(}) - - -comment(/*********************** -EM::Connection::Connect -***********************/) - -directive(void) ident(EM)operator(::)ident(Connection)operator(::)ident(Connect) operator(()directive(const) pre_type(char) operator(*)ident(host)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(Signature) operator(=) ident(evma_connect_to_server) operator(()ident(host)operator(,) ident(port)operator(\);) - ident(Eventables)operator(.)ident(insert)operator(() ident(make_pair) operator(()ident(Signature)operator(,) local_variable(this)operator(\)\);) -operator(}) - -comment(/******************* -EM::Acceptor::Start -*******************/) - -directive(void) ident(EM)operator(::)ident(Acceptor)operator(::)ident(Start) operator(()directive(const) pre_type(char) operator(*)ident(host)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(Signature) operator(=) ident(evma_create_tcp_server) operator(()ident(host)operator(,) ident(port)operator(\);) - ident(Eventables)operator(.)ident(insert)operator(() ident(make_pair) operator(()ident(Signature)operator(,) local_variable(this)operator(\)\);) -operator(}) - - - -comment(/************ -EM::Callback -************/) - -directive(void) ident(EM)operator(::)ident(Callback) operator(()directive(const) pre_type(char) operator(*)ident(sig)operator(,) pre_type(int) ident(ev)operator(,) directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(\)) -operator({) - ident(EM)operator(::)ident(Eventable) operator(*)ident(e)operator(;) - directive(void) operator((*)ident(f)operator(\)(\);) - - reserved(switch) operator(()ident(ev)operator(\)) operator({) - reserved(case) ident(EM_TIMER_FIRED)operator(:) - ident(f) operator(=) ident(Timers) operator([)ident(data)operator(];) - reserved(if) operator(()ident(f)operator(\)) - operator((*)ident(f)operator(\)(\);) - ident(Timers)operator(.)ident(erase) operator(()ident(sig)operator(\);) - reserved(break)operator(;) - - reserved(case) ident(EM_CONNECTION_READ)operator(:) - ident(e) operator(=) ident(EM)operator(::)ident(Eventables) operator([)ident(sig)operator(];) - ident(e)operator(->)ident(ReceiveData) operator(()ident(data)operator(,) ident(length)operator(\);) - reserved(break)operator(;) - - reserved(case) ident(EM_CONNECTION_COMPLETED)operator(:) - ident(e) operator(=) ident(EM)operator(::)ident(Eventables) operator([)ident(sig)operator(];) - ident(e)operator(->)ident(ConnectionCompleted)operator((\);) - reserved(break)operator(;) - - reserved(case) ident(EM_CONNECTION_ACCEPTED)operator(:) - ident(e) operator(=) ident(EM)operator(::)ident(Eventables) operator([)ident(sig)operator(];) - ident(e)operator(->)ident(Accept) operator(()ident(data)operator(\);) - reserved(break)operator(;) - - reserved(case) ident(EM_CONNECTION_UNBOUND)operator(:) - ident(e) operator(=) ident(EM)operator(::)ident(Eventables) operator([)ident(sig)operator(];) - ident(e)operator(->)ident(Unbind)operator((\);) - ident(EM)operator(::)ident(Eventables)operator(.)ident(erase) operator(()ident(sig)operator(\);) - reserved(delete) ident(e)operator(;) - reserved(break)operator(;) - operator(}) -operator(}) - -comment(/***************************************************************************** - -$Id$ - -File: ed.cpp -Date: 06Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - - - -comment(/******************** -SetSocketNonblocking -********************/) - -pre_type(bool) ident(SetSocketNonblocking) operator(()ident(SOCKET) ident(sd)operator(\)) -operator({) - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(val) operator(=) ident(fcntl) operator(()ident(sd)operator(,) ident(F_GETFL)operator(,) integer(0)operator(\);) - reserved(return) operator(()ident(fcntl) operator(()ident(sd)operator(,) ident(F_SETFL)operator(,) ident(val) operator(|) ident(O_NONBLOCK)operator(\)) operator(!=) ident(SOCKET_ERROR)operator(\)) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(;) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - pre_type(unsigned) pre_type(long) ident(one) operator(=) integer(1)operator(;) - reserved(return) operator(()ident(ioctlsocket) operator(()ident(sd)operator(,) ident(FIONBIO)operator(,) operator(&)ident(one)operator(\)) operator(==) integer(0)operator(\)) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/**************************************** -EventableDescriptor::EventableDescriptor -****************************************/) - -ident(EventableDescriptor)operator(::)ident(EventableDescriptor) operator(()pre_type(int) ident(sd)operator(,) ident(EventMachine_t) operator(*)ident(em)operator(\):) - ident(bCloseNow) operator(()pre_constant(false)operator(\),) - ident(bCloseAfterWriting) operator(()pre_constant(false)operator(\),) - ident(MySocket) operator(()ident(sd)operator(\),) - ident(EventCallback) operator(()pre_constant(NULL)operator(\),) - ident(LastRead) operator(()integer(0)operator(\),) - ident(LastWritten) operator(()integer(0)operator(\),) - ident(bCallbackUnbind) operator(()pre_constant(true)operator(\),) - ident(MyEventMachine) operator(()ident(em)operator(\)) -operator({) - comment(/* There are three ways to close a socket, all of which should - * automatically signal to the event machine that this object - * should be removed from the polling scheduler. - * First is a hard close, intended for bad errors or possible - * security violations. It immediately closes the connection - * and puts this object into an error state. - * Second is to set bCloseNow, which will cause the event machine - * to delete this object (and thus close the connection in our - * destructor\) the next chance it gets. bCloseNow also inhibits - * the writing of new data on the socket (but not necessarily - * the reading of new data\). - * The third way is to set bCloseAfterWriting, which inhibits - * the writing of new data and converts to bCloseNow as soon - * as everything in the outbound queue has been written. - * bCloseAfterWriting is really for use only by protocol handlers - * (for example, HTTP writes an HTML page and then closes the - * connection\). All of the error states we generate internally - * cause an immediate close to be scheduled, which may have the - * effect of discarding outbound data. - */) - - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad eventable descriptor)delimiter(")>operator(\);) - reserved(if) operator(()ident(MyEventMachine) operator(==) pre_constant(NULL)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad em in eventable descriptor)delimiter(")>operator(\);) - ident(CreatedAt) operator(=) ident(gCurrentLoopTime)operator(;) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(data)operator(.)ident(ptr) operator(=) local_variable(this)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/***************************************** -EventableDescriptor::~EventableDescriptor -*****************************************/) - -ident(EventableDescriptor)operator(::~)ident(EventableDescriptor)operator((\)) -operator({) - reserved(if) operator(()ident(EventCallback) operator(&&) ident(bCallbackUnbind)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_UNBOUND)operator(,) pre_constant(NULL)operator(,) integer(0)operator(\);) - ident(Close)operator((\);) -operator(}) - - -comment(/************************************* -EventableDescriptor::SetEventCallback -*************************************/) - -directive(void) ident(EventableDescriptor)operator(::)ident(SetEventCallback) operator(()directive(void)operator((*)ident(cb)operator(\)()directive(const) pre_type(char)operator(*,) pre_type(int)operator(,) directive(const) pre_type(char)operator(*,) pre_type(int)operator(\)\)) -operator({) - ident(EventCallback) operator(=) ident(cb)operator(;) -operator(}) - - -comment(/************************** -EventableDescriptor::Close -**************************/) - -directive(void) ident(EventableDescriptor)operator(::)ident(Close)operator((\)) -operator({) - comment(// Close the socket right now. Intended for emergencies.) - reserved(if) operator(()ident(MySocket) operator(!=) ident(INVALID_SOCKET)operator(\)) operator({) - ident(shutdown) operator(()ident(MySocket)operator(,) integer(1)operator(\);) - ident(closesocket) operator(()ident(MySocket)operator(\);) - ident(MySocket) operator(=) ident(INVALID_SOCKET)operator(;) - operator(}) -operator(}) - - -comment(/********************************* -EventableDescriptor::ShouldDelete -*********************************/) - -pre_type(bool) ident(EventableDescriptor)operator(::)ident(ShouldDelete)operator((\)) -operator({) - comment(/* For use by a socket manager, which needs to know if this object - * should be removed from scheduling events and deleted. - * Has an immediate close been scheduled, or are we already closed? - * If either of these are the case, return true. In theory, the manager will - * then delete us, which in turn will make sure the socket is closed. - * Note, if bCloseAfterWriting is true, we check a virtual method to see - * if there is outbound data to write, and only request a close if there is none. - */) - - reserved(return) operator((()ident(MySocket) operator(==) ident(INVALID_SOCKET)operator(\)) operator(||) ident(bCloseNow) operator(||) operator(()ident(bCloseAfterWriting) operator(&&) operator(()ident(GetOutboundDataSize)operator((\)) operator(<=) integer(0)operator(\)\)\);) -operator(}) - - -comment(/********************************** -EventableDescriptor::ScheduleClose -**********************************/) - -directive(void) ident(EventableDescriptor)operator(::)ident(ScheduleClose) operator(()pre_type(bool) ident(after_writing)operator(\)) -operator({) - comment(// KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.) - reserved(if) operator(()ident(after_writing)operator(\)) - ident(bCloseAfterWriting) operator(=) pre_constant(true)operator(;) - reserved(else) - ident(bCloseNow) operator(=) pre_constant(true)operator(;) -operator(}) - - -comment(/************************************* -EventableDescriptor::IsCloseScheduled -*************************************/) - -pre_type(bool) ident(EventableDescriptor)operator(::)ident(IsCloseScheduled)operator((\)) -operator({) - comment(// KEEP THIS SYNCHRONIZED WITH ::ScheduleClose.) - reserved(return) operator(()ident(bCloseNow) operator(||) ident(bCloseAfterWriting)operator(\);) -operator(}) - - -comment(/****************************************** -ConnectionDescriptor::ConnectionDescriptor -******************************************/) - -ident(ConnectionDescriptor)operator(::)ident(ConnectionDescriptor) operator(()pre_type(int) ident(sd)operator(,) ident(EventMachine_t) operator(*)ident(em)operator(\):) - ident(EventableDescriptor) operator(()ident(sd)operator(,) ident(em)operator(\),) - ident(bConnectPending) operator(()pre_constant(false)operator(\),) - ident(bNotifyReadable) operator(()pre_constant(false)operator(\),) - ident(bNotifyWritable) operator(()pre_constant(false)operator(\),) - ident(bReadAttemptedAfterClose) operator(()pre_constant(false)operator(\),) - ident(bWriteAttemptedAfterClose) operator(()pre_constant(false)operator(\),) - ident(OutboundDataSize) operator(()integer(0)operator(\),) - preprocessor(#ifdef) ident(WITH_SSL) - ident(SslBox) operator(()pre_constant(NULL)operator(\),) - preprocessor(#endif) - ident(bIsServer) operator(()pre_constant(false)operator(\),) - ident(LastIo) operator(()ident(gCurrentLoopTime)operator(\),) - ident(InactivityTimeout) operator(()integer(0)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLOUT)operator(;) - preprocessor(#endif) - comment(// 22Jan09: Moved ArmKqueueWriter into SetConnectPending(\) to fix assertion failure in _WriteOutboundData(\)) -operator(}) - - -comment(/******************************************* -ConnectionDescriptor::~ConnectionDescriptor -*******************************************/) - -ident(ConnectionDescriptor)operator(::~)ident(ConnectionDescriptor)operator((\)) -operator({) - comment(// Run down any stranded outbound data.) - reserved(for) operator(()ident(size_t) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(OutboundPages)operator(.)ident(size)operator((\);) ident(i)operator(++\)) - ident(OutboundPages)operator([)ident(i)operator(])operator(.)ident(Free)operator((\);) - - preprocessor(#ifdef) ident(WITH_SSL) - reserved(if) operator(()ident(SslBox)operator(\)) - reserved(delete) ident(SslBox)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/************************************************** -STATIC: ConnectionDescriptor::SendDataToConnection -**************************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(SendDataToConnection) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(data_length)operator(\)) -operator({) - comment(// TODO: This is something of a hack, or at least it's a static method of the wrong class.) - comment(// TODO: Poor polymorphism here. We should be calling one virtual method) - comment(// instead of hacking out the runtime information of the target object.) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(dynamic_cast) operator(<)ident(ConnectionDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(cd)operator(\)) - reserved(return) ident(cd)operator(->)ident(SendOutboundData) operator(()ident(data)operator(,) ident(data_length)operator(\);) - ident(DatagramDescriptor) operator(*)ident(ds) operator(=) reserved(dynamic_cast) operator(<)ident(DatagramDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ds)operator(\)) - reserved(return) ident(ds)operator(->)ident(SendOutboundData) operator(()ident(data)operator(,) ident(data_length)operator(\);) - preprocessor(#ifdef) ident(OS_UNIX) - ident(PipeDescriptor) operator(*)ident(ps) operator(=) reserved(dynamic_cast) operator(<)ident(PipeDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ps)operator(\)) - reserved(return) ident(ps)operator(->)ident(SendOutboundData) operator(()ident(data)operator(,) ident(data_length)operator(\);) - preprocessor(#endif) - reserved(return) operator(-)integer(1)operator(;) -operator(}) - - -comment(/********************************************* -STATIC: ConnectionDescriptor::CloseConnection -*********************************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(CloseConnection) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) pre_type(bool) ident(after_writing)operator(\)) -operator({) - comment(// TODO: This is something of a hack, or at least it's a static method of the wrong class.) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) reserved(dynamic_cast) operator(<)ident(EventableDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ed)operator(\)) - ident(ed)operator(->)ident(ScheduleClose) operator(()ident(after_writing)operator(\);) -operator(}) - -comment(/*********************************************** -STATIC: ConnectionDescriptor::ReportErrorStatus -***********************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(ReportErrorStatus) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - comment(// TODO: This is something of a hack, or at least it's a static method of the wrong class.) - comment(// TODO: Poor polymorphism here. We should be calling one virtual method) - comment(// instead of hacking out the runtime information of the target object.) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(dynamic_cast) operator(<)ident(ConnectionDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(cd)operator(\)) - reserved(return) ident(cd)operator(->)ident(_ReportErrorStatus)operator((\);) - reserved(return) operator(-)integer(1)operator(;) -operator(}) - -comment(/*************************************** -ConnectionDescriptor::SetConnectPending -****************************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(SetConnectPending)operator(()pre_type(bool) ident(f)operator(\)) -operator({) - ident(bConnectPending) operator(=) ident(f)operator(;) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueWriter) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/************************************** -ConnectionDescriptor::SendOutboundData -**************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(SendOutboundData) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(\)) -operator({) - preprocessor(#ifdef) ident(WITH_SSL) - reserved(if) operator(()ident(SslBox)operator(\)) operator({) - reserved(if) operator(()ident(length) operator(>) integer(0)operator(\)) operator({) - pre_type(int) ident(w) operator(=) ident(SslBox)operator(->)ident(PutPlaintext) operator(()ident(data)operator(,) ident(length)operator(\);) - reserved(if) operator(()ident(w) operator(<) integer(0)operator(\)) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - reserved(else) - ident(_DispatchCiphertext)operator((\);) - operator(}) - comment(// TODO: What's the correct return value?) - reserved(return) integer(1)operator(;) comment(// That's a wild guess, almost certainly wrong.) - operator(}) - reserved(else) - preprocessor(#endif) - reserved(return) ident(_SendRawOutboundData) operator(()ident(data)operator(,) ident(length)operator(\);) -operator(}) - - - -comment(/****************************************** -ConnectionDescriptor::_SendRawOutboundData -******************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(_SendRawOutboundData) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(\)) -operator({) - comment(/* This internal method is called to schedule bytes that - * will be sent out to the remote peer. - * It's not directly accessed by the caller, who hits ::SendOutboundData, - * which may or may not filter or encrypt the caller's data before - * sending it here. - */) - - comment(// Highly naive and incomplete implementation.) - comment(// There's no throttle for runaways (which should abort only this connection) - comment(// and not the whole process\), and no coalescing of small pages.) - comment(// (Well, not so bad, small pages are coalesced in ::Write\)) - - reserved(if) operator(()ident(IsCloseScheduled)operator((\)\)) - comment(//if (bCloseNow || bCloseAfterWriting\)) - reserved(return) integer(0)operator(;) - - reserved(if) operator((!)ident(data) operator(&&) operator(()ident(length) operator(>) integer(0)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad outbound data)delimiter(")>operator(\);) - pre_type(char) operator(*)ident(buffer) operator(=) operator(()pre_type(char) operator(*\)) ident(malloc) operator(()ident(length) operator(+) integer(1)operator(\);) - reserved(if) operator((!)ident(buffer)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no allocation for outbound data)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(buffer)operator(,) ident(data)operator(,) ident(length)operator(\);) - ident(buffer) operator([)ident(length)operator(]) operator(=) integer(0)operator(;) - ident(OutboundPages)operator(.)ident(push_back) operator(()ident(OutboundPage) operator(()ident(buffer)operator(,) ident(length)operator(\)\);) - ident(OutboundDataSize) operator(+=) ident(length)operator(;) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) ident(EPOLLOUT)operator(\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueWriter) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - reserved(return) ident(length)operator(;) -operator(}) - - - -comment(/*********************************** -ConnectionDescriptor::SelectForRead -***********************************/) - -pre_type(bool) ident(ConnectionDescriptor)operator(::)ident(SelectForRead)operator((\)) -operator({) - comment(/* A connection descriptor is always scheduled for read, - * UNLESS it's in a pending-connect state. - * On Linux, unlike Unix, a nonblocking socket on which - * connect has been called, does NOT necessarily select - * both readable and writable in case of error. - * The socket will select writable when the disposition - * of the connect is known. On the other hand, a socket - * which successfully connects and selects writable may - * indeed have some data available on it, so it will - * select readable in that case, violating expectations! - * So we will not poll for readability until the socket - * is known to be in a connected state. - */) - - reserved(return) ident(bConnectPending) operator(?) pre_constant(false) operator(:) pre_constant(true)operator(;) -operator(}) - - -comment(/************************************ -ConnectionDescriptor::SelectForWrite -************************************/) - -pre_type(bool) ident(ConnectionDescriptor)operator(::)ident(SelectForWrite)operator((\)) -operator({) - comment(/* Cf the notes under SelectForRead. - * In a pending-connect state, we ALWAYS select for writable. - * In a normal state, we only select for writable when we - * have outgoing data to send. - */) - - reserved(if) operator(()ident(bConnectPending) operator(||) ident(bNotifyWritable)operator(\)) - reserved(return) pre_constant(true)operator(;) - reserved(else) operator({) - reserved(return) operator(()ident(GetOutboundDataSize)operator((\)) operator(>) integer(0)operator(\);) - operator(}) -operator(}) - - -comment(/************************** -ConnectionDescriptor::Read -**************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(Read)operator((\)) -operator({) - comment(/* Read and dispatch data on a socket that has selected readable. - * It's theoretically possible to get and dispatch incoming data on - * a socket that has already been scheduled for closing or close-after-writing. - * In those cases, we'll leave it up the to protocol handler to "do the - * right thing" (which probably means to ignore the incoming data\). - * - * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come - * here with the socket already closed, after the process receives - * a ctrl-C signal (not sure if that's TERM or INT on BSD\). The application - * was one in which network connections were doing a lot of interleaved reads - * and writes. - * Since we always write before reading (in order to keep the outbound queues - * as light as possible\), I think what happened is that an interrupt caused - * the socket to be closed in ConnectionDescriptor::Write. We'll then - * come here in the same pass through the main event loop, and won't get - * cleaned up until immediately after. - * We originally asserted that the socket was valid when we got here. - * To deal properly with the possibility that we are closed when we get here, - * I removed the assert. HOWEVER, the potential for an infinite loop scares me, - * so even though this is really clunky, I added a flag to assert that we never - * come here more than once after being closed. (FCianfrocca\) - */) - - pre_type(int) ident(sd) operator(=) ident(GetSocket)operator((\);) - comment(//assert (sd != INVALID_SOCKET\); (original, removed 22Aug06\)) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - ident(assert) operator((!)ident(bReadAttemptedAfterClose)operator(\);) - ident(bReadAttemptedAfterClose) operator(=) pre_constant(true)operator(;) - reserved(return)operator(;) - operator(}) - - reserved(if) operator(()ident(bNotifyReadable)operator(\)) operator({) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_NOTIFY_READABLE)operator(,) pre_constant(NULL)operator(,) integer(0)operator(\);) - reserved(return)operator(;) - operator(}) - - ident(LastIo) operator(=) ident(gCurrentLoopTime)operator(;) - - pre_type(int) ident(total_bytes_read) operator(=) integer(0)operator(;) - pre_type(char) ident(readbuffer) operator([)integer(16) operator(*) integer(1024) operator(+) integer(1)operator(];) - - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) integer(10)operator(;) ident(i)operator(++\)) operator({) - comment(// Don't read just one buffer and then move on. This is faster) - comment(// if there is a lot of incoming.) - comment(// But don't read indefinitely. Give other sockets a chance to run.) - comment(// NOTICE, we're reading one less than the buffer size.) - comment(// That's so we can put a guard byte at the end of what we send) - comment(// to user code.) - - - pre_type(int) ident(r) operator(=) ident(recv) operator(()ident(sd)operator(,) ident(readbuffer)operator(,) reserved(sizeof)operator(()ident(readbuffer)operator(\)) operator(-) integer(1)operator(,) integer(0)operator(\);) - comment(//cerr << "<R:" << r << ">";) - - reserved(if) operator(()ident(r) operator(>) integer(0)operator(\)) operator({) - ident(total_bytes_read) operator(+=) ident(r)operator(;) - ident(LastRead) operator(=) ident(gCurrentLoopTime)operator(;) - - comment(// Add a null-terminator at the the end of the buffer) - comment(// that we will send to the callback.) - comment(// DO NOT EVER CHANGE THIS. We want to explicitly allow users) - comment(// to be able to depend on this behavior, so they will have) - comment(// the option to do some things faster. Additionally it's) - comment(// a security guard against buffer overflows.) - ident(readbuffer) operator([)ident(r)operator(]) operator(=) integer(0)operator(;) - ident(_DispatchInboundData) operator(()ident(readbuffer)operator(,) ident(r)operator(\);) - operator(}) - reserved(else) reserved(if) operator(()ident(r) operator(==) integer(0)operator(\)) operator({) - reserved(break)operator(;) - operator(}) - reserved(else) operator({) - comment(// Basically a would-block, meaning we've read everything there is to read.) - reserved(break)operator(;) - operator(}) - - operator(}) - - - reserved(if) operator(()ident(total_bytes_read) operator(==) integer(0)operator(\)) operator({) - comment(// If we read no data on a socket that selected readable,) - comment(// it generally means the other end closed the connection gracefully.) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) - operator(}) - -operator(}) - - - -comment(/****************************************** -ConnectionDescriptor::_DispatchInboundData -******************************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(_DispatchInboundData) operator(()directive(const) pre_type(char) operator(*)ident(buffer)operator(,) pre_type(int) ident(size)operator(\)) -operator({) - preprocessor(#ifdef) ident(WITH_SSL) - reserved(if) operator(()ident(SslBox)operator(\)) operator({) - ident(SslBox)operator(->)ident(PutCiphertext) operator(()ident(buffer)operator(,) ident(size)operator(\);) - - pre_type(int) ident(s)operator(;) - pre_type(char) ident(B) operator([)integer(2048)operator(];) - reserved(while) operator((()ident(s) operator(=) ident(SslBox)operator(->)ident(GetPlaintext) operator(()ident(B)operator(,) reserved(sizeof)operator(()ident(B)operator(\)) operator(-) integer(1)operator(\)\)) operator(>) integer(0)operator(\)) operator({) - ident(B) operator([)ident(s)operator(]) operator(=) integer(0)operator(;) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_READ)operator(,) ident(B)operator(,) ident(s)operator(\);) - operator(}) - comment(// INCOMPLETE, s may indicate an SSL error that would force the connection down.) - ident(_DispatchCiphertext)operator((\);) - operator(}) - reserved(else) operator({) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_READ)operator(,) ident(buffer)operator(,) ident(size)operator(\);) - operator(}) - preprocessor(#endif) - - preprocessor(#ifdef) ident(WITHOUT_SSL) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_READ)operator(,) ident(buffer)operator(,) ident(size)operator(\);) - preprocessor(#endif) -operator(}) - - - - - -comment(/*************************** -ConnectionDescriptor::Write -***************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(Write)operator((\)) -operator({) - comment(/* A socket which is in a pending-connect state will select - * writable when the disposition of the connect is known. - * At that point, check to be sure there are no errors, - * and if none, then promote the socket out of the pending - * state. - * TODO: I haven't figured out how Windows signals errors on - * unconnected sockets. Maybe it does the untraditional but - * logical thing and makes the socket selectable for error. - * If so, it's unsupported here for the time being, and connect - * errors will have to be caught by the timeout mechanism. - */) - - reserved(if) operator(()ident(bConnectPending)operator(\)) operator({) - pre_type(int) ident(error)operator(;) - ident(socklen_t) ident(len)operator(;) - ident(len) operator(=) reserved(sizeof)operator(()ident(error)operator(\);) - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(o) operator(=) ident(getsockopt) operator(()ident(GetSocket)operator((\),) ident(SOL_SOCKET)operator(,) ident(SO_ERROR)operator(,) operator(&)ident(error)operator(,) operator(&)ident(len)operator(\);) - preprocessor(#endif) - preprocessor(#ifdef) ident(OS_WIN32) - pre_type(int) ident(o) operator(=) ident(getsockopt) operator(()ident(GetSocket)operator((\),) ident(SOL_SOCKET)operator(,) ident(SO_ERROR)operator(,) operator(()pre_type(char)operator(*\)&)ident(error)operator(,) operator(&)ident(len)operator(\);) - preprocessor(#endif) - reserved(if) operator((()ident(o) operator(==) integer(0)operator(\)) operator(&&) operator(()ident(error) operator(==) integer(0)operator(\)\)) operator({) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_COMPLETED)operator(,) string<delimiter(")delimiter(")>operator(,) integer(0)operator(\);) - ident(bConnectPending) operator(=) pre_constant(false)operator(;) - preprocessor(#ifdef) ident(HAVE_EPOLL) - comment(// The callback may have scheduled outbound data.) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLIN) operator(|) operator(()ident(SelectForWrite)operator((\)) operator(?) ident(EPOLLOUT) operator(:) integer(0)operator(\);) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()local_variable(this)operator(\);) - comment(// The callback may have scheduled outbound data.) - reserved(if) operator(()ident(SelectForWrite)operator((\)\)) - ident(MyEventMachine)operator(->)ident(ArmKqueueWriter) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - operator(}) - reserved(else) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) - operator(}) - reserved(else) operator({) - - reserved(if) operator(()ident(bNotifyWritable)operator(\)) operator({) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_NOTIFY_WRITABLE)operator(,) pre_constant(NULL)operator(,) integer(0)operator(\);) - reserved(return)operator(;) - operator(}) - - ident(_WriteOutboundData)operator((\);) - operator(}) -operator(}) - - -comment(/**************************************** -ConnectionDescriptor::_WriteOutboundData -****************************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(_WriteOutboundData)operator((\)) -operator({) - comment(/* This is a helper function called by ::Write. - * It's possible for a socket to select writable and then no longer - * be writable by the time we get around to writing. The kernel might - * have used up its available output buffers between the select call - * and when we get here. So this condition is not an error. - * - * 20Jul07, added the same kind of protection against an invalid socket - * that is at the top of ::Read. Not entirely how this could happen in - * real life (connection-reset from the remote peer, perhaps?\), but I'm - * doing it to address some reports of crashing under heavy loads. - */) - - pre_type(int) ident(sd) operator(=) ident(GetSocket)operator((\);) - comment(//assert (sd != INVALID_SOCKET\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - ident(assert) operator((!)ident(bWriteAttemptedAfterClose)operator(\);) - ident(bWriteAttemptedAfterClose) operator(=) pre_constant(true)operator(;) - reserved(return)operator(;) - operator(}) - - ident(LastIo) operator(=) ident(gCurrentLoopTime)operator(;) - pre_type(char) ident(output_buffer) operator([)integer(16) operator(*) integer(1024)operator(];) - ident(size_t) ident(nbytes) operator(=) integer(0)operator(;) - - reserved(while) operator((()ident(OutboundPages)operator(.)ident(size)operator((\)) operator(>) integer(0)operator(\)) operator(&&) operator(()ident(nbytes) operator(<) reserved(sizeof)operator(()ident(output_buffer)operator(\)\)\)) operator({) - ident(OutboundPage) operator(*)ident(op) operator(=) operator(&()ident(OutboundPages)operator([)integer(0)operator(]\);) - reserved(if) operator((()ident(nbytes) operator(+) ident(op)operator(->)ident(Length) operator(-) ident(op)operator(->)ident(Offset)operator(\)) operator(<) reserved(sizeof) operator(()ident(output_buffer)operator(\)\)) operator({) - ident(memcpy) operator(()ident(output_buffer) operator(+) ident(nbytes)operator(,) ident(op)operator(->)ident(Buffer) operator(+) ident(op)operator(->)ident(Offset)operator(,) ident(op)operator(->)ident(Length) operator(-) ident(op)operator(->)ident(Offset)operator(\);) - ident(nbytes) operator(+=) operator(()ident(op)operator(->)ident(Length) operator(-) ident(op)operator(->)ident(Offset)operator(\);) - ident(op)operator(->)ident(Free)operator((\);) - ident(OutboundPages)operator(.)ident(pop_front)operator((\);) - operator(}) - reserved(else) operator({) - pre_type(int) ident(len) operator(=) reserved(sizeof)operator(()ident(output_buffer)operator(\)) operator(-) ident(nbytes)operator(;) - ident(memcpy) operator(()ident(output_buffer) operator(+) ident(nbytes)operator(,) ident(op)operator(->)ident(Buffer) operator(+) ident(op)operator(->)ident(Offset)operator(,) ident(len)operator(\);) - ident(op)operator(->)ident(Offset) operator(+=) ident(len)operator(;) - ident(nbytes) operator(+=) ident(len)operator(;) - operator(}) - operator(}) - - comment(// We should never have gotten here if there were no data to write,) - comment(// so assert that as a sanity check.) - comment(// Don't bother to make sure nbytes is less than output_buffer because) - comment(// if it were we probably would have crashed already.) - ident(assert) operator(()ident(nbytes) operator(>) integer(0)operator(\);) - - ident(assert) operator(()ident(GetSocket)operator((\)) operator(!=) ident(INVALID_SOCKET)operator(\);) - pre_type(int) ident(bytes_written) operator(=) ident(send) operator(()ident(GetSocket)operator((\),) ident(output_buffer)operator(,) ident(nbytes)operator(,) integer(0)operator(\);) - - pre_type(bool) ident(err) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(bytes_written) operator(<) integer(0)operator(\)) operator({) - ident(err) operator(=) pre_constant(true)operator(;) - ident(bytes_written) operator(=) integer(0)operator(;) - operator(}) - - ident(assert) operator(()ident(bytes_written) operator(>=) integer(0)operator(\);) - ident(OutboundDataSize) operator(-=) ident(bytes_written)operator(;) - reserved(if) operator((()ident(size_t)operator(\))ident(bytes_written) operator(<) ident(nbytes)operator(\)) operator({) - pre_type(int) ident(len) operator(=) ident(nbytes) operator(-) ident(bytes_written)operator(;) - pre_type(char) operator(*)ident(buffer) operator(=) operator(()pre_type(char)operator(*\)) ident(malloc) operator(()ident(len) operator(+) integer(1)operator(\);) - reserved(if) operator((!)ident(buffer)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad alloc throwing back data)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(buffer)operator(,) ident(output_buffer) operator(+) ident(bytes_written)operator(,) ident(len)operator(\);) - ident(buffer) operator([)ident(len)operator(]) operator(=) integer(0)operator(;) - ident(OutboundPages)operator(.)ident(push_front) operator(()ident(OutboundPage) operator(()ident(buffer)operator(,) ident(len)operator(\)\);) - operator(}) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) operator(()ident(SelectForWrite)operator((\)) operator(?) ident(EPOLLOUT) operator(:) integer(0)operator(\)\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(if) operator(()ident(SelectForWrite)operator((\)\)) - ident(MyEventMachine)operator(->)ident(ArmKqueueWriter) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - - - reserved(if) operator(()ident(err)operator(\)) operator({) - preprocessor(#ifdef) ident(OS_UNIX) - reserved(if) operator((()ident(errno) operator(!=) ident(EINPROGRESS)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(EWOULDBLOCK)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(EINTR)operator(\)\)) - preprocessor(#endif) - preprocessor(#ifdef) ident(OS_WIN32) - reserved(if) operator((()ident(errno) operator(!=) ident(WSAEINPROGRESS)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(WSAEWOULDBLOCK)operator(\)\)) - preprocessor(#endif) - ident(Close)operator((\);) - operator(}) -operator(}) - - -comment(/**************************************** -ConnectionDescriptor::_ReportErrorStatus -****************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(_ReportErrorStatus)operator((\)) -operator({) - pre_type(int) ident(error)operator(;) - ident(socklen_t) ident(len)operator(;) - ident(len) operator(=) reserved(sizeof)operator(()ident(error)operator(\);) - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(o) operator(=) ident(getsockopt) operator(()ident(GetSocket)operator((\),) ident(SOL_SOCKET)operator(,) ident(SO_ERROR)operator(,) operator(&)ident(error)operator(,) operator(&)ident(len)operator(\);) - preprocessor(#endif) - preprocessor(#ifdef) ident(OS_WIN32) - pre_type(int) ident(o) operator(=) ident(getsockopt) operator(()ident(GetSocket)operator((\),) ident(SOL_SOCKET)operator(,) ident(SO_ERROR)operator(,) operator(()pre_type(char)operator(*\)&)ident(error)operator(,) operator(&)ident(len)operator(\);) - preprocessor(#endif) - reserved(if) operator((()ident(o) operator(==) integer(0)operator(\)) operator(&&) operator(()ident(error) operator(==) integer(0)operator(\)\)) - reserved(return) integer(0)operator(;) - reserved(else) - reserved(return) integer(1)operator(;) -operator(}) - - -comment(/****************************** -ConnectionDescriptor::StartTls -******************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(StartTls)operator((\)) -operator({) - preprocessor(#ifdef) ident(WITH_SSL) - reserved(if) operator(()ident(SslBox)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(SSL/TLS already running on connection)delimiter(")>operator(\);) - - ident(SslBox) operator(=) reserved(new) ident(SslBox_t) operator(()ident(bIsServer)operator(,) ident(PrivateKeyFilename)operator(,) ident(CertChainFilename)operator(\);) - ident(_DispatchCiphertext)operator((\);) - preprocessor(#endif) - - preprocessor(#ifdef) ident(WITHOUT_SSL) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(Encryption not available on this event-machine)delimiter(")>operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/********************************* -ConnectionDescriptor::SetTlsParms -*********************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(SetTlsParms) operator(()directive(const) pre_type(char) operator(*)ident(privkey_filename)operator(,) directive(const) pre_type(char) operator(*)ident(certchain_filename)operator(\)) -operator({) - preprocessor(#ifdef) ident(WITH_SSL) - reserved(if) operator(()ident(SslBox)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(call SetTlsParms before calling StartTls)delimiter(")>operator(\);) - reserved(if) operator(()ident(privkey_filename) operator(&&) operator(*)ident(privkey_filename)operator(\)) - ident(PrivateKeyFilename) operator(=) ident(privkey_filename)operator(;) - reserved(if) operator(()ident(certchain_filename) operator(&&) operator(*)ident(certchain_filename)operator(\)) - ident(CertChainFilename) operator(=) ident(certchain_filename)operator(;) - preprocessor(#endif) - - preprocessor(#ifdef) ident(WITHOUT_SSL) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(Encryption not available on this event-machine)delimiter(")>operator(\);) - preprocessor(#endif) -operator(}) - - - -comment(/***************************************** -ConnectionDescriptor::_DispatchCiphertext -*****************************************/) -preprocessor(#ifdef) ident(WITH_SSL) -directive(void) ident(ConnectionDescriptor)operator(::)ident(_DispatchCiphertext)operator((\)) -operator({) - ident(assert) operator(()ident(SslBox)operator(\);) - - - pre_type(char) ident(BigBuf) operator([)integer(2048)operator(];) - pre_type(bool) ident(did_work)operator(;) - - reserved(do) operator({) - ident(did_work) operator(=) pre_constant(false)operator(;) - - comment(// try to drain ciphertext) - reserved(while) operator(()ident(SslBox)operator(->)ident(CanGetCiphertext)operator((\)\)) operator({) - pre_type(int) ident(r) operator(=) ident(SslBox)operator(->)ident(GetCiphertext) operator(()ident(BigBuf)operator(,) reserved(sizeof)operator(()ident(BigBuf)operator(\)\);) - ident(assert) operator(()ident(r) operator(>) integer(0)operator(\);) - ident(_SendRawOutboundData) operator(()ident(BigBuf)operator(,) ident(r)operator(\);) - ident(did_work) operator(=) pre_constant(true)operator(;) - operator(}) - - comment(// Pump the SslBox, in case it has queued outgoing plaintext) - comment(// This will return >0 if data was written,) - comment(// 0 if no data was written, and <0 if there was a fatal error.) - pre_type(bool) ident(pump)operator(;) - reserved(do) operator({) - ident(pump) operator(=) pre_constant(false)operator(;) - pre_type(int) ident(w) operator(=) ident(SslBox)operator(->)ident(PutPlaintext) operator(()pre_constant(NULL)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(w) operator(>) integer(0)operator(\)) operator({) - ident(did_work) operator(=) pre_constant(true)operator(;) - ident(pump) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(else) reserved(if) operator(()ident(w) operator(<) integer(0)operator(\)) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - operator(}) reserved(while) operator(()ident(pump)operator(\);) - - comment(// try to put plaintext. INCOMPLETE, doesn't belong here?) - comment(// In SendOutboundData, we're spooling plaintext directly) - comment(// into SslBox. That may be wrong, we may need to buffer it) - comment(// up here! ) - comment(/* - const char *ptr; - int ptr_length; - while (OutboundPlaintext.GetPage (&ptr, &ptr_length\)\) { - assert (ptr && (ptr_length > 0\)\); - int w = SslMachine.PutPlaintext (ptr, ptr_length\); - if (w > 0\) { - OutboundPlaintext.DiscardBytes (w\); - did_work = true; - } - else - break; - } - */) - - operator(}) reserved(while) operator(()ident(did_work)operator(\);) - -operator(}) -preprocessor(#endif) - - - -comment(/******************************* -ConnectionDescriptor::Heartbeat -*******************************/) - -directive(void) ident(ConnectionDescriptor)operator(::)ident(Heartbeat)operator((\)) -operator({) - comment(/* Only allow a certain amount of time to go by while waiting - * for a pending connect. If it expires, then kill the socket. - * For a connected socket, close it if its inactivity timer - * has expired. - */) - - reserved(if) operator(()ident(bConnectPending)operator(\)) operator({) - reserved(if) operator((()ident(gCurrentLoopTime) operator(-) ident(CreatedAt)operator(\)) operator(>=) ident(PendingConnectTimeout)operator(\)) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) - operator(}) - reserved(else) operator({) - reserved(if) operator(()ident(InactivityTimeout) operator(&&) operator((()ident(gCurrentLoopTime) operator(-) ident(LastIo)operator(\)) operator(>=) ident(InactivityTimeout)operator(\)\)) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) - operator(}) -operator(}) - - -comment(/**************************************** -LoopbreakDescriptor::LoopbreakDescriptor -****************************************/) - -ident(LoopbreakDescriptor)operator(::)ident(LoopbreakDescriptor) operator(()pre_type(int) ident(sd)operator(,) ident(EventMachine_t) operator(*)ident(parent_em)operator(\):) - ident(EventableDescriptor) operator(()ident(sd)operator(,) ident(parent_em)operator(\)) -operator({) - comment(/* This is really bad and ugly. Change someday if possible. - * We have to know about an event-machine (probably the one that owns us\), - * so we can pass newly-created connections to it. - */) - - ident(bCallbackUnbind) operator(=) pre_constant(false)operator(;) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLIN)operator(;) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - - - -comment(/************************* -LoopbreakDescriptor::Read -*************************/) - -directive(void) ident(LoopbreakDescriptor)operator(::)ident(Read)operator((\)) -operator({) - comment(// TODO, refactor, this code is probably in the wrong place.) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(_ReadLoopBreaker)operator((\);) -operator(}) - - -comment(/************************** -LoopbreakDescriptor::Write -**************************/) - -directive(void) ident(LoopbreakDescriptor)operator(::)ident(Write)operator((\)) -operator({) - comment(// Why are we here?) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad code path in loopbreak)delimiter(")>operator(\);) -operator(}) - -comment(/************************************** -AcceptorDescriptor::AcceptorDescriptor -**************************************/) - -ident(AcceptorDescriptor)operator(::)ident(AcceptorDescriptor) operator(()pre_type(int) ident(sd)operator(,) ident(EventMachine_t) operator(*)ident(parent_em)operator(\):) - ident(EventableDescriptor) operator(()ident(sd)operator(,) ident(parent_em)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLIN)operator(;) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/*************************************** -AcceptorDescriptor::~AcceptorDescriptor -***************************************/) - -ident(AcceptorDescriptor)operator(::~)ident(AcceptorDescriptor)operator((\)) -operator({) -operator(}) - -comment(/**************************************** -STATIC: AcceptorDescriptor::StopAcceptor -****************************************/) - -directive(void) ident(AcceptorDescriptor)operator(::)ident(StopAcceptor) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(\)) -operator({) - comment(// TODO: This is something of a hack, or at least it's a static method of the wrong class.) - ident(AcceptorDescriptor) operator(*)ident(ad) operator(=) reserved(dynamic_cast) operator(<)ident(AcceptorDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(ad)operator(\)) - ident(ad)operator(->)ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - reserved(else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(failed to close nonexistent acceptor)delimiter(")>operator(\);) -operator(}) - - -comment(/************************ -AcceptorDescriptor::Read -************************/) - -directive(void) ident(AcceptorDescriptor)operator(::)ident(Read)operator((\)) -operator({) - comment(/* Accept up to a certain number of sockets on the listening connection. - * Don't try to accept all that are present, because this would allow a DoS attack - * in which no data were ever read or written. We should accept more than one, - * if available, to keep the partially accepted sockets from backing up in the kernel. - */) - - comment(/* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it - * for readability. According to Stevens UNP, it's possible for an acceptor to select readable - * and then block when we call accept. For example, the other end resets the connection after - * the socket selects readable and before we call accept. The kernel will remove the dead - * socket from the accept queue. If the accept queue is now empty, accept will block. - */) - - - reserved(struct) ident(sockaddr_in) ident(pin)operator(;) - ident(socklen_t) ident(addrlen) operator(=) reserved(sizeof) operator(()ident(pin)operator(\);) - - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) integer(10)operator(;) ident(i)operator(++\)) operator({) - pre_type(int) ident(sd) operator(=) ident(accept) operator(()ident(GetSocket)operator((\),) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(pin)operator(,) operator(&)ident(addrlen)operator(\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - comment(// This breaks the loop when we've accepted everything on the kernel queue,) - comment(// up to 10 new connections. But what if the *first* accept fails?) - comment(// Does that mean anything serious is happening, beyond the situation) - comment(// described in the note above?) - reserved(break)operator(;) - operator(}) - - comment(// Set the newly-accepted socket non-blocking.) - comment(// On Windows, this may fail because, weirdly, Windows inherits the non-blocking) - comment(// attribute that we applied to the acceptor socket into the accepted one.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(sd)operator(\)\)) operator({) - comment(//int val = fcntl (sd, F_GETFL, 0\);) - comment(//if (fcntl (sd, F_SETFL, val | O_NONBLOCK\) == -1\) {) - ident(shutdown) operator(()ident(sd)operator(,) integer(1)operator(\);) - ident(closesocket) operator(()ident(sd)operator(\);) - reserved(continue)operator(;) - operator(}) - - - comment(// Disable slow-start (Nagle algorithm\). Eventually make this configurable.) - pre_type(int) ident(one) operator(=) integer(1)operator(;) - ident(setsockopt) operator(()ident(sd)operator(,) ident(IPPROTO_TCP)operator(,) ident(TCP_NODELAY)operator(,) operator(()pre_type(char)operator(*\)) operator(&)ident(one)operator(,) reserved(sizeof)operator(()ident(one)operator(\)\);) - - - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(sd)operator(,) ident(MyEventMachine)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no newly accepted connection)delimiter(")>operator(\);) - ident(cd)operator(->)ident(SetServerMode)operator((\);) - reserved(if) operator(()ident(EventCallback)operator(\)) operator({) - operator((*)ident(EventCallback)operator(\)) operator(()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_ACCEPTED)operator(,) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(size)operator((\)\);) - operator(}) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(cd)operator(->)ident(GetEpollEvent)operator((\)->)ident(events) operator(=) ident(EPOLLIN) operator(|) operator(()ident(cd)operator(->)ident(SelectForWrite)operator((\)) operator(?) ident(EPOLLOUT) operator(:) integer(0)operator(\);) - preprocessor(#endif) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Add) operator(()ident(cd)operator(\);) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(if) operator(()ident(cd)operator(->)ident(SelectForWrite)operator((\)\)) - ident(MyEventMachine)operator(->)ident(ArmKqueueWriter) operator(()ident(cd)operator(\);) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()ident(cd)operator(\);) - preprocessor(#endif) - operator(}) - -operator(}) - - -comment(/************************* -AcceptorDescriptor::Write -*************************/) - -directive(void) ident(AcceptorDescriptor)operator(::)ident(Write)operator((\)) -operator({) - comment(// Why are we here?) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad code path in acceptor)delimiter(")>operator(\);) -operator(}) - - -comment(/***************************** -AcceptorDescriptor::Heartbeat -*****************************/) - -directive(void) ident(AcceptorDescriptor)operator(::)ident(Heartbeat)operator((\)) -operator({) - comment(// No-op) -operator(}) - - -comment(/******************************* -AcceptorDescriptor::GetSockname -*******************************/) - -pre_type(bool) ident(AcceptorDescriptor)operator(::)ident(GetSockname) operator(()reserved(struct) ident(sockaddr) operator(*)ident(s)operator(\)) -operator({) - pre_type(bool) ident(ok) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(s)operator(\)) operator({) - ident(socklen_t) ident(len) operator(=) reserved(sizeof)operator((*)ident(s)operator(\);) - pre_type(int) ident(gp) operator(=) ident(getsockname) operator(()ident(GetSocket)operator((\),) ident(s)operator(,) operator(&)ident(len)operator(\);) - reserved(if) operator(()ident(gp) operator(==) integer(0)operator(\)) - ident(ok) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(return) ident(ok)operator(;) -operator(}) - - - -comment(/************************************** -DatagramDescriptor::DatagramDescriptor -**************************************/) - -ident(DatagramDescriptor)operator(::)ident(DatagramDescriptor) operator(()pre_type(int) ident(sd)operator(,) ident(EventMachine_t) operator(*)ident(parent_em)operator(\):) - ident(EventableDescriptor) operator(()ident(sd)operator(,) ident(parent_em)operator(\),) - ident(OutboundDataSize) operator(()integer(0)operator(\),) - ident(LastIo) operator(()ident(gCurrentLoopTime)operator(\),) - ident(InactivityTimeout) operator(()integer(0)operator(\)) -operator({) - ident(memset) operator((&)ident(ReturnAddress)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(ReturnAddress)operator(\)\);) - - comment(/* Provisionally added 19Oct07. All datagram sockets support broadcasting. - * Until now, sending to a broadcast address would give EACCES (permission denied\) - * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order - * to accept a packet to a broadcast address. Solaris doesn't require it. I think - * Windows DOES require it but I'm not sure. - * - * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST - * on a UDP socket in order to enable broadcasting. The reason for requiring the option - * in the first place is so that applications don't send broadcast datagrams by mistake. - * I imagine that could happen if a user of an application typed in an address that happened - * to be a broadcast address on that particular subnet. - * - * This is provisional because someone may eventually come up with a good reason not to - * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API - * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T - * EXPLICITLY SET THE OPTION. - */) - - pre_type(int) ident(oval) operator(=) integer(1)operator(;) - pre_type(int) ident(sob) operator(=) ident(setsockopt) operator(()ident(GetSocket)operator((\),) ident(SOL_SOCKET)operator(,) ident(SO_BROADCAST)operator(,) operator(()pre_type(char)operator(*\)&)ident(oval)operator(,) reserved(sizeof)operator(()ident(oval)operator(\)\);) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLIN)operator(;) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/*************************************** -DatagramDescriptor::~DatagramDescriptor -***************************************/) - -ident(DatagramDescriptor)operator(::~)ident(DatagramDescriptor)operator((\)) -operator({) - comment(// Run down any stranded outbound data.) - reserved(for) operator(()ident(size_t) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(OutboundPages)operator(.)ident(size)operator((\);) ident(i)operator(++\)) - ident(OutboundPages)operator([)ident(i)operator(])operator(.)ident(Free)operator((\);) -operator(}) - - -comment(/***************************** -DatagramDescriptor::Heartbeat -*****************************/) - -directive(void) ident(DatagramDescriptor)operator(::)ident(Heartbeat)operator((\)) -operator({) - comment(// Close it if its inactivity timer has expired.) - - reserved(if) operator(()ident(InactivityTimeout) operator(&&) operator((()ident(gCurrentLoopTime) operator(-) ident(LastIo)operator(\)) operator(>=) ident(InactivityTimeout)operator(\)\)) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) -operator(}) - - -comment(/************************ -DatagramDescriptor::Read -************************/) - -directive(void) ident(DatagramDescriptor)operator(::)ident(Read)operator((\)) -operator({) - pre_type(int) ident(sd) operator(=) ident(GetSocket)operator((\);) - ident(assert) operator(()ident(sd) operator(!=) ident(INVALID_SOCKET)operator(\);) - ident(LastIo) operator(=) ident(gCurrentLoopTime)operator(;) - - comment(// This is an extremely large read buffer.) - comment(// In many cases you wouldn't expect to get any more than 4K.) - pre_type(char) ident(readbuffer) operator([)integer(16) operator(*) integer(1024)operator(];) - - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) integer(10)operator(;) ident(i)operator(++\)) operator({) - comment(// Don't read just one buffer and then move on. This is faster) - comment(// if there is a lot of incoming.) - comment(// But don't read indefinitely. Give other sockets a chance to run.) - comment(// NOTICE, we're reading one less than the buffer size.) - comment(// That's so we can put a guard byte at the end of what we send) - comment(// to user code.) - - reserved(struct) ident(sockaddr_in) ident(sin)operator(;) - ident(socklen_t) ident(slen) operator(=) reserved(sizeof) operator(()ident(sin)operator(\);) - ident(memset) operator((&)ident(sin)operator(,) integer(0)operator(,) ident(slen)operator(\);) - - pre_type(int) ident(r) operator(=) ident(recvfrom) operator(()ident(sd)operator(,) ident(readbuffer)operator(,) reserved(sizeof)operator(()ident(readbuffer)operator(\)) operator(-) integer(1)operator(,) integer(0)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(sin)operator(,) operator(&)ident(slen)operator(\);) - comment(//cerr << "<R:" << r << ">";) - - comment(// In UDP, a zero-length packet is perfectly legal.) - reserved(if) operator(()ident(r) operator(>=) integer(0)operator(\)) operator({) - ident(LastRead) operator(=) ident(gCurrentLoopTime)operator(;) - - comment(// Add a null-terminator at the the end of the buffer) - comment(// that we will send to the callback.) - comment(// DO NOT EVER CHANGE THIS. We want to explicitly allow users) - comment(// to be able to depend on this behavior, so they will have) - comment(// the option to do some things faster. Additionally it's) - comment(// a security guard against buffer overflows.) - ident(readbuffer) operator([)ident(r)operator(]) operator(=) integer(0)operator(;) - - - comment(// Set up a "temporary" return address so that callers can "reply" to us) - comment(// from within the callback we are about to invoke. That means that ordinary) - comment(// calls to "send_data_to_connection" (which is of course misnamed in this) - comment(// case\) will result in packets being sent back to the same place that sent) - comment(// us this one.) - comment(// There is a different call (evma_send_datagram\) for cases where the caller) - comment(// actually wants to send a packet somewhere else.) - - ident(memset) operator((&)ident(ReturnAddress)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(ReturnAddress)operator(\)\);) - ident(memcpy) operator((&)ident(ReturnAddress)operator(,) operator(&)ident(sin)operator(,) ident(slen)operator(\);) - - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_READ)operator(,) ident(readbuffer)operator(,) ident(r)operator(\);) - - operator(}) - reserved(else) operator({) - comment(// Basically a would-block, meaning we've read everything there is to read.) - reserved(break)operator(;) - operator(}) - - operator(}) - - -operator(}) - - -comment(/************************* -DatagramDescriptor::Write -*************************/) - -directive(void) ident(DatagramDescriptor)operator(::)ident(Write)operator((\)) -operator({) - comment(/* It's possible for a socket to select writable and then no longer - * be writable by the time we get around to writing. The kernel might - * have used up its available output buffers between the select call - * and when we get here. So this condition is not an error. - * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData, - * but differs in the that the outbound data pages (received from the - * user\) are _message-structured._ That is, we send each of them out - * one message at a time. - * TODO, we are currently suppressing the EMSGSIZE error!!! - */) - - pre_type(int) ident(sd) operator(=) ident(GetSocket)operator((\);) - ident(assert) operator(()ident(sd) operator(!=) ident(INVALID_SOCKET)operator(\);) - ident(LastIo) operator(=) ident(gCurrentLoopTime)operator(;) - - ident(assert) operator(()ident(OutboundPages)operator(.)ident(size)operator((\)) operator(>) integer(0)operator(\);) - - comment(// Send out up to 10 packets, then cycle the machine.) - reserved(for) operator(()pre_type(int) ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) integer(10)operator(;) ident(i)operator(++\)) operator({) - reserved(if) operator(()ident(OutboundPages)operator(.)ident(size)operator((\)) operator(<=) integer(0)operator(\)) - reserved(break)operator(;) - ident(OutboundPage) operator(*)ident(op) operator(=) operator(&()ident(OutboundPages)operator([)integer(0)operator(]\);) - - comment(// The nasty cast to (char*\) is needed because Windows is brain-dead.) - pre_type(int) ident(s) operator(=) ident(sendto) operator(()ident(sd)operator(,) operator(()pre_type(char)operator(*\))ident(op)operator(->)ident(Buffer)operator(,) ident(op)operator(->)ident(Length)operator(,) integer(0)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&()ident(op)operator(->)ident(From)operator(\),) reserved(sizeof)operator(()ident(op)operator(->)ident(From)operator(\)\);) - pre_type(int) ident(e) operator(=) ident(errno)operator(;) - - ident(OutboundDataSize) operator(-=) ident(op)operator(->)ident(Length)operator(;) - ident(op)operator(->)ident(Free)operator((\);) - ident(OutboundPages)operator(.)ident(pop_front)operator((\);) - - reserved(if) operator(()ident(s) operator(==) ident(SOCKET_ERROR)operator(\)) operator({) - preprocessor(#ifdef) ident(OS_UNIX) - reserved(if) operator((()ident(e) operator(!=) ident(EINPROGRESS)operator(\)) operator(&&) operator(()ident(e) operator(!=) ident(EWOULDBLOCK)operator(\)) operator(&&) operator(()ident(e) operator(!=) ident(EINTR)operator(\)\)) operator({) - preprocessor(#endif) - preprocessor(#ifdef) ident(OS_WIN32) - reserved(if) operator((()ident(e) operator(!=) ident(WSAEINPROGRESS)operator(\)) operator(&&) operator(()ident(e) operator(!=) ident(WSAEWOULDBLOCK)operator(\)\)) operator({) - preprocessor(#endif) - ident(Close)operator((\);) - reserved(break)operator(;) - operator(}) - operator(}) - operator(}) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) operator(()ident(SelectForWrite)operator((\)) operator(?) ident(EPOLLOUT) operator(:) integer(0)operator(\)\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/********************************** -DatagramDescriptor::SelectForWrite -**********************************/) - -pre_type(bool) ident(DatagramDescriptor)operator(::)ident(SelectForWrite)operator((\)) -operator({) - comment(/* Changed 15Nov07, per bug report by Mark Zvillius. - * The outbound data size will be zero if there are zero-length outbound packets, - * so we now select writable in case the outbound page buffer is not empty. - * Note that the superclass ShouldDelete method still checks for outbound data size, - * which may be wrong. - */) - comment(//return (GetOutboundDataSize(\) > 0\); (Original\)) - reserved(return) operator(()ident(OutboundPages)operator(.)ident(size)operator((\)) operator(>) integer(0)operator(\);) -operator(}) - - -comment(/************************************ -DatagramDescriptor::SendOutboundData -************************************/) - -pre_type(int) ident(DatagramDescriptor)operator(::)ident(SendOutboundData) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(\)) -operator({) - comment(// This is an exact clone of ConnectionDescriptor::SendOutboundData.) - comment(// That means it needs to move to a common ancestor.) - - reserved(if) operator(()ident(IsCloseScheduled)operator((\)\)) - comment(//if (bCloseNow || bCloseAfterWriting\)) - reserved(return) integer(0)operator(;) - - reserved(if) operator((!)ident(data) operator(&&) operator(()ident(length) operator(>) integer(0)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad outbound data)delimiter(")>operator(\);) - pre_type(char) operator(*)ident(buffer) operator(=) operator(()pre_type(char) operator(*\)) ident(malloc) operator(()ident(length) operator(+) integer(1)operator(\);) - reserved(if) operator((!)ident(buffer)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no allocation for outbound data)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(buffer)operator(,) ident(data)operator(,) ident(length)operator(\);) - ident(buffer) operator([)ident(length)operator(]) operator(=) integer(0)operator(;) - ident(OutboundPages)operator(.)ident(push_back) operator(()ident(OutboundPage) operator(()ident(buffer)operator(,) ident(length)operator(,) ident(ReturnAddress)operator(\)\);) - ident(OutboundDataSize) operator(+=) ident(length)operator(;) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) ident(EPOLLOUT)operator(\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - reserved(return) ident(length)operator(;) -operator(}) - - -comment(/**************************************** -DatagramDescriptor::SendOutboundDatagram -****************************************/) - -pre_type(int) ident(DatagramDescriptor)operator(::)ident(SendOutboundDatagram) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(,) directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - comment(// This is an exact clone of ConnectionDescriptor::SendOutboundData.) - comment(// That means it needs to move to a common ancestor.) - comment(// TODO: Refactor this so there's no overlap with SendOutboundData.) - - reserved(if) operator(()ident(IsCloseScheduled)operator((\)\)) - comment(//if (bCloseNow || bCloseAfterWriting\)) - reserved(return) integer(0)operator(;) - - reserved(if) operator((!)ident(address) operator(||) operator(!*)ident(address) operator(||) operator(!)ident(port)operator(\)) - reserved(return) integer(0)operator(;) - - ident(sockaddr_in) ident(pin)operator(;) - pre_type(unsigned) pre_type(long) ident(HostAddr)operator(;) - - ident(HostAddr) operator(=) ident(inet_addr) operator(()ident(address)operator(\);) - reserved(if) operator(()ident(HostAddr) operator(==) ident(INADDR_NONE)operator(\)) operator({) - comment(// The nasty cast to (char*\) is because Windows is brain-dead.) - ident(hostent) operator(*)ident(hp) operator(=) ident(gethostbyname) operator((()pre_type(char)operator(*\))ident(address)operator(\);) - reserved(if) operator((!)ident(hp)operator(\)) - reserved(return) integer(0)operator(;) - ident(HostAddr) operator(=) operator((()ident(in_addr)operator(*\)()ident(hp)operator(->)ident(h_addr)operator(\)\)->)ident(s_addr)operator(;) - operator(}) - - ident(memset) operator((&)ident(pin)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(pin)operator(\)\);) - ident(pin)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(pin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(HostAddr)operator(;) - ident(pin)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - - - - reserved(if) operator((!)ident(data) operator(&&) operator(()ident(length) operator(>) integer(0)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad outbound data)delimiter(")>operator(\);) - pre_type(char) operator(*)ident(buffer) operator(=) operator(()pre_type(char) operator(*\)) ident(malloc) operator(()ident(length) operator(+) integer(1)operator(\);) - reserved(if) operator((!)ident(buffer)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no allocation for outbound data)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(buffer)operator(,) ident(data)operator(,) ident(length)operator(\);) - ident(buffer) operator([)ident(length)operator(]) operator(=) integer(0)operator(;) - ident(OutboundPages)operator(.)ident(push_back) operator(()ident(OutboundPage) operator(()ident(buffer)operator(,) ident(length)operator(,) ident(pin)operator(\)\);) - ident(OutboundDataSize) operator(+=) ident(length)operator(;) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) ident(EPOLLOUT)operator(\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - reserved(return) ident(length)operator(;) -operator(}) - - -comment(/**************************************** -STATIC: DatagramDescriptor::SendDatagram -****************************************/) - -pre_type(int) ident(DatagramDescriptor)operator(::)ident(SendDatagram) operator(()directive(const) pre_type(char) operator(*)ident(binding)operator(,) directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(,) directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(DatagramDescriptor) operator(*)ident(dd) operator(=) reserved(dynamic_cast) operator(<)ident(DatagramDescriptor)operator(*>) operator(()ident(Bindable_t)operator(::)ident(GetObject) operator(()ident(binding)operator(\)\);) - reserved(if) operator(()ident(dd)operator(\)) - reserved(return) ident(dd)operator(->)ident(SendOutboundDatagram) operator(()ident(data)operator(,) ident(length)operator(,) ident(address)operator(,) ident(port)operator(\);) - reserved(else) - reserved(return) operator(-)integer(1)operator(;) -operator(}) - - -comment(/********************************* -ConnectionDescriptor::GetPeername -*********************************/) - -pre_type(bool) ident(ConnectionDescriptor)operator(::)ident(GetPeername) operator(()reserved(struct) ident(sockaddr) operator(*)ident(s)operator(\)) -operator({) - pre_type(bool) ident(ok) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(s)operator(\)) operator({) - ident(socklen_t) ident(len) operator(=) reserved(sizeof)operator((*)ident(s)operator(\);) - pre_type(int) ident(gp) operator(=) ident(getpeername) operator(()ident(GetSocket)operator((\),) ident(s)operator(,) operator(&)ident(len)operator(\);) - reserved(if) operator(()ident(gp) operator(==) integer(0)operator(\)) - ident(ok) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(return) ident(ok)operator(;) -operator(}) - -comment(/********************************* -ConnectionDescriptor::GetSockname -*********************************/) - -pre_type(bool) ident(ConnectionDescriptor)operator(::)ident(GetSockname) operator(()reserved(struct) ident(sockaddr) operator(*)ident(s)operator(\)) -operator({) - pre_type(bool) ident(ok) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(s)operator(\)) operator({) - ident(socklen_t) ident(len) operator(=) reserved(sizeof)operator((*)ident(s)operator(\);) - pre_type(int) ident(gp) operator(=) ident(getsockname) operator(()ident(GetSocket)operator((\),) ident(s)operator(,) operator(&)ident(len)operator(\);) - reserved(if) operator(()ident(gp) operator(==) integer(0)operator(\)) - ident(ok) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(return) ident(ok)operator(;) -operator(}) - - -comment(/********************************************** -ConnectionDescriptor::GetCommInactivityTimeout -**********************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(GetCommInactivityTimeout) operator(()pre_type(int) operator(*)ident(value)operator(\)) -operator({) - reserved(if) operator(()ident(value)operator(\)) operator({) - operator(*)ident(value) operator(=) ident(InactivityTimeout)operator(;) - reserved(return) integer(1)operator(;) - operator(}) - reserved(else) operator({) - comment(// TODO, extended logging, got bad parameter.) - reserved(return) integer(0)operator(;) - operator(}) -operator(}) - - -comment(/********************************************** -ConnectionDescriptor::SetCommInactivityTimeout -**********************************************/) - -pre_type(int) ident(ConnectionDescriptor)operator(::)ident(SetCommInactivityTimeout) operator(()pre_type(int) operator(*)ident(value)operator(\)) -operator({) - pre_type(int) ident(out) operator(=) integer(0)operator(;) - - reserved(if) operator(()ident(value)operator(\)) operator({) - reserved(if) operator(((*)ident(value)operator(==)integer(0)operator(\)) operator(||) operator((*)ident(value) operator(>=) integer(2)operator(\)\)) operator({) - comment(// Replace the value and send the old one back to the caller.) - pre_type(int) ident(v) operator(=) operator(*)ident(value)operator(;) - operator(*)ident(value) operator(=) ident(InactivityTimeout)operator(;) - ident(InactivityTimeout) operator(=) ident(v)operator(;) - ident(out) operator(=) integer(1)operator(;) - operator(}) - reserved(else) operator({) - comment(// TODO, extended logging, got bad value.) - operator(}) - operator(}) - reserved(else) operator({) - comment(// TODO, extended logging, got bad parameter.) - operator(}) - - reserved(return) ident(out)operator(;) -operator(}) - -comment(/******************************* -DatagramDescriptor::GetPeername -*******************************/) - -pre_type(bool) ident(DatagramDescriptor)operator(::)ident(GetPeername) operator(()reserved(struct) ident(sockaddr) operator(*)ident(s)operator(\)) -operator({) - pre_type(bool) ident(ok) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(s)operator(\)) operator({) - ident(memset) operator(()ident(s)operator(,) integer(0)operator(,) reserved(sizeof)operator(()reserved(struct) ident(sockaddr)operator(\)\);) - ident(memcpy) operator(()ident(s)operator(,) operator(&)ident(ReturnAddress)operator(,) reserved(sizeof)operator(()ident(ReturnAddress)operator(\)\);) - ident(ok) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(return) ident(ok)operator(;) -operator(}) - -comment(/******************************* -DatagramDescriptor::GetSockname -*******************************/) - -pre_type(bool) ident(DatagramDescriptor)operator(::)ident(GetSockname) operator(()reserved(struct) ident(sockaddr) operator(*)ident(s)operator(\)) -operator({) - pre_type(bool) ident(ok) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(s)operator(\)) operator({) - ident(socklen_t) ident(len) operator(=) reserved(sizeof)operator((*)ident(s)operator(\);) - pre_type(int) ident(gp) operator(=) ident(getsockname) operator(()ident(GetSocket)operator((\),) ident(s)operator(,) operator(&)ident(len)operator(\);) - reserved(if) operator(()ident(gp) operator(==) integer(0)operator(\)) - ident(ok) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(return) ident(ok)operator(;) -operator(}) - - - -comment(/******************************************** -DatagramDescriptor::GetCommInactivityTimeout -********************************************/) - -pre_type(int) ident(DatagramDescriptor)operator(::)ident(GetCommInactivityTimeout) operator(()pre_type(int) operator(*)ident(value)operator(\)) -operator({) - reserved(if) operator(()ident(value)operator(\)) operator({) - operator(*)ident(value) operator(=) ident(InactivityTimeout)operator(;) - reserved(return) integer(1)operator(;) - operator(}) - reserved(else) operator({) - comment(// TODO, extended logging, got bad parameter.) - reserved(return) integer(0)operator(;) - operator(}) -operator(}) - -comment(/******************************************** -DatagramDescriptor::SetCommInactivityTimeout -********************************************/) - -pre_type(int) ident(DatagramDescriptor)operator(::)ident(SetCommInactivityTimeout) operator(()pre_type(int) operator(*)ident(value)operator(\)) -operator({) - pre_type(int) ident(out) operator(=) integer(0)operator(;) - - reserved(if) operator(()ident(value)operator(\)) operator({) - reserved(if) operator(((*)ident(value)operator(==)integer(0)operator(\)) operator(||) operator((*)ident(value) operator(>=) integer(2)operator(\)\)) operator({) - comment(// Replace the value and send the old one back to the caller.) - pre_type(int) ident(v) operator(=) operator(*)ident(value)operator(;) - operator(*)ident(value) operator(=) ident(InactivityTimeout)operator(;) - ident(InactivityTimeout) operator(=) ident(v)operator(;) - ident(out) operator(=) integer(1)operator(;) - operator(}) - reserved(else) operator({) - comment(// TODO, extended logging, got bad value.) - operator(}) - operator(}) - reserved(else) operator({) - comment(// TODO, extended logging, got bad parameter.) - operator(}) - - reserved(return) ident(out)operator(;) -operator(}) - -comment(/***************************************************************************** - -$Id$ - -File: em.cpp -Date: 06Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -comment(// THIS ENTIRE FILE WILL EVENTUALLY BE FOR UNIX BUILDS ONLY.) -comment(//#ifdef OS_UNIX) - - -preprocessor(#include) include("project.h") - -comment(// Keep a global variable floating around) -comment(// with the current loop time as set by the Event Machine.) -comment(// This avoids the need for frequent expensive calls to time(NULL\);) -ident(time_t) ident(gCurrentLoopTime)operator(;) - -preprocessor(#ifdef) ident(OS_WIN32) -pre_type(unsigned) ident(gTickCountTickover)operator(;) -pre_type(unsigned) ident(gLastTickCount)operator(;) -preprocessor(#endif) - - -comment(/* The numer of max outstanding timers was once a const enum defined in em.h. - * Now we define it here so that users can change its value if necessary. - */) -directive(static) pre_type(int) ident(MaxOutstandingTimers) operator(=) integer(1000)operator(;) - - -comment(/* Internal helper to convert strings to internet addresses. IPv6-aware. - * Not reentrant or threadsafe, optimized for speed. - */) -directive(static) reserved(struct) ident(sockaddr) operator(*)ident(name2address) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(,) pre_type(int) operator(*)ident(family)operator(,) pre_type(int) operator(*)ident(bind_size)operator(\);) - - -comment(/*************************************** -STATIC EventMachine_t::SetMaxTimerCount -***************************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(SetMaxTimerCount) operator(()pre_type(int) ident(count)operator(\)) -operator({) - comment(/* Allow a user to increase the maximum number of outstanding timers. - * If this gets "too high" (a metric that is of course platform dependent\), - * bad things will happen like performance problems and possible overuse - * of memory. - * The actual timer mechanism is very efficient so it's hard to know what - * the practical max, but 100,000 shouldn't be too problematical. - */) - reserved(if) operator(()ident(count) operator(<) integer(100)operator(\)) - ident(count) operator(=) integer(100)operator(;) - ident(MaxOutstandingTimers) operator(=) ident(count)operator(;) -operator(}) - - - -comment(/****************************** -EventMachine_t::EventMachine_t -******************************/) - -ident(EventMachine_t)operator(::)ident(EventMachine_t) operator(()directive(void) operator((*)ident(event_callback)operator(\)()directive(const) pre_type(char)operator(*,) pre_type(int)operator(,) directive(const) pre_type(char)operator(*,) pre_type(int)operator(\)\):) - ident(EventCallback) operator(()ident(event_callback)operator(\),) - ident(NextHeartbeatTime) operator(()integer(0)operator(\),) - ident(LoopBreakerReader) operator((-)integer(1)operator(\),) - ident(LoopBreakerWriter) operator((-)integer(1)operator(\),) - ident(bEpoll) operator(()pre_constant(false)operator(\),) - ident(bKqueue) operator(()pre_constant(false)operator(\),) - ident(epfd) operator((-)integer(1)operator(\)) -operator({) - comment(// Default time-slice is just smaller than one hundred mills.) - ident(Quantum)operator(.)ident(tv_sec) operator(=) integer(0)operator(;) - ident(Quantum)operator(.)ident(tv_usec) operator(=) integer(90000)operator(;) - - ident(gTerminateSignalReceived) operator(=) pre_constant(false)operator(;) - comment(// Make sure the current loop time is sane, in case we do any initializations of) - comment(// objects before we start running.) - ident(gCurrentLoopTime) operator(=) ident(time)operator(()pre_constant(NULL)operator(\);) - - comment(/* We initialize the network library here (only on Windows of course\) - * and initialize "loop breakers." Our destructor also does some network-level - * cleanup. There's thus an implicit assumption that any given instance of EventMachine_t - * will only call ::Run once. Is that a good assumption? Should we move some of these - * inits and de-inits into ::Run? - */) - preprocessor(#ifdef) ident(OS_WIN32) - ident(WSADATA) ident(w)operator(;) - ident(WSAStartup) operator(()ident(MAKEWORD) operator(()integer(1)operator(,) integer(1)operator(\),) operator(&)ident(w)operator(\);) - preprocessor(#endif) - - ident(_InitializeLoopBreaker)operator((\);) -operator(}) - - -comment(/******************************* -EventMachine_t::~EventMachine_t -*******************************/) - -ident(EventMachine_t)operator(::~)ident(EventMachine_t)operator((\)) -operator({) - comment(// Run down descriptors) - ident(size_t) ident(i)operator(;) - reserved(for) operator(()ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) ident(NewDescriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) - reserved(delete) ident(NewDescriptors)operator([)ident(i)operator(];) - reserved(for) operator(()ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) - reserved(delete) ident(Descriptors)operator([)ident(i)operator(];) - - ident(close) operator(()ident(LoopBreakerReader)operator(\);) - ident(close) operator(()ident(LoopBreakerWriter)operator(\);) - - reserved(if) operator(()ident(epfd) operator(!=) operator(-)integer(1)operator(\)) - ident(close) operator(()ident(epfd)operator(\);) - reserved(if) operator(()ident(kqfd) operator(!=) operator(-)integer(1)operator(\)) - ident(close) operator(()ident(kqfd)operator(\);) -operator(}) - - -comment(/************************* -EventMachine_t::_UseEpoll -*************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_UseEpoll)operator((\)) -operator({) - comment(/* Temporary. - * Use an internal flag to switch in epoll-based functionality until we determine - * how it should be integrated properly and the extent of the required changes. - * A permanent solution needs to allow the integration of additional technologies, - * like kqueue and Solaris's events. - */) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(bEpoll) operator(=) pre_constant(true)operator(;) - preprocessor(#endif) -operator(}) - -comment(/************************** -EventMachine_t::_UseKqueue -**************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_UseKqueue)operator((\)) -operator({) - comment(/* Temporary. - * See comments under _UseEpoll. - */) - - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(bKqueue) operator(=) pre_constant(true)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/**************************** -EventMachine_t::ScheduleHalt -****************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(ScheduleHalt)operator((\)) -operator({) - comment(/* This is how we stop the machine. - * This can be called by clients. Signal handlers will probably - * set the global flag. - * For now this means there can only be one EventMachine ever running at a time. - * - * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here, - * because it may be called from signal handlers invoked from code that we don't - * control. At this writing (20Sep06\), EM does NOT install any signal handlers of - * its own. - * - * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens? - * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler. - */) - ident(gTerminateSignalReceived) operator(=) pre_constant(true)operator(;) -operator(}) - - - -comment(/******************************* -EventMachine_t::SetTimerQuantum -*******************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(SetTimerQuantum) operator(()pre_type(int) ident(interval)operator(\)) -operator({) - comment(/* We get a timer-quantum expressed in milliseconds. - * Don't set a quantum smaller than 5 or larger than 2500. - */) - - reserved(if) operator((()ident(interval) operator(<) integer(5)operator(\)) operator(||) operator(()ident(interval) operator(>) integer(2500)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(invalid timer-quantum)delimiter(")>operator(\);) - - ident(Quantum)operator(.)ident(tv_sec) operator(=) ident(interval) operator(/) integer(1000)operator(;) - ident(Quantum)operator(.)ident(tv_usec) operator(=) operator(()ident(interval) operator(%) integer(1000)operator(\)) operator(*) integer(1000)operator(;) -operator(}) - - -comment(/************************************* -(STATIC\) EventMachine_t::SetuidString -*************************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(SetuidString) operator(()directive(const) pre_type(char) operator(*)ident(username)operator(\)) -operator({) - comment(/* This method takes a caller-supplied username and tries to setuid - * to that user. There is no meaningful implementation (and no error\) - * on Windows. On Unix, a failure to setuid the caller-supplied string - * causes a fatal abort, because presumably the program is calling here - * in order to fulfill a security requirement. If we fail silently, - * the user may continue to run with too much privilege. - * - * TODO, we need to decide on and document a way of generating C++ level errors - * that can be wrapped in documented Ruby exceptions, so users can catch - * and handle them. And distinguish it from errors that we WON'T let the Ruby - * user catch (like security-violations and resource-overallocation\). - * A setuid failure here would be in the latter category. - */) - - preprocessor(#ifdef) ident(OS_UNIX) - reserved(if) operator((!)ident(username) operator(||) operator(!*)ident(username)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(setuid_string failed: no username specified)delimiter(")>operator(\);) - - reserved(struct) ident(passwd) operator(*)ident(p) operator(=) ident(getpwnam) operator(()ident(username)operator(\);) - reserved(if) operator((!)ident(p)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(setuid_string failed: unknown username)delimiter(")>operator(\);) - - reserved(if) operator(()ident(setuid) operator(()ident(p)operator(->)ident(pw_uid)operator(\)) operator(!=) integer(0)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(setuid_string failed: no setuid)delimiter(")>operator(\);) - - comment(// Success.) - preprocessor(#endif) -operator(}) - - -comment(/**************************************** -(STATIC\) EventMachine_t::SetRlimitNofile -****************************************/) - -pre_type(int) ident(EventMachine_t)operator(::)ident(SetRlimitNofile) operator(()pre_type(int) ident(nofiles)operator(\)) -operator({) - preprocessor(#ifdef) ident(OS_UNIX) - reserved(struct) ident(rlimit) ident(rlim)operator(;) - ident(getrlimit) operator(()ident(RLIMIT_NOFILE)operator(,) operator(&)ident(rlim)operator(\);) - reserved(if) operator(()ident(nofiles) operator(>=) integer(0)operator(\)) operator({) - ident(rlim)operator(.)ident(rlim_cur) operator(=) ident(nofiles)operator(;) - reserved(if) operator(()ident(nofiles) operator(>) ident(rlim)operator(.)ident(rlim_max)operator(\)) - ident(rlim)operator(.)ident(rlim_max) operator(=) ident(nofiles)operator(;) - ident(setrlimit) operator(()ident(RLIMIT_NOFILE)operator(,) operator(&)ident(rlim)operator(\);) - comment(// ignore the error return, for now at least.) - comment(// TODO, emit an error message someday when we have proper debug levels.) - operator(}) - ident(getrlimit) operator(()ident(RLIMIT_NOFILE)operator(,) operator(&)ident(rlim)operator(\);) - reserved(return) ident(rlim)operator(.)ident(rlim_cur)operator(;) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - comment(// No meaningful implementation on Windows.) - reserved(return) integer(0)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/********************************* -EventMachine_t::SignalLoopBreaker -*********************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(SignalLoopBreaker)operator((\)) -operator({) - preprocessor(#ifdef) ident(OS_UNIX) - ident(write) operator(()ident(LoopBreakerWriter)operator(,) string<delimiter(")delimiter(")>operator(,) integer(1)operator(\);) - preprocessor(#endif) - preprocessor(#ifdef) ident(OS_WIN32) - ident(sendto) operator(()ident(LoopBreakerReader)operator(,) string<delimiter(")delimiter(")>operator(,) integer(0)operator(,) integer(0)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&()ident(LoopBreakerTarget)operator(\),) reserved(sizeof)operator(()ident(LoopBreakerTarget)operator(\)\);) - preprocessor(#endif) -operator(}) - - -comment(/************************************** -EventMachine_t::_InitializeLoopBreaker -**************************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_InitializeLoopBreaker)operator((\)) -operator({) - comment(/* A "loop-breaker" is a socket-descriptor that we can write to in order - * to break the main select loop. Primarily useful for things running on - * threads other than the main EM thread, so they can trigger processing - * of events that arise exogenously to the EM. - * Keep the loop-breaker pipe out of the main descriptor set, otherwise - * its events will get passed on to user code. - */) - - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(fd)operator([)integer(2)operator(];) - reserved(if) operator(()ident(pipe) operator(()ident(fd)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no loop breaker)delimiter(")>operator(\);) - - ident(LoopBreakerWriter) operator(=) ident(fd)operator([)integer(1)operator(];) - ident(LoopBreakerReader) operator(=) ident(fd)operator([)integer(0)operator(];) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - pre_type(int) ident(sd) operator(=) ident(socket) operator(()ident(AF_INET)operator(,) ident(SOCK_DGRAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no loop breaker socket)delimiter(")>operator(\);) - ident(SetSocketNonblocking) operator(()ident(sd)operator(\);) - - ident(memset) operator((&)ident(LoopBreakerTarget)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(LoopBreakerTarget)operator(\)\);) - ident(LoopBreakerTarget)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(LoopBreakerTarget)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(inet_addr) operator(()string<delimiter(")content(127.0.0.1)delimiter(")>operator(\);) - - ident(srand) operator((()pre_type(int)operator(\))ident(time)operator(()pre_constant(NULL)operator(\)\);) - pre_type(int) ident(i)operator(;) - reserved(for) operator(()ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) integer(100)operator(;) ident(i)operator(++\)) operator({) - pre_type(int) ident(r) operator(=) operator(()ident(rand)operator((\)) operator(%) integer(10000)operator(\)) operator(+) integer(20000)operator(;) - ident(LoopBreakerTarget)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(r)operator(\);) - reserved(if) operator(()ident(bind) operator(()ident(sd)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(LoopBreakerTarget)operator(,) reserved(sizeof)operator(()ident(LoopBreakerTarget)operator(\)\)) operator(==) integer(0)operator(\)) - reserved(break)operator(;) - operator(}) - - reserved(if) operator(()ident(i) operator(==) integer(100)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no loop breaker)delimiter(")>operator(\);) - ident(LoopBreakerReader) operator(=) ident(sd)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/******************* -EventMachine_t::Run -*******************/) - -directive(void) ident(EventMachine_t)operator(::)ident(Run)operator((\)) -operator({) - preprocessor(#ifdef) ident(OS_WIN32) - ident(HookControlC) operator(()pre_constant(true)operator(\);) - preprocessor(#endif) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - reserved(if) operator(()ident(bEpoll)operator(\)) operator({) - ident(epfd) operator(=) ident(epoll_create) operator(()ident(MaxEpollDescriptors)operator(\);) - reserved(if) operator(()ident(epfd) operator(==) operator(-)integer(1)operator(\)) operator({) - pre_type(char) ident(buf)operator([)integer(200)operator(];) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(unable to create epoll descriptor: %s)delimiter(")>operator(,) ident(strerror)operator(()ident(errno)operator(\)\);) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(buf)operator(\);) - operator(}) - pre_type(int) ident(cloexec) operator(=) ident(fcntl) operator(()ident(epfd)operator(,) ident(F_GETFD)operator(,) integer(0)operator(\);) - ident(assert) operator(()ident(cloexec) operator(>=) integer(0)operator(\);) - ident(cloexec) operator(|=) ident(FD_CLOEXEC)operator(;) - ident(fcntl) operator(()ident(epfd)operator(,) ident(F_SETFD)operator(,) ident(cloexec)operator(\);) - - ident(assert) operator(()ident(LoopBreakerReader) operator(>=) integer(0)operator(\);) - ident(LoopbreakDescriptor) operator(*)ident(ld) operator(=) reserved(new) ident(LoopbreakDescriptor) operator(()ident(LoopBreakerReader)operator(,) local_variable(this)operator(\);) - ident(assert) operator(()ident(ld)operator(\);) - ident(Add) operator(()ident(ld)operator(\);) - operator(}) - preprocessor(#endif) - - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(if) operator(()ident(bKqueue)operator(\)) operator({) - ident(kqfd) operator(=) ident(kqueue)operator((\);) - reserved(if) operator(()ident(kqfd) operator(==) operator(-)integer(1)operator(\)) operator({) - pre_type(char) ident(buf)operator([)integer(200)operator(];) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(unable to create kqueue descriptor: %s)delimiter(")>operator(,) ident(strerror)operator(()ident(errno)operator(\)\);) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(buf)operator(\);) - operator(}) - comment(// cloexec not needed. By definition, kqueues are not carried across forks.) - - ident(assert) operator(()ident(LoopBreakerReader) operator(>=) integer(0)operator(\);) - ident(LoopbreakDescriptor) operator(*)ident(ld) operator(=) reserved(new) ident(LoopbreakDescriptor) operator(()ident(LoopBreakerReader)operator(,) local_variable(this)operator(\);) - ident(assert) operator(()ident(ld)operator(\);) - ident(Add) operator(()ident(ld)operator(\);) - operator(}) - preprocessor(#endif) - - reserved(while) operator(()pre_constant(true)operator(\)) operator({) - ident(gCurrentLoopTime) operator(=) ident(time)operator(()pre_constant(NULL)operator(\);) - reserved(if) operator((!)ident(_RunTimers)operator((\)\)) - reserved(break)operator(;) - - comment(/* _Add must precede _Modify because the same descriptor might - * be on both lists during the same pass through the machine, - * and to modify a descriptor before adding it would fail. - */) - ident(_AddNewDescriptors)operator((\);) - ident(_ModifyDescriptors)operator((\);) - - reserved(if) operator((!)ident(_RunOnce)operator((\)\)) - reserved(break)operator(;) - reserved(if) operator(()ident(gTerminateSignalReceived)operator(\)) - reserved(break)operator(;) - operator(}) - - preprocessor(#ifdef) ident(OS_WIN32) - ident(HookControlC) operator(()pre_constant(false)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/************************ -EventMachine_t::_RunOnce -************************/) - -pre_type(bool) ident(EventMachine_t)operator(::)ident(_RunOnce)operator((\)) -operator({) - reserved(if) operator(()ident(bEpoll)operator(\)) - reserved(return) ident(_RunEpollOnce)operator((\);) - reserved(else) reserved(if) operator(()ident(bKqueue)operator(\)) - reserved(return) ident(_RunKqueueOnce)operator((\);) - reserved(else) - reserved(return) ident(_RunSelectOnce)operator((\);) -operator(}) - - - -comment(/***************************** -EventMachine_t::_RunEpollOnce -*****************************/) - -pre_type(bool) ident(EventMachine_t)operator(::)ident(_RunEpollOnce)operator((\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(assert) operator(()ident(epfd) operator(!=) operator(-)integer(1)operator(\);) - reserved(struct) ident(epoll_event) ident(ev) operator([)ident(MaxEpollDescriptors)operator(];) - pre_type(int) ident(s)operator(;) - - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(TRAP_BEG)operator(;) - preprocessor(#endif) - ident(s) operator(=) ident(epoll_wait) operator(()ident(epfd)operator(,) ident(ev)operator(,) ident(MaxEpollDescriptors)operator(,) integer(50)operator(\);) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(TRAP_END)operator(;) - preprocessor(#endif) - - reserved(if) operator(()ident(s) operator(>) integer(0)operator(\)) operator({) - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(s)operator(;) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) operator(()ident(EventableDescriptor)operator(*\)) ident(ev)operator([)ident(i)operator(])operator(.)ident(data)operator(.)ident(ptr)operator(;) - - reserved(if) operator(()ident(ev)operator([)ident(i)operator(])operator(.)ident(events) operator(&) operator(()ident(EPOLLERR) operator(|) ident(EPOLLHUP)operator(\)\)) - ident(ed)operator(->)ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - reserved(if) operator(()ident(ev)operator([)ident(i)operator(])operator(.)ident(events) operator(&) ident(EPOLLIN)operator(\)) - ident(ed)operator(->)ident(Read)operator((\);) - reserved(if) operator(()ident(ev)operator([)ident(i)operator(])operator(.)ident(events) operator(&) ident(EPOLLOUT)operator(\)) operator({) - ident(ed)operator(->)ident(Write)operator((\);) - ident(epoll_ctl) operator(()ident(epfd)operator(,) ident(EPOLL_CTL_MOD)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(ed)operator(->)ident(GetEpollEvent)operator((\)\);) - comment(// Ignoring return value) - operator(}) - operator(}) - operator(}) - reserved(else) reserved(if) operator(()ident(s) operator(<) integer(0)operator(\)) operator({) - comment(// epoll_wait can fail on error in a handful of ways.) - comment(// If this happens, then wait for a little while to avoid busy-looping.) - comment(// If the error was EINTR, we probably caught SIGCHLD or something,) - comment(// so keep the wait short.) - ident(timeval) ident(tv) operator(=) operator({)integer(0)operator(,) operator((()ident(errno) operator(==) ident(EINTR)operator(\)) operator(?) integer(5) operator(:) integer(50)operator(\)) operator(*) integer(1000)operator(};) - ident(EmSelect) operator(()integer(0)operator(,) pre_constant(NULL)operator(,) pre_constant(NULL)operator(,) pre_constant(NULL)operator(,) operator(&)ident(tv)operator(\);) - operator(}) - - operator({) comment(// cleanup dying sockets) - comment(// vector::pop_back works in constant time.) - comment(// TODO, rip this out and only delete the descriptors we know have died,) - comment(// rather than traversing the whole list.) - comment(// Modified 05Jan08 per suggestions by Chris Heath. It's possible that) - comment(// an EventableDescriptor will have a descriptor value of -1. That will) - comment(// happen if EventableDescriptor::Close was called on it. In that case,) - comment(// don't call epoll_ctl to remove the socket's filters from the epoll set.) - comment(// According to the epoll docs, this happens automatically when the) - comment(// descriptor is closed anyway. This is different from the case where) - comment(// the socket has already been closed but the descriptor in the ED object) - comment(// hasn't yet been set to INVALID_SOCKET.) - pre_type(int) ident(i)operator(,) ident(j)operator(;) - pre_type(int) ident(nSockets) operator(=) ident(Descriptors)operator(.)ident(size)operator((\);) - reserved(for) operator(()ident(i)operator(=)integer(0)operator(,) ident(j)operator(=)integer(0)operator(;) ident(i) operator(<) ident(nSockets)operator(;) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - reserved(if) operator(()ident(ed)operator(->)ident(ShouldDelete)operator((\)\)) operator({) - reserved(if) operator(()ident(ed)operator(->)ident(GetSocket)operator((\)) operator(!=) ident(INVALID_SOCKET)operator(\)) operator({) - ident(assert) operator(()ident(bEpoll)operator(\);) comment(// wouldn't be in this method otherwise.) - ident(assert) operator(()ident(epfd) operator(!=) operator(-)integer(1)operator(\);) - pre_type(int) ident(e) operator(=) ident(epoll_ctl) operator(()ident(epfd)operator(,) ident(EPOLL_CTL_DEL)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(ed)operator(->)ident(GetEpollEvent)operator((\)\);) - comment(// ENOENT or EBADF are not errors because the socket may be already closed when we get here.) - reserved(if) operator(()ident(e) operator(&&) operator(()ident(errno) operator(!=) ident(ENOENT)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(EBADF)operator(\)\)) operator({) - pre_type(char) ident(buf) operator([)integer(200)operator(];) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(unable to delete epoll event: %s)delimiter(")>operator(,) ident(strerror)operator(()ident(errno)operator(\)\);) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(buf)operator(\);) - operator(}) - operator(}) - - ident(ModifiedDescriptors)operator(.)ident(erase) operator(()ident(ed)operator(\);) - reserved(delete) ident(ed)operator(;) - operator(}) - reserved(else) - ident(Descriptors) operator([)ident(j)operator(++]) operator(=) ident(ed)operator(;) - operator(}) - reserved(while) operator((()ident(size_t)operator(\))ident(j) operator(<) ident(Descriptors)operator(.)ident(size)operator((\)\)) - ident(Descriptors)operator(.)ident(pop_back)operator((\);) - - operator(}) - - comment(// TODO, heartbeats.) - comment(// Added 14Sep07, its absence was noted by Brian Candler. But the comment was here, indicated) - comment(// that this got thought about and not done when EPOLL was originally written. Was there a reason) - comment(// not to do it, or was it an oversight? Certainly, running a heartbeat on 50,000 connections every) - comment(// two seconds can get to be a real bear, especially if all we're doing is timing out dead ones.) - comment(// Maybe there's a better way to do this. (Or maybe it's not that expensive after all.\)) - comment(//) - operator({) comment(// dispatch heartbeats) - reserved(if) operator(()ident(gCurrentLoopTime) operator(>=) ident(NextHeartbeatTime)operator(\)) operator({) - ident(NextHeartbeatTime) operator(=) ident(gCurrentLoopTime) operator(+) ident(HeartbeatInterval)operator(;) - - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - ident(ed)operator(->)ident(Heartbeat)operator((\);) - operator(}) - operator(}) - operator(}) - - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - reserved(if) operator((!)ident(rb_thread_alone)operator((\)\)) operator({) - ident(rb_thread_schedule)operator((\);) - operator(}) - preprocessor(#endif) - - reserved(return) pre_constant(true)operator(;) - preprocessor(#else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(epoll is not implemented on this platform)delimiter(")>operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/****************************** -EventMachine_t::_RunKqueueOnce -******************************/) - -pre_type(bool) ident(EventMachine_t)operator(::)ident(_RunKqueueOnce)operator((\)) -operator({) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(assert) operator(()ident(kqfd) operator(!=) operator(-)integer(1)operator(\);) - directive(const) pre_type(int) ident(maxKevents) operator(=) integer(2000)operator(;) - reserved(struct) ident(kevent) ident(Karray) operator([)ident(maxKevents)operator(];) - reserved(struct) ident(timespec) ident(ts) operator(=) operator({)integer(0)operator(,) integer(10000000)operator(};) comment(// Too frequent. Use blocking_region) - - pre_type(int) ident(k)operator(;) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(TRAP_BEG)operator(;) - preprocessor(#endif) - ident(k) operator(=) ident(kevent) operator(()ident(kqfd)operator(,) pre_constant(NULL)operator(,) integer(0)operator(,) ident(Karray)operator(,) ident(maxKevents)operator(,) operator(&)ident(ts)operator(\);) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - ident(TRAP_END)operator(;) - preprocessor(#endif) - reserved(struct) ident(kevent) operator(*)ident(ke) operator(=) ident(Karray)operator(;) - reserved(while) operator(()ident(k) operator(>) integer(0)operator(\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) operator(()ident(EventableDescriptor)operator(*\)) operator(()ident(ke)operator(->)ident(udata)operator(\);) - ident(assert) operator(()ident(ed)operator(\);) - - reserved(if) operator(()ident(ke)operator(->)ident(filter) operator(==) ident(EVFILT_READ)operator(\)) - ident(ed)operator(->)ident(Read)operator((\);) - reserved(else) reserved(if) operator(()ident(ke)operator(->)ident(filter) operator(==) ident(EVFILT_WRITE)operator(\)) - ident(ed)operator(->)ident(Write)operator((\);) - reserved(else) - ident(cerr) operator(<<) string<delimiter(")content(Discarding unknown kqueue event )delimiter(")> operator(<<) ident(ke)operator(->)ident(filter) operator(<<) ident(endl)operator(;) - - operator(--)ident(k)operator(;) - operator(++)ident(ke)operator(;) - operator(}) - - operator({) comment(// cleanup dying sockets) - comment(// vector::pop_back works in constant time.) - comment(// TODO, rip this out and only delete the descriptors we know have died,) - comment(// rather than traversing the whole list.) - comment(// In kqueue, closing a descriptor automatically removes its event filters.) - - pre_type(int) ident(i)operator(,) ident(j)operator(;) - pre_type(int) ident(nSockets) operator(=) ident(Descriptors)operator(.)ident(size)operator((\);) - reserved(for) operator(()ident(i)operator(=)integer(0)operator(,) ident(j)operator(=)integer(0)operator(;) ident(i) operator(<) ident(nSockets)operator(;) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - reserved(if) operator(()ident(ed)operator(->)ident(ShouldDelete)operator((\)\)) operator({) - ident(ModifiedDescriptors)operator(.)ident(erase) operator(()ident(ed)operator(\);) - reserved(delete) ident(ed)operator(;) - operator(}) - reserved(else) - ident(Descriptors) operator([)ident(j)operator(++]) operator(=) ident(ed)operator(;) - operator(}) - reserved(while) operator((()ident(size_t)operator(\))ident(j) operator(<) ident(Descriptors)operator(.)ident(size)operator((\)\)) - ident(Descriptors)operator(.)ident(pop_back)operator((\);) - - operator(}) - - operator({) comment(// dispatch heartbeats) - reserved(if) operator(()ident(gCurrentLoopTime) operator(>=) ident(NextHeartbeatTime)operator(\)) operator({) - ident(NextHeartbeatTime) operator(=) ident(gCurrentLoopTime) operator(+) ident(HeartbeatInterval)operator(;) - - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - ident(ed)operator(->)ident(Heartbeat)operator((\);) - operator(}) - operator(}) - operator(}) - - - comment(// TODO, replace this with rb_thread_blocking_region for 1.9 builds.) - preprocessor(#ifdef) ident(BUILD_FOR_RUBY) - reserved(if) operator((!)ident(rb_thread_alone)operator((\)\)) operator({) - ident(rb_thread_schedule)operator((\);) - operator(}) - preprocessor(#endif) - - reserved(return) pre_constant(true)operator(;) - preprocessor(#else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(kqueue is not implemented on this platform)delimiter(")>operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/********************************* -EventMachine_t::_ModifyEpollEvent -*********************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_ModifyEpollEvent) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - reserved(if) operator(()ident(bEpoll)operator(\)) operator({) - ident(assert) operator(()ident(epfd) operator(!=) operator(-)integer(1)operator(\);) - ident(assert) operator(()ident(ed)operator(\);) - pre_type(int) ident(e) operator(=) ident(epoll_ctl) operator(()ident(epfd)operator(,) ident(EPOLL_CTL_MOD)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(ed)operator(->)ident(GetEpollEvent)operator((\)\);) - reserved(if) operator(()ident(e)operator(\)) operator({) - pre_type(char) ident(buf) operator([)integer(200)operator(];) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(unable to modify epoll event: %s)delimiter(")>operator(,) ident(strerror)operator(()ident(errno)operator(\)\);) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(buf)operator(\);) - operator(}) - operator(}) - preprocessor(#endif) -operator(}) - - - -comment(/************************** -SelectData_t::SelectData_t -**************************/) - -ident(SelectData_t)operator(::)ident(SelectData_t)operator((\)) -operator({) - ident(maxsocket) operator(=) integer(0)operator(;) - ident(FD_ZERO) operator((&)ident(fdreads)operator(\);) - ident(FD_ZERO) operator((&)ident(fdwrites)operator(\);) -operator(}) - - -preprocessor(#ifdef) ident(BUILD_FOR_RUBY) -comment(/***************** -_SelectDataSelect -*****************/) - -preprocessor(#ifdef) ident(HAVE_TBR) -directive(static) ident(VALUE) ident(_SelectDataSelect) operator(()directive(void) operator(*)ident(v)operator(\)) -operator({) - ident(SelectData_t) operator(*)ident(sd) operator(=) operator(()ident(SelectData_t)operator(*\))ident(v)operator(;) - ident(sd)operator(->)ident(nSockets) operator(=) ident(select) operator(()ident(sd)operator(->)ident(maxsocket)operator(+)integer(1)operator(,) operator(&()ident(sd)operator(->)ident(fdreads)operator(\),) operator(&()ident(sd)operator(->)ident(fdwrites)operator(\),) pre_constant(NULL)operator(,) operator(&()ident(sd)operator(->)ident(tv)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) -preprocessor(#endif) - -comment(/********************* -SelectData_t::_Select -*********************/) - -pre_type(int) ident(SelectData_t)operator(::)ident(_Select)operator((\)) -operator({) - preprocessor(#ifdef) ident(HAVE_TBR) - ident(rb_thread_blocking_region) operator(()ident(_SelectDataSelect)operator(,) operator(()directive(void)operator(*\))local_variable(this)operator(,) ident(RUBY_UBF_IO)operator(,) integer(0)operator(\);) - reserved(return) ident(nSockets)operator(;) - preprocessor(#endif) - - preprocessor(#ifndef) ident(HAVE_TBR) - reserved(return) ident(EmSelect) operator(()ident(maxsocket)operator(+)integer(1)operator(,) operator(&)ident(fdreads)operator(,) operator(&)ident(fdwrites)operator(,) pre_constant(NULL)operator(,) operator(&)ident(tv)operator(\);) - preprocessor(#endif) -operator(}) -preprocessor(#endif) - - - -comment(/****************************** -EventMachine_t::_RunSelectOnce -******************************/) - -pre_type(bool) ident(EventMachine_t)operator(::)ident(_RunSelectOnce)operator((\)) -operator({) - comment(// Crank the event machine once.) - comment(// If there are no descriptors to process, then sleep) - comment(// for a few hundred mills to avoid busy-looping.) - comment(// Return T/F to indicate whether we should continue.) - comment(// This is based on a select loop. Alternately provide epoll) - comment(// if we know we're running on a 2.6 kernel.) - comment(// epoll will be effective if we provide it as an alternative,) - comment(// however it has the same problem interoperating with Ruby) - comment(// threads that select does.) - - comment(//cerr << "X";) - - comment(/* This protection is now obsolete, because we will ALWAYS - * have at least one descriptor (the loop-breaker\) to read. - */) - comment(/* - if (Descriptors.size(\) == 0\) { - #ifdef OS_UNIX - timeval tv = {0, 200 * 1000}; - EmSelect (0, NULL, NULL, NULL, &tv\); - return true; - #endif - #ifdef OS_WIN32 - Sleep (200\); - return true; - #endif - } - */) - - ident(SelectData_t) ident(SelectData)operator(;) - comment(/* - fd_set fdreads, fdwrites; - FD_ZERO (&fdreads\); - FD_ZERO (&fdwrites\); - - int maxsocket = 0; - */) - - comment(// Always read the loop-breaker reader.) - comment(// Changed 23Aug06, provisionally implemented for Windows with a UDP socket) - comment(// running on localhost with a randomly-chosen port. (*Puke*\)) - comment(// Windows has a version of the Unix pipe(\) library function, but it doesn't) - comment(// give you back descriptors that are selectable.) - ident(FD_SET) operator(()ident(LoopBreakerReader)operator(,) operator(&()ident(SelectData)operator(.)ident(fdreads)operator(\)\);) - reserved(if) operator(()ident(SelectData)operator(.)ident(maxsocket) operator(<) ident(LoopBreakerReader)operator(\)) - ident(SelectData)operator(.)ident(maxsocket) operator(=) ident(LoopBreakerReader)operator(;) - - comment(// prepare the sockets for reading and writing) - ident(size_t) ident(i)operator(;) - reserved(for) operator(()ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - pre_type(int) ident(sd) operator(=) ident(ed)operator(->)ident(GetSocket)operator((\);) - ident(assert) operator(()ident(sd) operator(!=) ident(INVALID_SOCKET)operator(\);) - - reserved(if) operator(()ident(ed)operator(->)ident(SelectForRead)operator((\)\)) - ident(FD_SET) operator(()ident(sd)operator(,) operator(&()ident(SelectData)operator(.)ident(fdreads)operator(\)\);) - reserved(if) operator(()ident(ed)operator(->)ident(SelectForWrite)operator((\)\)) - ident(FD_SET) operator(()ident(sd)operator(,) operator(&()ident(SelectData)operator(.)ident(fdwrites)operator(\)\);) - - reserved(if) operator(()ident(SelectData)operator(.)ident(maxsocket) operator(<) ident(sd)operator(\)) - ident(SelectData)operator(.)ident(maxsocket) operator(=) ident(sd)operator(;) - operator(}) - - - operator({) comment(// read and write the sockets) - comment(//timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.) - comment(//timeval tv = Quantum;) - ident(SelectData)operator(.)ident(tv) operator(=) ident(Quantum)operator(;) - pre_type(int) ident(s) operator(=) ident(SelectData)operator(.)ident(_Select)operator((\);) - comment(//rb_thread_blocking_region(xxx,(void*\)&SelectData,RUBY_UBF_IO,0\);) - comment(//int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads\), &(SelectData.fdwrites\), NULL, &(SelectData.tv\)\);) - comment(//int s = SelectData.nSockets;) - reserved(if) operator(()ident(s) operator(>) integer(0)operator(\)) operator({) - comment(/* Changed 01Jun07. We used to handle the Loop-breaker right here. - * Now we do it AFTER all the regular descriptors. There's an - * incredibly important and subtle reason for this. Code on - * loop breakers is sometimes used to cause the reactor core to - * cycle (for example, to allow outbound network buffers to drain\). - * If a loop-breaker handler reschedules itself (say, after determining - * that the write buffers are still too full\), then it will execute - * IMMEDIATELY if _ReadLoopBreaker is done here instead of after - * the other descriptors are processed. That defeats the whole purpose. - */) - reserved(for) operator(()ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - pre_type(int) ident(sd) operator(=) ident(ed)operator(->)ident(GetSocket)operator((\);) - ident(assert) operator(()ident(sd) operator(!=) ident(INVALID_SOCKET)operator(\);) - - reserved(if) operator(()ident(FD_ISSET) operator(()ident(sd)operator(,) operator(&()ident(SelectData)operator(.)ident(fdwrites)operator(\)\)\)) - ident(ed)operator(->)ident(Write)operator((\);) - reserved(if) operator(()ident(FD_ISSET) operator(()ident(sd)operator(,) operator(&()ident(SelectData)operator(.)ident(fdreads)operator(\)\)\)) - ident(ed)operator(->)ident(Read)operator((\);) - operator(}) - - reserved(if) operator(()ident(FD_ISSET) operator(()ident(LoopBreakerReader)operator(,) operator(&()ident(SelectData)operator(.)ident(fdreads)operator(\)\)\)) - ident(_ReadLoopBreaker)operator((\);) - operator(}) - reserved(else) reserved(if) operator(()ident(s) operator(<) integer(0)operator(\)) operator({) - comment(// select can fail on error in a handful of ways.) - comment(// If this happens, then wait for a little while to avoid busy-looping.) - comment(// If the error was EINTR, we probably caught SIGCHLD or something,) - comment(// so keep the wait short.) - ident(timeval) ident(tv) operator(=) operator({)integer(0)operator(,) operator((()ident(errno) operator(==) ident(EINTR)operator(\)) operator(?) integer(5) operator(:) integer(50)operator(\)) operator(*) integer(1000)operator(};) - ident(EmSelect) operator(()integer(0)operator(,) pre_constant(NULL)operator(,) pre_constant(NULL)operator(,) pre_constant(NULL)operator(,) operator(&)ident(tv)operator(\);) - operator(}) - operator(}) - - - operator({) comment(// dispatch heartbeats) - reserved(if) operator(()ident(gCurrentLoopTime) operator(>=) ident(NextHeartbeatTime)operator(\)) operator({) - ident(NextHeartbeatTime) operator(=) ident(gCurrentLoopTime) operator(+) ident(HeartbeatInterval)operator(;) - - reserved(for) operator(()ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - ident(ed)operator(->)ident(Heartbeat)operator((\);) - operator(}) - operator(}) - operator(}) - - operator({) comment(// cleanup dying sockets) - comment(// vector::pop_back works in constant time.) - pre_type(int) ident(i)operator(,) ident(j)operator(;) - pre_type(int) ident(nSockets) operator(=) ident(Descriptors)operator(.)ident(size)operator((\);) - reserved(for) operator(()ident(i)operator(=)integer(0)operator(,) ident(j)operator(=)integer(0)operator(;) ident(i) operator(<) ident(nSockets)operator(;) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - reserved(if) operator(()ident(ed)operator(->)ident(ShouldDelete)operator((\)\)) - reserved(delete) ident(ed)operator(;) - reserved(else) - ident(Descriptors) operator([)ident(j)operator(++]) operator(=) ident(ed)operator(;) - operator(}) - reserved(while) operator((()ident(size_t)operator(\))ident(j) operator(<) ident(Descriptors)operator(.)ident(size)operator((\)\)) - ident(Descriptors)operator(.)ident(pop_back)operator((\);) - - operator(}) - - reserved(return) pre_constant(true)operator(;) -operator(}) - - -comment(/******************************** -EventMachine_t::_ReadLoopBreaker -********************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_ReadLoopBreaker)operator((\)) -operator({) - comment(/* The loop breaker has selected readable. - * Read it ONCE (it may block if we try to read it twice\) - * and send a loop-break event back to user code. - */) - pre_type(char) ident(buffer) operator([)integer(1024)operator(];) - ident(read) operator(()ident(LoopBreakerReader)operator(,) ident(buffer)operator(,) reserved(sizeof)operator(()ident(buffer)operator(\)\);) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()string<delimiter(")delimiter(")>operator(,) ident(EM_LOOPBREAK_SIGNAL)operator(,) string<delimiter(")delimiter(")>operator(,) integer(0)operator(\);) -operator(}) - - -comment(/************************** -EventMachine_t::_RunTimers -**************************/) - -pre_type(bool) ident(EventMachine_t)operator(::)ident(_RunTimers)operator((\)) -operator({) - comment(// These are caller-defined timer handlers.) - comment(// Return T/F to indicate whether we should continue the main loop.) - comment(// We rely on the fact that multimaps sort by their keys to avoid) - comment(// inspecting the whole list every time we come here.) - comment(// Just keep inspecting and processing the list head until we hit) - comment(// one that hasn't expired yet.) - - preprocessor(#ifdef) ident(OS_UNIX) - reserved(struct) ident(timeval) ident(tv)operator(;) - ident(gettimeofday) operator((&)ident(tv)operator(,) pre_constant(NULL)operator(\);) - ident(Int64) ident(now) operator(=) operator(((()ident(Int64)operator(\)()ident(tv)operator(.)ident(tv_sec)operator(\)\)) operator(*) integer(1000000LL)operator(\)) operator(+) operator((()ident(Int64)operator(\)()ident(tv)operator(.)ident(tv_usec)operator(\)\);) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - pre_type(unsigned) ident(tick) operator(=) ident(GetTickCount)operator((\);) - reserved(if) operator(()ident(tick) operator(<) ident(gLastTickCount)operator(\)) - ident(gTickCountTickover) operator(+=) integer(1)operator(;) - ident(gLastTickCount) operator(=) ident(tick)operator(;) - ident(Int64) ident(now) operator(=) operator((()ident(Int64)operator(\))ident(gTickCountTickover) operator(<<) integer(32)operator(\)) operator(+) operator(()ident(Int64)operator(\))ident(tick)operator(;) - preprocessor(#endif) - - reserved(while) operator(()pre_constant(true)operator(\)) operator({) - ident(multimap)operator(<)ident(Int64)operator(,)ident(Timer_t)operator(>::)ident(iterator) ident(i) operator(=) ident(Timers)operator(.)ident(begin)operator((\);) - reserved(if) operator(()ident(i) operator(==) ident(Timers)operator(.)ident(end)operator((\)\)) - reserved(break)operator(;) - reserved(if) operator(()ident(i)operator(->)ident(first) operator(>) ident(now)operator(\)) - reserved(break)operator(;) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)) operator(()string<delimiter(")delimiter(")>operator(,) ident(EM_TIMER_FIRED)operator(,) ident(i)operator(->)ident(second)operator(.)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(i)operator(->)ident(second)operator(.)ident(GetBinding)operator((\))operator(.)ident(length)operator((\)\);) - ident(Timers)operator(.)ident(erase) operator(()ident(i)operator(\);) - operator(}) - reserved(return) pre_constant(true)operator(;) -operator(}) - - - -comment(/*********************************** -EventMachine_t::InstallOneshotTimer -***********************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(InstallOneshotTimer) operator(()pre_type(int) ident(milliseconds)operator(\)) -operator({) - reserved(if) operator(()ident(Timers)operator(.)ident(size)operator((\)) operator(>) ident(MaxOutstandingTimers)operator(\)) - reserved(return) pre_constant(false)operator(;) - comment(// Don't use the global loop-time variable here, because we might) - comment(// get called before the main event machine is running.) - - preprocessor(#ifdef) ident(OS_UNIX) - reserved(struct) ident(timeval) ident(tv)operator(;) - ident(gettimeofday) operator((&)ident(tv)operator(,) pre_constant(NULL)operator(\);) - ident(Int64) ident(fire_at) operator(=) operator(((()ident(Int64)operator(\)()ident(tv)operator(.)ident(tv_sec)operator(\)\)) operator(*) integer(1000000LL)operator(\)) operator(+) operator((()ident(Int64)operator(\)()ident(tv)operator(.)ident(tv_usec)operator(\)\);) - ident(fire_at) operator(+=) operator((()ident(Int64)operator(\))ident(milliseconds)operator(\)) operator(*) integer(1000LL)operator(;) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - pre_type(unsigned) ident(tick) operator(=) ident(GetTickCount)operator((\);) - reserved(if) operator(()ident(tick) operator(<) ident(gLastTickCount)operator(\)) - ident(gTickCountTickover) operator(+=) integer(1)operator(;) - ident(gLastTickCount) operator(=) ident(tick)operator(;) - - ident(Int64) ident(fire_at) operator(=) operator((()ident(Int64)operator(\))ident(gTickCountTickover) operator(<<) integer(32)operator(\)) operator(+) operator(()ident(Int64)operator(\))ident(tick)operator(;) - ident(fire_at) operator(+=) operator(()ident(Int64)operator(\))ident(milliseconds)operator(;) - preprocessor(#endif) - - ident(Timer_t) ident(t)operator(;) - ident(multimap)operator(<)ident(Int64)operator(,)ident(Timer_t)operator(>::)ident(iterator) ident(i) operator(=) - ident(Timers)operator(.)ident(insert) operator(()ident(make_pair) operator(()ident(fire_at)operator(,) ident(t)operator(\)\);) - reserved(return) ident(i)operator(->)ident(second)operator(.)ident(GetBindingChars)operator((\);) -operator(}) - - -comment(/******************************* -EventMachine_t::ConnectToServer -*******************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(ConnectToServer) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - comment(/* We want to spend no more than a few seconds waiting for a connection - * to a remote host. So we use a nonblocking connect. - * Linux disobeys the usual rules for nonblocking connects. - * Per Stevens (UNP p.410\), you expect a nonblocking connect to select - * both readable and writable on error, and not to return EINPROGRESS - * if the connect can be fulfilled immediately. Linux violates both - * of these expectations. - * Any kind of nonblocking connect on Linux returns EINPROGRESS. - * The socket will then return writable when the disposition of the - * connect is known, but it will not also be readable in case of - * error! Weirdly, it will be readable in case there is data to read!!! - * (Which can happen with protocols like SSH and SMTP.\) - * I suppose if you were so inclined you could consider this logical, - * but it's not the way Unix has historically done it. - * So we ignore the readable flag and read getsockopt to see if there - * was an error connecting. A select timeout works as expected. - * In regard to getsockopt: Linux does the Berkeley-style thing, - * not the Solaris-style, and returns zero with the error code in - * the error parameter. - * Return the binding-text of the newly-created pending connection, - * or NULL if there was a problem. - */) - - reserved(if) operator((!)ident(server) operator(||) operator(!*)ident(server) operator(||) operator(!)ident(port)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - pre_type(int) ident(family)operator(,) ident(bind_size)operator(;) - reserved(struct) ident(sockaddr) operator(*)ident(bind_as) operator(=) ident(name2address) operator(()ident(server)operator(,) ident(port)operator(,) operator(&)ident(family)operator(,) operator(&)ident(bind_size)operator(\);) - reserved(if) operator((!)ident(bind_as)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - pre_type(int) ident(sd) operator(=) ident(socket) operator(()ident(family)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - comment(/* - sockaddr_in pin; - unsigned long HostAddr; - - HostAddr = inet_addr (server\); - if (HostAddr == INADDR_NONE\) { - hostent *hp = gethostbyname ((char*\)server\); // Windows requires (char*\) - if (!hp\) { - // TODO: This gives the caller a fatal error. Not good. - // They can respond by catching RuntimeError (blecch\). - // Possibly we need to fire an unbind event and provide - // a status code so user code can detect the cause of the - // failure. - return NULL; - } - HostAddr = ((in_addr*\)(hp->h_addr\)\)->s_addr; - } - - memset (&pin, 0, sizeof(pin\)\); - pin.sin_family = AF_INET; - pin.sin_addr.s_addr = HostAddr; - pin.sin_port = htons (port\); - - int sd = socket (AF_INET, SOCK_STREAM, 0\); - if (sd == INVALID_SOCKET\) - return NULL; - */) - - comment(// From here on, ALL error returns must close the socket.) - comment(// Set the new socket nonblocking.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(sd)operator(\)\)) operator({) - ident(closesocket) operator(()ident(sd)operator(\);) - reserved(return) pre_constant(NULL)operator(;) - operator(}) - comment(// Disable slow-start (Nagle algorithm\).) - pre_type(int) ident(one) operator(=) integer(1)operator(;) - ident(setsockopt) operator(()ident(sd)operator(,) ident(IPPROTO_TCP)operator(,) ident(TCP_NODELAY)operator(,) operator(()pre_type(char)operator(*\)) operator(&)ident(one)operator(,) reserved(sizeof)operator(()ident(one)operator(\)\);) - - directive(const) pre_type(char) operator(*)ident(out) operator(=) pre_constant(NULL)operator(;) - - preprocessor(#ifdef) ident(OS_UNIX) - comment(//if (connect (sd, (sockaddr*\)&pin, sizeof pin\) == 0\) {) - reserved(if) operator(()ident(connect) operator(()ident(sd)operator(,) ident(bind_as)operator(,) ident(bind_size)operator(\)) operator(==) integer(0)operator(\)) operator({) - comment(// This is a connect success, which Linux appears) - comment(// never to give when the socket is nonblocking,) - comment(// even if the connection is intramachine or to) - comment(// localhost.) - - comment(/* Changed this branch 08Aug06. Evidently some kernels - * (FreeBSD for example\) will actually return success from - * a nonblocking connect. This is a pretty simple case, - * just set up the new connection and clear the pending flag. - * Thanks to Chris Ochs for helping track this down. - * This branch never gets taken on Linux or (oddly\) OSX. - * The original behavior was to throw an unimplemented, - * which the user saw as a fatal exception. Very unfriendly. - * - * Tweaked 10Aug06. Even though the connect disposition is - * known, we still set the connect-pending flag. That way - * some needed initialization will happen in the ConnectionDescriptor. - * (To wit, the ConnectionCompleted event gets sent to the client.\) - */) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(sd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no connection allocated)delimiter(")>operator(\);) - ident(cd)operator(->)ident(SetConnectPending) operator(()pre_constant(true)operator(\);) - ident(Add) operator(()ident(cd)operator(\);) - ident(out) operator(=) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - reserved(else) reserved(if) operator(()ident(errno) operator(==) ident(EINPROGRESS)operator(\)) operator({) - comment(// Errno will generally always be EINPROGRESS, but on Linux) - comment(// we have to look at getsockopt to be sure what really happened.) - pre_type(int) ident(error)operator(;) - ident(socklen_t) ident(len)operator(;) - ident(len) operator(=) reserved(sizeof)operator(()ident(error)operator(\);) - pre_type(int) ident(o) operator(=) ident(getsockopt) operator(()ident(sd)operator(,) ident(SOL_SOCKET)operator(,) ident(SO_ERROR)operator(,) operator(&)ident(error)operator(,) operator(&)ident(len)operator(\);) - reserved(if) operator((()ident(o) operator(==) integer(0)operator(\)) operator(&&) operator(()ident(error) operator(==) integer(0)operator(\)\)) operator({) - comment(// Here, there's no disposition.) - comment(// Put the connection on the stack and wait for it to complete) - comment(// or time out.) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(sd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no connection allocated)delimiter(")>operator(\);) - ident(cd)operator(->)ident(SetConnectPending) operator(()pre_constant(true)operator(\);) - ident(Add) operator(()ident(cd)operator(\);) - ident(out) operator(=) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - reserved(else) operator({) - comment(/* This could be connection refused or some such thing. - * We will come here on Linux if a localhost connection fails. - * Changed 16Jul06: Originally this branch was a no-op, and - * we'd drop down to the end of the method, close the socket, - * and return NULL, which would cause the caller to GET A - * FATAL EXCEPTION. Now we keep the socket around but schedule an - * immediate close on it, so the caller will get a close-event - * scheduled on it. This was only an issue for localhost connections - * to non-listening ports. We may eventually need to revise this - * revised behavior, in case it causes problems like making it hard - * for people to know that a failure occurred. - */) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(sd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no connection allocated)delimiter(")>operator(\);) - ident(cd)operator(->)ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - ident(Add) operator(()ident(cd)operator(\);) - ident(out) operator(=) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - operator(}) - reserved(else) operator({) - comment(// The error from connect was something other then EINPROGRESS.) - operator(}) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - comment(//if (connect (sd, (sockaddr*\)&pin, sizeof pin\) == 0\) {) - reserved(if) operator(()ident(connect) operator(()ident(sd)operator(,) ident(bind_as)operator(,) ident(bind_size)operator(\)) operator(==) integer(0)operator(\)) operator({) - comment(// This is a connect success, which Windows appears) - comment(// never to give when the socket is nonblocking,) - comment(// even if the connection is intramachine or to) - comment(// localhost.) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unimplemented)delimiter(")>operator(\);) - operator(}) - reserved(else) reserved(if) operator(()ident(WSAGetLastError)operator((\)) operator(==) ident(WSAEWOULDBLOCK)operator(\)) operator({) - comment(// Here, there's no disposition.) - comment(// Windows appears not to surface refused connections or) - comment(// such stuff at this point.) - comment(// Put the connection on the stack and wait for it to complete) - comment(// or time out.) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(sd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no connection allocated)delimiter(")>operator(\);) - ident(cd)operator(->)ident(SetConnectPending) operator(()pre_constant(true)operator(\);) - ident(Add) operator(()ident(cd)operator(\);) - ident(out) operator(=) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - reserved(else) operator({) - comment(// The error from connect was something other then WSAEWOULDBLOCK.) - operator(}) - - preprocessor(#endif) - - reserved(if) operator(()ident(out) operator(==) pre_constant(NULL)operator(\)) - ident(closesocket) operator(()ident(sd)operator(\);) - reserved(return) ident(out)operator(;) -operator(}) - -comment(/*********************************** -EventMachine_t::ConnectToUnixServer -***********************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(ConnectToUnixServer) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(\)) -operator({) - comment(/* Connect to a Unix-domain server, which by definition is running - * on the same host. - * There is no meaningful implementation on Windows. - * There's no need to do a nonblocking connect, since the connection - * is always local and can always be fulfilled immediately. - */) - - preprocessor(#ifdef) ident(OS_WIN32) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unix-domain connection unavailable on this platform)delimiter(")>operator(\);) - reserved(return) pre_constant(NULL)operator(;) - preprocessor(#endif) - - comment(// The whole rest of this function is only compiled on Unix systems.) - preprocessor(#ifdef) ident(OS_UNIX) - - directive(const) pre_type(char) operator(*)ident(out) operator(=) pre_constant(NULL)operator(;) - - reserved(if) operator((!)ident(server) operator(||) operator(!*)ident(server)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - ident(sockaddr_un) ident(pun)operator(;) - ident(memset) operator((&)ident(pun)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(pun)operator(\)\);) - ident(pun)operator(.)ident(sun_family) operator(=) ident(AF_LOCAL)operator(;) - - comment(// You ordinarily expect the server name field to be at least 1024 bytes long,) - comment(// but on Linux it can be MUCH shorter.) - reserved(if) operator(()ident(strlen)operator(()ident(server)operator(\)) operator(>=) reserved(sizeof)operator(()ident(pun)operator(.)ident(sun_path)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unix-domain server name is too long)delimiter(")>operator(\);) - - - ident(strcpy) operator(()ident(pun)operator(.)ident(sun_path)operator(,) ident(server)operator(\);) - - pre_type(int) ident(fd) operator(=) ident(socket) operator(()ident(AF_LOCAL)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(fd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - comment(// From here on, ALL error returns must close the socket.) - comment(// NOTE: At this point, the socket is still a blocking socket.) - reserved(if) operator(()ident(connect) operator(()ident(fd)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(pun)operator(,) reserved(sizeof)operator(()ident(pun)operator(\)\)) operator(!=) integer(0)operator(\)) operator({) - ident(closesocket) operator(()ident(fd)operator(\);) - reserved(return) pre_constant(NULL)operator(;) - operator(}) - - comment(// Set the newly-connected socket nonblocking.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(fd)operator(\)\)) operator({) - ident(closesocket) operator(()ident(fd)operator(\);) - reserved(return) pre_constant(NULL)operator(;) - operator(}) - - comment(// Set up a connection descriptor and add it to the event-machine.) - comment(// Observe, even though we know the connection status is connect-success,) - comment(// we still set the "pending" flag, so some needed initializations take) - comment(// place.) - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(fd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no connection allocated)delimiter(")>operator(\);) - ident(cd)operator(->)ident(SetConnectPending) operator(()pre_constant(true)operator(\);) - ident(Add) operator(()ident(cd)operator(\);) - ident(out) operator(=) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - - reserved(if) operator(()ident(out) operator(==) pre_constant(NULL)operator(\)) - ident(closesocket) operator(()ident(fd)operator(\);) - - reserved(return) ident(out)operator(;) - preprocessor(#endif) -operator(}) - -comment(/************************ -EventMachine_t::AttachFD -************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(AttachFD) operator(()pre_type(int) ident(fd)operator(,) pre_type(bool) ident(notify_readable)operator(,) pre_type(bool) ident(notify_writable)operator(\)) -operator({) - preprocessor(#ifdef) ident(OS_UNIX) - reserved(if) operator(()ident(fcntl)operator(()ident(fd)operator(,) ident(F_GETFL)operator(,) integer(0)operator(\)) operator(<) integer(0)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(invalid file descriptor)delimiter(")>operator(\);) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - comment(// TODO: add better check for invalid file descriptors (see ioctlsocket or getsockopt\)) - reserved(if) operator(()ident(fd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(invalid file descriptor)delimiter(")>operator(\);) - preprocessor(#endif) - - operator({)comment(// Check for duplicate descriptors) - ident(size_t) ident(i)operator(;) - reserved(for) operator(()ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) ident(Descriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - reserved(if) operator(()ident(ed)operator(->)ident(GetSocket)operator((\)) operator(==) ident(fd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(adding existing descriptor)delimiter(")>operator(\);) - operator(}) - - reserved(for) operator(()ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) ident(NewDescriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(NewDescriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ed)operator(\);) - reserved(if) operator(()ident(ed)operator(->)ident(GetSocket)operator((\)) operator(==) ident(fd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(adding existing new descriptor)delimiter(")>operator(\);) - operator(}) - operator(}) - - ident(ConnectionDescriptor) operator(*)ident(cd) operator(=) reserved(new) ident(ConnectionDescriptor) operator(()ident(fd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(cd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no connection allocated)delimiter(")>operator(\);) - - ident(cd)operator(->)ident(SetConnectPending) operator(()pre_constant(true)operator(\);) - ident(cd)operator(->)ident(SetNotifyReadable) operator(()ident(notify_readable)operator(\);) - ident(cd)operator(->)ident(SetNotifyWritable) operator(()ident(notify_writable)operator(\);) - - ident(Add) operator(()ident(cd)operator(\);) - - directive(const) pre_type(char) operator(*)ident(out) operator(=) pre_constant(NULL)operator(;) - ident(out) operator(=) ident(cd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - reserved(if) operator(()ident(out) operator(==) pre_constant(NULL)operator(\)) - ident(closesocket) operator(()ident(fd)operator(\);) - reserved(return) ident(out)operator(;) -operator(}) - -comment(/************************ -EventMachine_t::DetachFD -************************/) - -pre_type(int) ident(EventMachine_t)operator(::)ident(DetachFD) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - reserved(if) operator((!)ident(ed)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(detaching bad descriptor)delimiter(")>operator(\);) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - reserved(if) operator(()ident(bEpoll)operator(\)) operator({) - reserved(if) operator(()ident(ed)operator(->)ident(GetSocket)operator((\)) operator(!=) ident(INVALID_SOCKET)operator(\)) operator({) - ident(assert) operator(()ident(bEpoll)operator(\);) comment(// wouldn't be in this method otherwise.) - ident(assert) operator(()ident(epfd) operator(!=) operator(-)integer(1)operator(\);) - pre_type(int) ident(e) operator(=) ident(epoll_ctl) operator(()ident(epfd)operator(,) ident(EPOLL_CTL_DEL)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(ed)operator(->)ident(GetEpollEvent)operator((\)\);) - comment(// ENOENT or EBADF are not errors because the socket may be already closed when we get here.) - reserved(if) operator(()ident(e) operator(&&) operator(()ident(errno) operator(!=) ident(ENOENT)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(EBADF)operator(\)\)) operator({) - pre_type(char) ident(buf) operator([)integer(200)operator(];) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(unable to delete epoll event: %s)delimiter(")>operator(,) ident(strerror)operator(()ident(errno)operator(\)\);) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(buf)operator(\);) - operator(}) - operator(}) - operator(}) - preprocessor(#endif) - - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(if) operator(()ident(bKqueue)operator(\)) operator({) - reserved(struct) ident(kevent) ident(k)operator(;) - ident(EV_SET) operator((&)ident(k)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(EVFILT_READ)operator(,) ident(EV_DELETE)operator(,) integer(0)operator(,) integer(0)operator(,) ident(ed)operator(\);) - pre_type(int) ident(t) operator(=) ident(kevent) operator(()ident(kqfd)operator(,) operator(&)ident(k)operator(,) integer(1)operator(,) pre_constant(NULL)operator(,) integer(0)operator(,) pre_constant(NULL)operator(\);) - ident(assert) operator(()ident(t) operator(==) integer(0)operator(\);) - operator(}) - preprocessor(#endif) - - operator({) comment(// remove descriptor from lists) - pre_type(int) ident(i)operator(,) ident(j)operator(;) - pre_type(int) ident(nSockets) operator(=) ident(Descriptors)operator(.)ident(size)operator((\);) - reserved(for) operator(()ident(i)operator(=)integer(0)operator(,) ident(j)operator(=)integer(0)operator(;) ident(i) operator(<) ident(nSockets)operator(;) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ted) operator(=) ident(Descriptors)operator([)ident(i)operator(];) - ident(assert) operator(()ident(ted)operator(\);) - reserved(if) operator(()ident(ted) operator(!=) ident(ed)operator(\)) - ident(Descriptors) operator([)ident(j)operator(++]) operator(=) ident(ted)operator(;) - operator(}) - reserved(while) operator((()ident(size_t)operator(\))ident(j) operator(<) ident(Descriptors)operator(.)ident(size)operator((\)\)) - ident(Descriptors)operator(.)ident(pop_back)operator((\);) - - ident(ModifiedDescriptors)operator(.)ident(erase) operator(()ident(ed)operator(\);) - operator(}) - - pre_type(int) ident(fd) operator(=) ident(ed)operator(->)ident(GetSocket)operator((\);) - - comment(// We depend on ~EventableDescriptor not calling close(\) if the socket is invalid) - ident(ed)operator(->)ident(SetSocketInvalid)operator((\);) - reserved(delete) ident(ed)operator(;) - - reserved(return) ident(fd)operator(;) -operator(}) - -comment(/************ -name2address -************/) - -reserved(struct) ident(sockaddr) operator(*)ident(name2address) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(,) pre_type(int) operator(*)ident(family)operator(,) pre_type(int) operator(*)ident(bind_size)operator(\)) -operator({) - comment(// THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed.) - comment(// Check the more-common cases first.) - comment(// Return NULL if no resolution.) - - directive(static) reserved(struct) ident(sockaddr_in) ident(in4)operator(;) - preprocessor(#ifndef) ident(__CYGWIN__) - directive(static) reserved(struct) ident(sockaddr_in6) ident(in6)operator(;) - preprocessor(#endif) - reserved(struct) ident(hostent) operator(*)ident(hp)operator(;) - - reserved(if) operator((!)ident(server) operator(||) operator(!*)ident(server)operator(\)) - ident(server) operator(=) string<delimiter(")content(0.0.0.0)delimiter(")>operator(;) - - ident(memset) operator((&)ident(in4)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(in4)operator(\)\);) - reserved(if) operator(() operator(()ident(in4)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(inet_addr) operator(()ident(server)operator(\)\)) operator(!=) ident(INADDR_NONE)operator(\)) operator({) - reserved(if) operator(()ident(family)operator(\)) - operator(*)ident(family) operator(=) ident(AF_INET)operator(;) - reserved(if) operator(()ident(bind_size)operator(\)) - operator(*)ident(bind_size) operator(=) reserved(sizeof)operator(()ident(in4)operator(\);) - ident(in4)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(in4)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - reserved(return) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(in4)operator(;) - operator(}) - - preprocessor(#if) ident(defined)operator(()ident(OS_UNIX)operator(\)) operator(&&) operator(!)ident(defined)operator(()ident(__CYGWIN__)operator(\)) - ident(memset) operator((&)ident(in6)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(in6)operator(\)\);) - reserved(if) operator(()ident(inet_pton) operator(()ident(AF_INET6)operator(,) ident(server)operator(,) ident(in6)operator(.)ident(sin6_addr)operator(.)ident(s6_addr)operator(\)) operator(>) integer(0)operator(\)) operator({) - reserved(if) operator(()ident(family)operator(\)) - operator(*)ident(family) operator(=) ident(AF_INET6)operator(;) - reserved(if) operator(()ident(bind_size)operator(\)) - operator(*)ident(bind_size) operator(=) reserved(sizeof)operator(()ident(in6)operator(\);) - ident(in6)operator(.)ident(sin6_family) operator(=) ident(AF_INET6)operator(;) - ident(in6)operator(.)ident(sin6_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - reserved(return) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(in6)operator(;) - operator(}) - preprocessor(#endif) - - preprocessor(#ifdef) ident(OS_WIN32) - comment(// TODO, must complete this branch. Windows doesn't have inet_pton.) - comment(// A possible approach is to make a getaddrinfo call with the supplied) - comment(// server address, constraining the hints to ipv6 and seeing if we) - comment(// get any addresses.) - comment(// For the time being, Ipv6 addresses aren't supported on Windows.) - preprocessor(#endif) - - ident(hp) operator(=) ident(gethostbyname) operator((()pre_type(char)operator(*\))ident(server)operator(\);) comment(// Windows requires the cast.) - reserved(if) operator(()ident(hp)operator(\)) operator({) - ident(in4)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) operator((()ident(in_addr)operator(*\)()ident(hp)operator(->)ident(h_addr)operator(\)\)->)ident(s_addr)operator(;) - reserved(if) operator(()ident(family)operator(\)) - operator(*)ident(family) operator(=) ident(AF_INET)operator(;) - reserved(if) operator(()ident(bind_size)operator(\)) - operator(*)ident(bind_size) operator(=) reserved(sizeof)operator(()ident(in4)operator(\);) - ident(in4)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(in4)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - reserved(return) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(in4)operator(;) - operator(}) - - reserved(return) pre_constant(NULL)operator(;) -operator(}) - - -comment(/******************************* -EventMachine_t::CreateTcpServer -*******************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(CreateTcpServer) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - comment(/* Create a TCP-acceptor (server\) socket and add it to the event machine. - * Return the binding of the new acceptor to the caller. - * This binding will be referenced when the new acceptor sends events - * to indicate accepted connections. - */) - - - pre_type(int) ident(family)operator(,) ident(bind_size)operator(;) - reserved(struct) ident(sockaddr) operator(*)ident(bind_here) operator(=) ident(name2address) operator(()ident(server)operator(,) ident(port)operator(,) operator(&)ident(family)operator(,) operator(&)ident(bind_size)operator(\);) - reserved(if) operator((!)ident(bind_here)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - directive(const) pre_type(char) operator(*)ident(output_binding) operator(=) pre_constant(NULL)operator(;) - - comment(//struct sockaddr_in sin;) - - pre_type(int) ident(sd_accept) operator(=) ident(socket) operator(()ident(family)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd_accept) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - reserved(goto) ident(fail)operator(;) - operator(}) - - comment(/* - memset (&sin, 0, sizeof(sin\)\); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons (port\); - - if (server && *server\) { - sin.sin_addr.s_addr = inet_addr (server\); - if (sin.sin_addr.s_addr == INADDR_NONE\) { - hostent *hp = gethostbyname ((char*\)server\); // Windows requires the cast. - if (hp == NULL\) { - //__warning ("hostname not resolved: ", server\); - goto fail; - } - sin.sin_addr.s_addr = ((in_addr*\)(hp->h_addr\)\)->s_addr; - } - } - */) - - operator({) comment(// set reuseaddr to improve performance on restarts.) - pre_type(int) ident(oval) operator(=) integer(1)operator(;) - reserved(if) operator(()ident(setsockopt) operator(()ident(sd_accept)operator(,) ident(SOL_SOCKET)operator(,) ident(SO_REUSEADDR)operator(,) operator(()pre_type(char)operator(*\)&)ident(oval)operator(,) reserved(sizeof)operator(()ident(oval)operator(\)\)) operator(<) integer(0)operator(\)) operator({) - comment(//__warning ("setsockopt failed while creating listener",""\);) - reserved(goto) ident(fail)operator(;) - operator(}) - operator(}) - - operator({) comment(// set CLOEXEC. Only makes sense on Unix) - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(cloexec) operator(=) ident(fcntl) operator(()ident(sd_accept)operator(,) ident(F_GETFD)operator(,) integer(0)operator(\);) - ident(assert) operator(()ident(cloexec) operator(>=) integer(0)operator(\);) - ident(cloexec) operator(|=) ident(FD_CLOEXEC)operator(;) - ident(fcntl) operator(()ident(sd_accept)operator(,) ident(F_SETFD)operator(,) ident(cloexec)operator(\);) - preprocessor(#endif) - operator(}) - - - comment(//if (bind (sd_accept, (struct sockaddr*\)&sin, sizeof(sin\)\)\) {) - reserved(if) operator(()ident(bind) operator(()ident(sd_accept)operator(,) ident(bind_here)operator(,) ident(bind_size)operator(\)\)) operator({) - comment(//__warning ("binding failed"\);) - reserved(goto) ident(fail)operator(;) - operator(}) - - reserved(if) operator(()ident(listen) operator(()ident(sd_accept)operator(,) integer(100)operator(\)\)) operator({) - comment(//__warning ("listen failed"\);) - reserved(goto) ident(fail)operator(;) - operator(}) - - operator({) - comment(// Set the acceptor non-blocking.) - comment(// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(sd_accept)operator(\)\)) operator({) - comment(//int val = fcntl (sd_accept, F_GETFL, 0\);) - comment(//if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK\) == -1\) {) - reserved(goto) ident(fail)operator(;) - operator(}) - operator(}) - - operator({) comment(// Looking good.) - ident(AcceptorDescriptor) operator(*)ident(ad) operator(=) reserved(new) ident(AcceptorDescriptor) operator(()ident(sd_accept)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(ad)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to allocate acceptor)delimiter(")>operator(\);) - ident(Add) operator(()ident(ad)operator(\);) - ident(output_binding) operator(=) ident(ad)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - - reserved(return) ident(output_binding)operator(;) - - label(fail:) - reserved(if) operator(()ident(sd_accept) operator(!=) ident(INVALID_SOCKET)operator(\)) - ident(closesocket) operator(()ident(sd_accept)operator(\);) - reserved(return) pre_constant(NULL)operator(;) -operator(}) - - -comment(/********************************** -EventMachine_t::OpenDatagramSocket -**********************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(OpenDatagramSocket) operator(()directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(output_binding) operator(=) pre_constant(NULL)operator(;) - - pre_type(int) ident(sd) operator(=) ident(socket) operator(()ident(AF_INET)operator(,) ident(SOCK_DGRAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(goto) ident(fail)operator(;) - comment(// from here on, early returns must close the socket!) - - - reserved(struct) ident(sockaddr_in) ident(sin)operator(;) - ident(memset) operator((&)ident(sin)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(sin)operator(\)\);) - ident(sin)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(sin)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - - - reserved(if) operator(()ident(address) operator(&&) operator(*)ident(address)operator(\)) operator({) - ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(inet_addr) operator(()ident(address)operator(\);) - reserved(if) operator(()ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(==) ident(INADDR_NONE)operator(\)) operator({) - ident(hostent) operator(*)ident(hp) operator(=) ident(gethostbyname) operator((()pre_type(char)operator(*\))ident(address)operator(\);) comment(// Windows requires the cast.) - reserved(if) operator(()ident(hp) operator(==) pre_constant(NULL)operator(\)) - reserved(goto) ident(fail)operator(;) - ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) operator((()ident(in_addr)operator(*\)()ident(hp)operator(->)ident(h_addr)operator(\)\)->)ident(s_addr)operator(;) - operator(}) - operator(}) - reserved(else) - ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(htonl) operator(()ident(INADDR_ANY)operator(\);) - - - comment(// Set the new socket nonblocking.) - operator({) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(sd)operator(\)\)) - comment(//int val = fcntl (sd, F_GETFL, 0\);) - comment(//if (fcntl (sd, F_SETFL, val | O_NONBLOCK\) == -1\)) - reserved(goto) ident(fail)operator(;) - operator(}) - - reserved(if) operator(()ident(bind) operator(()ident(sd)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(sin)operator(,) reserved(sizeof)operator(()ident(sin)operator(\)\)) operator(!=) integer(0)operator(\)) - reserved(goto) ident(fail)operator(;) - - operator({) comment(// Looking good.) - ident(DatagramDescriptor) operator(*)ident(ds) operator(=) reserved(new) ident(DatagramDescriptor) operator(()ident(sd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(ds)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to allocate datagram-socket)delimiter(")>operator(\);) - ident(Add) operator(()ident(ds)operator(\);) - ident(output_binding) operator(=) ident(ds)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - - reserved(return) ident(output_binding)operator(;) - - label(fail:) - reserved(if) operator(()ident(sd) operator(!=) ident(INVALID_SOCKET)operator(\)) - ident(closesocket) operator(()ident(sd)operator(\);) - reserved(return) pre_constant(NULL)operator(;) -operator(}) - - - -comment(/******************* -EventMachine_t::Add -*******************/) - -directive(void) ident(EventMachine_t)operator(::)ident(Add) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - reserved(if) operator((!)ident(ed)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(added bad descriptor)delimiter(")>operator(\);) - ident(ed)operator(->)ident(SetEventCallback) operator(()ident(EventCallback)operator(\);) - ident(NewDescriptors)operator(.)ident(push_back) operator(()ident(ed)operator(\);) -operator(}) - - -comment(/******************************* -EventMachine_t::ArmKqueueWriter -*******************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(ArmKqueueWriter) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(if) operator(()ident(bKqueue)operator(\)) operator({) - reserved(if) operator((!)ident(ed)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(added bad descriptor)delimiter(")>operator(\);) - reserved(struct) ident(kevent) ident(k)operator(;) - ident(EV_SET) operator((&)ident(k)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(EVFILT_WRITE)operator(,) ident(EV_ADD) operator(|) ident(EV_ONESHOT)operator(,) integer(0)operator(,) integer(0)operator(,) ident(ed)operator(\);) - pre_type(int) ident(t) operator(=) ident(kevent) operator(()ident(kqfd)operator(,) operator(&)ident(k)operator(,) integer(1)operator(,) pre_constant(NULL)operator(,) integer(0)operator(,) pre_constant(NULL)operator(\);) - ident(assert) operator(()ident(t) operator(==) integer(0)operator(\);) - operator(}) - preprocessor(#endif) -operator(}) - -comment(/******************************* -EventMachine_t::ArmKqueueReader -*******************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(ArmKqueueReader) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(if) operator(()ident(bKqueue)operator(\)) operator({) - reserved(if) operator((!)ident(ed)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(added bad descriptor)delimiter(")>operator(\);) - reserved(struct) ident(kevent) ident(k)operator(;) - ident(EV_SET) operator((&)ident(k)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(EVFILT_READ)operator(,) ident(EV_ADD)operator(,) integer(0)operator(,) integer(0)operator(,) ident(ed)operator(\);) - pre_type(int) ident(t) operator(=) ident(kevent) operator(()ident(kqfd)operator(,) operator(&)ident(k)operator(,) integer(1)operator(,) pre_constant(NULL)operator(,) integer(0)operator(,) pre_constant(NULL)operator(\);) - ident(assert) operator(()ident(t) operator(==) integer(0)operator(\);) - operator(}) - preprocessor(#endif) -operator(}) - -comment(/********************************** -EventMachine_t::_AddNewDescriptors -**********************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_AddNewDescriptors)operator((\)) -operator({) - comment(/* Avoid adding descriptors to the main descriptor list - * while we're actually traversing the list. - * Any descriptors that are added as a result of processing timers - * or acceptors should go on a temporary queue and then added - * while we're not traversing the main list. - * Also, it (rarely\) happens that a newly-created descriptor - * is immediately scheduled to close. It might be a good - * idea not to bother scheduling these for I/O but if - * we do that, we might bypass some important processing. - */) - - reserved(for) operator(()ident(size_t) ident(i) operator(=) integer(0)operator(;) ident(i) operator(<) ident(NewDescriptors)operator(.)ident(size)operator((\);) ident(i)operator(++\)) operator({) - ident(EventableDescriptor) operator(*)ident(ed) operator(=) ident(NewDescriptors)operator([)ident(i)operator(];) - reserved(if) operator(()ident(ed) operator(==) pre_constant(NULL)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(adding bad descriptor)delimiter(")>operator(\);) - - preprocessor(#if) ident(HAVE_EPOLL) - reserved(if) operator(()ident(bEpoll)operator(\)) operator({) - ident(assert) operator(()ident(epfd) operator(!=) operator(-)integer(1)operator(\);) - pre_type(int) ident(e) operator(=) ident(epoll_ctl) operator(()ident(epfd)operator(,) ident(EPOLL_CTL_ADD)operator(,) ident(ed)operator(->)ident(GetSocket)operator((\),) ident(ed)operator(->)ident(GetEpollEvent)operator((\)\);) - reserved(if) operator(()ident(e)operator(\)) operator({) - pre_type(char) ident(buf) operator([)integer(200)operator(];) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(unable to add new descriptor: %s)delimiter(")>operator(,) ident(strerror)operator(()ident(errno)operator(\)\);) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()ident(buf)operator(\);) - operator(}) - operator(}) - preprocessor(#endif) - - preprocessor(#if) ident(HAVE_KQUEUE) - comment(/* - if (bKqueue\) { - // INCOMPLETE. Some descriptors don't want to be readable. - assert (kqfd != -1\); - struct kevent k; - EV_SET (&k, ed->GetSocket(\), EVFILT_READ, EV_ADD, 0, 0, ed\); - int t = kevent (kqfd, &k, 1, NULL, 0, NULL\); - assert (t == 0\); - } - */) - preprocessor(#endif) - - ident(Descriptors)operator(.)ident(push_back) operator(()ident(ed)operator(\);) - operator(}) - ident(NewDescriptors)operator(.)ident(clear)operator((\);) -operator(}) - - -comment(/********************************** -EventMachine_t::_ModifyDescriptors -**********************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(_ModifyDescriptors)operator((\)) -operator({) - comment(/* For implementations which don't level check every descriptor on - * every pass through the machine, as select does. - * If we're not selecting, then descriptors need a way to signal to the - * machine that their readable or writable status has changed. - * That's what the ::Modify call is for. We do it this way to avoid - * modifying descriptors during the loop traversal, where it can easily - * happen that an object (like a UDP socket\) gets data written on it by - * the application during #post_init. That would take place BEFORE the - * descriptor even gets added to the epoll descriptor, so the modify - * operation will crash messily. - * Another really messy possibility is for a descriptor to put itself - * on the Modified list, and then get deleted before we get here. - * Remember, deletes happen after the I/O traversal and before the - * next pass through here. So we have to make sure when we delete a - * descriptor to remove it from the Modified list. - */) - - preprocessor(#ifdef) ident(HAVE_EPOLL) - reserved(if) operator(()ident(bEpoll)operator(\)) operator({) - ident(set)operator(<)ident(EventableDescriptor)operator(*>::)ident(iterator) ident(i) operator(=) ident(ModifiedDescriptors)operator(.)ident(begin)operator((\);) - reserved(while) operator(()ident(i) operator(!=) ident(ModifiedDescriptors)operator(.)ident(end)operator((\)\)) operator({) - ident(assert) operator((*)ident(i)operator(\);) - ident(_ModifyEpollEvent) operator((*)ident(i)operator(\);) - operator(++)ident(i)operator(;) - operator(}) - operator(}) - preprocessor(#endif) - - ident(ModifiedDescriptors)operator(.)ident(clear)operator((\);) -operator(}) - - -comment(/********************** -EventMachine_t::Modify -**********************/) - -directive(void) ident(EventMachine_t)operator(::)ident(Modify) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - reserved(if) operator((!)ident(ed)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(modified bad descriptor)delimiter(")>operator(\);) - ident(ModifiedDescriptors)operator(.)ident(insert) operator(()ident(ed)operator(\);) -operator(}) - - -comment(/*********************************** -EventMachine_t::_OpenFileForWriting -***********************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(_OpenFileForWriting) operator(()directive(const) pre_type(char) operator(*)ident(filename)operator(\)) -operator({) - comment(/* - * Return the binding-text of the newly-opened file, - * or NULL if there was a problem. - */) - - reserved(if) operator((!)ident(filename) operator(||) operator(!*)ident(filename)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - pre_type(int) ident(fd) operator(=) ident(open) operator(()ident(filename)operator(,) ident(O_CREAT)operator(|)ident(O_TRUNC)operator(|)ident(O_WRONLY)operator(|)ident(O_NONBLOCK)operator(,) oct(0644)operator(\);) - - ident(FileStreamDescriptor) operator(*)ident(fsd) operator(=) reserved(new) ident(FileStreamDescriptor) operator(()ident(fd)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(fsd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no file-stream allocated)delimiter(")>operator(\);) - ident(Add) operator(()ident(fsd)operator(\);) - reserved(return) ident(fsd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - -operator(}) - - -comment(/************************************** -EventMachine_t::CreateUnixDomainServer -**************************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(CreateUnixDomainServer) operator(()directive(const) pre_type(char) operator(*)ident(filename)operator(\)) -operator({) - comment(/* Create a UNIX-domain acceptor (server\) socket and add it to the event machine. - * Return the binding of the new acceptor to the caller. - * This binding will be referenced when the new acceptor sends events - * to indicate accepted connections. - * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS. - */) - - preprocessor(#ifdef) ident(OS_WIN32) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unix-domain server unavailable on this platform)delimiter(")>operator(\);) - preprocessor(#endif) - - comment(// The whole rest of this function is only compiled on Unix systems.) - preprocessor(#ifdef) ident(OS_UNIX) - directive(const) pre_type(char) operator(*)ident(output_binding) operator(=) pre_constant(NULL)operator(;) - - reserved(struct) ident(sockaddr_un) ident(s_sun)operator(;) - - pre_type(int) ident(sd_accept) operator(=) ident(socket) operator(()ident(AF_LOCAL)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd_accept) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - reserved(goto) ident(fail)operator(;) - operator(}) - - reserved(if) operator((!)ident(filename) operator(||) operator(!*)ident(filename)operator(\)) - reserved(goto) ident(fail)operator(;) - ident(unlink) operator(()ident(filename)operator(\);) - - ident(bzero) operator((&)ident(s_sun)operator(,) reserved(sizeof)operator(()ident(s_sun)operator(\)\);) - ident(s_sun)operator(.)ident(sun_family) operator(=) ident(AF_LOCAL)operator(;) - ident(strncpy) operator(()ident(s_sun)operator(.)ident(sun_path)operator(,) ident(filename)operator(,) reserved(sizeof)operator(()ident(s_sun)operator(.)ident(sun_path)operator(\)-)integer(1)operator(\);) - - comment(// don't bother with reuseaddr for a local socket.) - - operator({) comment(// set CLOEXEC. Only makes sense on Unix) - preprocessor(#ifdef) ident(OS_UNIX) - pre_type(int) ident(cloexec) operator(=) ident(fcntl) operator(()ident(sd_accept)operator(,) ident(F_GETFD)operator(,) integer(0)operator(\);) - ident(assert) operator(()ident(cloexec) operator(>=) integer(0)operator(\);) - ident(cloexec) operator(|=) ident(FD_CLOEXEC)operator(;) - ident(fcntl) operator(()ident(sd_accept)operator(,) ident(F_SETFD)operator(,) ident(cloexec)operator(\);) - preprocessor(#endif) - operator(}) - - reserved(if) operator(()ident(bind) operator(()ident(sd_accept)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(s_sun)operator(,) reserved(sizeof)operator(()ident(s_sun)operator(\)\)\)) operator({) - comment(//__warning ("binding failed"\);) - reserved(goto) ident(fail)operator(;) - operator(}) - - reserved(if) operator(()ident(listen) operator(()ident(sd_accept)operator(,) integer(100)operator(\)\)) operator({) - comment(//__warning ("listen failed"\);) - reserved(goto) ident(fail)operator(;) - operator(}) - - operator({) - comment(// Set the acceptor non-blocking.) - comment(// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(sd_accept)operator(\)\)) operator({) - comment(//int val = fcntl (sd_accept, F_GETFL, 0\);) - comment(//if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK\) == -1\) {) - reserved(goto) ident(fail)operator(;) - operator(}) - operator(}) - - operator({) comment(// Looking good.) - ident(AcceptorDescriptor) operator(*)ident(ad) operator(=) reserved(new) ident(AcceptorDescriptor) operator(()ident(sd_accept)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(ad)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to allocate acceptor)delimiter(")>operator(\);) - ident(Add) operator(()ident(ad)operator(\);) - ident(output_binding) operator(=) ident(ad)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - - reserved(return) ident(output_binding)operator(;) - - label(fail:) - reserved(if) operator(()ident(sd_accept) operator(!=) ident(INVALID_SOCKET)operator(\)) - ident(closesocket) operator(()ident(sd_accept)operator(\);) - reserved(return) pre_constant(NULL)operator(;) - preprocessor(#endif) comment(// OS_UNIX) -operator(}) - - -comment(/********************* -EventMachine_t::Popen -*********************/) -preprocessor(#if) ident(OBSOLETE) -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(Popen) operator(()directive(const) pre_type(char) operator(*)ident(cmd)operator(,) directive(const) pre_type(char) operator(*)ident(mode)operator(\)) -operator({) - preprocessor(#ifdef) ident(OS_WIN32) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(popen is currently unavailable on this platform)delimiter(")>operator(\);) - preprocessor(#endif) - - comment(// The whole rest of this function is only compiled on Unix systems.) - comment(// Eventually we need this functionality (or a full-duplex equivalent\) on Windows.) - preprocessor(#ifdef) ident(OS_UNIX) - directive(const) pre_type(char) operator(*)ident(output_binding) operator(=) pre_constant(NULL)operator(;) - - ident(FILE) operator(*)ident(fp) operator(=) ident(popen) operator(()ident(cmd)operator(,) ident(mode)operator(\);) - reserved(if) operator((!)ident(fp)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - comment(// From here, all early returns must pclose the stream.) - - comment(// According to the pipe(2\) manpage, descriptors returned from pipe have both) - comment(// CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(fileno) operator(()ident(fp)operator(\)\)\)) operator({) - ident(pclose) operator(()ident(fp)operator(\);) - reserved(return) pre_constant(NULL)operator(;) - operator(}) - - operator({) comment(// Looking good.) - ident(PipeDescriptor) operator(*)ident(pd) operator(=) reserved(new) ident(PipeDescriptor) operator(()ident(fp)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(pd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to allocate pipe)delimiter(")>operator(\);) - ident(Add) operator(()ident(pd)operator(\);) - ident(output_binding) operator(=) ident(pd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - - reserved(return) ident(output_binding)operator(;) - preprocessor(#endif) -operator(}) -preprocessor(#endif) comment(// OBSOLETE) - -comment(/************************** -EventMachine_t::Socketpair -**************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(Socketpair) operator(()pre_type(char) operator(*) directive(const)operator(*)ident(cmd_strings)operator(\)) -operator({) - preprocessor(#ifdef) ident(OS_WIN32) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(socketpair is currently unavailable on this platform)delimiter(")>operator(\);) - preprocessor(#endif) - - comment(// The whole rest of this function is only compiled on Unix systems.) - comment(// Eventually we need this functionality (or a full-duplex equivalent\) on Windows.) - preprocessor(#ifdef) ident(OS_UNIX) - comment(// Make sure the incoming array of command strings is sane.) - reserved(if) operator((!)ident(cmd_strings)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - pre_type(int) ident(j)operator(;) - reserved(for) operator(()ident(j)operator(=)integer(0)operator(;) ident(j) operator(<) integer(100) operator(&&) ident(cmd_strings)operator([)ident(j)operator(];) ident(j)operator(++\)) - operator(;) - reserved(if) operator((()ident(j)operator(==)integer(0)operator(\)) operator(||) operator(()ident(j)operator(==)integer(100)operator(\)\)) - reserved(return) pre_constant(NULL)operator(;) - - directive(const) pre_type(char) operator(*)ident(output_binding) operator(=) pre_constant(NULL)operator(;) - - pre_type(int) ident(sv)operator([)integer(2)operator(];) - reserved(if) operator(()ident(socketpair) operator(()ident(AF_LOCAL)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(,) ident(sv)operator(\)) operator(<) integer(0)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - comment(// from here, all early returns must close the pair of sockets.) - - comment(// Set the parent side of the socketpair nonblocking.) - comment(// We don't care about the child side, and most child processes will expect their) - comment(// stdout to be blocking. Thanks to Duane Johnson and Bill Kelly for pointing this out.) - comment(// Obviously DON'T set CLOEXEC.) - reserved(if) operator((!)ident(SetSocketNonblocking) operator(()ident(sv)operator([)integer(0)operator(]\)\)) operator({) - ident(close) operator(()ident(sv)operator([)integer(0)operator(]\);) - ident(close) operator(()ident(sv)operator([)integer(1)operator(]\);) - reserved(return) pre_constant(NULL)operator(;) - operator(}) - - ident(pid_t) ident(f) operator(=) ident(fork)operator((\);) - reserved(if) operator(()ident(f) operator(>) integer(0)operator(\)) operator({) - ident(close) operator(()ident(sv)operator([)integer(1)operator(]\);) - ident(PipeDescriptor) operator(*)ident(pd) operator(=) reserved(new) ident(PipeDescriptor) operator(()ident(sv)operator([)integer(0)operator(],) ident(f)operator(,) local_variable(this)operator(\);) - reserved(if) operator((!)ident(pd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to allocate pipe)delimiter(")>operator(\);) - ident(Add) operator(()ident(pd)operator(\);) - ident(output_binding) operator(=) ident(pd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - operator(}) - reserved(else) reserved(if) operator(()ident(f) operator(==) integer(0)operator(\)) operator({) - ident(close) operator(()ident(sv)operator([)integer(0)operator(]\);) - ident(dup2) operator(()ident(sv)operator([)integer(1)operator(],) ident(STDIN_FILENO)operator(\);) - ident(close) operator(()ident(sv)operator([)integer(1)operator(]\);) - ident(dup2) operator(()ident(STDIN_FILENO)operator(,) ident(STDOUT_FILENO)operator(\);) - ident(execvp) operator(()ident(cmd_strings)operator([)integer(0)operator(],) ident(cmd_strings)operator(+)integer(1)operator(\);) - ident(exit) operator((-)integer(1)operator(\);) comment(// end the child process if the exec doesn't work.) - operator(}) - reserved(else) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no fork)delimiter(")>operator(\);) - - reserved(return) ident(output_binding)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/**************************** -EventMachine_t::OpenKeyboard -****************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(OpenKeyboard)operator((\)) -operator({) - ident(KeyboardDescriptor) operator(*)ident(kd) operator(=) reserved(new) ident(KeyboardDescriptor) operator(()local_variable(this)operator(\);) - reserved(if) operator((!)ident(kd)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no keyboard-object allocated)delimiter(")>operator(\);) - ident(Add) operator(()ident(kd)operator(\);) - reserved(return) ident(kd)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) -operator(}) - - - - - -comment(//#endif // OS_UNIX) - -comment(/***************************************************************************** - -$Id$ - -File: emwin.cpp -Date: 05May06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - -comment(// THIS ENTIRE FILE IS FOR WINDOWS BUILDS ONLY) -comment(// INCOMPLETE AND DISABLED FOR NOW.) -preprocessor(#ifdef) ident(xOS_WIN32) - -preprocessor(#include) include("project.h") - - -comment(// Keep a global variable floating around) -comment(// with the current loop time as set by the Event Machine.) -comment(// This avoids the need for frequent expensive calls to time(NULL\);) -ident(time_t) ident(gCurrentLoopTime)operator(;) - - -comment(/****************************** -EventMachine_t::EventMachine_t -******************************/) - -ident(EventMachine_t)operator(::)ident(EventMachine_t) operator(()directive(void) operator((*)ident(event_callback)operator(\)()directive(const) pre_type(char)operator(*,) pre_type(int)operator(,) directive(const) pre_type(char)operator(*,) pre_type(int)operator(\)\):) - ident(EventCallback) operator(()ident(event_callback)operator(\),) - ident(NextHeartbeatTime) operator(()integer(0)operator(\)) -operator({) - ident(gTerminateSignalReceived) operator(=) pre_constant(false)operator(;) - ident(Iocp) operator(=) pre_constant(NULL)operator(;) -operator(}) - - -comment(/******************************* -EventMachine_t::~EventMachine_t -*******************************/) - -ident(EventMachine_t)operator(::~)ident(EventMachine_t)operator((\)) -operator({) - ident(cerr) operator(<<) string<delimiter(")content(EM __dt)char(\\n)delimiter(")>operator(;) - reserved(if) operator(()ident(Iocp)operator(\)) - ident(CloseHandle) operator(()ident(Iocp)operator(\);) -operator(}) - - -comment(/**************************** -EventMachine_t::ScheduleHalt -****************************/) - -directive(void) ident(EventMachine_t)operator(::)ident(ScheduleHalt)operator((\)) -operator({) - comment(/* This is how we stop the machine. - * This can be called by clients. Signal handlers will probably - * set the global flag. - * For now this means there can only be one EventMachine ever running at a time. - */) - ident(gTerminateSignalReceived) operator(=) pre_constant(true)operator(;) -operator(}) - - - -comment(/******************* -EventMachine_t::Run -*******************/) - -directive(void) ident(EventMachine_t)operator(::)ident(Run)operator((\)) -operator({) - ident(HookControlC) operator(()pre_constant(true)operator(\);) - - ident(Iocp) operator(=) ident(CreateIoCompletionPort) operator(()ident(INVALID_HANDLE_VALUE)operator(,) pre_constant(NULL)operator(,) integer(0)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(Iocp) operator(==) pre_constant(NULL)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no completion port)delimiter(")>operator(\);) - - - ident(DWORD) ident(nBytes)operator(,) ident(nCompletionKey)operator(;) - ident(LPOVERLAPPED) ident(Overlapped)operator(;) - - reserved(do) operator({) - ident(gCurrentLoopTime) operator(=) ident(time)operator(()pre_constant(NULL)operator(\);) - comment(// Have some kind of strategy that will dequeue maybe up to 10 completions ) - comment(// without running the timers as long as they are available immediately.) - comment(// Otherwise in a busy server we're calling them every time through the loop.) - reserved(if) operator((!)ident(_RunTimers)operator((\)\)) - reserved(break)operator(;) - reserved(if) operator(()ident(GetQueuedCompletionStatus) operator(()ident(Iocp)operator(,) operator(&)ident(nBytes)operator(,) operator(&)ident(nCompletionKey)operator(,) operator(&)ident(Overlapped)operator(,) integer(1000)operator(\)\)) operator({) - operator(}) - ident(cerr) operator(<<) string<delimiter(")content(+)delimiter(")>operator(;) - operator(}) reserved(while) operator((!)ident(gTerminateSignalReceived)operator(\);) - - - comment(/* - while (true\) { - gCurrentLoopTime = time(NULL\); - if (!_RunTimers(\)\) - break; - _AddNewDescriptors(\); - if (!_RunOnce(\)\) - break; - if (gTerminateSignalReceived\) - break; - } - */) - - ident(HookControlC) operator(()pre_constant(false)operator(\);) -operator(}) - - -comment(/************************** -EventMachine_t::_RunTimers -**************************/) - -pre_type(bool) ident(EventMachine_t)operator(::)ident(_RunTimers)operator((\)) -operator({) - comment(// These are caller-defined timer handlers.) - comment(// Return T/F to indicate whether we should continue the main loop.) - comment(// We rely on the fact that multimaps sort by their keys to avoid) - comment(// inspecting the whole list every time we come here.) - comment(// Just keep inspecting and processing the list head until we hit) - comment(// one that hasn't expired yet.) - - reserved(while) operator(()pre_constant(true)operator(\)) operator({) - ident(multimap)operator(<)ident(time_t)operator(,)ident(Timer_t)operator(>::)ident(iterator) ident(i) operator(=) ident(Timers)operator(.)ident(begin)operator((\);) - reserved(if) operator(()ident(i) operator(==) ident(Timers)operator(.)ident(end)operator((\)\)) - reserved(break)operator(;) - reserved(if) operator(()ident(i)operator(->)ident(first) operator(>) ident(gCurrentLoopTime)operator(\)) - reserved(break)operator(;) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)) operator(()string<delimiter(")delimiter(")>operator(,) ident(EM_TIMER_FIRED)operator(,) ident(i)operator(->)ident(second)operator(.)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(i)operator(->)ident(second)operator(.)ident(GetBinding)operator((\))operator(.)ident(length)operator((\)\);) - ident(Timers)operator(.)ident(erase) operator(()ident(i)operator(\);) - operator(}) - reserved(return) pre_constant(true)operator(;) -operator(}) - - -comment(/*********************************** -EventMachine_t::InstallOneshotTimer -***********************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(InstallOneshotTimer) operator(()pre_type(int) ident(seconds)operator(\)) -operator({) - reserved(if) operator(()ident(Timers)operator(.)ident(size)operator((\)) operator(>) ident(MaxOutstandingTimers)operator(\)) - reserved(return) pre_constant(false)operator(;) - comment(// Don't use the global loop-time variable here, because we might) - comment(// get called before the main event machine is running.) - - ident(Timer_t) ident(t)operator(;) - ident(Timers)operator(.)ident(insert) operator(()ident(make_pair) operator(()ident(time)operator(()pre_constant(NULL)operator(\)) operator(+) ident(seconds)operator(,) ident(t)operator(\)\);) - reserved(return) ident(t)operator(.)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) -operator(}) - - -comment(/********************************** -EventMachine_t::OpenDatagramSocket -**********************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(OpenDatagramSocket) operator(()directive(const) pre_type(char) operator(*)ident(address)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - ident(cerr) operator(<<) string<delimiter(")content(OPEN DATAGRAM SOCKET)char(\\n)delimiter(")>operator(;) - reserved(return) string<delimiter(")content(Unimplemented)delimiter(")>operator(;) -operator(}) - - -comment(/******************************* -EventMachine_t::CreateTcpServer -*******************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(CreateTcpServer) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - comment(/* Create a TCP-acceptor (server\) socket and add it to the event machine. - * Return the binding of the new acceptor to the caller. - * This binding will be referenced when the new acceptor sends events - * to indicate accepted connections. - */) - - directive(const) pre_type(char) operator(*)ident(output_binding) operator(=) pre_constant(NULL)operator(;) - - reserved(struct) ident(sockaddr_in) ident(sin)operator(;) - - ident(SOCKET) ident(sd_accept) operator(=) ident(socket) operator(()ident(AF_INET)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd_accept) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - reserved(goto) ident(fail)operator(;) - operator(}) - - ident(memset) operator((&)ident(sin)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(sin)operator(\)\);) - ident(sin)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(INADDR_ANY)operator(;) - ident(sin)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - - reserved(if) operator(()ident(server) operator(&&) operator(*)ident(server)operator(\)) operator({) - ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(inet_addr) operator(()ident(server)operator(\);) - reserved(if) operator(()ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(==) ident(INADDR_NONE)operator(\)) operator({) - ident(hostent) operator(*)ident(hp) operator(=) ident(gethostbyname) operator(()ident(server)operator(\);) - reserved(if) operator(()ident(hp) operator(==) pre_constant(NULL)operator(\)) operator({) - comment(//__warning ("hostname not resolved: ", server\);) - reserved(goto) ident(fail)operator(;) - operator(}) - ident(sin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) operator((()ident(in_addr)operator(*\)()ident(hp)operator(->)ident(h_addr)operator(\)\)->)ident(s_addr)operator(;) - operator(}) - operator(}) - - - comment(// No need to set reuseaddr on Windows.) - - - reserved(if) operator(()ident(bind) operator(()ident(sd_accept)operator(,) operator(()reserved(struct) ident(sockaddr)operator(*\)&)ident(sin)operator(,) reserved(sizeof)operator(()ident(sin)operator(\)\)\)) operator({) - comment(//__warning ("binding failed"\);) - reserved(goto) ident(fail)operator(;) - operator(}) - - reserved(if) operator(()ident(listen) operator(()ident(sd_accept)operator(,) integer(100)operator(\)\)) operator({) - comment(//__warning ("listen failed"\);) - reserved(goto) ident(fail)operator(;) - operator(}) - - operator({) comment(// Looking good.) - ident(AcceptorDescriptor) operator(*)ident(ad) operator(=) reserved(new) ident(AcceptorDescriptor) operator(()local_variable(this)operator(,) ident(sd_accept)operator(\);) - reserved(if) operator((!)ident(ad)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to allocate acceptor)delimiter(")>operator(\);) - ident(Add) operator(()ident(ad)operator(\);) - ident(output_binding) operator(=) ident(ad)operator(->)ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\);) - - ident(CreateIoCompletionPort) operator((()ident(HANDLE)operator(\))ident(sd_accept)operator(,) ident(Iocp)operator(,) pre_constant(NULL)operator(,) integer(0)operator(\);) - ident(SOCKET) ident(sd) operator(=) ident(socket) operator(()ident(AF_INET)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - ident(CreateIoCompletionPort) operator((()ident(HANDLE)operator(\))ident(sd)operator(,) ident(Iocp)operator(,) pre_constant(NULL)operator(,) integer(0)operator(\);) - ident(AcceptEx) operator(()ident(sd_accept)operator(,) ident(sd)operator(,) - operator(}) - - reserved(return) ident(output_binding)operator(;) - - label(fail:) - reserved(if) operator(()ident(sd_accept) operator(!=) ident(INVALID_SOCKET)operator(\)) - ident(closesocket) operator(()ident(sd_accept)operator(\);) - reserved(return) pre_constant(NULL)operator(;) -operator(}) - - -comment(/******************************* -EventMachine_t::ConnectToServer -*******************************/) - -directive(const) pre_type(char) operator(*)ident(EventMachine_t)operator(::)ident(ConnectToServer) operator(()directive(const) pre_type(char) operator(*)ident(server)operator(,) pre_type(int) ident(port)operator(\)) -operator({) - reserved(if) operator((!)ident(server) operator(||) operator(!*)ident(server) operator(||) operator(!)ident(port)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - ident(sockaddr_in) ident(pin)operator(;) - pre_type(unsigned) pre_type(long) ident(HostAddr)operator(;) - - ident(HostAddr) operator(=) ident(inet_addr) operator(()ident(server)operator(\);) - reserved(if) operator(()ident(HostAddr) operator(==) ident(INADDR_NONE)operator(\)) operator({) - ident(hostent) operator(*)ident(hp) operator(=) ident(gethostbyname) operator(()ident(server)operator(\);) - reserved(if) operator((!)ident(hp)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - ident(HostAddr) operator(=) operator((()ident(in_addr)operator(*\)()ident(hp)operator(->)ident(h_addr)operator(\)\)->)ident(s_addr)operator(;) - operator(}) - - ident(memset) operator((&)ident(pin)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(pin)operator(\)\);) - ident(pin)operator(.)ident(sin_family) operator(=) ident(AF_INET)operator(;) - ident(pin)operator(.)ident(sin_addr)operator(.)ident(s_addr) operator(=) ident(HostAddr)operator(;) - ident(pin)operator(.)ident(sin_port) operator(=) ident(htons) operator(()ident(port)operator(\);) - - pre_type(int) ident(sd) operator(=) ident(socket) operator(()ident(AF_INET)operator(,) ident(SOCK_STREAM)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) - reserved(return) pre_constant(NULL)operator(;) - - - ident(LPOVERLAPPED) ident(olap) operator(=) operator(()ident(LPOVERLAPPED)operator(\)) ident(calloc) operator(()integer(1)operator(,) reserved(sizeof) operator(()ident(OVERLAPPED)operator(\)\);) - ident(cerr) operator(<<) string<delimiter(")content(I'm dying now)char(\\n)delimiter(")>operator(;) - reserved(throw) ident(runtime_error) operator(()string<delimiter(")content(UNIMPLEMENTED!!!)char(\\n)delimiter(")>operator(\);) - -operator(}) - - - -comment(/******************* -EventMachine_t::Add -*******************/) - -directive(void) ident(EventMachine_t)operator(::)ident(Add) operator(()ident(EventableDescriptor) operator(*)ident(ed)operator(\)) -operator({) - ident(cerr) operator(<<) string<delimiter(")content(ADD)char(\\n)delimiter(")>operator(;) -operator(}) - - - -preprocessor(#endif) comment(// OS_WIN32) - -comment(/***************************************************************************** - -$Id$ - -File: epoll.cpp -Date: 06Jun07 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - -preprocessor(#ifdef) ident(HAVE_EPOLL) - -preprocessor(#include) include("project.h") - -preprocessor(#endif) comment(// HAVE_EPOLL) - -comment(/***************************************************************************** - -$Id: mapper.cpp 4527 2007-07-04 10:21:34Z francis $ - -File: mapper.cpp -Date: 02Jul07 - -Copyright (C\) 2007 by Francis Cianfrocca. All Rights Reserved. -Gmail: garbagecat10 - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - -comment(//////////////////////////////////////////////////////////////////////) -comment(// UNIX implementation) -comment(//////////////////////////////////////////////////////////////////////) - - -preprocessor(#ifdef) ident(OS_UNIX) - -preprocessor(#include) include(<sys/types.h>) -preprocessor(#include) include(<sys/stat.h>) -preprocessor(#include) include(<sys/mman.h>) -preprocessor(#include) include(<fcntl.h>) -preprocessor(#include) include(<errno.h>) - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include("unistd.h") -preprocessor(#include) include(<string>) -preprocessor(#include) include(<cstring>) -preprocessor(#include) include(<stdexcept>) -directive(using) reserved(namespace) ident(std)operator(;) - -preprocessor(#include) include("mapper.h") - -comment(/****************** -Mapper_t::Mapper_t -******************/) - -ident(Mapper_t)operator(::)ident(Mapper_t) operator(()directive(const) pre_type(string) operator(&)ident(filename)operator(\)) -operator({) - comment(/* We ASSUME we can open the file. - * (More precisely, we assume someone else checked before we got here.\) - */) - - ident(Fd) operator(=) ident(open) operator(()ident(filename)operator(.)ident(c_str)operator((\),) ident(O_RDONLY)operator(\);) - reserved(if) operator(()ident(Fd) operator(<) integer(0)operator(\)) - reserved(throw) ident(runtime_error) operator(()ident(strerror) operator(()ident(errno)operator(\)\);) - - reserved(struct) ident(stat) ident(st)operator(;) - reserved(if) operator(()ident(fstat) operator(()ident(Fd)operator(,) operator(&)ident(st)operator(\)\)) - reserved(throw) ident(runtime_error) operator(()ident(strerror) operator(()ident(errno)operator(\)\);) - ident(FileSize) operator(=) ident(st)operator(.)ident(st_size)operator(;) - - ident(MapPoint) operator(=) operator(()directive(const) pre_type(char)operator(*\)) ident(mmap) operator(()integer(0)operator(,) ident(FileSize)operator(,) ident(PROT_READ)operator(,) ident(MAP_SHARED)operator(,) ident(Fd)operator(,) integer(0)operator(\);) - reserved(if) operator(()ident(MapPoint) operator(==) ident(MAP_FAILED)operator(\)) - reserved(throw) ident(runtime_error) operator(()ident(strerror) operator(()ident(errno)operator(\)\);) -operator(}) - - -comment(/******************* -Mapper_t::~Mapper_t -*******************/) - -ident(Mapper_t)operator(::~)ident(Mapper_t)operator((\)) -operator({) - ident(Close)operator((\);) -operator(}) - - -comment(/*************** -Mapper_t::Close -***************/) - -directive(void) ident(Mapper_t)operator(::)ident(Close)operator((\)) -operator({) - comment(// Can be called multiple times.) - comment(// Calls to GetChunk are invalid after a call to Close.) - reserved(if) operator(()ident(MapPoint)operator(\)) operator({) - ident(munmap) operator((()directive(void)operator(*\))ident(MapPoint)operator(,) ident(FileSize)operator(\);) - ident(MapPoint) operator(=) pre_constant(NULL)operator(;) - operator(}) - reserved(if) operator(()ident(Fd) operator(>=) integer(0)operator(\)) operator({) - ident(close) operator(()ident(Fd)operator(\);) - ident(Fd) operator(=) operator(-)integer(1)operator(;) - operator(}) -operator(}) - -comment(/****************** -Mapper_t::GetChunk -******************/) - -directive(const) pre_type(char) operator(*)ident(Mapper_t)operator(::)ident(GetChunk) operator(()pre_type(unsigned) ident(start)operator(\)) -operator({) - reserved(return) ident(MapPoint) operator(+) ident(start)operator(;) -operator(}) - - - -preprocessor(#endif) comment(// OS_UNIX) - - -comment(//////////////////////////////////////////////////////////////////////) -comment(// WINDOWS implementation) -comment(//////////////////////////////////////////////////////////////////////) - -preprocessor(#ifdef) ident(OS_WIN32) - -preprocessor(#include) include(<windows.h>) - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<string>) -preprocessor(#include) include(<stdexcept>) -directive(using) reserved(namespace) ident(std)operator(;) - -preprocessor(#include) include("mapper.h") - -comment(/****************** -Mapper_t::Mapper_t -******************/) - -ident(Mapper_t)operator(::)ident(Mapper_t) operator(()directive(const) pre_type(string) operator(&)ident(filename)operator(\)) -operator({) - comment(/* We ASSUME we can open the file. - * (More precisely, we assume someone else checked before we got here.\) - */) - - ident(hFile) operator(=) ident(INVALID_HANDLE_VALUE)operator(;) - ident(hMapping) operator(=) pre_constant(NULL)operator(;) - ident(MapPoint) operator(=) pre_constant(NULL)operator(;) - ident(FileSize) operator(=) integer(0)operator(;) - - ident(hFile) operator(=) ident(CreateFile) operator(()ident(filename)operator(.)ident(c_str)operator((\),) ident(GENERIC_READ)operator(|)ident(GENERIC_WRITE)operator(,) ident(FILE_SHARE_DELETE)operator(|)ident(FILE_SHARE_READ)operator(|)ident(FILE_SHARE_WRITE)operator(,) pre_constant(NULL)operator(,) ident(OPEN_EXISTING)operator(,) ident(FILE_ATTRIBUTE_NORMAL)operator(,) pre_constant(NULL)operator(\);) - - reserved(if) operator(()ident(hFile) operator(==) ident(INVALID_HANDLE_VALUE)operator(\)) - reserved(throw) ident(runtime_error) operator(()string<delimiter(")content(File not found)delimiter(")>operator(\);) - - ident(BY_HANDLE_FILE_INFORMATION) ident(i)operator(;) - reserved(if) operator(()ident(GetFileInformationByHandle) operator(()ident(hFile)operator(,) operator(&)ident(i)operator(\)\)) - ident(FileSize) operator(=) ident(i)operator(.)ident(nFileSizeLow)operator(;) - - ident(hMapping) operator(=) ident(CreateFileMapping) operator(()ident(hFile)operator(,) pre_constant(NULL)operator(,) ident(PAGE_READWRITE)operator(,) integer(0)operator(,) integer(0)operator(,) pre_constant(NULL)operator(\);) - reserved(if) operator((!)ident(hMapping)operator(\)) - reserved(throw) ident(runtime_error) operator(()string<delimiter(")content(File not mapped)delimiter(")>operator(\);) - - ident(MapPoint) operator(=) operator(()directive(const) pre_type(char)operator(*\)) ident(MapViewOfFile) operator(()ident(hMapping)operator(,) ident(FILE_MAP_WRITE)operator(,) integer(0)operator(,) integer(0)operator(,) integer(0)operator(\);) - reserved(if) operator((!)ident(MapPoint)operator(\)) - reserved(throw) ident(runtime_error) operator(()string<delimiter(")content(Mappoint not read)delimiter(")>operator(\);) -operator(}) - - -comment(/******************* -Mapper_t::~Mapper_t -*******************/) - -ident(Mapper_t)operator(::~)ident(Mapper_t)operator((\)) -operator({) - ident(Close)operator((\);) -operator(}) - -comment(/*************** -Mapper_t::Close -***************/) - -directive(void) ident(Mapper_t)operator(::)ident(Close)operator((\)) -operator({) - comment(// Can be called multiple times.) - comment(// Calls to GetChunk are invalid after a call to Close.) - reserved(if) operator(()ident(MapPoint)operator(\)) operator({) - ident(UnmapViewOfFile) operator(()ident(MapPoint)operator(\);) - ident(MapPoint) operator(=) pre_constant(NULL)operator(;) - operator(}) - reserved(if) operator(()ident(hMapping) operator(!=) pre_constant(NULL)operator(\)) operator({) - ident(CloseHandle) operator(()ident(hMapping)operator(\);) - ident(hMapping) operator(=) pre_constant(NULL)operator(;) - operator(}) - reserved(if) operator(()ident(hFile) operator(!=) ident(INVALID_HANDLE_VALUE)operator(\)) operator({) - ident(CloseHandle) operator(()ident(hFile)operator(\);) - ident(hMapping) operator(=) ident(INVALID_HANDLE_VALUE)operator(;) - operator(}) -operator(}) - - -comment(/****************** -Mapper_t::GetChunk -******************/) - -directive(const) pre_type(char) operator(*)ident(Mapper_t)operator(::)ident(GetChunk) operator(()pre_type(unsigned) ident(start)operator(\)) -operator({) - reserved(return) ident(MapPoint) operator(+) ident(start)operator(;) -operator(}) - - - -preprocessor(#endif) comment(// OS_WINDOWS) -comment(/***************************************************************************** - -$Id: rubymain.cpp 4529 2007-07-04 11:32:22Z francis $ - -File: rubymain.cpp -Date: 02Jul07 - -Copyright (C\) 2007 by Francis Cianfrocca. All Rights Reserved. -Gmail: garbagecat10 - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<stdexcept>) -directive(using) reserved(namespace) ident(std)operator(;) - -preprocessor(#include) include(<ruby.h>) -preprocessor(#include) include("mapper.h") - -directive(static) ident(VALUE) ident(EmModule)operator(;) -directive(static) ident(VALUE) ident(FastFileReader)operator(;) -directive(static) ident(VALUE) ident(Mapper)operator(;) - - - -comment(/********* -mapper_dt -*********/) - -directive(static) directive(void) ident(mapper_dt) operator(()directive(void) operator(*)ident(ptr)operator(\)) -operator({) - reserved(if) operator(()ident(ptr)operator(\)) - reserved(delete) operator(()ident(Mapper_t)operator(*\)) ident(ptr)operator(;) -operator(}) - -comment(/********** -mapper_new -**********/) - -directive(static) ident(VALUE) ident(mapper_new) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(filename)operator(\)) -operator({) - ident(Mapper_t) operator(*)ident(m) operator(=) reserved(new) ident(Mapper_t) operator(()ident(StringValuePtr) operator(()ident(filename)operator(\)\);) - reserved(if) operator((!)ident(m)operator(\)) - ident(rb_raise) operator(()ident(rb_eException)operator(,) string<delimiter(")content(No Mapper Object)delimiter(")>operator(\);) - ident(VALUE) ident(v) operator(=) ident(Data_Wrap_Struct) operator(()ident(Mapper)operator(,) integer(0)operator(,) ident(mapper_dt)operator(,) operator(()directive(void)operator(*\))ident(m)operator(\);) - reserved(return) ident(v)operator(;) -operator(}) - - -comment(/**************** -mapper_get_chunk -****************/) - -directive(static) ident(VALUE) ident(mapper_get_chunk) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(start)operator(,) ident(VALUE) ident(length)operator(\)) -operator({) - ident(Mapper_t) operator(*)ident(m) operator(=) pre_constant(NULL)operator(;) - ident(Data_Get_Struct) operator(()ident(self)operator(,) ident(Mapper_t)operator(,) ident(m)operator(\);) - reserved(if) operator((!)ident(m)operator(\)) - ident(rb_raise) operator(()ident(rb_eException)operator(,) string<delimiter(")content(No Mapper Object)delimiter(")>operator(\);) - - comment(// TODO, what if some moron sends us a negative start value?) - pre_type(unsigned) ident(_start) operator(=) ident(NUM2INT) operator(()ident(start)operator(\);) - pre_type(unsigned) ident(_length) operator(=) ident(NUM2INT) operator(()ident(length)operator(\);) - reserved(if) operator((()ident(_start) operator(+) ident(_length)operator(\)) operator(>) ident(m)operator(->)ident(GetFileSize)operator((\)\)) - ident(rb_raise) operator(()ident(rb_eException)operator(,) string<delimiter(")content(Mapper Range Error)delimiter(")>operator(\);) - - directive(const) pre_type(char) operator(*)ident(chunk) operator(=) ident(m)operator(->)ident(GetChunk) operator(()ident(_start)operator(\);) - reserved(if) operator((!)ident(chunk)operator(\)) - ident(rb_raise) operator(()ident(rb_eException)operator(,) string<delimiter(")content(No Mapper Chunk)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new) operator(()ident(chunk)operator(,) ident(_length)operator(\);) -operator(}) - -comment(/************ -mapper_close -************/) - -directive(static) ident(VALUE) ident(mapper_close) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(Mapper_t) operator(*)ident(m) operator(=) pre_constant(NULL)operator(;) - ident(Data_Get_Struct) operator(()ident(self)operator(,) ident(Mapper_t)operator(,) ident(m)operator(\);) - reserved(if) operator((!)ident(m)operator(\)) - ident(rb_raise) operator(()ident(rb_eException)operator(,) string<delimiter(")content(No Mapper Object)delimiter(")>operator(\);) - ident(m)operator(->)ident(Close)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/*********** -mapper_size -***********/) - -directive(static) ident(VALUE) ident(mapper_size) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(Mapper_t) operator(*)ident(m) operator(=) pre_constant(NULL)operator(;) - ident(Data_Get_Struct) operator(()ident(self)operator(,) ident(Mapper_t)operator(,) ident(m)operator(\);) - reserved(if) operator((!)ident(m)operator(\)) - ident(rb_raise) operator(()ident(rb_eException)operator(,) string<delimiter(")content(No Mapper Object)delimiter(")>operator(\);) - reserved(return) ident(INT2NUM) operator(()ident(m)operator(->)ident(GetFileSize)operator((\)\);) -operator(}) - - -comment(/********************** -Init_fastfilereaderext -**********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(Init_fastfilereaderext)operator((\)) -operator({) - ident(EmModule) operator(=) ident(rb_define_module) operator(()string<delimiter(")content(EventMachine)delimiter(")>operator(\);) - ident(FastFileReader) operator(=) ident(rb_define_class_under) operator(()ident(EmModule)operator(,) string<delimiter(")content(FastFileReader)delimiter(")>operator(,) ident(rb_cObject)operator(\);) - ident(Mapper) operator(=) ident(rb_define_class_under) operator(()ident(FastFileReader)operator(,) string<delimiter(")content(Mapper)delimiter(")>operator(,) ident(rb_cObject)operator(\);) - - ident(rb_define_module_function) operator(()ident(Mapper)operator(,) string<delimiter(")content(new)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(mapper_new)operator(,) integer(1)operator(\);) - ident(rb_define_method) operator(()ident(Mapper)operator(,) string<delimiter(")content(size)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(mapper_size)operator(,) integer(0)operator(\);) - ident(rb_define_method) operator(()ident(Mapper)operator(,) string<delimiter(")content(close)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(mapper_close)operator(,) integer(0)operator(\);) - ident(rb_define_method) operator(()ident(Mapper)operator(,) string<delimiter(")content(get_chunk)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(mapper_get_chunk)operator(,) integer(2)operator(\);) -operator(}) - - - -comment(/***************************************************************************** - -$Id$ - -File: files.cpp -Date: 26Aug06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - - -comment(/****************************************** -FileStreamDescriptor::FileStreamDescriptor -******************************************/) - -ident(FileStreamDescriptor)operator(::)ident(FileStreamDescriptor) operator(()pre_type(int) ident(fd)operator(,) ident(EventMachine_t) operator(*)ident(em)operator(\):) - ident(EventableDescriptor) operator(()ident(fd)operator(,) ident(em)operator(\),) - ident(OutboundDataSize) operator(()integer(0)operator(\)) -operator({) -ident(cerr) operator(<<) string<delimiter(")content(#####)delimiter(")>operator(;) -operator(}) - - -comment(/******************************************* -FileStreamDescriptor::~FileStreamDescriptor -*******************************************/) - -ident(FileStreamDescriptor)operator(::~)ident(FileStreamDescriptor)operator((\)) -operator({) - comment(// Run down any stranded outbound data.) - reserved(for) operator(()ident(size_t) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(OutboundPages)operator(.)ident(size)operator((\);) ident(i)operator(++\)) - ident(OutboundPages)operator([)ident(i)operator(])operator(.)ident(Free)operator((\);) -operator(}) - - -comment(/************************** -FileStreamDescriptor::Read -**************************/) - -directive(void) ident(FileStreamDescriptor)operator(::)ident(Read)operator((\)) -operator({) -operator(}) - -comment(/*************************** -FileStreamDescriptor::Write -***************************/) - -directive(void) ident(FileStreamDescriptor)operator(::)ident(Write)operator((\)) -operator({) -operator(}) - - -comment(/******************************* -FileStreamDescriptor::Heartbeat -*******************************/) - -directive(void) ident(FileStreamDescriptor)operator(::)ident(Heartbeat)operator((\)) -operator({) -operator(}) - - -comment(/*********************************** -FileStreamDescriptor::SelectForRead -***********************************/) - -pre_type(bool) ident(FileStreamDescriptor)operator(::)ident(SelectForRead)operator((\)) -operator({) - ident(cerr) operator(<<) string<delimiter(")content(R?)delimiter(")>operator(;) - reserved(return) pre_constant(false)operator(;) -operator(}) - - -comment(/************************************ -FileStreamDescriptor::SelectForWrite -************************************/) - -pre_type(bool) ident(FileStreamDescriptor)operator(::)ident(SelectForWrite)operator((\)) -operator({) - ident(cerr) operator(<<) string<delimiter(")content(W?)delimiter(")>operator(;) - reserved(return) pre_constant(false)operator(;) -operator(}) - - -comment(/***************************************************************************** - -$Id$ - -File: kb.cpp -Date: 24Aug07 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - - -comment(/************************************** -KeyboardDescriptor::KeyboardDescriptor -**************************************/) - -ident(KeyboardDescriptor)operator(::)ident(KeyboardDescriptor) operator(()ident(EventMachine_t) operator(*)ident(parent_em)operator(\):) - ident(EventableDescriptor) operator(()integer(0)operator(,) ident(parent_em)operator(\),) - ident(bReadAttemptedAfterClose) operator(()pre_constant(false)operator(\),) - ident(LastIo) operator(()ident(gCurrentLoopTime)operator(\),) - ident(InactivityTimeout) operator(()integer(0)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLIN)operator(;) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/*************************************** -KeyboardDescriptor::~KeyboardDescriptor -***************************************/) - -ident(KeyboardDescriptor)operator(::~)ident(KeyboardDescriptor)operator((\)) -operator({) -operator(}) - - -comment(/************************* -KeyboardDescriptor::Write -*************************/) - -directive(void) ident(KeyboardDescriptor)operator(::)ident(Write)operator((\)) -operator({) - comment(// Why are we here?) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad code path in keyboard handler)delimiter(")>operator(\);) -operator(}) - - -comment(/***************************** -KeyboardDescriptor::Heartbeat -*****************************/) - -directive(void) ident(KeyboardDescriptor)operator(::)ident(Heartbeat)operator((\)) -operator({) - comment(// no-op) -operator(}) - - -comment(/************************ -KeyboardDescriptor::Read -************************/) - -directive(void) ident(KeyboardDescriptor)operator(::)ident(Read)operator((\)) -operator({) - pre_type(char) ident(c)operator(;) - ident(read) operator(()ident(GetSocket)operator((\),) operator(&)ident(c)operator(,) integer(1)operator(\);) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_READ)operator(,) operator(&)ident(c)operator(,) integer(1)operator(\);) -operator(}) - - - - -comment(#if 0 -/****************************** -PipeDescriptor::PipeDescriptor -******************************/ - -PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em\): - EventableDescriptor (fd, parent_em\), - bReadAttemptedAfterClose (false\), - LastIo (gCurrentLoopTime\), - InactivityTimeout (0\), - OutboundDataSize (0\), - SubprocessPid (subpid\) -{ - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif -} - - -/******************************* -PipeDescriptor::~PipeDescriptor -*******************************/ - -PipeDescriptor::~PipeDescriptor(\) -{ - // Run down any stranded outbound data. - for (size_t i=0; i < OutboundPages.size(\); i++\) - OutboundPages[i].Free(\); - - /* As a virtual destructor, we come here before the base-class - * destructor that closes our file-descriptor. - * We have to make sure the subprocess goes down (if it's not - * already down\) and we have to reap the zombie. - * - * This implementation is PROVISIONAL and will surely be improved. - * The intention here is that we never block, hence the highly - * undesirable sleeps. But if we can't reap the subprocess even - * after sending it SIGKILL, then something is wrong and we - * throw a fatal exception, which is also not something we should - * be doing. - * - * Eventually the right thing to do will be to have the reactor - * core respond to SIGCHLD by chaining a handler on top of the - * one Ruby may have installed, and dealing with a list of dead - * children that are pending cleanup. - * - * Since we want to have a signal processor integrated into the - * client-visible API, let's wait until that is done before cleaning - * this up. - */ - - struct timespec req = {0, 10000000}; - kill (SubprocessPid, SIGTERM\); - nanosleep (&req, NULL\); - if (waitpid (SubprocessPid, NULL, WNOHANG\) == 0\) { - kill (SubprocessPid, SIGKILL\); - nanosleep (&req, NULL\); - if (waitpid (SubprocessPid, NULL, WNOHANG\) == 0\) - throw std::runtime_error ("unable to reap subprocess"\); - } -} - - - -/******************** -PipeDescriptor::Read -********************/ - -void PipeDescriptor::Read(\) -{ - int sd = GetSocket(\); - if (sd == INVALID_SOCKET\) { - assert (!bReadAttemptedAfterClose\); - bReadAttemptedAfterClose = true; - return; - } - - LastIo = gCurrentLoopTime; - - int total_bytes_read = 0; - char readbuffer [16 * 1024]; - - for (int i=0; i < 10; i++\) { - // Don't read just one buffer and then move on. This is faster - // if there is a lot of incoming. - // But don't read indefinitely. Give other sockets a chance to run. - // NOTICE, we're reading one less than the buffer size. - // That's so we can put a guard byte at the end of what we send - // to user code. - // Use read instead of recv, which on Linux gives a "socket operation - // on nonsocket" error. - - - int r = read (sd, readbuffer, sizeof(readbuffer\) - 1\); - //cerr << "<R:" << r << ">"; - - if (r > 0\) { - total_bytes_read += r; - LastRead = gCurrentLoopTime; - - // Add a null-terminator at the the end of the buffer - // that we will send to the callback. - // DO NOT EVER CHANGE THIS. We want to explicitly allow users - // to be able to depend on this behavior, so they will have - // the option to do some things faster. Additionally it's - // a security guard against buffer overflows. - readbuffer [r] = 0; - if (EventCallback\) - (*EventCallback\)(GetBinding(\).c_str(\), EM_CONNECTION_READ, readbuffer, r\); - } - else if (r == 0\) { - break; - } - else { - // Basically a would-block, meaning we've read everything there is to read. - break; - } - - } - - - if (total_bytes_read == 0\) { - // If we read no data on a socket that selected readable, - // it generally means the other end closed the connection gracefully. - ScheduleClose (false\); - //bCloseNow = true; - } - -} - -/********************* -PipeDescriptor::Write -*********************/ - -void PipeDescriptor::Write(\) -{ - int sd = GetSocket(\); - assert (sd != INVALID_SOCKET\); - - LastIo = gCurrentLoopTime; - char output_buffer [16 * 1024]; - size_t nbytes = 0; - - while ((OutboundPages.size(\) > 0\) && (nbytes < sizeof(output_buffer\)\)\) { - OutboundPage *op = &(OutboundPages[0]\); - if ((nbytes + op->Length - op->Offset\) < sizeof (output_buffer\)\) { - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset\); - nbytes += (op->Length - op->Offset\); - op->Free(\); - OutboundPages.pop_front(\); - } - else { - int len = sizeof(output_buffer\) - nbytes; - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len\); - op->Offset += len; - nbytes += len; - } - } - - // We should never have gotten here if there were no data to write, - // so assert that as a sanity check. - // Don't bother to make sure nbytes is less than output_buffer because - // if it were we probably would have crashed already. - assert (nbytes > 0\); - - assert (GetSocket(\) != INVALID_SOCKET\); - int bytes_written = write (GetSocket(\), output_buffer, nbytes\); - - if (bytes_written > 0\) { - OutboundDataSize -= bytes_written; - if ((size_t\)bytes_written < nbytes\) { - int len = nbytes - bytes_written; - char *buffer = (char*\) malloc (len + 1\); - if (!buffer\) - throw std::runtime_error ("bad alloc throwing back data"\); - memcpy (buffer, output_buffer + bytes_written, len\); - buffer [len] = 0; - OutboundPages.push_front (OutboundPage (buffer, len\)\); - } - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | (SelectForWrite(\) ? EPOLLOUT : 0\)\); - assert (MyEventMachine\); - MyEventMachine->Modify (this\); - #endif - } - else { - #ifdef OS_UNIX - if ((errno != EINPROGRESS\) && (errno != EWOULDBLOCK\) && (errno != EINTR\)\) - #endif - #ifdef OS_WIN32 - if ((errno != WSAEINPROGRESS\) && (errno != WSAEWOULDBLOCK\)\) - #endif - Close(\); - } -} - - -/************************* -PipeDescriptor::Heartbeat -*************************/ - -void PipeDescriptor::Heartbeat(\) -{ - // If an inactivity timeout is defined, then check for it. - if (InactivityTimeout && ((gCurrentLoopTime - LastIo\) >= InactivityTimeout\)\) - ScheduleClose (false\); - //bCloseNow = true; -} - - -/***************************** -PipeDescriptor::SelectForRead -*****************************/ - -bool PipeDescriptor::SelectForRead(\) -{ - /* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */ - return true; -} - -/****************************** -PipeDescriptor::SelectForWrite -******************************/ - -bool PipeDescriptor::SelectForWrite(\) -{ - /* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */ - return (GetOutboundDataSize(\) > 0\); -} - - - - -/******************************** -PipeDescriptor::SendOutboundData -********************************/ - -int PipeDescriptor::SendOutboundData (const char *data, int length\) -{ - //if (bCloseNow || bCloseAfterWriting\) - if (IsCloseScheduled(\)\) - return 0; - - if (!data && (length > 0\)\) - throw std::runtime_error ("bad outbound data"\); - char *buffer = (char *\) malloc (length + 1\); - if (!buffer\) - throw std::runtime_error ("no allocation for outbound data"\); - memcpy (buffer, data, length\); - buffer [length] = 0; - OutboundPages.push_back (OutboundPage (buffer, length\)\); - OutboundDataSize += length; - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | EPOLLOUT\); - assert (MyEventMachine\); - MyEventMachine->Modify (this\); - #endif - return length; -} - -/******************************** -PipeDescriptor::GetSubprocessPid -********************************/ - -bool PipeDescriptor::GetSubprocessPid (pid_t *pid\) -{ - bool ok = false; - if (pid && (SubprocessPid > 0\)\) { - *pid = SubprocessPid; - ok = true; - } - return ok; -} - -#endif ) - -comment(/***************************************************************************** - -$Id$ - -File: page.cpp -Date: 30Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - -preprocessor(#include) include("project.h") - - -comment(/****************** -PageList::PageList -******************/) - -ident(PageList)operator(::)ident(PageList)operator((\)) -operator({) -operator(}) - - -comment(/******************* -PageList::~PageList -*******************/) - -ident(PageList)operator(::~)ident(PageList)operator((\)) -operator({) - reserved(while) operator(()ident(HasPages)operator((\)\)) - ident(PopFront)operator((\);) -operator(}) - - -comment(/*************** -PageList::Front -***************/) - -directive(void) ident(PageList)operator(::)ident(Front) operator(()directive(const) pre_type(char) operator(**)ident(page)operator(,) pre_type(int) operator(*)ident(length)operator(\)) -operator({) - ident(assert) operator(()ident(page) operator(&&) ident(length)operator(\);) - - reserved(if) operator(()ident(HasPages)operator((\)\)) operator({) - ident(Page) ident(p) operator(=) ident(Pages)operator(.)ident(front)operator((\);) - operator(*)ident(page) operator(=) ident(p)operator(.)ident(Buffer)operator(;) - operator(*)ident(length) operator(=) ident(p)operator(.)ident(Size)operator(;) - operator(}) - reserved(else) operator({) - operator(*)ident(page) operator(=) pre_constant(NULL)operator(;) - operator(*)ident(length) operator(=) integer(0)operator(;) - operator(}) -operator(}) - - -comment(/****************** -PageList::PopFront -******************/) - -directive(void) ident(PageList)operator(::)ident(PopFront)operator((\)) -operator({) - reserved(if) operator(()ident(HasPages)operator((\)\)) operator({) - ident(Page) ident(p) operator(=) ident(Pages)operator(.)ident(front)operator((\);) - ident(Pages)operator(.)ident(pop_front)operator((\);) - reserved(if) operator(()ident(p)operator(.)ident(Buffer)operator(\)) - ident(free) operator((()directive(void)operator(*\))ident(p)operator(.)ident(Buffer)operator(\);) - operator(}) -operator(}) - - -comment(/****************** -PageList::HasPages -******************/) - -pre_type(bool) ident(PageList)operator(::)ident(HasPages)operator((\)) -operator({) - reserved(return) operator(()ident(Pages)operator(.)ident(size)operator((\)) operator(>) integer(0)operator(\)) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(;) -operator(}) - - -comment(/************** -PageList::Push -**************/) - -directive(void) ident(PageList)operator(::)ident(Push) operator(()directive(const) pre_type(char) operator(*)ident(buf)operator(,) pre_type(int) ident(size)operator(\)) -operator({) - reserved(if) operator(()ident(buf) operator(&&) operator(()ident(size) operator(>) integer(0)operator(\)\)) operator({) - pre_type(char) operator(*)ident(copy) operator(=) operator(()pre_type(char)operator(*\)) ident(malloc) operator(()ident(size)operator(\);) - reserved(if) operator((!)ident(copy)operator(\)) - reserved(throw) ident(runtime_error) operator(()string<delimiter(")content(no memory in pagelist)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(copy)operator(,) ident(buf)operator(,) ident(size)operator(\);) - ident(Pages)operator(.)ident(push_back) operator(()ident(Page) operator(()ident(copy)operator(,) ident(size)operator(\)\);) - operator(}) -operator(}) - - - - - -comment(/***************************************************************************** - -$Id$ - -File: pipe.cpp -Date: 30May07 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - - -preprocessor(#ifdef) ident(OS_UNIX) -comment(// THIS ENTIRE FILE IS ONLY COMPILED ON UNIX-LIKE SYSTEMS.) - -comment(/****************************** -PipeDescriptor::PipeDescriptor -******************************/) - -ident(PipeDescriptor)operator(::)ident(PipeDescriptor) operator(()pre_type(int) ident(fd)operator(,) ident(pid_t) ident(subpid)operator(,) ident(EventMachine_t) operator(*)ident(parent_em)operator(\):) - ident(EventableDescriptor) operator(()ident(fd)operator(,) ident(parent_em)operator(\),) - ident(bReadAttemptedAfterClose) operator(()pre_constant(false)operator(\),) - ident(LastIo) operator(()ident(gCurrentLoopTime)operator(\),) - ident(InactivityTimeout) operator(()integer(0)operator(\),) - ident(OutboundDataSize) operator(()integer(0)operator(\),) - ident(SubprocessPid) operator(()ident(subpid)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) ident(EPOLLIN)operator(;) - preprocessor(#endif) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - ident(MyEventMachine)operator(->)ident(ArmKqueueReader) operator(()local_variable(this)operator(\);) - preprocessor(#endif) -operator(}) - - -comment(/******************************* -PipeDescriptor::~PipeDescriptor -*******************************/) - -ident(PipeDescriptor)operator(::~)ident(PipeDescriptor)operator((\)) -operator({) - comment(// Run down any stranded outbound data.) - reserved(for) operator(()ident(size_t) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(OutboundPages)operator(.)ident(size)operator((\);) ident(i)operator(++\)) - ident(OutboundPages)operator([)ident(i)operator(])operator(.)ident(Free)operator((\);) - - comment(/* As a virtual destructor, we come here before the base-class - * destructor that closes our file-descriptor. - * We have to make sure the subprocess goes down (if it's not - * already down\) and we have to reap the zombie. - * - * This implementation is PROVISIONAL and will surely be improved. - * The intention here is that we never block, hence the highly - * undesirable sleeps. But if we can't reap the subprocess even - * after sending it SIGKILL, then something is wrong and we - * throw a fatal exception, which is also not something we should - * be doing. - * - * Eventually the right thing to do will be to have the reactor - * core respond to SIGCHLD by chaining a handler on top of the - * one Ruby may have installed, and dealing with a list of dead - * children that are pending cleanup. - * - * Since we want to have a signal processor integrated into the - * client-visible API, let's wait until that is done before cleaning - * this up. - * - * Added a very ugly hack to support passing the subprocess's exit - * status to the user. It only makes logical sense for user code to access - * the subprocess exit status in the unbind callback. But unbind is called - * back during the EventableDescriptor destructor. So by that time there's - * no way to call back this object through an object binding, because it's - * already been cleaned up. We might have added a parameter to the unbind - * callback, but that would probably break a huge amount of existing code. - * So the hack-solution is to define an instance variable in the EventMachine - * object and stick the exit status in there, where it can easily be accessed - * with an accessor visible to user code. - * User code should ONLY access the exit status from within the unbind callback. - * Otherwise there's no guarantee it'll be valid. - * This hack won't make it impossible to run multiple EventMachines in a single - * process, but it will make it impossible to reliably nest unbind calls - * within other unbind calls. (Not sure if that's even possible.\) - */) - - ident(assert) operator(()ident(MyEventMachine)operator(\);) - - comment(// check if the process is already dead) - reserved(if) operator(()ident(waitpid) operator(()ident(SubprocessPid)operator(,) operator(&()ident(MyEventMachine)operator(->)ident(SubprocessExitStatus)operator(\),) ident(WNOHANG)operator(\)) operator(==) integer(0)operator(\)) operator({) - ident(kill) operator(()ident(SubprocessPid)operator(,) ident(SIGTERM)operator(\);) - comment(// wait 0.25s for process to die) - reserved(struct) ident(timespec) ident(req) operator(=) operator({)integer(0)operator(,) integer(250000000)operator(};) - ident(nanosleep) operator((&)ident(req)operator(,) pre_constant(NULL)operator(\);) - reserved(if) operator(()ident(waitpid) operator(()ident(SubprocessPid)operator(,) operator(&()ident(MyEventMachine)operator(->)ident(SubprocessExitStatus)operator(\),) ident(WNOHANG)operator(\)) operator(==) integer(0)operator(\)) operator({) - ident(kill) operator(()ident(SubprocessPid)operator(,) ident(SIGKILL)operator(\);) - comment(// wait 0.5s for process to die) - reserved(struct) ident(timespec) ident(req) operator(=) operator({)integer(0)operator(,) integer(500000000)operator(};) - ident(nanosleep) operator((&)ident(req)operator(,) pre_constant(NULL)operator(\);) - reserved(if) operator(()ident(waitpid) operator(()ident(SubprocessPid)operator(,) operator(&()ident(MyEventMachine)operator(->)ident(SubprocessExitStatus)operator(\),) ident(WNOHANG)operator(\)) operator(==) integer(0)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(unable to reap subprocess)delimiter(")>operator(\);) - operator(}) - operator(}) -operator(}) - - - -comment(/******************** -PipeDescriptor::Read -********************/) - -directive(void) ident(PipeDescriptor)operator(::)ident(Read)operator((\)) -operator({) - pre_type(int) ident(sd) operator(=) ident(GetSocket)operator((\);) - reserved(if) operator(()ident(sd) operator(==) ident(INVALID_SOCKET)operator(\)) operator({) - ident(assert) operator((!)ident(bReadAttemptedAfterClose)operator(\);) - ident(bReadAttemptedAfterClose) operator(=) pre_constant(true)operator(;) - reserved(return)operator(;) - operator(}) - - ident(LastIo) operator(=) ident(gCurrentLoopTime)operator(;) - - pre_type(int) ident(total_bytes_read) operator(=) integer(0)operator(;) - pre_type(char) ident(readbuffer) operator([)integer(16) operator(*) integer(1024)operator(];) - - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) integer(10)operator(;) ident(i)operator(++\)) operator({) - comment(// Don't read just one buffer and then move on. This is faster) - comment(// if there is a lot of incoming.) - comment(// But don't read indefinitely. Give other sockets a chance to run.) - comment(// NOTICE, we're reading one less than the buffer size.) - comment(// That's so we can put a guard byte at the end of what we send) - comment(// to user code.) - comment(// Use read instead of recv, which on Linux gives a "socket operation) - comment(// on nonsocket" error.) - - - pre_type(int) ident(r) operator(=) ident(read) operator(()ident(sd)operator(,) ident(readbuffer)operator(,) reserved(sizeof)operator(()ident(readbuffer)operator(\)) operator(-) integer(1)operator(\);) - comment(//cerr << "<R:" << r << ">";) - - reserved(if) operator(()ident(r) operator(>) integer(0)operator(\)) operator({) - ident(total_bytes_read) operator(+=) ident(r)operator(;) - ident(LastRead) operator(=) ident(gCurrentLoopTime)operator(;) - - comment(// Add a null-terminator at the the end of the buffer) - comment(// that we will send to the callback.) - comment(// DO NOT EVER CHANGE THIS. We want to explicitly allow users) - comment(// to be able to depend on this behavior, so they will have) - comment(// the option to do some things faster. Additionally it's) - comment(// a security guard against buffer overflows.) - ident(readbuffer) operator([)ident(r)operator(]) operator(=) integer(0)operator(;) - reserved(if) operator(()ident(EventCallback)operator(\)) - operator((*)ident(EventCallback)operator(\)()ident(GetBinding)operator((\))operator(.)ident(c_str)operator((\),) ident(EM_CONNECTION_READ)operator(,) ident(readbuffer)operator(,) ident(r)operator(\);) - operator(}) - reserved(else) reserved(if) operator(()ident(r) operator(==) integer(0)operator(\)) operator({) - reserved(break)operator(;) - operator(}) - reserved(else) operator({) - comment(// Basically a would-block, meaning we've read everything there is to read.) - reserved(break)operator(;) - operator(}) - - operator(}) - - - reserved(if) operator(()ident(total_bytes_read) operator(==) integer(0)operator(\)) operator({) - comment(// If we read no data on a socket that selected readable,) - comment(// it generally means the other end closed the connection gracefully.) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) - operator(}) - -operator(}) - -comment(/********************* -PipeDescriptor::Write -*********************/) - -directive(void) ident(PipeDescriptor)operator(::)ident(Write)operator((\)) -operator({) - pre_type(int) ident(sd) operator(=) ident(GetSocket)operator((\);) - ident(assert) operator(()ident(sd) operator(!=) ident(INVALID_SOCKET)operator(\);) - - ident(LastIo) operator(=) ident(gCurrentLoopTime)operator(;) - pre_type(char) ident(output_buffer) operator([)integer(16) operator(*) integer(1024)operator(];) - ident(size_t) ident(nbytes) operator(=) integer(0)operator(;) - - reserved(while) operator((()ident(OutboundPages)operator(.)ident(size)operator((\)) operator(>) integer(0)operator(\)) operator(&&) operator(()ident(nbytes) operator(<) reserved(sizeof)operator(()ident(output_buffer)operator(\)\)\)) operator({) - ident(OutboundPage) operator(*)ident(op) operator(=) operator(&()ident(OutboundPages)operator([)integer(0)operator(]\);) - reserved(if) operator((()ident(nbytes) operator(+) ident(op)operator(->)ident(Length) operator(-) ident(op)operator(->)ident(Offset)operator(\)) operator(<) reserved(sizeof) operator(()ident(output_buffer)operator(\)\)) operator({) - ident(memcpy) operator(()ident(output_buffer) operator(+) ident(nbytes)operator(,) ident(op)operator(->)ident(Buffer) operator(+) ident(op)operator(->)ident(Offset)operator(,) ident(op)operator(->)ident(Length) operator(-) ident(op)operator(->)ident(Offset)operator(\);) - ident(nbytes) operator(+=) operator(()ident(op)operator(->)ident(Length) operator(-) ident(op)operator(->)ident(Offset)operator(\);) - ident(op)operator(->)ident(Free)operator((\);) - ident(OutboundPages)operator(.)ident(pop_front)operator((\);) - operator(}) - reserved(else) operator({) - pre_type(int) ident(len) operator(=) reserved(sizeof)operator(()ident(output_buffer)operator(\)) operator(-) ident(nbytes)operator(;) - ident(memcpy) operator(()ident(output_buffer) operator(+) ident(nbytes)operator(,) ident(op)operator(->)ident(Buffer) operator(+) ident(op)operator(->)ident(Offset)operator(,) ident(len)operator(\);) - ident(op)operator(->)ident(Offset) operator(+=) ident(len)operator(;) - ident(nbytes) operator(+=) ident(len)operator(;) - operator(}) - operator(}) - - comment(// We should never have gotten here if there were no data to write,) - comment(// so assert that as a sanity check.) - comment(// Don't bother to make sure nbytes is less than output_buffer because) - comment(// if it were we probably would have crashed already.) - ident(assert) operator(()ident(nbytes) operator(>) integer(0)operator(\);) - - ident(assert) operator(()ident(GetSocket)operator((\)) operator(!=) ident(INVALID_SOCKET)operator(\);) - pre_type(int) ident(bytes_written) operator(=) ident(write) operator(()ident(GetSocket)operator((\),) ident(output_buffer)operator(,) ident(nbytes)operator(\);) - - reserved(if) operator(()ident(bytes_written) operator(>) integer(0)operator(\)) operator({) - ident(OutboundDataSize) operator(-=) ident(bytes_written)operator(;) - reserved(if) operator((()ident(size_t)operator(\))ident(bytes_written) operator(<) ident(nbytes)operator(\)) operator({) - pre_type(int) ident(len) operator(=) ident(nbytes) operator(-) ident(bytes_written)operator(;) - pre_type(char) operator(*)ident(buffer) operator(=) operator(()pre_type(char)operator(*\)) ident(malloc) operator(()ident(len) operator(+) integer(1)operator(\);) - reserved(if) operator((!)ident(buffer)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad alloc throwing back data)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(buffer)operator(,) ident(output_buffer) operator(+) ident(bytes_written)operator(,) ident(len)operator(\);) - ident(buffer) operator([)ident(len)operator(]) operator(=) integer(0)operator(;) - ident(OutboundPages)operator(.)ident(push_front) operator(()ident(OutboundPage) operator(()ident(buffer)operator(,) ident(len)operator(\)\);) - operator(}) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) operator(()ident(SelectForWrite)operator((\)) operator(?) ident(EPOLLOUT) operator(:) integer(0)operator(\)\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - operator(}) - reserved(else) operator({) - preprocessor(#ifdef) ident(OS_UNIX) - reserved(if) operator((()ident(errno) operator(!=) ident(EINPROGRESS)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(EWOULDBLOCK)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(EINTR)operator(\)\)) - preprocessor(#endif) - preprocessor(#ifdef) ident(OS_WIN32) - reserved(if) operator((()ident(errno) operator(!=) ident(WSAEINPROGRESS)operator(\)) operator(&&) operator(()ident(errno) operator(!=) ident(WSAEWOULDBLOCK)operator(\)\)) - preprocessor(#endif) - ident(Close)operator((\);) - operator(}) -operator(}) - - -comment(/************************* -PipeDescriptor::Heartbeat -*************************/) - -directive(void) ident(PipeDescriptor)operator(::)ident(Heartbeat)operator((\)) -operator({) - comment(// If an inactivity timeout is defined, then check for it.) - reserved(if) operator(()ident(InactivityTimeout) operator(&&) operator((()ident(gCurrentLoopTime) operator(-) ident(LastIo)operator(\)) operator(>=) ident(InactivityTimeout)operator(\)\)) - ident(ScheduleClose) operator(()pre_constant(false)operator(\);) - comment(//bCloseNow = true;) -operator(}) - - -comment(/***************************** -PipeDescriptor::SelectForRead -*****************************/) - -pre_type(bool) ident(PipeDescriptor)operator(::)ident(SelectForRead)operator((\)) -operator({) - comment(/* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */) - reserved(return) pre_constant(true)operator(;) -operator(}) - -comment(/****************************** -PipeDescriptor::SelectForWrite -******************************/) - -pre_type(bool) ident(PipeDescriptor)operator(::)ident(SelectForWrite)operator((\)) -operator({) - comment(/* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */) - reserved(return) operator(()ident(GetOutboundDataSize)operator((\)) operator(>) integer(0)operator(\);) -operator(}) - - - - -comment(/******************************** -PipeDescriptor::SendOutboundData -********************************/) - -pre_type(int) ident(PipeDescriptor)operator(::)ident(SendOutboundData) operator(()directive(const) pre_type(char) operator(*)ident(data)operator(,) pre_type(int) ident(length)operator(\)) -operator({) - comment(//if (bCloseNow || bCloseAfterWriting\)) - reserved(if) operator(()ident(IsCloseScheduled)operator((\)\)) - reserved(return) integer(0)operator(;) - - reserved(if) operator((!)ident(data) operator(&&) operator(()ident(length) operator(>) integer(0)operator(\)\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(bad outbound data)delimiter(")>operator(\);) - pre_type(char) operator(*)ident(buffer) operator(=) operator(()pre_type(char) operator(*\)) ident(malloc) operator(()ident(length) operator(+) integer(1)operator(\);) - reserved(if) operator((!)ident(buffer)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no allocation for outbound data)delimiter(")>operator(\);) - ident(memcpy) operator(()ident(buffer)operator(,) ident(data)operator(,) ident(length)operator(\);) - ident(buffer) operator([)ident(length)operator(]) operator(=) integer(0)operator(;) - ident(OutboundPages)operator(.)ident(push_back) operator(()ident(OutboundPage) operator(()ident(buffer)operator(,) ident(length)operator(\)\);) - ident(OutboundDataSize) operator(+=) ident(length)operator(;) - preprocessor(#ifdef) ident(HAVE_EPOLL) - ident(EpollEvent)operator(.)ident(events) operator(=) operator(()ident(EPOLLIN) operator(|) ident(EPOLLOUT)operator(\);) - ident(assert) operator(()ident(MyEventMachine)operator(\);) - ident(MyEventMachine)operator(->)ident(Modify) operator(()local_variable(this)operator(\);) - preprocessor(#endif) - reserved(return) ident(length)operator(;) -operator(}) - -comment(/******************************** -PipeDescriptor::GetSubprocessPid -********************************/) - -pre_type(bool) ident(PipeDescriptor)operator(::)ident(GetSubprocessPid) operator(()ident(pid_t) operator(*)ident(pid)operator(\)) -operator({) - pre_type(bool) ident(ok) operator(=) pre_constant(false)operator(;) - reserved(if) operator(()ident(pid) operator(&&) operator(()ident(SubprocessPid) operator(>) integer(0)operator(\)\)) operator({) - operator(*)ident(pid) operator(=) ident(SubprocessPid)operator(;) - ident(ok) operator(=) pre_constant(true)operator(;) - operator(}) - reserved(return) ident(ok)operator(;) -operator(}) - - -preprocessor(#endif) comment(// OS_UNIX) - -comment(/***************************************************************************** - -$Id$ - -File: rubymain.cpp -Date: 06Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") -preprocessor(#include) include("eventmachine.h") -preprocessor(#include) include(<ruby.h>) - - - -comment(/******* -Statics -*******/) - -directive(static) ident(VALUE) ident(EmModule)operator(;) -directive(static) ident(VALUE) ident(EmConnection)operator(;) - -directive(static) ident(VALUE) ident(Intern_at_signature)operator(;) -directive(static) ident(VALUE) ident(Intern_at_timers)operator(;) -directive(static) ident(VALUE) ident(Intern_at_conns)operator(;) -directive(static) ident(VALUE) ident(Intern_event_callback)operator(;) -directive(static) ident(VALUE) ident(Intern_run_deferred_callbacks)operator(;) -directive(static) ident(VALUE) ident(Intern_delete)operator(;) -directive(static) ident(VALUE) ident(Intern_call)operator(;) -directive(static) ident(VALUE) ident(Intern_receive_data)operator(;) - -directive(static) ident(VALUE) ident(Intern_notify_readable)operator(;) -directive(static) ident(VALUE) ident(Intern_notify_writable)operator(;) - -comment(/**************** -t_event_callback -****************/) - -directive(static) directive(void) ident(event_callback) operator(()directive(const) pre_type(char) operator(*)ident(a1)operator(,) pre_type(int) ident(a2)operator(,) directive(const) pre_type(char) operator(*)ident(a3)operator(,) pre_type(int) ident(a4)operator(\)) -operator({) - reserved(if) operator(()ident(a2) operator(==) ident(EM_CONNECTION_READ)operator(\)) operator({) - ident(VALUE) ident(t) operator(=) ident(rb_ivar_get) operator(()ident(EmModule)operator(,) ident(Intern_at_conns)operator(\);) - ident(VALUE) ident(q) operator(=) ident(rb_hash_aref) operator(()ident(t)operator(,) ident(rb_str_new2)operator(()ident(a1)operator(\)\);) - reserved(if) operator(()ident(q) operator(==) ident(Qnil)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no connection)delimiter(")>operator(\);) - ident(rb_funcall) operator(()ident(q)operator(,) ident(Intern_receive_data)operator(,) integer(1)operator(,) ident(rb_str_new) operator(()ident(a3)operator(,) ident(a4)operator(\)\);) - operator(}) - reserved(else) reserved(if) operator(()ident(a2) operator(==) ident(EM_CONNECTION_NOTIFY_READABLE)operator(\)) operator({) - ident(VALUE) ident(t) operator(=) ident(rb_ivar_get) operator(()ident(EmModule)operator(,) ident(Intern_at_conns)operator(\);) - ident(VALUE) ident(q) operator(=) ident(rb_hash_aref) operator(()ident(t)operator(,) ident(rb_str_new2)operator(()ident(a1)operator(\)\);) - reserved(if) operator(()ident(q) operator(==) ident(Qnil)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no connection)delimiter(")>operator(\);) - ident(rb_funcall) operator(()ident(q)operator(,) ident(Intern_notify_readable)operator(,) integer(0)operator(\);) - operator(}) - reserved(else) reserved(if) operator(()ident(a2) operator(==) ident(EM_CONNECTION_NOTIFY_WRITABLE)operator(\)) operator({) - ident(VALUE) ident(t) operator(=) ident(rb_ivar_get) operator(()ident(EmModule)operator(,) ident(Intern_at_conns)operator(\);) - ident(VALUE) ident(q) operator(=) ident(rb_hash_aref) operator(()ident(t)operator(,) ident(rb_str_new2)operator(()ident(a1)operator(\)\);) - reserved(if) operator(()ident(q) operator(==) ident(Qnil)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no connection)delimiter(")>operator(\);) - ident(rb_funcall) operator(()ident(q)operator(,) ident(Intern_notify_writable)operator(,) integer(0)operator(\);) - operator(}) - reserved(else) reserved(if) operator(()ident(a2) operator(==) ident(EM_LOOPBREAK_SIGNAL)operator(\)) operator({) - ident(rb_funcall) operator(()ident(EmModule)operator(,) ident(Intern_run_deferred_callbacks)operator(,) integer(0)operator(\);) - operator(}) - reserved(else) reserved(if) operator(()ident(a2) operator(==) ident(EM_TIMER_FIRED)operator(\)) operator({) - ident(VALUE) ident(t) operator(=) ident(rb_ivar_get) operator(()ident(EmModule)operator(,) ident(Intern_at_timers)operator(\);) - ident(VALUE) ident(q) operator(=) ident(rb_funcall) operator(()ident(t)operator(,) ident(Intern_delete)operator(,) integer(1)operator(,) ident(rb_str_new)operator(()ident(a3)operator(,) ident(a4)operator(\)\);) - reserved(if) operator(()ident(q) operator(==) ident(Qnil)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no timer)delimiter(")>operator(\);) - ident(rb_funcall) operator(()ident(q)operator(,) ident(Intern_call)operator(,) integer(0)operator(\);) - operator(}) - reserved(else) - ident(rb_funcall) operator(()ident(EmModule)operator(,) ident(Intern_event_callback)operator(,) integer(3)operator(,) ident(rb_str_new2)operator(()ident(a1)operator(\),) operator(()ident(a2) operator(<<) integer(1)operator(\)) operator(|) integer(1)operator(,) ident(rb_str_new)operator(()ident(a3)operator(,)ident(a4)operator(\)\);) -operator(}) - - - -comment(/************************** -t_initialize_event_machine -**************************/) - -directive(static) ident(VALUE) ident(t_initialize_event_machine) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(evma_initialize_library) operator(()ident(event_callback)operator(\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - - - -comment(/***************************** -t_run_machine_without_threads -*****************************/) - -directive(static) ident(VALUE) ident(t_run_machine_without_threads) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(evma_run_machine)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - - -comment(/******************* -t_add_oneshot_timer -*******************/) - -directive(static) ident(VALUE) ident(t_add_oneshot_timer) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(interval)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_install_oneshot_timer) operator(()ident(FIX2INT) operator(()ident(interval)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no timer)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - - -comment(/************** -t_start_server -**************/) - -directive(static) ident(VALUE) ident(t_start_server) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(server)operator(,) ident(VALUE) ident(port)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_create_tcp_server) operator(()ident(StringValuePtr)operator(()ident(server)operator(\),) ident(FIX2INT)operator(()ident(port)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no acceptor)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - -comment(/************* -t_stop_server -*************/) - -directive(static) ident(VALUE) ident(t_stop_server) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - ident(evma_stop_tcp_server) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - - -comment(/******************* -t_start_unix_server -*******************/) - -directive(static) ident(VALUE) ident(t_start_unix_server) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(filename)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_create_unix_domain_server) operator(()ident(StringValuePtr)operator(()ident(filename)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no unix-domain acceptor)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - - - -comment(/*********** -t_send_data -***********/) - -directive(static) ident(VALUE) ident(t_send_data) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(,) ident(VALUE) ident(data)operator(,) ident(VALUE) ident(data_length)operator(\)) -operator({) - pre_type(int) ident(b) operator(=) ident(evma_send_data_to_connection) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) ident(StringValuePtr) operator(()ident(data)operator(\),) ident(FIX2INT) operator(()ident(data_length)operator(\)\);) - reserved(return) ident(INT2NUM) operator(()ident(b)operator(\);) -operator(}) - - -comment(/*********** -t_start_tls -***********/) - -directive(static) ident(VALUE) ident(t_start_tls) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - ident(evma_start_tls) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/*************** -t_set_tls_parms -***************/) - -directive(static) ident(VALUE) ident(t_set_tls_parms) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(,) ident(VALUE) ident(privkeyfile)operator(,) ident(VALUE) ident(certchainfile)operator(\)) -operator({) - comment(/* set_tls_parms takes a series of positional arguments for specifying such things - * as private keys and certificate chains. - * It's expected that the parameter list will grow as we add more supported features. - * ALL of these parameters are optional, and can be specified as empty or NULL strings. - */) - ident(evma_set_tls_parms) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) ident(StringValuePtr) operator(()ident(privkeyfile)operator(\),) ident(StringValuePtr) operator(()ident(certchainfile)operator(\)) operator(\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/************** -t_get_peername -**************/) - -directive(static) ident(VALUE) ident(t_get_peername) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - reserved(struct) ident(sockaddr) ident(s)operator(;) - reserved(if) operator(()ident(evma_get_peername) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator(&)ident(s)operator(\)\)) operator({) - reserved(return) ident(rb_str_new) operator((()directive(const) pre_type(char)operator(*\)&)ident(s)operator(,) reserved(sizeof)operator(()ident(s)operator(\)\);) - operator(}) - - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/************** -t_get_sockname -**************/) - -directive(static) ident(VALUE) ident(t_get_sockname) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - reserved(struct) ident(sockaddr) ident(s)operator(;) - reserved(if) operator(()ident(evma_get_sockname) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator(&)ident(s)operator(\)\)) operator({) - reserved(return) ident(rb_str_new) operator((()directive(const) pre_type(char)operator(*\)&)ident(s)operator(,) reserved(sizeof)operator(()ident(s)operator(\)\);) - operator(}) - - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/******************** -t_get_subprocess_pid -********************/) - -directive(static) ident(VALUE) ident(t_get_subprocess_pid) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - ident(pid_t) ident(pid)operator(;) - reserved(if) operator(()ident(evma_get_subprocess_pid) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator(&)ident(pid)operator(\)\)) operator({) - reserved(return) ident(INT2NUM) operator(()ident(pid)operator(\);) - operator(}) - - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/*********************** -t_get_subprocess_status -***********************/) - -directive(static) ident(VALUE) ident(t_get_subprocess_status) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - pre_type(int) ident(status)operator(;) - reserved(if) operator(()ident(evma_get_subprocess_status) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator(&)ident(status)operator(\)\)) operator({) - reserved(return) ident(INT2NUM) operator(()ident(status)operator(\);) - operator(}) - - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/***************************** -t_get_comm_inactivity_timeout -*****************************/) - -directive(static) ident(VALUE) ident(t_get_comm_inactivity_timeout) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - pre_type(int) ident(timeout)operator(;) - reserved(if) operator(()ident(evma_get_comm_inactivity_timeout) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator(&)ident(timeout)operator(\)\)) - reserved(return) ident(INT2FIX) operator(()ident(timeout)operator(\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/***************************** -t_set_comm_inactivity_timeout -*****************************/) - -directive(static) ident(VALUE) ident(t_set_comm_inactivity_timeout) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(,) ident(VALUE) ident(timeout)operator(\)) -operator({) - pre_type(int) ident(ti) operator(=) ident(FIX2INT) operator(()ident(timeout)operator(\);) - reserved(if) operator(()ident(evma_set_comm_inactivity_timeout) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator(&)ident(ti)operator(\)\);) - reserved(return) ident(Qtrue)operator(;) - reserved(return) ident(Qnil)operator(;) -operator(}) - - -comment(/*************** -t_send_datagram -***************/) - -directive(static) ident(VALUE) ident(t_send_datagram) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(,) ident(VALUE) ident(data)operator(,) ident(VALUE) ident(data_length)operator(,) ident(VALUE) ident(address)operator(,) ident(VALUE) ident(port)operator(\)) -operator({) - pre_type(int) ident(b) operator(=) ident(evma_send_datagram) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) ident(StringValuePtr) operator(()ident(data)operator(\),) ident(FIX2INT) operator(()ident(data_length)operator(\),) ident(StringValuePtr)operator(()ident(address)operator(\),) ident(FIX2INT)operator(()ident(port)operator(\)\);) - reserved(return) ident(INT2NUM) operator(()ident(b)operator(\);) -operator(}) - - -comment(/****************** -t_close_connection -******************/) - -directive(static) ident(VALUE) ident(t_close_connection) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(,) ident(VALUE) ident(after_writing)operator(\)) -operator({) - ident(evma_close_connection) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\),) operator((()ident(after_writing) operator(==) ident(Qtrue)operator(\)) operator(?) integer(1) operator(:) integer(0)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/******************************** -t_report_connection_error_status -********************************/) - -directive(static) ident(VALUE) ident(t_report_connection_error_status) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - pre_type(int) ident(b) operator(=) ident(evma_report_connection_error_status) operator(()ident(StringValuePtr) operator(()ident(signature)operator(\)\);) - reserved(return) ident(INT2NUM) operator(()ident(b)operator(\);) -operator(}) - - - -comment(/**************** -t_connect_server -****************/) - -directive(static) ident(VALUE) ident(t_connect_server) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(server)operator(,) ident(VALUE) ident(port)operator(\)) -operator({) - comment(// Avoid FIX2INT in this case, because it doesn't deal with type errors properly.) - comment(// Specifically, if the value of port comes in as a string rather than an integer,) - comment(// NUM2INT will throw a type error, but FIX2INT will generate garbage.) - - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_connect_to_server) operator(()ident(StringValuePtr)operator(()ident(server)operator(\),) ident(NUM2INT)operator(()ident(port)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no connection)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - -comment(/********************* -t_connect_unix_server -*********************/) - -directive(static) ident(VALUE) ident(t_connect_unix_server) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(serversocket)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_connect_to_unix_server) operator(()ident(StringValuePtr)operator(()ident(serversocket)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no connection)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - -comment(/*********** -t_attach_fd -***********/) - -directive(static) ident(VALUE) ident(t_attach_fd) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(file_descriptor)operator(,) ident(VALUE) ident(read_mode)operator(,) ident(VALUE) ident(write_mode)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_attach_fd) operator(()ident(NUM2INT)operator(()ident(file_descriptor)operator(\),) operator(()ident(read_mode) operator(==) ident(Qtrue)operator(\)) operator(?) integer(1) operator(:) integer(0)operator(,) operator(()ident(write_mode) operator(==) ident(Qtrue)operator(\)) operator(?) integer(1) operator(:) integer(0)operator(\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no connection)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - -comment(/*********** -t_detach_fd -***********/) - -directive(static) ident(VALUE) ident(t_detach_fd) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(\)) -operator({) - reserved(return) ident(INT2NUM)operator(()ident(evma_detach_fd) operator(()ident(StringValuePtr)operator(()ident(signature)operator(\)\)\);) -operator(}) - -comment(/***************** -t_open_udp_socket -*****************/) - -directive(static) ident(VALUE) ident(t_open_udp_socket) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(server)operator(,) ident(VALUE) ident(port)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_open_datagram_socket) operator(()ident(StringValuePtr)operator(()ident(server)operator(\),) ident(FIX2INT)operator(()ident(port)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no datagram socket)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - - - -comment(/***************** -t_release_machine -*****************/) - -directive(static) ident(VALUE) ident(t_release_machine) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(evma_release_library)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - - -comment(/****** -t_stop -******/) - -directive(static) ident(VALUE) ident(t_stop) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(evma_stop_machine)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/****************** -t_signal_loopbreak -******************/) - -directive(static) ident(VALUE) ident(t_signal_loopbreak) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(evma_signal_loopbreak)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/************** -t_library_type -**************/) - -directive(static) ident(VALUE) ident(t_library_type) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - reserved(return) ident(rb_eval_string) operator(()string<delimiter(")content(:extension)delimiter(")>operator(\);) -operator(}) - - - -comment(/******************* -t_set_timer_quantum -*******************/) - -directive(static) ident(VALUE) ident(t_set_timer_quantum) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(interval)operator(\)) -operator({) - ident(evma_set_timer_quantum) operator(()ident(FIX2INT) operator(()ident(interval)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/******************** -t_set_max_timer_count -********************/) - -directive(static) ident(VALUE) ident(t_set_max_timer_count) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(ct)operator(\)) -operator({) - ident(evma_set_max_timer_count) operator(()ident(FIX2INT) operator(()ident(ct)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/*************** -t_setuid_string -***************/) - -directive(static) ident(VALUE) ident(t_setuid_string) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(username)operator(\)) -operator({) - ident(evma_setuid_string) operator(()ident(StringValuePtr) operator(()ident(username)operator(\)\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - - - -comment(/************* -t__write_file -*************/) - -directive(static) ident(VALUE) ident(t__write_file) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(filename)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma__write_file) operator(()ident(StringValuePtr) operator(()ident(filename)operator(\)\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(file not opened)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - -comment(/************** -t_invoke_popen -**************/) - -directive(static) ident(VALUE) ident(t_invoke_popen) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(cmd)operator(\)) -operator({) - comment(// 1.8.7+) - preprocessor(#ifdef) ident(RARRAY_LEN) - pre_type(int) ident(len) operator(=) ident(RARRAY_LEN)operator(()ident(cmd)operator(\);) - preprocessor(#else) - pre_type(int) ident(len) operator(=) ident(RARRAY) operator(()ident(cmd)operator(\)->)ident(len)operator(;) - preprocessor(#endif) - reserved(if) operator(()ident(len) operator(>) integer(98)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(too many arguments to popen)delimiter(")>operator(\);) - pre_type(char) operator(*)ident(strings) operator([)integer(100)operator(];) - reserved(for) operator(()pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i) operator(<) ident(len)operator(;) ident(i)operator(++\)) operator({) - ident(VALUE) ident(ix) operator(=) ident(INT2FIX) operator(()ident(i)operator(\);) - ident(VALUE) ident(s) operator(=) ident(rb_ary_aref) operator(()integer(1)operator(,) operator(&)ident(ix)operator(,) ident(cmd)operator(\);) - ident(strings)operator([)ident(i)operator(]) operator(=) ident(StringValuePtr) operator(()ident(s)operator(\);) - operator(}) - ident(strings)operator([)ident(len)operator(]) operator(=) pre_constant(NULL)operator(;) - - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_popen) operator(()ident(strings)operator(\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) operator({) - pre_type(char) operator(*)ident(err) operator(=) ident(strerror) operator(()ident(errno)operator(\);) - pre_type(char) ident(buf)operator([)integer(100)operator(];) - ident(memset) operator(()ident(buf)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)\);) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(no popen: %s)delimiter(")>operator(,) operator(()ident(err)operator(?)ident(err)operator(:)string<delimiter(")content(???)delimiter(")>operator(\)\);) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) ident(buf)operator(\);) - operator(}) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - - -comment(/*************** -t_read_keyboard -***************/) - -directive(static) ident(VALUE) ident(t_read_keyboard) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - directive(const) pre_type(char) operator(*)ident(f) operator(=) ident(evma_open_keyboard)operator((\);) - reserved(if) operator((!)ident(f) operator(||) operator(!*)ident(f)operator(\)) - ident(rb_raise) operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(no keyboard reader)delimiter(")>operator(\);) - reserved(return) ident(rb_str_new2) operator(()ident(f)operator(\);) -operator(}) - - -comment(/******** -t__epoll -********/) - -directive(static) ident(VALUE) ident(t__epoll) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - comment(// Temporary.) - ident(evma__epoll)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/********** -t__epoll_p -**********/) - -directive(static) ident(VALUE) ident(t__epoll_p) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_EPOLL) - reserved(return) ident(Qtrue)operator(;) - preprocessor(#else) - reserved(return) ident(Qfalse)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/********* -t__kqueue -*********/) - -directive(static) ident(VALUE) ident(t__kqueue) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - comment(// Temporary.) - ident(evma__kqueue)operator((\);) - reserved(return) ident(Qnil)operator(;) -operator(}) - -comment(/*********** -t__kqueue_p -***********/) - -directive(static) ident(VALUE) ident(t__kqueue_p) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - preprocessor(#ifdef) ident(HAVE_KQUEUE) - reserved(return) ident(Qtrue)operator(;) - preprocessor(#else) - reserved(return) ident(Qfalse)operator(;) - preprocessor(#endif) -operator(}) - - -comment(/**************** -t_send_file_data -****************/) - -directive(static) ident(VALUE) ident(t_send_file_data) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(signature)operator(,) ident(VALUE) ident(filename)operator(\)) -operator({) - - comment(/* The current implementation of evma_send_file_data_to_connection enforces a strict - * upper limit on the file size it will transmit (currently 32K\). The function returns - * zero on success, -1 if the requested file exceeds its size limit, and a positive - * number for other errors. - * TODO: Positive return values are actually errno's, which is probably the wrong way to - * do this. For one thing it's ugly. For another, we can't be sure zero is never a real errno. - */) - - pre_type(int) ident(b) operator(=) ident(evma_send_file_data_to_connection) operator(()ident(StringValuePtr)operator(()ident(signature)operator(\),) ident(StringValuePtr)operator(()ident(filename)operator(\)\);) - reserved(if) operator(()ident(b) operator(==) operator(-)integer(1)operator(\)) - ident(rb_raise)operator(()ident(rb_eRuntimeError)operator(,) string<delimiter(")content(File too large. send_file_data(\) supports files under 32k.)delimiter(")>operator(\);) - reserved(if) operator(()ident(b) operator(>) integer(0)operator(\)) operator({) - pre_type(char) operator(*)ident(err) operator(=) ident(strerror) operator(()ident(b)operator(\);) - pre_type(char) ident(buf)operator([)integer(1024)operator(];) - ident(memset) operator(()ident(buf)operator(,) integer(0)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)\);) - ident(snprintf) operator(()ident(buf)operator(,) reserved(sizeof)operator(()ident(buf)operator(\)-)integer(1)operator(,) string<delimiter(")content(: %s %s)delimiter(")>operator(,) ident(StringValuePtr)operator(()ident(filename)operator(\),()ident(err)operator(?)ident(err)operator(:)string<delimiter(")content(???)delimiter(")>operator(\)\);) - - ident(rb_raise) operator(()ident(rb_eIOError)operator(,) ident(buf)operator(\);) - operator(}) - - reserved(return) ident(INT2NUM) operator(()integer(0)operator(\);) -operator(}) - - -comment(/******************* -t_set_rlimit_nofile -*******************/) - -directive(static) ident(VALUE) ident(t_set_rlimit_nofile) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(arg)operator(\)) -operator({) - ident(arg) operator(=) operator(()ident(NIL_P)operator(()ident(arg)operator(\)\)) operator(?) operator(-)integer(1) operator(:) ident(NUM2INT) operator(()ident(arg)operator(\);) - reserved(return) ident(INT2NUM) operator(()ident(evma_set_rlimit_nofile) operator(()ident(arg)operator(\)\);) -operator(}) - -comment(/*************************** -conn_get_outbound_data_size -***************************/) - -directive(static) ident(VALUE) ident(conn_get_outbound_data_size) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(VALUE) ident(sig) operator(=) ident(rb_ivar_get) operator(()ident(self)operator(,) ident(Intern_at_signature)operator(\);) - reserved(return) ident(INT2NUM) operator(()ident(evma_get_outbound_data_size) operator(()ident(StringValuePtr)operator(()ident(sig)operator(\)\)\);) -operator(}) - - -comment(/****************************** -conn_associate_callback_target -******************************/) - -directive(static) ident(VALUE) ident(conn_associate_callback_target) operator(()ident(VALUE) ident(self)operator(,) ident(VALUE) ident(sig)operator(\)) -operator({) - comment(// No-op for the time being.) - reserved(return) ident(Qnil)operator(;) -operator(}) - - -comment(/*************** -t_get_loop_time -****************/) - -directive(static) ident(VALUE) ident(t_get_loop_time) operator(()ident(VALUE) ident(self)operator(\)) -operator({) - ident(VALUE) ident(cTime) operator(=) ident(rb_path2class)operator(()string<delimiter(")content(Time)delimiter(")>operator(\);) - reserved(if) operator(()ident(gCurrentLoopTime) operator(!=) integer(0)operator(\)) operator({) - reserved(return) ident(rb_funcall)operator(()ident(cTime)operator(,) - ident(rb_intern)operator(()string<delimiter(")content(at)delimiter(")>operator(\),) - integer(1)operator(,) - ident(INT2NUM)operator(()ident(gCurrentLoopTime)operator(\)\);) - operator(}) - reserved(return) ident(Qnil)operator(;) -operator(}) - - -comment(/********************* -Init_rubyeventmachine -*********************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> directive(void) ident(Init_rubyeventmachine)operator((\)) -operator({) - comment(// Tuck away some symbol values so we don't have to look 'em up every time we need 'em.) - ident(Intern_at_signature) operator(=) ident(rb_intern) operator(()string<delimiter(")content(@signature)delimiter(")>operator(\);) - ident(Intern_at_timers) operator(=) ident(rb_intern) operator(()string<delimiter(")content(@timers)delimiter(")>operator(\);) - ident(Intern_at_conns) operator(=) ident(rb_intern) operator(()string<delimiter(")content(@conns)delimiter(")>operator(\);) - - ident(Intern_event_callback) operator(=) ident(rb_intern) operator(()string<delimiter(")content(event_callback)delimiter(")>operator(\);) - ident(Intern_run_deferred_callbacks) operator(=) ident(rb_intern) operator(()string<delimiter(")content(run_deferred_callbacks)delimiter(")>operator(\);) - ident(Intern_delete) operator(=) ident(rb_intern) operator(()string<delimiter(")content(delete)delimiter(")>operator(\);) - ident(Intern_call) operator(=) ident(rb_intern) operator(()string<delimiter(")content(call)delimiter(")>operator(\);) - ident(Intern_receive_data) operator(=) ident(rb_intern) operator(()string<delimiter(")content(receive_data)delimiter(")>operator(\);) - - ident(Intern_notify_readable) operator(=) ident(rb_intern) operator(()string<delimiter(")content(notify_readable)delimiter(")>operator(\);) - ident(Intern_notify_writable) operator(=) ident(rb_intern) operator(()string<delimiter(")content(notify_writable)delimiter(")>operator(\);) - - comment(// INCOMPLETE, we need to define class Connections inside module EventMachine) - comment(// run_machine and run_machine_without_threads are now identical.) - comment(// Must deprecate the without_threads variant.) - ident(EmModule) operator(=) ident(rb_define_module) operator(()string<delimiter(")content(EventMachine)delimiter(")>operator(\);) - ident(EmConnection) operator(=) ident(rb_define_class_under) operator(()ident(EmModule)operator(,) string<delimiter(")content(Connection)delimiter(")>operator(,) ident(rb_cObject)operator(\);) - - ident(rb_define_class_under) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionNotBound)delimiter(")>operator(,) ident(rb_eException)operator(\);) - ident(rb_define_class_under) operator(()ident(EmModule)operator(,) string<delimiter(")content(NoHandlerForAcceptedConnection)delimiter(")>operator(,) ident(rb_eException)operator(\);) - ident(rb_define_class_under) operator(()ident(EmModule)operator(,) string<delimiter(")content(UnknownTimerFired)delimiter(")>operator(,) ident(rb_eException)operator(\);) - - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(initialize_event_machine)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_initialize_event_machine)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(run_machine)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_run_machine_without_threads)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(run_machine_without_threads)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_run_machine_without_threads)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(add_oneshot_timer)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_add_oneshot_timer)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(start_tcp_server)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_start_server)operator(,) integer(2)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(stop_tcp_server)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_stop_server)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(start_unix_server)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_start_unix_server)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(set_tls_parms)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_set_tls_parms)operator(,) integer(3)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(start_tls)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_start_tls)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(send_data)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_send_data)operator(,) integer(3)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(send_datagram)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_send_datagram)operator(,) integer(5)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(close_connection)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_close_connection)operator(,) integer(2)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(report_connection_error_status)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_report_connection_error_status)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(connect_server)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_connect_server)operator(,) integer(2)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(connect_unix_server)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_connect_unix_server)operator(,) integer(1)operator(\);) - - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(attach_fd)delimiter(")>operator(,) operator(()ident(VALUE) operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_attach_fd)operator(,) integer(3)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(detach_fd)delimiter(")>operator(,) operator(()ident(VALUE) operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_detach_fd)operator(,) integer(1)operator(\);) - - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(current_time)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_get_loop_time)operator(,) integer(0)operator(\);) - - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(open_udp_socket)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_open_udp_socket)operator(,) integer(2)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(read_keyboard)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_read_keyboard)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(release_machine)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_release_machine)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(stop)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_stop)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(signal_loopbreak)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_signal_loopbreak)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(library_type)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_library_type)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(set_timer_quantum)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_set_timer_quantum)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(set_max_timer_count)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_set_max_timer_count)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(setuid_string)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_setuid_string)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(invoke_popen)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_invoke_popen)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(send_file_data)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_send_file_data)operator(,) integer(2)operator(\);) - - comment(// Provisional:) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(_write_file)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t__write_file)operator(,) integer(1)operator(\);) - - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(get_peername)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_get_peername)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(get_sockname)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_get_sockname)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(get_subprocess_pid)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_get_subprocess_pid)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(get_subprocess_status)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_get_subprocess_status)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(get_comm_inactivity_timeout)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_get_comm_inactivity_timeout)operator(,) integer(1)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(set_comm_inactivity_timeout)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_set_comm_inactivity_timeout)operator(,) integer(2)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(set_rlimit_nofile)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t_set_rlimit_nofile)operator(,) integer(1)operator(\);) - - comment(// Temporary:) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(epoll)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t__epoll)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(kqueue)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t__kqueue)operator(,) integer(0)operator(\);) - - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(epoll?)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t__epoll_p)operator(,) integer(0)operator(\);) - ident(rb_define_module_function) operator(()ident(EmModule)operator(,) string<delimiter(")content(kqueue?)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(t__kqueue_p)operator(,) integer(0)operator(\);) - - ident(rb_define_method) operator(()ident(EmConnection)operator(,) string<delimiter(")content(get_outbound_data_size)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(conn_get_outbound_data_size)operator(,) integer(0)operator(\);) - ident(rb_define_method) operator(()ident(EmConnection)operator(,) string<delimiter(")content(associate_callback_target)delimiter(")>operator(,) operator(()ident(VALUE)operator((*\)()operator(.)operator(.)operator(.)operator(\)\))ident(conn_associate_callback_target)operator(,) integer(1)operator(\);) - - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(TimerFired)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(100)operator(\)\);) - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionData)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(101)operator(\)\);) - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionUnbound)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(102)operator(\)\);) - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionAccepted)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(103)operator(\)\);) - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionCompleted)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(104)operator(\)\);) - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(LoopbreakSignalled)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(105)operator(\)\);) - - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionNotifyReadable)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(106)operator(\)\);) - ident(rb_define_const) operator(()ident(EmModule)operator(,) string<delimiter(")content(ConnectionNotifyWritable)delimiter(")>operator(,) ident(INT2NUM)operator(()integer(107)operator(\)\);) - -operator(}) - -comment(/***************************************************************************** - -$Id$ - -File: sigs.cpp -Date: 06Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - -preprocessor(#include) include("project.h") - - -pre_type(bool) ident(gTerminateSignalReceived)operator(;) - - -comment(/************** -SigtermHandler -**************/) - -directive(void) ident(SigtermHandler) operator(()pre_type(int) ident(sig)operator(\)) -operator({) - comment(// This is a signal-handler, don't do anything frisky. Interrupts are disabled.) - comment(// Set the terminate flag WITHOUT trying to lock a mutex- otherwise we can easily) - comment(// self-deadlock, especially if the event machine is looping quickly.) - ident(gTerminateSignalReceived) operator(=) pre_constant(true)operator(;) -operator(}) - - -comment(/********************* -InstallSignalHandlers -*********************/) - -directive(void) ident(InstallSignalHandlers)operator((\)) -operator({) - preprocessor(#ifdef) ident(OS_UNIX) - directive(static) pre_type(bool) ident(bInstalled) operator(=) pre_constant(false)operator(;) - reserved(if) operator((!)ident(bInstalled)operator(\)) operator({) - ident(bInstalled) operator(=) pre_constant(true)operator(;) - ident(signal) operator(()ident(SIGINT)operator(,) ident(SigtermHandler)operator(\);) - ident(signal) operator(()ident(SIGTERM)operator(,) ident(SigtermHandler)operator(\);) - ident(signal) operator(()ident(SIGPIPE)operator(,) ident(SIG_IGN)operator(\);) - operator(}) - preprocessor(#endif) -operator(}) - - - -comment(/******************* -WintelSignalHandler -*******************/) - -preprocessor(#ifdef) ident(OS_WIN32) -ident(BOOL) ident(WINAPI) ident(WintelSignalHandler) operator(()ident(DWORD) ident(control)operator(\)) -operator({) - reserved(if) operator(()ident(control) operator(==) ident(CTRL_C_EVENT)operator(\)) - ident(gTerminateSignalReceived) operator(=) pre_constant(true)operator(;) - reserved(return) ident(TRUE)operator(;) -operator(}) -preprocessor(#endif) - -comment(/************ -HookControlC -************/) - -preprocessor(#ifdef) ident(OS_WIN32) -directive(void) ident(HookControlC) operator(()pre_type(bool) ident(hook)operator(\)) -operator({) - reserved(if) operator(()ident(hook)operator(\)) operator({) - comment(// INSTALL hook) - ident(SetConsoleCtrlHandler) operator(()ident(WintelSignalHandler)operator(,) ident(TRUE)operator(\);) - operator(}) - reserved(else) operator({) - comment(// UNINSTALL hook) - ident(SetConsoleCtrlHandler) operator(()ident(WintelSignalHandler)operator(,) ident(FALSE)operator(\);) - operator(}) -operator(}) -preprocessor(#endif) - - -comment(/***************************************************************************** - -$Id$ - -File: ssl.cpp -Date: 30Apr06 - -Copyright (C\) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1\) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option\) any later version; or 2\) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/) - - -preprocessor(#ifdef) ident(WITH_SSL) - -preprocessor(#include) include("project.h") - - -pre_type(bool) ident(SslContext_t)operator(::)ident(bLibraryInitialized) operator(=) pre_constant(false)operator(;) - - - -directive(static) directive(void) ident(InitializeDefaultCredentials)operator((\);) -directive(static) ident(EVP_PKEY) operator(*)ident(DefaultPrivateKey) operator(=) pre_constant(NULL)operator(;) -directive(static) ident(X509) operator(*)ident(DefaultCertificate) operator(=) pre_constant(NULL)operator(;) - -directive(static) pre_type(char) ident(PrivateMaterials)operator([]) operator(=) operator({) -string<delimiter(")content(-----BEGIN RSA PRIVATE KEY-----)char(\\n)delimiter(")> -string<delimiter(")content(MIICXAIBAAKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxwVDWV)char(\\n)delimiter(")> -string<delimiter(")content(Igdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t39hJ/)char(\\n)delimiter(")> -string<delimiter(")content(AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQIDAQAB)char(\\n)delimiter(")> -string<delimiter(")content(AoGALA89gIFcr6BIBo8N5fL3aNHpZXjAICtGav+kTUpuxSiaym9cAeTHuAVv8Xgk)char(\\n)delimiter(")> -string<delimiter(")content(H2Wbq11uz+6JMLpkQJH/WZ7EV59DPOicXrp0Imr73F3EXBfR7t2EQDYHPMthOA1D)char(\\n)delimiter(")> -string<delimiter(")content(I9EtCzvV608Ze90hiJ7E3guGrGppZfJ+eUWCPgy8CZH1vRECQQDv67rwV/oU1aDo)char(\\n)delimiter(")> -string<delimiter(")content(6/+d5nqjeW6mWkGqTnUU96jXap8EIw6B+0cUKskwx6mHJv+tEMM2748ZY7b0yBlg)char(\\n)delimiter(")> -string<delimiter(")content(w4KDghbFAkEAz2h8PjSJG55LwqmXih1RONSgdN9hjB12LwXL1CaDh7/lkEhq0PlK)char(\\n)delimiter(")> -string<delimiter(")content(PCAUwQSdM17Sl0Xxm2CZiekTSlwmHrtqXQJAF3+8QJwtV2sRJp8u2zVe37IeH1cJ)char(\\n)delimiter(")> -string<delimiter(")content(xXeHyjTzqZ2803fnjN2iuZvzNr7noOA1/Kp+pFvUZUU5/0G2Ep8zolPUjQJAFA7k)char(\\n)delimiter(")> -string<delimiter(")content(xRdLkzIx3XeNQjwnmLlncyYPRv+qaE3FMpUu7zftuZBnVCJnvXzUxP3vPgKTlzGa)char(\\n)delimiter(")> -string<delimiter(")content(dg5XivDRfsV+okY5uQJBAMV4FesUuLQVEKb6lMs7rzZwpeGQhFDRfywJzfom2TLn)char(\\n)delimiter(")> -string<delimiter(")content(2RdJQQ3dcgnhdVDgt5o1qkmsqQh8uJrJ9SdyLIaZQIc=)char(\\n)delimiter(")> -string<delimiter(")content(-----END RSA PRIVATE KEY-----)char(\\n)delimiter(")> -string<delimiter(")content(-----BEGIN CERTIFICATE-----)char(\\n)delimiter(")> -string<delimiter(")content(MIID6TCCA1KgAwIBAgIJANm4W/Tzs+s+MA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD)char(\\n)delimiter(")> -string<delimiter(")content(VQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYw)char(\\n)delimiter(")> -string<delimiter(")content(FAYDVQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsG)char(\\n)delimiter(")> -string<delimiter(")content(A1UEAxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2lu)char(\\n)delimiter(")> -string<delimiter(")content(ZWVyaW5nQHN0ZWFtaGVhdC5uZXQwHhcNMDYwNTA1MTcwNjAzWhcNMjQwMjIwMTcw)char(\\n)delimiter(")> -string<delimiter(")content(NjAzWjCBqjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQH)char(\\n)delimiter(")> -string<delimiter(")content(EwhOZXcgWW9yazEWMBQGA1UEChMNU3RlYW1oZWF0Lm5ldDEUMBIGA1UECxMLRW5n)char(\\n)delimiter(")> -string<delimiter(")content(aW5lZXJpbmcxHTAbBgNVBAMTFG9wZW5jYS5zdGVhbWhlYXQubmV0MSgwJgYJKoZI)char(\\n)delimiter(")> -string<delimiter(")content(hvcNAQkBFhllbmdpbmVlcmluZ0BzdGVhbWhlYXQubmV0MIGfMA0GCSqGSIb3DQEB)char(\\n)delimiter(")> -string<delimiter(")content(AQUAA4GNADCBiQKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxw)char(\\n)delimiter(")> -string<delimiter(")content(VDWVIgdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t3)char(\\n)delimiter(")> -string<delimiter(")content(9hJ/AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQID)char(\\n)delimiter(")> -string<delimiter(")content(AQABo4IBEzCCAQ8wHQYDVR0OBBYEFPJvPd1Fcmd8o/Tm88r+NjYPICCkMIHfBgNV)char(\\n)delimiter(")> -string<delimiter(")content(HSMEgdcwgdSAFPJvPd1Fcmd8o/Tm88r+NjYPICCkoYGwpIGtMIGqMQswCQYDVQQG)char(\\n)delimiter(")> -string<delimiter(")content(EwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYwFAYD)char(\\n)delimiter(")> -string<delimiter(")content(VQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsGA1UE)char(\\n)delimiter(")> -string<delimiter(")content(AxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2luZWVy)char(\\n)delimiter(")> -string<delimiter(")content(aW5nQHN0ZWFtaGVhdC5uZXSCCQDZuFv087PrPjAMBgNVHRMEBTADAQH/MA0GCSqG)char(\\n)delimiter(")> -string<delimiter(")content(SIb3DQEBBQUAA4GBAC1CXey/4UoLgJiwcEMDxOvW74plks23090iziFIlGgcIhk0)char(\\n)delimiter(")> -string<delimiter(")content(Df6hTAs7H3MWww62ddvR8l07AWfSzSP5L6mDsbvq7EmQsmPODwb6C+i2aF3EDL8j)char(\\n)delimiter(")> -string<delimiter(")content(uw73m4YIGI0Zw2XdBpiOGkx2H56Kya6mJJe/5XORZedh1wpI7zki01tHYbcy)char(\\n)delimiter(")> -string<delimiter(")content(-----END CERTIFICATE-----)char(\\n)delimiter(")>operator(};) - -comment(/* These private materials were made with: - * openssl req -new -x509 -keyout cakey.pem -out cacert.pem -nodes -days 6500 - * TODO: We need a full-blown capability to work with user-supplied - * keypairs and properly-signed certificates. - */) - - -comment(/***************** -builtin_passwd_cb -*****************/) - -directive(extern) string<delimiter(")content(C)delimiter(")> pre_type(int) ident(builtin_passwd_cb) operator(()pre_type(char) operator(*)ident(buf)operator(,) pre_type(int) ident(bufsize)operator(,) pre_type(int) ident(rwflag)operator(,) directive(void) operator(*)ident(userdata)operator(\)) -operator({) - ident(strcpy) operator(()ident(buf)operator(,) string<delimiter(")content(kittycat)delimiter(")>operator(\);) - reserved(return) integer(8)operator(;) -operator(}) - -comment(/**************************** -InitializeDefaultCredentials -****************************/) - -directive(static) directive(void) ident(InitializeDefaultCredentials)operator((\)) -operator({) - ident(BIO) operator(*)ident(bio) operator(=) ident(BIO_new_mem_buf) operator(()ident(PrivateMaterials)operator(,) operator(-)integer(1)operator(\);) - ident(assert) operator(()ident(bio)operator(\);) - - reserved(if) operator(()ident(DefaultPrivateKey)operator(\)) operator({) - comment(// we may come here in a restart.) - ident(EVP_PKEY_free) operator(()ident(DefaultPrivateKey)operator(\);) - ident(DefaultPrivateKey) operator(=) pre_constant(NULL)operator(;) - operator(}) - ident(PEM_read_bio_PrivateKey) operator(()ident(bio)operator(,) operator(&)ident(DefaultPrivateKey)operator(,) ident(builtin_passwd_cb)operator(,) integer(0)operator(\);) - - reserved(if) operator(()ident(DefaultCertificate)operator(\)) operator({) - comment(// we may come here in a restart.) - ident(X509_free) operator(()ident(DefaultCertificate)operator(\);) - ident(DefaultCertificate) operator(=) pre_constant(NULL)operator(;) - operator(}) - ident(PEM_read_bio_X509) operator(()ident(bio)operator(,) operator(&)ident(DefaultCertificate)operator(,) pre_constant(NULL)operator(,) integer(0)operator(\);) - - ident(BIO_free) operator(()ident(bio)operator(\);) -operator(}) - - - -comment(/************************** -SslContext_t::SslContext_t -**************************/) - -ident(SslContext_t)operator(::)ident(SslContext_t) operator(()pre_type(bool) ident(is_server)operator(,) directive(const) pre_type(string) operator(&)ident(privkeyfile)operator(,) directive(const) pre_type(string) operator(&)ident(certchainfile)operator(\):) - ident(pCtx) operator(()pre_constant(NULL)operator(\),) - ident(PrivateKey) operator(()pre_constant(NULL)operator(\),) - ident(Certificate) operator(()pre_constant(NULL)operator(\)) -operator({) - comment(/* TODO: the usage of the specified private-key and cert-chain filenames only applies to - * client-side connections at this point. Server connections currently use the default materials. - * That needs to be fixed asap. - * Also, in this implementation, server-side connections use statically defined X-509 defaults. - * One thing I'm really not clear on is whether or not you have to explicitly free X509 and EVP_PKEY - * objects when we call our destructor, or whether just calling SSL_CTX_free is enough. - */) - - reserved(if) operator((!)ident(bLibraryInitialized)operator(\)) operator({) - ident(bLibraryInitialized) operator(=) pre_constant(true)operator(;) - ident(SSL_library_init)operator((\);) - ident(OpenSSL_add_ssl_algorithms)operator((\);) - ident(OpenSSL_add_all_algorithms)operator((\);) - ident(SSL_load_error_strings)operator((\);) - ident(ERR_load_crypto_strings)operator((\);) - - ident(InitializeDefaultCredentials)operator((\);) - operator(}) - - ident(bIsServer) operator(=) ident(is_server)operator(;) - ident(pCtx) operator(=) ident(SSL_CTX_new) operator(()ident(is_server) operator(?) ident(SSLv23_server_method)operator((\)) operator(:) ident(SSLv23_client_method)operator((\)\);) - reserved(if) operator((!)ident(pCtx)operator(\)) - reserved(throw) ident(std)operator(::)ident(runtime_error) operator(()string<delimiter(")content(no SSL context)delimiter(")>operator(\);) - - ident(SSL_CTX_set_options) operator(()ident(pCtx)operator(,) ident(SSL_OP_ALL)operator(\);) - comment(//SSL_CTX_set_options (pCtx, (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3\)\);) - - reserved(if) operator(()ident(is_server)operator(\)) operator({) - comment(// The SSL_CTX calls here do NOT allocate memory.) - pre_type(int) ident(e)operator(;) - reserved(if) operator(()ident(privkeyfile)operator(.)ident(length)operator((\)) operator(>) integer(0)operator(\)) - ident(e) operator(=) ident(SSL_CTX_use_PrivateKey_file) operator(()ident(pCtx)operator(,) ident(privkeyfile)operator(.)ident(c_str)operator((\),) ident(SSL_FILETYPE_PEM)operator(\);) - reserved(else) - ident(e) operator(=) ident(SSL_CTX_use_PrivateKey) operator(()ident(pCtx)operator(,) ident(DefaultPrivateKey)operator(\);) - ident(assert) operator(()ident(e) operator(>) integer(0)operator(\);) - reserved(if) operator(()ident(certchainfile)operator(.)ident(length)operator((\)) operator(>) integer(0)operator(\)) - ident(e) operator(=) ident(SSL_CTX_use_certificate_chain_file) operator(()ident(pCtx)operator(,) ident(certchainfile)operator(.)ident(c_str)operator((\)\);) - reserved(else) - ident(e) operator(=) ident(SSL_CTX_use_certificate) operator(()ident(pCtx)operator(,) ident(DefaultCertificate)operator(\);) - ident(assert) operator(()ident(e) operator(>) integer(0)operator(\);) - operator(}) - - ident(SSL_CTX_set_cipher_list) operator(()ident(pCtx)operator(,) string<delimiter(")content(ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH)delimiter(")>operator(\);) - - reserved(if) operator(()ident(is_server)operator(\)) operator({) - ident(SSL_CTX_sess_set_cache_size) operator(()ident(pCtx)operator(,) integer(128)operator(\);) - ident(SSL_CTX_set_session_id_context) operator(()ident(pCtx)operator(,) operator(()pre_type(unsigned) pre_type(char)operator(*\))string<delimiter(")content(eventmachine)delimiter(")>operator(,) integer(12)operator(\);) - operator(}) - reserved(else) operator({) - pre_type(int) ident(e)operator(;) - reserved(if) operator(()ident(privkeyfile)operator(.)ident(length)operator((\)) operator(>) integer(0)operator(\)) operator({) - ident(e) operator(=) ident(SSL_CTX_use_PrivateKey_file) operator(()ident(pCtx)operator(,) ident(privkeyfile)operator(.)ident(c_str)operator((\),) ident(SSL_FILETYPE_PEM)operator(\);) - ident(assert) operator(()ident(e) operator(>) integer(0)operator(\);) - operator(}) - reserved(if) operator(()ident(certchainfile)operator(.)ident(length)operator((\)) operator(>) integer(0)operator(\)) operator({) - ident(e) operator(=) ident(SSL_CTX_use_certificate_chain_file) operator(()ident(pCtx)operator(,) ident(certchainfile)operator(.)ident(c_str)operator((\)\);) - ident(assert) operator(()ident(e) operator(>) integer(0)operator(\);) - operator(}) - operator(}) -operator(}) - - - -comment(/*************************** -SslContext_t::~SslContext_t -***************************/) - -ident(SslContext_t)operator(::~)ident(SslContext_t)operator((\)) -operator({) - reserved(if) operator(()ident(pCtx)operator(\)) - ident(SSL_CTX_free) operator(()ident(pCtx)operator(\);) - reserved(if) operator(()ident(PrivateKey)operator(\)) - ident(EVP_PKEY_free) operator(()ident(PrivateKey)operator(\);) - reserved(if) operator(()ident(Certificate)operator(\)) - ident(X509_free) operator(()ident(Certificate)operator(\);) -operator(}) - - - -comment(/****************** -SslBox_t::SslBox_t -******************/) - -ident(SslBox_t)operator(::)ident(SslBox_t) operator(()pre_type(bool) ident(is_server)operator(,) directive(const) pre_type(string) operator(&)ident(privkeyfile)operator(,) directive(const) pre_type(string) operator(&)ident(certchainfile)operator(\):) - ident(bIsServer) operator(()ident(is_server)operator(\),) - ident(pSSL) operator(()pre_constant(NULL)operator(\),) - ident(pbioRead) operator(()pre_constant(NULL)operator(\),) - ident(pbioWrite) operator(()pre_constant(NULL)operator(\)) -operator({) - comment(/* TODO someday: make it possible to re-use SSL contexts so we don't have to create - * a new one every time we come here. - */) - - ident(Context) operator(=) reserved(new) ident(SslContext_t) operator(()ident(bIsServer)operator(,) ident(privkeyfile)operator(,) ident(certchainfile)operator(\);) - ident(assert) operator(()ident(Context)operator(\);) - - ident(pbioRead) operator(=) ident(BIO_new) operator(()ident(BIO_s_mem)operator((\)\);) - ident(assert) operator(()ident(pbioRead)operator(\);) - - ident(pbioWrite) operator(=) ident(BIO_new) operator(()ident(BIO_s_mem)operator((\)\);) - ident(assert) operator(()ident(pbioWrite)operator(\);) - - ident(pSSL) operator(=) ident(SSL_new) operator(()ident(Context)operator(->)ident(pCtx)operator(\);) - ident(assert) operator(()ident(pSSL)operator(\);) - ident(SSL_set_bio) operator(()ident(pSSL)operator(,) ident(pbioRead)operator(,) ident(pbioWrite)operator(\);) - - reserved(if) operator((!)ident(bIsServer)operator(\)) - ident(SSL_connect) operator(()ident(pSSL)operator(\);) -operator(}) - - - -comment(/******************* -SslBox_t::~SslBox_t -*******************/) - -ident(SslBox_t)operator(::~)ident(SslBox_t)operator((\)) -operator({) - comment(// Freeing pSSL will also free the associated BIOs, so DON'T free them separately.) - reserved(if) operator(()ident(pSSL)operator(\)) operator({) - reserved(if) operator(()ident(SSL_get_shutdown) operator(()ident(pSSL)operator(\)) operator(&) ident(SSL_RECEIVED_SHUTDOWN)operator(\)) - ident(SSL_shutdown) operator(()ident(pSSL)operator(\);) - reserved(else) - ident(SSL_clear) operator(()ident(pSSL)operator(\);) - ident(SSL_free) operator(()ident(pSSL)operator(\);) - operator(}) - - reserved(delete) ident(Context)operator(;) -operator(}) - - - -comment(/*********************** -SslBox_t::PutCiphertext -***********************/) - -pre_type(bool) ident(SslBox_t)operator(::)ident(PutCiphertext) operator(()directive(const) pre_type(char) operator(*)ident(buf)operator(,) pre_type(int) ident(bufsize)operator(\)) -operator({) - ident(assert) operator(()ident(buf) operator(&&) operator(()ident(bufsize) operator(>) integer(0)operator(\)\);) - - ident(assert) operator(()ident(pbioRead)operator(\);) - pre_type(int) ident(n) operator(=) ident(BIO_write) operator(()ident(pbioRead)operator(,) ident(buf)operator(,) ident(bufsize)operator(\);) - - reserved(return) operator(()ident(n) operator(==) ident(bufsize)operator(\)) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(;) -operator(}) - - -comment(/********************** -SslBox_t::GetPlaintext -**********************/) - -pre_type(int) ident(SslBox_t)operator(::)ident(GetPlaintext) operator(()pre_type(char) operator(*)ident(buf)operator(,) pre_type(int) ident(bufsize)operator(\)) -operator({) - reserved(if) operator((!)ident(SSL_is_init_finished) operator(()ident(pSSL)operator(\)\)) operator({) - pre_type(int) ident(e) operator(=) ident(bIsServer) operator(?) ident(SSL_accept) operator(()ident(pSSL)operator(\)) operator(:) ident(SSL_connect) operator(()ident(pSSL)operator(\);) - reserved(if) operator(()ident(e) operator(<) integer(0)operator(\)) operator({) - pre_type(int) ident(er) operator(=) ident(SSL_get_error) operator(()ident(pSSL)operator(,) ident(e)operator(\);) - reserved(if) operator(()ident(er) operator(!=) ident(SSL_ERROR_WANT_READ)operator(\)) operator({) - comment(// Return -1 for a nonfatal error, -2 for an error that should force the connection down.) - reserved(return) operator(()ident(er) operator(==) ident(SSL_ERROR_SSL)operator(\)) operator(?) operator((-)integer(2)operator(\)) operator(:) operator((-)integer(1)operator(\);) - operator(}) - reserved(else) - reserved(return) integer(0)operator(;) - operator(}) - comment(// If handshake finished, FALL THROUGH and return the available plaintext.) - operator(}) - - reserved(if) operator((!)ident(SSL_is_init_finished) operator(()ident(pSSL)operator(\)\)) operator({) - comment(// We can get here if a browser abandons a handshake.) - comment(// The user can see a warning dialog and abort the connection.) - ident(cerr) operator(<<) string<delimiter(")content(<SSL_incomp>)delimiter(")>operator(;) - reserved(return) integer(0)operator(;) - operator(}) - - comment(//cerr << "CIPH: " << SSL_get_cipher (pSSL\) << endl;) - - pre_type(int) ident(n) operator(=) ident(SSL_read) operator(()ident(pSSL)operator(,) ident(buf)operator(,) ident(bufsize)operator(\);) - reserved(if) operator(()ident(n) operator(>=) integer(0)operator(\)) operator({) - reserved(return) ident(n)operator(;) - operator(}) - reserved(else) operator({) - reserved(if) operator(()ident(SSL_get_error) operator(()ident(pSSL)operator(,) ident(n)operator(\)) operator(==) ident(SSL_ERROR_WANT_READ)operator(\)) operator({) - reserved(return) integer(0)operator(;) - operator(}) - reserved(else) operator({) - reserved(return) operator(-)integer(1)operator(;) - operator(}) - operator(}) - - reserved(return) integer(0)operator(;) -operator(}) - - - -comment(/************************** -SslBox_t::CanGetCiphertext -**************************/) - -pre_type(bool) ident(SslBox_t)operator(::)ident(CanGetCiphertext)operator((\)) -operator({) - ident(assert) operator(()ident(pbioWrite)operator(\);) - reserved(return) ident(BIO_pending) operator(()ident(pbioWrite)operator(\)) operator(?) pre_constant(true) operator(:) pre_constant(false)operator(;) -operator(}) - - - -comment(/*********************** -SslBox_t::GetCiphertext -***********************/) - -pre_type(int) ident(SslBox_t)operator(::)ident(GetCiphertext) operator(()pre_type(char) operator(*)ident(buf)operator(,) pre_type(int) ident(bufsize)operator(\)) -operator({) - ident(assert) operator(()ident(pbioWrite)operator(\);) - ident(assert) operator(()ident(buf) operator(&&) operator(()ident(bufsize) operator(>) integer(0)operator(\)\);) - - reserved(return) ident(BIO_read) operator(()ident(pbioWrite)operator(,) ident(buf)operator(,) ident(bufsize)operator(\);) -operator(}) - - - -comment(/********************** -SslBox_t::PutPlaintext -**********************/) - -pre_type(int) ident(SslBox_t)operator(::)ident(PutPlaintext) operator(()directive(const) pre_type(char) operator(*)ident(buf)operator(,) pre_type(int) ident(bufsize)operator(\)) -operator({) - comment(// The caller will interpret the return value as the number of bytes written.) - comment(// WARNING WARNING WARNING, are there any situations in which a 0 or -1 return) - comment(// from SSL_write means we should immediately retry? The socket-machine loop) - comment(// will probably wait for a time-out cycle (perhaps a second\) before re-trying.) - comment(// THIS WOULD CAUSE A PERCEPTIBLE DELAY!) - - comment(/* We internally queue any outbound plaintext that can't be dispatched - * because we're in the middle of a handshake or something. - * When we get called, try to send any queued data first, and then - * send the caller's data (or queue it\). We may get called with no outbound - * data, which means we try to send the outbound queue and that's all. - * - * Return >0 if we wrote any data, 0 if we didn't, and <0 for a fatal error. - * Note that if we return 0, the connection is still considered live - * and we are signalling that we have accepted the outbound data (if any\). - */) - - ident(OutboundQ)operator(.)ident(Push) operator(()ident(buf)operator(,) ident(bufsize)operator(\);) - - reserved(if) operator((!)ident(SSL_is_init_finished) operator(()ident(pSSL)operator(\)\)) - reserved(return) integer(0)operator(;) - - pre_type(bool) ident(fatal) operator(=) pre_constant(false)operator(;) - pre_type(bool) ident(did_work) operator(=) pre_constant(false)operator(;) - - reserved(while) operator(()ident(OutboundQ)operator(.)ident(HasPages)operator((\)\)) operator({) - directive(const) pre_type(char) operator(*)ident(page)operator(;) - pre_type(int) ident(length)operator(;) - ident(OutboundQ)operator(.)ident(Front) operator((&)ident(page)operator(,) operator(&)ident(length)operator(\);) - ident(assert) operator(()ident(page) operator(&&) operator(()ident(length) operator(>) integer(0)operator(\)\);) - pre_type(int) ident(n) operator(=) ident(SSL_write) operator(()ident(pSSL)operator(,) ident(page)operator(,) ident(length)operator(\);) - reserved(if) operator(()ident(n) operator(>) integer(0)operator(\)) operator({) - ident(did_work) operator(=) pre_constant(true)operator(;) - ident(OutboundQ)operator(.)ident(PopFront)operator((\);) - operator(}) - reserved(else) operator({) - pre_type(int) ident(er) operator(=) ident(SSL_get_error) operator(()ident(pSSL)operator(,) ident(n)operator(\);) - reserved(if) operator((()ident(er) operator(!=) ident(SSL_ERROR_WANT_READ)operator(\)) operator(&&) operator(()ident(er) operator(!=) ident(SSL_ERROR_WANT_WRITE)operator(\)\)) - ident(fatal) operator(=) pre_constant(true)operator(;) - reserved(break)operator(;) - operator(}) - operator(}) - - - reserved(if) operator(()ident(did_work)operator(\)) - reserved(return) integer(1)operator(;) - reserved(else) reserved(if) operator(()ident(fatal)operator(\)) - reserved(return) operator(-)integer(1)operator(;) - reserved(else) - reserved(return) integer(0)operator(;) -operator(}) - - -preprocessor(#endif) comment(// WITH_SSL) - diff --git a/test/scanners/cpp/eventmachine.in.cpp b/test/scanners/cpp/eventmachine.in.cpp deleted file mode 100644 index 050d601..0000000 --- a/test/scanners/cpp/eventmachine.in.cpp +++ /dev/null @@ -1,7035 +0,0 @@ -/***************************************************************************** - -$Id$ - -File: binder.cpp -Date: 07Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - -#define DEV_URANDOM "/dev/urandom" - - -map<string, Bindable_t*> Bindable_t::BindingBag; - - -/******************************** -STATIC Bindable_t::CreateBinding -********************************/ - -string Bindable_t::CreateBinding() -{ - static int index = 0; - static string seed; - - if ((index >= 1000000) || (seed.length() == 0)) { - #ifdef OS_UNIX - int fd = open (DEV_URANDOM, O_RDONLY); - if (fd < 0) - throw std::runtime_error ("No entropy device"); - - unsigned char u[16]; - size_t r = read (fd, u, sizeof(u)); - if (r < sizeof(u)) - throw std::runtime_error ("Unable to read entropy device"); - - unsigned char *u1 = (unsigned char*)u; - char u2 [sizeof(u) * 2 + 1]; - - for (size_t i=0; i < sizeof(u); i++) - sprintf (u2 + (i * 2), "%02x", u1[i]); - - seed = string (u2); - #endif - - - #ifdef OS_WIN32 - UUID uuid; - UuidCreate (&uuid); - unsigned char *uuidstring = NULL; - UuidToString (&uuid, &uuidstring); - if (!uuidstring) - throw std::runtime_error ("Unable to read uuid"); - seed = string ((const char*)uuidstring); - - RpcStringFree (&uuidstring); - #endif - - index = 0; - - - } - - stringstream ss; - ss << seed << (++index); - return ss.str(); -} - - -/***************************** -STATIC: Bindable_t::GetObject -*****************************/ - -Bindable_t *Bindable_t::GetObject (const char *binding) -{ - string s (binding ? binding : ""); - return GetObject (s); -} - -/***************************** -STATIC: Bindable_t::GetObject -*****************************/ - -Bindable_t *Bindable_t::GetObject (const string &binding) -{ - map<string, Bindable_t*>::const_iterator i = BindingBag.find (binding); - if (i != BindingBag.end()) - return i->second; - else - return NULL; -} - - -/********************** -Bindable_t::Bindable_t -**********************/ - -Bindable_t::Bindable_t() -{ - Binding = Bindable_t::CreateBinding(); - BindingBag [Binding] = this; -} - - - -/*********************** -Bindable_t::~Bindable_t -***********************/ - -Bindable_t::~Bindable_t() -{ - BindingBag.erase (Binding); -} - - -/***************************************************************************** - -$Id$ - -File: cmain.cpp -Date: 06Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - - -static EventMachine_t *EventMachine; -static int bUseEpoll = 0; -static int bUseKqueue = 0; - -extern "C" void ensure_eventmachine (const char *caller = "unknown caller") -{ - if (!EventMachine) { - const int err_size = 128; - char err_string[err_size]; - snprintf (err_string, err_size, "eventmachine not initialized: %s", caller); - #ifdef BUILD_FOR_RUBY - rb_raise(rb_eRuntimeError, err_string); - #else - throw std::runtime_error (err_string); - #endif - } -} - -/*********************** -evma_initialize_library -***********************/ - -extern "C" void evma_initialize_library (void(*cb)(const char*, int, const char*, int)) -{ - // Probably a bad idea to mess with the signal mask of a process - // we're just being linked into. - //InstallSignalHandlers(); - if (EventMachine) - #ifdef BUILD_FOR_RUBY - rb_raise(rb_eRuntimeError, "eventmachine already initialized: evma_initialize_library"); - #else - throw std::runtime_error ("eventmachine already initialized: evma_initialize_library"); - #endif - EventMachine = new EventMachine_t (cb); - if (bUseEpoll) - EventMachine->_UseEpoll(); - if (bUseKqueue) - EventMachine->_UseKqueue(); -} - - -/******************** -evma_release_library -********************/ - -extern "C" void evma_release_library() -{ - ensure_eventmachine("evma_release_library"); - delete EventMachine; - EventMachine = NULL; -} - - -/**************** -evma_run_machine -****************/ - -extern "C" void evma_run_machine() -{ - ensure_eventmachine("evma_run_machine"); - EventMachine->Run(); -} - - -/************************** -evma_install_oneshot_timer -**************************/ - -extern "C" const char *evma_install_oneshot_timer (int seconds) -{ - ensure_eventmachine("evma_install_oneshot_timer"); - return EventMachine->InstallOneshotTimer (seconds); -} - - -/********************** -evma_connect_to_server -**********************/ - -extern "C" const char *evma_connect_to_server (const char *server, int port) -{ - ensure_eventmachine("evma_connect_to_server"); - return EventMachine->ConnectToServer (server, port); -} - -/*************************** -evma_connect_to_unix_server -***************************/ - -extern "C" const char *evma_connect_to_unix_server (const char *server) -{ - ensure_eventmachine("evma_connect_to_unix_server"); - return EventMachine->ConnectToUnixServer (server); -} - -/************** -evma_attach_fd -**************/ - -extern "C" const char *evma_attach_fd (int file_descriptor, int notify_readable, int notify_writable) -{ - ensure_eventmachine("evma_attach_fd"); - return EventMachine->AttachFD (file_descriptor, (notify_readable ? true : false), (notify_writable ? true : false)); -} - -/************** -evma_detach_fd -**************/ - -extern "C" int evma_detach_fd (const char *binding) -{ - ensure_eventmachine("evma_dettach_fd"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) - return EventMachine->DetachFD (ed); - else - #ifdef BUILD_FOR_RUBY - rb_raise(rb_eRuntimeError, "invalid binding to detach"); - #else - throw std::runtime_error ("invalid binding to detach"); - #endif -} - -/********************** -evma_create_tcp_server -**********************/ - -extern "C" const char *evma_create_tcp_server (const char *address, int port) -{ - ensure_eventmachine("evma_create_tcp_server"); - return EventMachine->CreateTcpServer (address, port); -} - -/****************************** -evma_create_unix_domain_server -******************************/ - -extern "C" const char *evma_create_unix_domain_server (const char *filename) -{ - ensure_eventmachine("evma_create_unix_domain_server"); - return EventMachine->CreateUnixDomainServer (filename); -} - -/************************* -evma_open_datagram_socket -*************************/ - -extern "C" const char *evma_open_datagram_socket (const char *address, int port) -{ - ensure_eventmachine("evma_open_datagram_socket"); - return EventMachine->OpenDatagramSocket (address, port); -} - -/****************** -evma_open_keyboard -******************/ - -extern "C" const char *evma_open_keyboard() -{ - ensure_eventmachine("evma_open_keyboard"); - return EventMachine->OpenKeyboard(); -} - - - -/**************************** -evma_send_data_to_connection -****************************/ - -extern "C" int evma_send_data_to_connection (const char *binding, const char *data, int data_length) -{ - ensure_eventmachine("evma_send_data_to_connection"); - return ConnectionDescriptor::SendDataToConnection (binding, data, data_length); -} - -/****************** -evma_send_datagram -******************/ - -extern "C" int evma_send_datagram (const char *binding, const char *data, int data_length, const char *address, int port) -{ - ensure_eventmachine("evma_send_datagram"); - return DatagramDescriptor::SendDatagram (binding, data, data_length, address, port); -} - - -/********************* -evma_close_connection -*********************/ - -extern "C" void evma_close_connection (const char *binding, int after_writing) -{ - ensure_eventmachine("evma_close_connection"); - ConnectionDescriptor::CloseConnection (binding, (after_writing ? true : false)); -} - -/*********************************** -evma_report_connection_error_status -***********************************/ - -extern "C" int evma_report_connection_error_status (const char *binding) -{ - ensure_eventmachine("evma_report_connection_error_status"); - return ConnectionDescriptor::ReportErrorStatus (binding); -} - -/******************** -evma_stop_tcp_server -********************/ - -extern "C" void evma_stop_tcp_server (const char *binding) -{ - ensure_eventmachine("evma_stop_tcp_server"); - AcceptorDescriptor::StopAcceptor (binding); -} - - -/***************** -evma_stop_machine -*****************/ - -extern "C" void evma_stop_machine() -{ - ensure_eventmachine("evma_stop_machine"); - EventMachine->ScheduleHalt(); -} - - -/************** -evma_start_tls -**************/ - -extern "C" void evma_start_tls (const char *binding) -{ - ensure_eventmachine("evma_start_tls"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) - ed->StartTls(); -} - -/****************** -evma_set_tls_parms -******************/ - -extern "C" void evma_set_tls_parms (const char *binding, const char *privatekey_filename, const char *certchain_filename) -{ - ensure_eventmachine("evma_set_tls_parms"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) - ed->SetTlsParms (privatekey_filename, certchain_filename); -} - - -/***************** -evma_get_peername -*****************/ - -extern "C" int evma_get_peername (const char *binding, struct sockaddr *sa) -{ - ensure_eventmachine("evma_get_peername"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) { - return ed->GetPeername (sa) ? 1 : 0; - } - else - return 0; -} - -/***************** -evma_get_sockname -*****************/ - -extern "C" int evma_get_sockname (const char *binding, struct sockaddr *sa) -{ - ensure_eventmachine("evma_get_sockname"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) { - return ed->GetSockname (sa) ? 1 : 0; - } - else - return 0; -} - -/*********************** -evma_get_subprocess_pid -***********************/ - -extern "C" int evma_get_subprocess_pid (const char *binding, pid_t *pid) -{ - ensure_eventmachine("evma_get_subprocess_pid"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) { - return ed->GetSubprocessPid (pid) ? 1 : 0; - } - else - return 0; -} - -/************************** -evma_get_subprocess_status -**************************/ - -extern "C" int evma_get_subprocess_status (const char *binding, int *status) -{ - ensure_eventmachine("evma_get_subprocess_status"); - if (status) { - *status = EventMachine->SubprocessExitStatus; - return 1; - } - else - return 0; -} - - -/********************* -evma_signal_loopbreak -*********************/ - -extern "C" void evma_signal_loopbreak() -{ - ensure_eventmachine("evma_signal_loopbreak"); - EventMachine->SignalLoopBreaker(); -} - - - -/**************** -evma__write_file -****************/ - -extern "C" const char *evma__write_file (const char *filename) -{ - ensure_eventmachine("evma__write_file"); - return EventMachine->_OpenFileForWriting (filename); -} - - -/******************************** -evma_get_comm_inactivity_timeout -********************************/ - -extern "C" int evma_get_comm_inactivity_timeout (const char *binding, int *value) -{ - ensure_eventmachine("evma_get_comm_inactivity_timeout"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) { - return ed->GetCommInactivityTimeout (value); - } - else - return 0; //Perhaps this should be an exception. Access to an unknown binding. -} - -/******************************** -evma_set_comm_inactivity_timeout -********************************/ - -extern "C" int evma_set_comm_inactivity_timeout (const char *binding, int *value) -{ - ensure_eventmachine("evma_set_comm_inactivity_timeout"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) { - return ed->SetCommInactivityTimeout (value); - } - else - return 0; //Perhaps this should be an exception. Access to an unknown binding. -} - - -/********************** -evma_set_timer_quantum -**********************/ - -extern "C" void evma_set_timer_quantum (int interval) -{ - ensure_eventmachine("evma_set_timer_quantum"); - EventMachine->SetTimerQuantum (interval); -} - -/************************ -evma_set_max_timer_count -************************/ - -extern "C" void evma_set_max_timer_count (int ct) -{ - // This may only be called if the reactor is not running. - - if (EventMachine) - #ifdef BUILD_FOR_RUBY - rb_raise(rb_eRuntimeError, "eventmachine already initialized: evma_set_max_timer_count"); - #else - throw std::runtime_error ("eventmachine already initialized: evma_set_max_timer_count"); - #endif - EventMachine_t::SetMaxTimerCount (ct); -} - -/****************** -evma_setuid_string -******************/ - -extern "C" void evma_setuid_string (const char *username) -{ - // We do NOT need to be running an EM instance because this method is static. - EventMachine_t::SetuidString (username); -} - - -/********** -evma_popen -**********/ - -extern "C" const char *evma_popen (char * const*cmd_strings) -{ - ensure_eventmachine("evma_popen"); - return EventMachine->Socketpair (cmd_strings); -} - - -/*************************** -evma_get_outbound_data_size -***************************/ - -extern "C" int evma_get_outbound_data_size (const char *binding) -{ - ensure_eventmachine("evma_get_outbound_data_size"); - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - return ed ? ed->GetOutboundDataSize() : 0; -} - - -/*********** -evma__epoll -***********/ - -extern "C" void evma__epoll() -{ - bUseEpoll = 1; -} - -/************ -evma__kqueue -************/ - -extern "C" void evma__kqueue() -{ - bUseKqueue = 1; -} - - -/********************** -evma_set_rlimit_nofile -**********************/ - -extern "C" int evma_set_rlimit_nofile (int nofiles) -{ - return EventMachine_t::SetRlimitNofile (nofiles); -} - - -/********************************* -evma_send_file_data_to_connection -*********************************/ - -extern "C" int evma_send_file_data_to_connection (const char *binding, const char *filename) -{ - /* This is a sugaring over send_data_to_connection that reads a file into a - * locally-allocated buffer, and sends the file data to the remote peer. - * Return the number of bytes written to the caller. - * TODO, needs to impose a limit on the file size. This is intended only for - * small files. (I don't know, maybe 8K or less.) For larger files, use interleaved - * I/O to avoid slowing the rest of the system down. - * TODO: we should return a code rather than barf, in case of file-not-found. - * TODO, does this compile on Windows? - * TODO, given that we want this to work only with small files, how about allocating - * the buffer on the stack rather than the heap? - * - * Modified 25Jul07. This now returns -1 on file-too-large; 0 for success, and a positive - * errno in case of other errors. - * - /* Contributed by Kirk Haines. - */ - - char data[32*1024]; - int r; - - ensure_eventmachine("evma_send_file_data_to_connection"); - - int Fd = open (filename, O_RDONLY); - - if (Fd < 0) - return errno; - // From here on, all early returns MUST close Fd. - - struct stat st; - if (fstat (Fd, &st)) { - int e = errno; - close (Fd); - return e; - } - - int filesize = st.st_size; - if (filesize <= 0) { - close (Fd); - return 0; - } - else if (filesize > sizeof(data)) { - close (Fd); - return -1; - } - - - r = read (Fd, data, filesize); - if (r != filesize) { - int e = errno; - close (Fd); - return e; - } - evma_send_data_to_connection (binding, data, r); - close (Fd); - - return 0; -} - -/***************************************************************************** - -$Id$ - -File: cplusplus.cpp -Date: 27Jul07 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - - -#include "project.h" - - -namespace EM { - static map<string, Eventable*> Eventables; - static map<string, void(*)()> Timers; -} - - -/******* -EM::Run -*******/ - -void EM::Run (void (*start_func)()) -{ - evma__epoll(); - evma_initialize_library (EM::Callback); - if (start_func) - AddTimer (0, start_func); - evma_run_machine(); - evma_release_library(); -} - -/************ -EM::AddTimer -************/ - -void EM::AddTimer (int milliseconds, void (*func)()) -{ - if (func) { - const char *sig = evma_install_oneshot_timer (milliseconds); - Timers.insert (make_pair (sig, func)); - } -} - - -/*************** -EM::StopReactor -***************/ - -void EM::StopReactor() -{ - evma_stop_machine(); -} - - -/******************** -EM::Acceptor::Accept -********************/ - -void EM::Acceptor::Accept (const char *signature) -{ - Connection *c = MakeConnection(); - c->Signature = signature; - Eventables.insert (make_pair (c->Signature, c)); - c->PostInit(); -} - -/************************ -EM::Connection::SendData -************************/ - -void EM::Connection::SendData (const char *data) -{ - if (data) - SendData (data, strlen (data)); -} - - -/************************ -EM::Connection::SendData -************************/ - -void EM::Connection::SendData (const char *data, int length) -{ - evma_send_data_to_connection (Signature.c_str(), data, length); -} - - -/********************* -EM::Connection::Close -*********************/ - -void EM::Connection::Close (bool afterWriting) -{ - evma_close_connection (Signature.c_str(), afterWriting); -} - - -/*********************** -EM::Connection::Connect -***********************/ - -void EM::Connection::Connect (const char *host, int port) -{ - Signature = evma_connect_to_server (host, port); - Eventables.insert( make_pair (Signature, this)); -} - -/******************* -EM::Acceptor::Start -*******************/ - -void EM::Acceptor::Start (const char *host, int port) -{ - Signature = evma_create_tcp_server (host, port); - Eventables.insert( make_pair (Signature, this)); -} - - - -/************ -EM::Callback -************/ - -void EM::Callback (const char *sig, int ev, const char *data, int length) -{ - EM::Eventable *e; - void (*f)(); - - switch (ev) { - case EM_TIMER_FIRED: - f = Timers [data]; - if (f) - (*f)(); - Timers.erase (sig); - break; - - case EM_CONNECTION_READ: - e = EM::Eventables [sig]; - e->ReceiveData (data, length); - break; - - case EM_CONNECTION_COMPLETED: - e = EM::Eventables [sig]; - e->ConnectionCompleted(); - break; - - case EM_CONNECTION_ACCEPTED: - e = EM::Eventables [sig]; - e->Accept (data); - break; - - case EM_CONNECTION_UNBOUND: - e = EM::Eventables [sig]; - e->Unbind(); - EM::Eventables.erase (sig); - delete e; - break; - } -} - -/***************************************************************************** - -$Id$ - -File: ed.cpp -Date: 06Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - - - -/******************** -SetSocketNonblocking -********************/ - -bool SetSocketNonblocking (SOCKET sd) -{ - #ifdef OS_UNIX - int val = fcntl (sd, F_GETFL, 0); - return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false; - #endif - - #ifdef OS_WIN32 - unsigned long one = 1; - return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false; - #endif -} - - -/**************************************** -EventableDescriptor::EventableDescriptor -****************************************/ - -EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em): - bCloseNow (false), - bCloseAfterWriting (false), - MySocket (sd), - EventCallback (NULL), - LastRead (0), - LastWritten (0), - bCallbackUnbind (true), - MyEventMachine (em) -{ - /* There are three ways to close a socket, all of which should - * automatically signal to the event machine that this object - * should be removed from the polling scheduler. - * First is a hard close, intended for bad errors or possible - * security violations. It immediately closes the connection - * and puts this object into an error state. - * Second is to set bCloseNow, which will cause the event machine - * to delete this object (and thus close the connection in our - * destructor) the next chance it gets. bCloseNow also inhibits - * the writing of new data on the socket (but not necessarily - * the reading of new data). - * The third way is to set bCloseAfterWriting, which inhibits - * the writing of new data and converts to bCloseNow as soon - * as everything in the outbound queue has been written. - * bCloseAfterWriting is really for use only by protocol handlers - * (for example, HTTP writes an HTML page and then closes the - * connection). All of the error states we generate internally - * cause an immediate close to be scheduled, which may have the - * effect of discarding outbound data. - */ - - if (sd == INVALID_SOCKET) - throw std::runtime_error ("bad eventable descriptor"); - if (MyEventMachine == NULL) - throw std::runtime_error ("bad em in eventable descriptor"); - CreatedAt = gCurrentLoopTime; - - #ifdef HAVE_EPOLL - EpollEvent.data.ptr = this; - #endif -} - - -/***************************************** -EventableDescriptor::~EventableDescriptor -*****************************************/ - -EventableDescriptor::~EventableDescriptor() -{ - if (EventCallback && bCallbackUnbind) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, 0); - Close(); -} - - -/************************************* -EventableDescriptor::SetEventCallback -*************************************/ - -void EventableDescriptor::SetEventCallback (void(*cb)(const char*, int, const char*, int)) -{ - EventCallback = cb; -} - - -/************************** -EventableDescriptor::Close -**************************/ - -void EventableDescriptor::Close() -{ - // Close the socket right now. Intended for emergencies. - if (MySocket != INVALID_SOCKET) { - shutdown (MySocket, 1); - closesocket (MySocket); - MySocket = INVALID_SOCKET; - } -} - - -/********************************* -EventableDescriptor::ShouldDelete -*********************************/ - -bool EventableDescriptor::ShouldDelete() -{ - /* For use by a socket manager, which needs to know if this object - * should be removed from scheduling events and deleted. - * Has an immediate close been scheduled, or are we already closed? - * If either of these are the case, return true. In theory, the manager will - * then delete us, which in turn will make sure the socket is closed. - * Note, if bCloseAfterWriting is true, we check a virtual method to see - * if there is outbound data to write, and only request a close if there is none. - */ - - return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0))); -} - - -/********************************** -EventableDescriptor::ScheduleClose -**********************************/ - -void EventableDescriptor::ScheduleClose (bool after_writing) -{ - // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled. - if (after_writing) - bCloseAfterWriting = true; - else - bCloseNow = true; -} - - -/************************************* -EventableDescriptor::IsCloseScheduled -*************************************/ - -bool EventableDescriptor::IsCloseScheduled() -{ - // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose. - return (bCloseNow || bCloseAfterWriting); -} - - -/****************************************** -ConnectionDescriptor::ConnectionDescriptor -******************************************/ - -ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em): - EventableDescriptor (sd, em), - bConnectPending (false), - bNotifyReadable (false), - bNotifyWritable (false), - bReadAttemptedAfterClose (false), - bWriteAttemptedAfterClose (false), - OutboundDataSize (0), - #ifdef WITH_SSL - SslBox (NULL), - #endif - bIsServer (false), - LastIo (gCurrentLoopTime), - InactivityTimeout (0) -{ - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLOUT; - #endif - // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData() -} - - -/******************************************* -ConnectionDescriptor::~ConnectionDescriptor -*******************************************/ - -ConnectionDescriptor::~ConnectionDescriptor() -{ - // Run down any stranded outbound data. - for (size_t i=0; i < OutboundPages.size(); i++) - OutboundPages[i].Free(); - - #ifdef WITH_SSL - if (SslBox) - delete SslBox; - #endif -} - - -/************************************************** -STATIC: ConnectionDescriptor::SendDataToConnection -**************************************************/ - -int ConnectionDescriptor::SendDataToConnection (const char *binding, const char *data, int data_length) -{ - // TODO: This is something of a hack, or at least it's a static method of the wrong class. - // TODO: Poor polymorphism here. We should be calling one virtual method - // instead of hacking out the runtime information of the target object. - ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding)); - if (cd) - return cd->SendOutboundData (data, data_length); - DatagramDescriptor *ds = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding)); - if (ds) - return ds->SendOutboundData (data, data_length); - #ifdef OS_UNIX - PipeDescriptor *ps = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding)); - if (ps) - return ps->SendOutboundData (data, data_length); - #endif - return -1; -} - - -/********************************************* -STATIC: ConnectionDescriptor::CloseConnection -*********************************************/ - -void ConnectionDescriptor::CloseConnection (const char *binding, bool after_writing) -{ - // TODO: This is something of a hack, or at least it's a static method of the wrong class. - EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding)); - if (ed) - ed->ScheduleClose (after_writing); -} - -/*********************************************** -STATIC: ConnectionDescriptor::ReportErrorStatus -***********************************************/ - -int ConnectionDescriptor::ReportErrorStatus (const char *binding) -{ - // TODO: This is something of a hack, or at least it's a static method of the wrong class. - // TODO: Poor polymorphism here. We should be calling one virtual method - // instead of hacking out the runtime information of the target object. - ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding)); - if (cd) - return cd->_ReportErrorStatus(); - return -1; -} - -/*************************************** -ConnectionDescriptor::SetConnectPending -****************************************/ - -void ConnectionDescriptor::SetConnectPending(bool f) -{ - bConnectPending = f; - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueWriter (this); - #endif -} - - -/************************************** -ConnectionDescriptor::SendOutboundData -**************************************/ - -int ConnectionDescriptor::SendOutboundData (const char *data, int length) -{ - #ifdef WITH_SSL - if (SslBox) { - if (length > 0) { - int w = SslBox->PutPlaintext (data, length); - if (w < 0) - ScheduleClose (false); - else - _DispatchCiphertext(); - } - // TODO: What's the correct return value? - return 1; // That's a wild guess, almost certainly wrong. - } - else - #endif - return _SendRawOutboundData (data, length); -} - - - -/****************************************** -ConnectionDescriptor::_SendRawOutboundData -******************************************/ - -int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length) -{ - /* This internal method is called to schedule bytes that - * will be sent out to the remote peer. - * It's not directly accessed by the caller, who hits ::SendOutboundData, - * which may or may not filter or encrypt the caller's data before - * sending it here. - */ - - // Highly naive and incomplete implementation. - // There's no throttle for runaways (which should abort only this connection - // and not the whole process), and no coalescing of small pages. - // (Well, not so bad, small pages are coalesced in ::Write) - - if (IsCloseScheduled()) - //if (bCloseNow || bCloseAfterWriting) - return 0; - - if (!data && (length > 0)) - throw std::runtime_error ("bad outbound data"); - char *buffer = (char *) malloc (length + 1); - if (!buffer) - throw std::runtime_error ("no allocation for outbound data"); - memcpy (buffer, data, length); - buffer [length] = 0; - OutboundPages.push_back (OutboundPage (buffer, length)); - OutboundDataSize += length; - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | EPOLLOUT); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueWriter (this); - #endif - return length; -} - - - -/*********************************** -ConnectionDescriptor::SelectForRead -***********************************/ - -bool ConnectionDescriptor::SelectForRead() -{ - /* A connection descriptor is always scheduled for read, - * UNLESS it's in a pending-connect state. - * On Linux, unlike Unix, a nonblocking socket on which - * connect has been called, does NOT necessarily select - * both readable and writable in case of error. - * The socket will select writable when the disposition - * of the connect is known. On the other hand, a socket - * which successfully connects and selects writable may - * indeed have some data available on it, so it will - * select readable in that case, violating expectations! - * So we will not poll for readability until the socket - * is known to be in a connected state. - */ - - return bConnectPending ? false : true; -} - - -/************************************ -ConnectionDescriptor::SelectForWrite -************************************/ - -bool ConnectionDescriptor::SelectForWrite() -{ - /* Cf the notes under SelectForRead. - * In a pending-connect state, we ALWAYS select for writable. - * In a normal state, we only select for writable when we - * have outgoing data to send. - */ - - if (bConnectPending || bNotifyWritable) - return true; - else { - return (GetOutboundDataSize() > 0); - } -} - - -/************************** -ConnectionDescriptor::Read -**************************/ - -void ConnectionDescriptor::Read() -{ - /* Read and dispatch data on a socket that has selected readable. - * It's theoretically possible to get and dispatch incoming data on - * a socket that has already been scheduled for closing or close-after-writing. - * In those cases, we'll leave it up the to protocol handler to "do the - * right thing" (which probably means to ignore the incoming data). - * - * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come - * here with the socket already closed, after the process receives - * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application - * was one in which network connections were doing a lot of interleaved reads - * and writes. - * Since we always write before reading (in order to keep the outbound queues - * as light as possible), I think what happened is that an interrupt caused - * the socket to be closed in ConnectionDescriptor::Write. We'll then - * come here in the same pass through the main event loop, and won't get - * cleaned up until immediately after. - * We originally asserted that the socket was valid when we got here. - * To deal properly with the possibility that we are closed when we get here, - * I removed the assert. HOWEVER, the potential for an infinite loop scares me, - * so even though this is really clunky, I added a flag to assert that we never - * come here more than once after being closed. (FCianfrocca) - */ - - int sd = GetSocket(); - //assert (sd != INVALID_SOCKET); (original, removed 22Aug06) - if (sd == INVALID_SOCKET) { - assert (!bReadAttemptedAfterClose); - bReadAttemptedAfterClose = true; - return; - } - - if (bNotifyReadable) { - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0); - return; - } - - LastIo = gCurrentLoopTime; - - int total_bytes_read = 0; - char readbuffer [16 * 1024 + 1]; - - for (int i=0; i < 10; i++) { - // Don't read just one buffer and then move on. This is faster - // if there is a lot of incoming. - // But don't read indefinitely. Give other sockets a chance to run. - // NOTICE, we're reading one less than the buffer size. - // That's so we can put a guard byte at the end of what we send - // to user code. - - - int r = recv (sd, readbuffer, sizeof(readbuffer) - 1, 0); - //cerr << "<R:" << r << ">"; - - if (r > 0) { - total_bytes_read += r; - LastRead = gCurrentLoopTime; - - // Add a null-terminator at the the end of the buffer - // that we will send to the callback. - // DO NOT EVER CHANGE THIS. We want to explicitly allow users - // to be able to depend on this behavior, so they will have - // the option to do some things faster. Additionally it's - // a security guard against buffer overflows. - readbuffer [r] = 0; - _DispatchInboundData (readbuffer, r); - } - else if (r == 0) { - break; - } - else { - // Basically a would-block, meaning we've read everything there is to read. - break; - } - - } - - - if (total_bytes_read == 0) { - // If we read no data on a socket that selected readable, - // it generally means the other end closed the connection gracefully. - ScheduleClose (false); - //bCloseNow = true; - } - -} - - - -/****************************************** -ConnectionDescriptor::_DispatchInboundData -******************************************/ - -void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size) -{ - #ifdef WITH_SSL - if (SslBox) { - SslBox->PutCiphertext (buffer, size); - - int s; - char B [2048]; - while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) { - B [s] = 0; - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, B, s); - } - // INCOMPLETE, s may indicate an SSL error that would force the connection down. - _DispatchCiphertext(); - } - else { - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buffer, size); - } - #endif - - #ifdef WITHOUT_SSL - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buffer, size); - #endif -} - - - - - -/*************************** -ConnectionDescriptor::Write -***************************/ - -void ConnectionDescriptor::Write() -{ - /* A socket which is in a pending-connect state will select - * writable when the disposition of the connect is known. - * At that point, check to be sure there are no errors, - * and if none, then promote the socket out of the pending - * state. - * TODO: I haven't figured out how Windows signals errors on - * unconnected sockets. Maybe it does the untraditional but - * logical thing and makes the socket selectable for error. - * If so, it's unsupported here for the time being, and connect - * errors will have to be caught by the timeout mechanism. - */ - - if (bConnectPending) { - int error; - socklen_t len; - len = sizeof(error); - #ifdef OS_UNIX - int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len); - #endif - #ifdef OS_WIN32 - int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len); - #endif - if ((o == 0) && (error == 0)) { - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_COMPLETED, "", 0); - bConnectPending = false; - #ifdef HAVE_EPOLL - // The callback may have scheduled outbound data. - EpollEvent.events = EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0); - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueReader (this); - // The callback may have scheduled outbound data. - if (SelectForWrite()) - MyEventMachine->ArmKqueueWriter (this); - #endif - } - else - ScheduleClose (false); - //bCloseNow = true; - } - else { - - if (bNotifyWritable) { - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0); - return; - } - - _WriteOutboundData(); - } -} - - -/**************************************** -ConnectionDescriptor::_WriteOutboundData -****************************************/ - -void ConnectionDescriptor::_WriteOutboundData() -{ - /* This is a helper function called by ::Write. - * It's possible for a socket to select writable and then no longer - * be writable by the time we get around to writing. The kernel might - * have used up its available output buffers between the select call - * and when we get here. So this condition is not an error. - * - * 20Jul07, added the same kind of protection against an invalid socket - * that is at the top of ::Read. Not entirely how this could happen in - * real life (connection-reset from the remote peer, perhaps?), but I'm - * doing it to address some reports of crashing under heavy loads. - */ - - int sd = GetSocket(); - //assert (sd != INVALID_SOCKET); - if (sd == INVALID_SOCKET) { - assert (!bWriteAttemptedAfterClose); - bWriteAttemptedAfterClose = true; - return; - } - - LastIo = gCurrentLoopTime; - char output_buffer [16 * 1024]; - size_t nbytes = 0; - - while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) { - OutboundPage *op = &(OutboundPages[0]); - if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) { - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset); - nbytes += (op->Length - op->Offset); - op->Free(); - OutboundPages.pop_front(); - } - else { - int len = sizeof(output_buffer) - nbytes; - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len); - op->Offset += len; - nbytes += len; - } - } - - // We should never have gotten here if there were no data to write, - // so assert that as a sanity check. - // Don't bother to make sure nbytes is less than output_buffer because - // if it were we probably would have crashed already. - assert (nbytes > 0); - - assert (GetSocket() != INVALID_SOCKET); - int bytes_written = send (GetSocket(), output_buffer, nbytes, 0); - - bool err = false; - if (bytes_written < 0) { - err = true; - bytes_written = 0; - } - - assert (bytes_written >= 0); - OutboundDataSize -= bytes_written; - if ((size_t)bytes_written < nbytes) { - int len = nbytes - bytes_written; - char *buffer = (char*) malloc (len + 1); - if (!buffer) - throw std::runtime_error ("bad alloc throwing back data"); - memcpy (buffer, output_buffer + bytes_written, len); - buffer [len] = 0; - OutboundPages.push_front (OutboundPage (buffer, len)); - } - - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0)); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - #ifdef HAVE_KQUEUE - if (SelectForWrite()) - MyEventMachine->ArmKqueueWriter (this); - #endif - - - if (err) { - #ifdef OS_UNIX - if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR)) - #endif - #ifdef OS_WIN32 - if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK)) - #endif - Close(); - } -} - - -/**************************************** -ConnectionDescriptor::_ReportErrorStatus -****************************************/ - -int ConnectionDescriptor::_ReportErrorStatus() -{ - int error; - socklen_t len; - len = sizeof(error); - #ifdef OS_UNIX - int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len); - #endif - #ifdef OS_WIN32 - int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len); - #endif - if ((o == 0) && (error == 0)) - return 0; - else - return 1; -} - - -/****************************** -ConnectionDescriptor::StartTls -******************************/ - -void ConnectionDescriptor::StartTls() -{ - #ifdef WITH_SSL - if (SslBox) - throw std::runtime_error ("SSL/TLS already running on connection"); - - SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename); - _DispatchCiphertext(); - #endif - - #ifdef WITHOUT_SSL - throw std::runtime_error ("Encryption not available on this event-machine"); - #endif -} - - -/********************************* -ConnectionDescriptor::SetTlsParms -*********************************/ - -void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename) -{ - #ifdef WITH_SSL - if (SslBox) - throw std::runtime_error ("call SetTlsParms before calling StartTls"); - if (privkey_filename && *privkey_filename) - PrivateKeyFilename = privkey_filename; - if (certchain_filename && *certchain_filename) - CertChainFilename = certchain_filename; - #endif - - #ifdef WITHOUT_SSL - throw std::runtime_error ("Encryption not available on this event-machine"); - #endif -} - - - -/***************************************** -ConnectionDescriptor::_DispatchCiphertext -*****************************************/ -#ifdef WITH_SSL -void ConnectionDescriptor::_DispatchCiphertext() -{ - assert (SslBox); - - - char BigBuf [2048]; - bool did_work; - - do { - did_work = false; - - // try to drain ciphertext - while (SslBox->CanGetCiphertext()) { - int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf)); - assert (r > 0); - _SendRawOutboundData (BigBuf, r); - did_work = true; - } - - // Pump the SslBox, in case it has queued outgoing plaintext - // This will return >0 if data was written, - // 0 if no data was written, and <0 if there was a fatal error. - bool pump; - do { - pump = false; - int w = SslBox->PutPlaintext (NULL, 0); - if (w > 0) { - did_work = true; - pump = true; - } - else if (w < 0) - ScheduleClose (false); - } while (pump); - - // try to put plaintext. INCOMPLETE, doesn't belong here? - // In SendOutboundData, we're spooling plaintext directly - // into SslBox. That may be wrong, we may need to buffer it - // up here! - /* - const char *ptr; - int ptr_length; - while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) { - assert (ptr && (ptr_length > 0)); - int w = SslMachine.PutPlaintext (ptr, ptr_length); - if (w > 0) { - OutboundPlaintext.DiscardBytes (w); - did_work = true; - } - else - break; - } - */ - - } while (did_work); - -} -#endif - - - -/******************************* -ConnectionDescriptor::Heartbeat -*******************************/ - -void ConnectionDescriptor::Heartbeat() -{ - /* Only allow a certain amount of time to go by while waiting - * for a pending connect. If it expires, then kill the socket. - * For a connected socket, close it if its inactivity timer - * has expired. - */ - - if (bConnectPending) { - if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout) - ScheduleClose (false); - //bCloseNow = true; - } - else { - if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout)) - ScheduleClose (false); - //bCloseNow = true; - } -} - - -/**************************************** -LoopbreakDescriptor::LoopbreakDescriptor -****************************************/ - -LoopbreakDescriptor::LoopbreakDescriptor (int sd, EventMachine_t *parent_em): - EventableDescriptor (sd, parent_em) -{ - /* This is really bad and ugly. Change someday if possible. - * We have to know about an event-machine (probably the one that owns us), - * so we can pass newly-created connections to it. - */ - - bCallbackUnbind = false; - - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueReader (this); - #endif -} - - - - -/************************* -LoopbreakDescriptor::Read -*************************/ - -void LoopbreakDescriptor::Read() -{ - // TODO, refactor, this code is probably in the wrong place. - assert (MyEventMachine); - MyEventMachine->_ReadLoopBreaker(); -} - - -/************************** -LoopbreakDescriptor::Write -**************************/ - -void LoopbreakDescriptor::Write() -{ - // Why are we here? - throw std::runtime_error ("bad code path in loopbreak"); -} - -/************************************** -AcceptorDescriptor::AcceptorDescriptor -**************************************/ - -AcceptorDescriptor::AcceptorDescriptor (int sd, EventMachine_t *parent_em): - EventableDescriptor (sd, parent_em) -{ - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueReader (this); - #endif -} - - -/*************************************** -AcceptorDescriptor::~AcceptorDescriptor -***************************************/ - -AcceptorDescriptor::~AcceptorDescriptor() -{ -} - -/**************************************** -STATIC: AcceptorDescriptor::StopAcceptor -****************************************/ - -void AcceptorDescriptor::StopAcceptor (const char *binding) -{ - // TODO: This is something of a hack, or at least it's a static method of the wrong class. - AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding)); - if (ad) - ad->ScheduleClose (false); - else - throw std::runtime_error ("failed to close nonexistent acceptor"); -} - - -/************************ -AcceptorDescriptor::Read -************************/ - -void AcceptorDescriptor::Read() -{ - /* Accept up to a certain number of sockets on the listening connection. - * Don't try to accept all that are present, because this would allow a DoS attack - * in which no data were ever read or written. We should accept more than one, - * if available, to keep the partially accepted sockets from backing up in the kernel. - */ - - /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it - * for readability. According to Stevens UNP, it's possible for an acceptor to select readable - * and then block when we call accept. For example, the other end resets the connection after - * the socket selects readable and before we call accept. The kernel will remove the dead - * socket from the accept queue. If the accept queue is now empty, accept will block. - */ - - - struct sockaddr_in pin; - socklen_t addrlen = sizeof (pin); - - for (int i=0; i < 10; i++) { - int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen); - if (sd == INVALID_SOCKET) { - // This breaks the loop when we've accepted everything on the kernel queue, - // up to 10 new connections. But what if the *first* accept fails? - // Does that mean anything serious is happening, beyond the situation - // described in the note above? - break; - } - - // Set the newly-accepted socket non-blocking. - // On Windows, this may fail because, weirdly, Windows inherits the non-blocking - // attribute that we applied to the acceptor socket into the accepted one. - if (!SetSocketNonblocking (sd)) { - //int val = fcntl (sd, F_GETFL, 0); - //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) { - shutdown (sd, 1); - closesocket (sd); - continue; - } - - - // Disable slow-start (Nagle algorithm). Eventually make this configurable. - int one = 1; - setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one)); - - - ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine); - if (!cd) - throw std::runtime_error ("no newly accepted connection"); - cd->SetServerMode(); - if (EventCallback) { - (*EventCallback) (GetBinding().c_str(), EM_CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size()); - } - #ifdef HAVE_EPOLL - cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0); - #endif - assert (MyEventMachine); - MyEventMachine->Add (cd); - #ifdef HAVE_KQUEUE - if (cd->SelectForWrite()) - MyEventMachine->ArmKqueueWriter (cd); - MyEventMachine->ArmKqueueReader (cd); - #endif - } - -} - - -/************************* -AcceptorDescriptor::Write -*************************/ - -void AcceptorDescriptor::Write() -{ - // Why are we here? - throw std::runtime_error ("bad code path in acceptor"); -} - - -/***************************** -AcceptorDescriptor::Heartbeat -*****************************/ - -void AcceptorDescriptor::Heartbeat() -{ - // No-op -} - - -/******************************* -AcceptorDescriptor::GetSockname -*******************************/ - -bool AcceptorDescriptor::GetSockname (struct sockaddr *s) -{ - bool ok = false; - if (s) { - socklen_t len = sizeof(*s); - int gp = getsockname (GetSocket(), s, &len); - if (gp == 0) - ok = true; - } - return ok; -} - - - -/************************************** -DatagramDescriptor::DatagramDescriptor -**************************************/ - -DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em): - EventableDescriptor (sd, parent_em), - OutboundDataSize (0), - LastIo (gCurrentLoopTime), - InactivityTimeout (0) -{ - memset (&ReturnAddress, 0, sizeof(ReturnAddress)); - - /* Provisionally added 19Oct07. All datagram sockets support broadcasting. - * Until now, sending to a broadcast address would give EACCES (permission denied) - * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order - * to accept a packet to a broadcast address. Solaris doesn't require it. I think - * Windows DOES require it but I'm not sure. - * - * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST - * on a UDP socket in order to enable broadcasting. The reason for requiring the option - * in the first place is so that applications don't send broadcast datagrams by mistake. - * I imagine that could happen if a user of an application typed in an address that happened - * to be a broadcast address on that particular subnet. - * - * This is provisional because someone may eventually come up with a good reason not to - * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API - * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T - * EXPLICITLY SET THE OPTION. - */ - - int oval = 1; - int sob = setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval)); - - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueReader (this); - #endif -} - - -/*************************************** -DatagramDescriptor::~DatagramDescriptor -***************************************/ - -DatagramDescriptor::~DatagramDescriptor() -{ - // Run down any stranded outbound data. - for (size_t i=0; i < OutboundPages.size(); i++) - OutboundPages[i].Free(); -} - - -/***************************** -DatagramDescriptor::Heartbeat -*****************************/ - -void DatagramDescriptor::Heartbeat() -{ - // Close it if its inactivity timer has expired. - - if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout)) - ScheduleClose (false); - //bCloseNow = true; -} - - -/************************ -DatagramDescriptor::Read -************************/ - -void DatagramDescriptor::Read() -{ - int sd = GetSocket(); - assert (sd != INVALID_SOCKET); - LastIo = gCurrentLoopTime; - - // This is an extremely large read buffer. - // In many cases you wouldn't expect to get any more than 4K. - char readbuffer [16 * 1024]; - - for (int i=0; i < 10; i++) { - // Don't read just one buffer and then move on. This is faster - // if there is a lot of incoming. - // But don't read indefinitely. Give other sockets a chance to run. - // NOTICE, we're reading one less than the buffer size. - // That's so we can put a guard byte at the end of what we send - // to user code. - - struct sockaddr_in sin; - socklen_t slen = sizeof (sin); - memset (&sin, 0, slen); - - int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen); - //cerr << "<R:" << r << ">"; - - // In UDP, a zero-length packet is perfectly legal. - if (r >= 0) { - LastRead = gCurrentLoopTime; - - // Add a null-terminator at the the end of the buffer - // that we will send to the callback. - // DO NOT EVER CHANGE THIS. We want to explicitly allow users - // to be able to depend on this behavior, so they will have - // the option to do some things faster. Additionally it's - // a security guard against buffer overflows. - readbuffer [r] = 0; - - - // Set up a "temporary" return address so that callers can "reply" to us - // from within the callback we are about to invoke. That means that ordinary - // calls to "send_data_to_connection" (which is of course misnamed in this - // case) will result in packets being sent back to the same place that sent - // us this one. - // There is a different call (evma_send_datagram) for cases where the caller - // actually wants to send a packet somewhere else. - - memset (&ReturnAddress, 0, sizeof(ReturnAddress)); - memcpy (&ReturnAddress, &sin, slen); - - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r); - - } - else { - // Basically a would-block, meaning we've read everything there is to read. - break; - } - - } - - -} - - -/************************* -DatagramDescriptor::Write -*************************/ - -void DatagramDescriptor::Write() -{ - /* It's possible for a socket to select writable and then no longer - * be writable by the time we get around to writing. The kernel might - * have used up its available output buffers between the select call - * and when we get here. So this condition is not an error. - * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData, - * but differs in the that the outbound data pages (received from the - * user) are _message-structured._ That is, we send each of them out - * one message at a time. - * TODO, we are currently suppressing the EMSGSIZE error!!! - */ - - int sd = GetSocket(); - assert (sd != INVALID_SOCKET); - LastIo = gCurrentLoopTime; - - assert (OutboundPages.size() > 0); - - // Send out up to 10 packets, then cycle the machine. - for (int i = 0; i < 10; i++) { - if (OutboundPages.size() <= 0) - break; - OutboundPage *op = &(OutboundPages[0]); - - // The nasty cast to (char*) is needed because Windows is brain-dead. - int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From)); - int e = errno; - - OutboundDataSize -= op->Length; - op->Free(); - OutboundPages.pop_front(); - - if (s == SOCKET_ERROR) { - #ifdef OS_UNIX - if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) { - #endif - #ifdef OS_WIN32 - if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) { - #endif - Close(); - break; - } - } - } - - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0)); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif -} - - -/********************************** -DatagramDescriptor::SelectForWrite -**********************************/ - -bool DatagramDescriptor::SelectForWrite() -{ - /* Changed 15Nov07, per bug report by Mark Zvillius. - * The outbound data size will be zero if there are zero-length outbound packets, - * so we now select writable in case the outbound page buffer is not empty. - * Note that the superclass ShouldDelete method still checks for outbound data size, - * which may be wrong. - */ - //return (GetOutboundDataSize() > 0); (Original) - return (OutboundPages.size() > 0); -} - - -/************************************ -DatagramDescriptor::SendOutboundData -************************************/ - -int DatagramDescriptor::SendOutboundData (const char *data, int length) -{ - // This is an exact clone of ConnectionDescriptor::SendOutboundData. - // That means it needs to move to a common ancestor. - - if (IsCloseScheduled()) - //if (bCloseNow || bCloseAfterWriting) - return 0; - - if (!data && (length > 0)) - throw std::runtime_error ("bad outbound data"); - char *buffer = (char *) malloc (length + 1); - if (!buffer) - throw std::runtime_error ("no allocation for outbound data"); - memcpy (buffer, data, length); - buffer [length] = 0; - OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress)); - OutboundDataSize += length; - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | EPOLLOUT); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - return length; -} - - -/**************************************** -DatagramDescriptor::SendOutboundDatagram -****************************************/ - -int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, const char *address, int port) -{ - // This is an exact clone of ConnectionDescriptor::SendOutboundData. - // That means it needs to move to a common ancestor. - // TODO: Refactor this so there's no overlap with SendOutboundData. - - if (IsCloseScheduled()) - //if (bCloseNow || bCloseAfterWriting) - return 0; - - if (!address || !*address || !port) - return 0; - - sockaddr_in pin; - unsigned long HostAddr; - - HostAddr = inet_addr (address); - if (HostAddr == INADDR_NONE) { - // The nasty cast to (char*) is because Windows is brain-dead. - hostent *hp = gethostbyname ((char*)address); - if (!hp) - return 0; - HostAddr = ((in_addr*)(hp->h_addr))->s_addr; - } - - memset (&pin, 0, sizeof(pin)); - pin.sin_family = AF_INET; - pin.sin_addr.s_addr = HostAddr; - pin.sin_port = htons (port); - - - - if (!data && (length > 0)) - throw std::runtime_error ("bad outbound data"); - char *buffer = (char *) malloc (length + 1); - if (!buffer) - throw std::runtime_error ("no allocation for outbound data"); - memcpy (buffer, data, length); - buffer [length] = 0; - OutboundPages.push_back (OutboundPage (buffer, length, pin)); - OutboundDataSize += length; - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | EPOLLOUT); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - return length; -} - - -/**************************************** -STATIC: DatagramDescriptor::SendDatagram -****************************************/ - -int DatagramDescriptor::SendDatagram (const char *binding, const char *data, int length, const char *address, int port) -{ - DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding)); - if (dd) - return dd->SendOutboundDatagram (data, length, address, port); - else - return -1; -} - - -/********************************* -ConnectionDescriptor::GetPeername -*********************************/ - -bool ConnectionDescriptor::GetPeername (struct sockaddr *s) -{ - bool ok = false; - if (s) { - socklen_t len = sizeof(*s); - int gp = getpeername (GetSocket(), s, &len); - if (gp == 0) - ok = true; - } - return ok; -} - -/********************************* -ConnectionDescriptor::GetSockname -*********************************/ - -bool ConnectionDescriptor::GetSockname (struct sockaddr *s) -{ - bool ok = false; - if (s) { - socklen_t len = sizeof(*s); - int gp = getsockname (GetSocket(), s, &len); - if (gp == 0) - ok = true; - } - return ok; -} - - -/********************************************** -ConnectionDescriptor::GetCommInactivityTimeout -**********************************************/ - -int ConnectionDescriptor::GetCommInactivityTimeout (int *value) -{ - if (value) { - *value = InactivityTimeout; - return 1; - } - else { - // TODO, extended logging, got bad parameter. - return 0; - } -} - - -/********************************************** -ConnectionDescriptor::SetCommInactivityTimeout -**********************************************/ - -int ConnectionDescriptor::SetCommInactivityTimeout (int *value) -{ - int out = 0; - - if (value) { - if ((*value==0) || (*value >= 2)) { - // Replace the value and send the old one back to the caller. - int v = *value; - *value = InactivityTimeout; - InactivityTimeout = v; - out = 1; - } - else { - // TODO, extended logging, got bad value. - } - } - else { - // TODO, extended logging, got bad parameter. - } - - return out; -} - -/******************************* -DatagramDescriptor::GetPeername -*******************************/ - -bool DatagramDescriptor::GetPeername (struct sockaddr *s) -{ - bool ok = false; - if (s) { - memset (s, 0, sizeof(struct sockaddr)); - memcpy (s, &ReturnAddress, sizeof(ReturnAddress)); - ok = true; - } - return ok; -} - -/******************************* -DatagramDescriptor::GetSockname -*******************************/ - -bool DatagramDescriptor::GetSockname (struct sockaddr *s) -{ - bool ok = false; - if (s) { - socklen_t len = sizeof(*s); - int gp = getsockname (GetSocket(), s, &len); - if (gp == 0) - ok = true; - } - return ok; -} - - - -/******************************************** -DatagramDescriptor::GetCommInactivityTimeout -********************************************/ - -int DatagramDescriptor::GetCommInactivityTimeout (int *value) -{ - if (value) { - *value = InactivityTimeout; - return 1; - } - else { - // TODO, extended logging, got bad parameter. - return 0; - } -} - -/******************************************** -DatagramDescriptor::SetCommInactivityTimeout -********************************************/ - -int DatagramDescriptor::SetCommInactivityTimeout (int *value) -{ - int out = 0; - - if (value) { - if ((*value==0) || (*value >= 2)) { - // Replace the value and send the old one back to the caller. - int v = *value; - *value = InactivityTimeout; - InactivityTimeout = v; - out = 1; - } - else { - // TODO, extended logging, got bad value. - } - } - else { - // TODO, extended logging, got bad parameter. - } - - return out; -} - -/***************************************************************************** - -$Id$ - -File: em.cpp -Date: 06Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -// THIS ENTIRE FILE WILL EVENTUALLY BE FOR UNIX BUILDS ONLY. -//#ifdef OS_UNIX - - -#include "project.h" - -// Keep a global variable floating around -// with the current loop time as set by the Event Machine. -// This avoids the need for frequent expensive calls to time(NULL); -time_t gCurrentLoopTime; - -#ifdef OS_WIN32 -unsigned gTickCountTickover; -unsigned gLastTickCount; -#endif - - -/* The numer of max outstanding timers was once a const enum defined in em.h. - * Now we define it here so that users can change its value if necessary. - */ -static int MaxOutstandingTimers = 1000; - - -/* Internal helper to convert strings to internet addresses. IPv6-aware. - * Not reentrant or threadsafe, optimized for speed. - */ -static struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size); - - -/*************************************** -STATIC EventMachine_t::SetMaxTimerCount -***************************************/ - -void EventMachine_t::SetMaxTimerCount (int count) -{ - /* Allow a user to increase the maximum number of outstanding timers. - * If this gets "too high" (a metric that is of course platform dependent), - * bad things will happen like performance problems and possible overuse - * of memory. - * The actual timer mechanism is very efficient so it's hard to know what - * the practical max, but 100,000 shouldn't be too problematical. - */ - if (count < 100) - count = 100; - MaxOutstandingTimers = count; -} - - - -/****************************** -EventMachine_t::EventMachine_t -******************************/ - -EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const char*, int)): - EventCallback (event_callback), - NextHeartbeatTime (0), - LoopBreakerReader (-1), - LoopBreakerWriter (-1), - bEpoll (false), - bKqueue (false), - epfd (-1) -{ - // Default time-slice is just smaller than one hundred mills. - Quantum.tv_sec = 0; - Quantum.tv_usec = 90000; - - gTerminateSignalReceived = false; - // Make sure the current loop time is sane, in case we do any initializations of - // objects before we start running. - gCurrentLoopTime = time(NULL); - - /* We initialize the network library here (only on Windows of course) - * and initialize "loop breakers." Our destructor also does some network-level - * cleanup. There's thus an implicit assumption that any given instance of EventMachine_t - * will only call ::Run once. Is that a good assumption? Should we move some of these - * inits and de-inits into ::Run? - */ - #ifdef OS_WIN32 - WSADATA w; - WSAStartup (MAKEWORD (1, 1), &w); - #endif - - _InitializeLoopBreaker(); -} - - -/******************************* -EventMachine_t::~EventMachine_t -*******************************/ - -EventMachine_t::~EventMachine_t() -{ - // Run down descriptors - size_t i; - for (i = 0; i < NewDescriptors.size(); i++) - delete NewDescriptors[i]; - for (i = 0; i < Descriptors.size(); i++) - delete Descriptors[i]; - - close (LoopBreakerReader); - close (LoopBreakerWriter); - - if (epfd != -1) - close (epfd); - if (kqfd != -1) - close (kqfd); -} - - -/************************* -EventMachine_t::_UseEpoll -*************************/ - -void EventMachine_t::_UseEpoll() -{ - /* Temporary. - * Use an internal flag to switch in epoll-based functionality until we determine - * how it should be integrated properly and the extent of the required changes. - * A permanent solution needs to allow the integration of additional technologies, - * like kqueue and Solaris's events. - */ - - #ifdef HAVE_EPOLL - bEpoll = true; - #endif -} - -/************************** -EventMachine_t::_UseKqueue -**************************/ - -void EventMachine_t::_UseKqueue() -{ - /* Temporary. - * See comments under _UseEpoll. - */ - - #ifdef HAVE_KQUEUE - bKqueue = true; - #endif -} - - -/**************************** -EventMachine_t::ScheduleHalt -****************************/ - -void EventMachine_t::ScheduleHalt() -{ - /* This is how we stop the machine. - * This can be called by clients. Signal handlers will probably - * set the global flag. - * For now this means there can only be one EventMachine ever running at a time. - * - * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here, - * because it may be called from signal handlers invoked from code that we don't - * control. At this writing (20Sep06), EM does NOT install any signal handlers of - * its own. - * - * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens? - * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler. - */ - gTerminateSignalReceived = true; -} - - - -/******************************* -EventMachine_t::SetTimerQuantum -*******************************/ - -void EventMachine_t::SetTimerQuantum (int interval) -{ - /* We get a timer-quantum expressed in milliseconds. - * Don't set a quantum smaller than 5 or larger than 2500. - */ - - if ((interval < 5) || (interval > 2500)) - throw std::runtime_error ("invalid timer-quantum"); - - Quantum.tv_sec = interval / 1000; - Quantum.tv_usec = (interval % 1000) * 1000; -} - - -/************************************* -(STATIC) EventMachine_t::SetuidString -*************************************/ - -void EventMachine_t::SetuidString (const char *username) -{ - /* This method takes a caller-supplied username and tries to setuid - * to that user. There is no meaningful implementation (and no error) - * on Windows. On Unix, a failure to setuid the caller-supplied string - * causes a fatal abort, because presumably the program is calling here - * in order to fulfill a security requirement. If we fail silently, - * the user may continue to run with too much privilege. - * - * TODO, we need to decide on and document a way of generating C++ level errors - * that can be wrapped in documented Ruby exceptions, so users can catch - * and handle them. And distinguish it from errors that we WON'T let the Ruby - * user catch (like security-violations and resource-overallocation). - * A setuid failure here would be in the latter category. - */ - - #ifdef OS_UNIX - if (!username || !*username) - throw std::runtime_error ("setuid_string failed: no username specified"); - - struct passwd *p = getpwnam (username); - if (!p) - throw std::runtime_error ("setuid_string failed: unknown username"); - - if (setuid (p->pw_uid) != 0) - throw std::runtime_error ("setuid_string failed: no setuid"); - - // Success. - #endif -} - - -/**************************************** -(STATIC) EventMachine_t::SetRlimitNofile -****************************************/ - -int EventMachine_t::SetRlimitNofile (int nofiles) -{ - #ifdef OS_UNIX - struct rlimit rlim; - getrlimit (RLIMIT_NOFILE, &rlim); - if (nofiles >= 0) { - rlim.rlim_cur = nofiles; - if (nofiles > rlim.rlim_max) - rlim.rlim_max = nofiles; - setrlimit (RLIMIT_NOFILE, &rlim); - // ignore the error return, for now at least. - // TODO, emit an error message someday when we have proper debug levels. - } - getrlimit (RLIMIT_NOFILE, &rlim); - return rlim.rlim_cur; - #endif - - #ifdef OS_WIN32 - // No meaningful implementation on Windows. - return 0; - #endif -} - - -/********************************* -EventMachine_t::SignalLoopBreaker -*********************************/ - -void EventMachine_t::SignalLoopBreaker() -{ - #ifdef OS_UNIX - write (LoopBreakerWriter, "", 1); - #endif - #ifdef OS_WIN32 - sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget)); - #endif -} - - -/************************************** -EventMachine_t::_InitializeLoopBreaker -**************************************/ - -void EventMachine_t::_InitializeLoopBreaker() -{ - /* A "loop-breaker" is a socket-descriptor that we can write to in order - * to break the main select loop. Primarily useful for things running on - * threads other than the main EM thread, so they can trigger processing - * of events that arise exogenously to the EM. - * Keep the loop-breaker pipe out of the main descriptor set, otherwise - * its events will get passed on to user code. - */ - - #ifdef OS_UNIX - int fd[2]; - if (pipe (fd)) - throw std::runtime_error ("no loop breaker"); - - LoopBreakerWriter = fd[1]; - LoopBreakerReader = fd[0]; - #endif - - #ifdef OS_WIN32 - int sd = socket (AF_INET, SOCK_DGRAM, 0); - if (sd == INVALID_SOCKET) - throw std::runtime_error ("no loop breaker socket"); - SetSocketNonblocking (sd); - - memset (&LoopBreakerTarget, 0, sizeof(LoopBreakerTarget)); - LoopBreakerTarget.sin_family = AF_INET; - LoopBreakerTarget.sin_addr.s_addr = inet_addr ("127.0.0.1"); - - srand ((int)time(NULL)); - int i; - for (i=0; i < 100; i++) { - int r = (rand() % 10000) + 20000; - LoopBreakerTarget.sin_port = htons (r); - if (bind (sd, (struct sockaddr*)&LoopBreakerTarget, sizeof(LoopBreakerTarget)) == 0) - break; - } - - if (i == 100) - throw std::runtime_error ("no loop breaker"); - LoopBreakerReader = sd; - #endif -} - - -/******************* -EventMachine_t::Run -*******************/ - -void EventMachine_t::Run() -{ - #ifdef OS_WIN32 - HookControlC (true); - #endif - - #ifdef HAVE_EPOLL - if (bEpoll) { - epfd = epoll_create (MaxEpollDescriptors); - if (epfd == -1) { - char buf[200]; - snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno)); - throw std::runtime_error (buf); - } - int cloexec = fcntl (epfd, F_GETFD, 0); - assert (cloexec >= 0); - cloexec |= FD_CLOEXEC; - fcntl (epfd, F_SETFD, cloexec); - - assert (LoopBreakerReader >= 0); - LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this); - assert (ld); - Add (ld); - } - #endif - - #ifdef HAVE_KQUEUE - if (bKqueue) { - kqfd = kqueue(); - if (kqfd == -1) { - char buf[200]; - snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno)); - throw std::runtime_error (buf); - } - // cloexec not needed. By definition, kqueues are not carried across forks. - - assert (LoopBreakerReader >= 0); - LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this); - assert (ld); - Add (ld); - } - #endif - - while (true) { - gCurrentLoopTime = time(NULL); - if (!_RunTimers()) - break; - - /* _Add must precede _Modify because the same descriptor might - * be on both lists during the same pass through the machine, - * and to modify a descriptor before adding it would fail. - */ - _AddNewDescriptors(); - _ModifyDescriptors(); - - if (!_RunOnce()) - break; - if (gTerminateSignalReceived) - break; - } - - #ifdef OS_WIN32 - HookControlC (false); - #endif -} - - -/************************ -EventMachine_t::_RunOnce -************************/ - -bool EventMachine_t::_RunOnce() -{ - if (bEpoll) - return _RunEpollOnce(); - else if (bKqueue) - return _RunKqueueOnce(); - else - return _RunSelectOnce(); -} - - - -/***************************** -EventMachine_t::_RunEpollOnce -*****************************/ - -bool EventMachine_t::_RunEpollOnce() -{ - #ifdef HAVE_EPOLL - assert (epfd != -1); - struct epoll_event ev [MaxEpollDescriptors]; - int s; - - #ifdef BUILD_FOR_RUBY - TRAP_BEG; - #endif - s = epoll_wait (epfd, ev, MaxEpollDescriptors, 50); - #ifdef BUILD_FOR_RUBY - TRAP_END; - #endif - - if (s > 0) { - for (int i=0; i < s; i++) { - EventableDescriptor *ed = (EventableDescriptor*) ev[i].data.ptr; - - if (ev[i].events & (EPOLLERR | EPOLLHUP)) - ed->ScheduleClose (false); - if (ev[i].events & EPOLLIN) - ed->Read(); - if (ev[i].events & EPOLLOUT) { - ed->Write(); - epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent()); - // Ignoring return value - } - } - } - else if (s < 0) { - // epoll_wait can fail on error in a handful of ways. - // If this happens, then wait for a little while to avoid busy-looping. - // If the error was EINTR, we probably caught SIGCHLD or something, - // so keep the wait short. - timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000}; - EmSelect (0, NULL, NULL, NULL, &tv); - } - - { // cleanup dying sockets - // vector::pop_back works in constant time. - // TODO, rip this out and only delete the descriptors we know have died, - // rather than traversing the whole list. - // Modified 05Jan08 per suggestions by Chris Heath. It's possible that - // an EventableDescriptor will have a descriptor value of -1. That will - // happen if EventableDescriptor::Close was called on it. In that case, - // don't call epoll_ctl to remove the socket's filters from the epoll set. - // According to the epoll docs, this happens automatically when the - // descriptor is closed anyway. This is different from the case where - // the socket has already been closed but the descriptor in the ED object - // hasn't yet been set to INVALID_SOCKET. - int i, j; - int nSockets = Descriptors.size(); - for (i=0, j=0; i < nSockets; i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - if (ed->ShouldDelete()) { - if (ed->GetSocket() != INVALID_SOCKET) { - assert (bEpoll); // wouldn't be in this method otherwise. - assert (epfd != -1); - int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent()); - // ENOENT or EBADF are not errors because the socket may be already closed when we get here. - if (e && (errno != ENOENT) && (errno != EBADF)) { - char buf [200]; - snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno)); - throw std::runtime_error (buf); - } - } - - ModifiedDescriptors.erase (ed); - delete ed; - } - else - Descriptors [j++] = ed; - } - while ((size_t)j < Descriptors.size()) - Descriptors.pop_back(); - - } - - // TODO, heartbeats. - // Added 14Sep07, its absence was noted by Brian Candler. But the comment was here, indicated - // that this got thought about and not done when EPOLL was originally written. Was there a reason - // not to do it, or was it an oversight? Certainly, running a heartbeat on 50,000 connections every - // two seconds can get to be a real bear, especially if all we're doing is timing out dead ones. - // Maybe there's a better way to do this. (Or maybe it's not that expensive after all.) - // - { // dispatch heartbeats - if (gCurrentLoopTime >= NextHeartbeatTime) { - NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval; - - for (int i=0; i < Descriptors.size(); i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - ed->Heartbeat(); - } - } - } - - #ifdef BUILD_FOR_RUBY - if (!rb_thread_alone()) { - rb_thread_schedule(); - } - #endif - - return true; - #else - throw std::runtime_error ("epoll is not implemented on this platform"); - #endif -} - - -/****************************** -EventMachine_t::_RunKqueueOnce -******************************/ - -bool EventMachine_t::_RunKqueueOnce() -{ - #ifdef HAVE_KQUEUE - assert (kqfd != -1); - const int maxKevents = 2000; - struct kevent Karray [maxKevents]; - struct timespec ts = {0, 10000000}; // Too frequent. Use blocking_region - - int k; - #ifdef BUILD_FOR_RUBY - TRAP_BEG; - #endif - k = kevent (kqfd, NULL, 0, Karray, maxKevents, &ts); - #ifdef BUILD_FOR_RUBY - TRAP_END; - #endif - struct kevent *ke = Karray; - while (k > 0) { - EventableDescriptor *ed = (EventableDescriptor*) (ke->udata); - assert (ed); - - if (ke->filter == EVFILT_READ) - ed->Read(); - else if (ke->filter == EVFILT_WRITE) - ed->Write(); - else - cerr << "Discarding unknown kqueue event " << ke->filter << endl; - - --k; - ++ke; - } - - { // cleanup dying sockets - // vector::pop_back works in constant time. - // TODO, rip this out and only delete the descriptors we know have died, - // rather than traversing the whole list. - // In kqueue, closing a descriptor automatically removes its event filters. - - int i, j; - int nSockets = Descriptors.size(); - for (i=0, j=0; i < nSockets; i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - if (ed->ShouldDelete()) { - ModifiedDescriptors.erase (ed); - delete ed; - } - else - Descriptors [j++] = ed; - } - while ((size_t)j < Descriptors.size()) - Descriptors.pop_back(); - - } - - { // dispatch heartbeats - if (gCurrentLoopTime >= NextHeartbeatTime) { - NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval; - - for (int i=0; i < Descriptors.size(); i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - ed->Heartbeat(); - } - } - } - - - // TODO, replace this with rb_thread_blocking_region for 1.9 builds. - #ifdef BUILD_FOR_RUBY - if (!rb_thread_alone()) { - rb_thread_schedule(); - } - #endif - - return true; - #else - throw std::runtime_error ("kqueue is not implemented on this platform"); - #endif -} - - -/********************************* -EventMachine_t::_ModifyEpollEvent -*********************************/ - -void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed) -{ - #ifdef HAVE_EPOLL - if (bEpoll) { - assert (epfd != -1); - assert (ed); - int e = epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent()); - if (e) { - char buf [200]; - snprintf (buf, sizeof(buf)-1, "unable to modify epoll event: %s", strerror(errno)); - throw std::runtime_error (buf); - } - } - #endif -} - - - -/************************** -SelectData_t::SelectData_t -**************************/ - -SelectData_t::SelectData_t() -{ - maxsocket = 0; - FD_ZERO (&fdreads); - FD_ZERO (&fdwrites); -} - - -#ifdef BUILD_FOR_RUBY -/***************** -_SelectDataSelect -*****************/ - -#ifdef HAVE_TBR -static VALUE _SelectDataSelect (void *v) -{ - SelectData_t *sd = (SelectData_t*)v; - sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), NULL, &(sd->tv)); - return Qnil; -} -#endif - -/********************* -SelectData_t::_Select -*********************/ - -int SelectData_t::_Select() -{ - #ifdef HAVE_TBR - rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0); - return nSockets; - #endif - - #ifndef HAVE_TBR - return EmSelect (maxsocket+1, &fdreads, &fdwrites, NULL, &tv); - #endif -} -#endif - - - -/****************************** -EventMachine_t::_RunSelectOnce -******************************/ - -bool EventMachine_t::_RunSelectOnce() -{ - // Crank the event machine once. - // If there are no descriptors to process, then sleep - // for a few hundred mills to avoid busy-looping. - // Return T/F to indicate whether we should continue. - // This is based on a select loop. Alternately provide epoll - // if we know we're running on a 2.6 kernel. - // epoll will be effective if we provide it as an alternative, - // however it has the same problem interoperating with Ruby - // threads that select does. - - //cerr << "X"; - - /* This protection is now obsolete, because we will ALWAYS - * have at least one descriptor (the loop-breaker) to read. - */ - /* - if (Descriptors.size() == 0) { - #ifdef OS_UNIX - timeval tv = {0, 200 * 1000}; - EmSelect (0, NULL, NULL, NULL, &tv); - return true; - #endif - #ifdef OS_WIN32 - Sleep (200); - return true; - #endif - } - */ - - SelectData_t SelectData; - /* - fd_set fdreads, fdwrites; - FD_ZERO (&fdreads); - FD_ZERO (&fdwrites); - - int maxsocket = 0; - */ - - // Always read the loop-breaker reader. - // Changed 23Aug06, provisionally implemented for Windows with a UDP socket - // running on localhost with a randomly-chosen port. (*Puke*) - // Windows has a version of the Unix pipe() library function, but it doesn't - // give you back descriptors that are selectable. - FD_SET (LoopBreakerReader, &(SelectData.fdreads)); - if (SelectData.maxsocket < LoopBreakerReader) - SelectData.maxsocket = LoopBreakerReader; - - // prepare the sockets for reading and writing - size_t i; - for (i = 0; i < Descriptors.size(); i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - int sd = ed->GetSocket(); - assert (sd != INVALID_SOCKET); - - if (ed->SelectForRead()) - FD_SET (sd, &(SelectData.fdreads)); - if (ed->SelectForWrite()) - FD_SET (sd, &(SelectData.fdwrites)); - - if (SelectData.maxsocket < sd) - SelectData.maxsocket = sd; - } - - - { // read and write the sockets - //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000. - //timeval tv = Quantum; - SelectData.tv = Quantum; - int s = SelectData._Select(); - //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0); - //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv)); - //int s = SelectData.nSockets; - if (s > 0) { - /* Changed 01Jun07. We used to handle the Loop-breaker right here. - * Now we do it AFTER all the regular descriptors. There's an - * incredibly important and subtle reason for this. Code on - * loop breakers is sometimes used to cause the reactor core to - * cycle (for example, to allow outbound network buffers to drain). - * If a loop-breaker handler reschedules itself (say, after determining - * that the write buffers are still too full), then it will execute - * IMMEDIATELY if _ReadLoopBreaker is done here instead of after - * the other descriptors are processed. That defeats the whole purpose. - */ - for (i=0; i < Descriptors.size(); i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - int sd = ed->GetSocket(); - assert (sd != INVALID_SOCKET); - - if (FD_ISSET (sd, &(SelectData.fdwrites))) - ed->Write(); - if (FD_ISSET (sd, &(SelectData.fdreads))) - ed->Read(); - } - - if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads))) - _ReadLoopBreaker(); - } - else if (s < 0) { - // select can fail on error in a handful of ways. - // If this happens, then wait for a little while to avoid busy-looping. - // If the error was EINTR, we probably caught SIGCHLD or something, - // so keep the wait short. - timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000}; - EmSelect (0, NULL, NULL, NULL, &tv); - } - } - - - { // dispatch heartbeats - if (gCurrentLoopTime >= NextHeartbeatTime) { - NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval; - - for (i=0; i < Descriptors.size(); i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - ed->Heartbeat(); - } - } - } - - { // cleanup dying sockets - // vector::pop_back works in constant time. - int i, j; - int nSockets = Descriptors.size(); - for (i=0, j=0; i < nSockets; i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - if (ed->ShouldDelete()) - delete ed; - else - Descriptors [j++] = ed; - } - while ((size_t)j < Descriptors.size()) - Descriptors.pop_back(); - - } - - return true; -} - - -/******************************** -EventMachine_t::_ReadLoopBreaker -********************************/ - -void EventMachine_t::_ReadLoopBreaker() -{ - /* The loop breaker has selected readable. - * Read it ONCE (it may block if we try to read it twice) - * and send a loop-break event back to user code. - */ - char buffer [1024]; - read (LoopBreakerReader, buffer, sizeof(buffer)); - if (EventCallback) - (*EventCallback)("", EM_LOOPBREAK_SIGNAL, "", 0); -} - - -/************************** -EventMachine_t::_RunTimers -**************************/ - -bool EventMachine_t::_RunTimers() -{ - // These are caller-defined timer handlers. - // Return T/F to indicate whether we should continue the main loop. - // We rely on the fact that multimaps sort by their keys to avoid - // inspecting the whole list every time we come here. - // Just keep inspecting and processing the list head until we hit - // one that hasn't expired yet. - - #ifdef OS_UNIX - struct timeval tv; - gettimeofday (&tv, NULL); - Int64 now = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec)); - #endif - - #ifdef OS_WIN32 - unsigned tick = GetTickCount(); - if (tick < gLastTickCount) - gTickCountTickover += 1; - gLastTickCount = tick; - Int64 now = ((Int64)gTickCountTickover << 32) + (Int64)tick; - #endif - - while (true) { - multimap<Int64,Timer_t>::iterator i = Timers.begin(); - if (i == Timers.end()) - break; - if (i->first > now) - break; - if (EventCallback) - (*EventCallback) ("", EM_TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length()); - Timers.erase (i); - } - return true; -} - - - -/*********************************** -EventMachine_t::InstallOneshotTimer -***********************************/ - -const char *EventMachine_t::InstallOneshotTimer (int milliseconds) -{ - if (Timers.size() > MaxOutstandingTimers) - return false; - // Don't use the global loop-time variable here, because we might - // get called before the main event machine is running. - - #ifdef OS_UNIX - struct timeval tv; - gettimeofday (&tv, NULL); - Int64 fire_at = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec)); - fire_at += ((Int64)milliseconds) * 1000LL; - #endif - - #ifdef OS_WIN32 - unsigned tick = GetTickCount(); - if (tick < gLastTickCount) - gTickCountTickover += 1; - gLastTickCount = tick; - - Int64 fire_at = ((Int64)gTickCountTickover << 32) + (Int64)tick; - fire_at += (Int64)milliseconds; - #endif - - Timer_t t; - multimap<Int64,Timer_t>::iterator i = - Timers.insert (make_pair (fire_at, t)); - return i->second.GetBindingChars(); -} - - -/******************************* -EventMachine_t::ConnectToServer -*******************************/ - -const char *EventMachine_t::ConnectToServer (const char *server, int port) -{ - /* We want to spend no more than a few seconds waiting for a connection - * to a remote host. So we use a nonblocking connect. - * Linux disobeys the usual rules for nonblocking connects. - * Per Stevens (UNP p.410), you expect a nonblocking connect to select - * both readable and writable on error, and not to return EINPROGRESS - * if the connect can be fulfilled immediately. Linux violates both - * of these expectations. - * Any kind of nonblocking connect on Linux returns EINPROGRESS. - * The socket will then return writable when the disposition of the - * connect is known, but it will not also be readable in case of - * error! Weirdly, it will be readable in case there is data to read!!! - * (Which can happen with protocols like SSH and SMTP.) - * I suppose if you were so inclined you could consider this logical, - * but it's not the way Unix has historically done it. - * So we ignore the readable flag and read getsockopt to see if there - * was an error connecting. A select timeout works as expected. - * In regard to getsockopt: Linux does the Berkeley-style thing, - * not the Solaris-style, and returns zero with the error code in - * the error parameter. - * Return the binding-text of the newly-created pending connection, - * or NULL if there was a problem. - */ - - if (!server || !*server || !port) - return NULL; - - int family, bind_size; - struct sockaddr *bind_as = name2address (server, port, &family, &bind_size); - if (!bind_as) - return NULL; - - int sd = socket (family, SOCK_STREAM, 0); - if (sd == INVALID_SOCKET) - return NULL; - - /* - sockaddr_in pin; - unsigned long HostAddr; - - HostAddr = inet_addr (server); - if (HostAddr == INADDR_NONE) { - hostent *hp = gethostbyname ((char*)server); // Windows requires (char*) - if (!hp) { - // TODO: This gives the caller a fatal error. Not good. - // They can respond by catching RuntimeError (blecch). - // Possibly we need to fire an unbind event and provide - // a status code so user code can detect the cause of the - // failure. - return NULL; - } - HostAddr = ((in_addr*)(hp->h_addr))->s_addr; - } - - memset (&pin, 0, sizeof(pin)); - pin.sin_family = AF_INET; - pin.sin_addr.s_addr = HostAddr; - pin.sin_port = htons (port); - - int sd = socket (AF_INET, SOCK_STREAM, 0); - if (sd == INVALID_SOCKET) - return NULL; - */ - - // From here on, ALL error returns must close the socket. - // Set the new socket nonblocking. - if (!SetSocketNonblocking (sd)) { - closesocket (sd); - return NULL; - } - // Disable slow-start (Nagle algorithm). - int one = 1; - setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one)); - - const char *out = NULL; - - #ifdef OS_UNIX - //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) { - if (connect (sd, bind_as, bind_size) == 0) { - // This is a connect success, which Linux appears - // never to give when the socket is nonblocking, - // even if the connection is intramachine or to - // localhost. - - /* Changed this branch 08Aug06. Evidently some kernels - * (FreeBSD for example) will actually return success from - * a nonblocking connect. This is a pretty simple case, - * just set up the new connection and clear the pending flag. - * Thanks to Chris Ochs for helping track this down. - * This branch never gets taken on Linux or (oddly) OSX. - * The original behavior was to throw an unimplemented, - * which the user saw as a fatal exception. Very unfriendly. - * - * Tweaked 10Aug06. Even though the connect disposition is - * known, we still set the connect-pending flag. That way - * some needed initialization will happen in the ConnectionDescriptor. - * (To wit, the ConnectionCompleted event gets sent to the client.) - */ - ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); - if (!cd) - throw std::runtime_error ("no connection allocated"); - cd->SetConnectPending (true); - Add (cd); - out = cd->GetBinding().c_str(); - } - else if (errno == EINPROGRESS) { - // Errno will generally always be EINPROGRESS, but on Linux - // we have to look at getsockopt to be sure what really happened. - int error; - socklen_t len; - len = sizeof(error); - int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len); - if ((o == 0) && (error == 0)) { - // Here, there's no disposition. - // Put the connection on the stack and wait for it to complete - // or time out. - ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); - if (!cd) - throw std::runtime_error ("no connection allocated"); - cd->SetConnectPending (true); - Add (cd); - out = cd->GetBinding().c_str(); - } - else { - /* This could be connection refused or some such thing. - * We will come here on Linux if a localhost connection fails. - * Changed 16Jul06: Originally this branch was a no-op, and - * we'd drop down to the end of the method, close the socket, - * and return NULL, which would cause the caller to GET A - * FATAL EXCEPTION. Now we keep the socket around but schedule an - * immediate close on it, so the caller will get a close-event - * scheduled on it. This was only an issue for localhost connections - * to non-listening ports. We may eventually need to revise this - * revised behavior, in case it causes problems like making it hard - * for people to know that a failure occurred. - */ - ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); - if (!cd) - throw std::runtime_error ("no connection allocated"); - cd->ScheduleClose (false); - Add (cd); - out = cd->GetBinding().c_str(); - } - } - else { - // The error from connect was something other then EINPROGRESS. - } - #endif - - #ifdef OS_WIN32 - //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) { - if (connect (sd, bind_as, bind_size) == 0) { - // This is a connect success, which Windows appears - // never to give when the socket is nonblocking, - // even if the connection is intramachine or to - // localhost. - throw std::runtime_error ("unimplemented"); - } - else if (WSAGetLastError() == WSAEWOULDBLOCK) { - // Here, there's no disposition. - // Windows appears not to surface refused connections or - // such stuff at this point. - // Put the connection on the stack and wait for it to complete - // or time out. - ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this); - if (!cd) - throw std::runtime_error ("no connection allocated"); - cd->SetConnectPending (true); - Add (cd); - out = cd->GetBinding().c_str(); - } - else { - // The error from connect was something other then WSAEWOULDBLOCK. - } - - #endif - - if (out == NULL) - closesocket (sd); - return out; -} - -/*********************************** -EventMachine_t::ConnectToUnixServer -***********************************/ - -const char *EventMachine_t::ConnectToUnixServer (const char *server) -{ - /* Connect to a Unix-domain server, which by definition is running - * on the same host. - * There is no meaningful implementation on Windows. - * There's no need to do a nonblocking connect, since the connection - * is always local and can always be fulfilled immediately. - */ - - #ifdef OS_WIN32 - throw std::runtime_error ("unix-domain connection unavailable on this platform"); - return NULL; - #endif - - // The whole rest of this function is only compiled on Unix systems. - #ifdef OS_UNIX - - const char *out = NULL; - - if (!server || !*server) - return NULL; - - sockaddr_un pun; - memset (&pun, 0, sizeof(pun)); - pun.sun_family = AF_LOCAL; - - // You ordinarily expect the server name field to be at least 1024 bytes long, - // but on Linux it can be MUCH shorter. - if (strlen(server) >= sizeof(pun.sun_path)) - throw std::runtime_error ("unix-domain server name is too long"); - - - strcpy (pun.sun_path, server); - - int fd = socket (AF_LOCAL, SOCK_STREAM, 0); - if (fd == INVALID_SOCKET) - return NULL; - - // From here on, ALL error returns must close the socket. - // NOTE: At this point, the socket is still a blocking socket. - if (connect (fd, (struct sockaddr*)&pun, sizeof(pun)) != 0) { - closesocket (fd); - return NULL; - } - - // Set the newly-connected socket nonblocking. - if (!SetSocketNonblocking (fd)) { - closesocket (fd); - return NULL; - } - - // Set up a connection descriptor and add it to the event-machine. - // Observe, even though we know the connection status is connect-success, - // we still set the "pending" flag, so some needed initializations take - // place. - ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this); - if (!cd) - throw std::runtime_error ("no connection allocated"); - cd->SetConnectPending (true); - Add (cd); - out = cd->GetBinding().c_str(); - - if (out == NULL) - closesocket (fd); - - return out; - #endif -} - -/************************ -EventMachine_t::AttachFD -************************/ - -const char *EventMachine_t::AttachFD (int fd, bool notify_readable, bool notify_writable) -{ - #ifdef OS_UNIX - if (fcntl(fd, F_GETFL, 0) < 0) - throw std::runtime_error ("invalid file descriptor"); - #endif - - #ifdef OS_WIN32 - // TODO: add better check for invalid file descriptors (see ioctlsocket or getsockopt) - if (fd == INVALID_SOCKET) - throw std::runtime_error ("invalid file descriptor"); - #endif - - {// Check for duplicate descriptors - size_t i; - for (i = 0; i < Descriptors.size(); i++) { - EventableDescriptor *ed = Descriptors[i]; - assert (ed); - if (ed->GetSocket() == fd) - throw std::runtime_error ("adding existing descriptor"); - } - - for (i = 0; i < NewDescriptors.size(); i++) { - EventableDescriptor *ed = NewDescriptors[i]; - assert (ed); - if (ed->GetSocket() == fd) - throw std::runtime_error ("adding existing new descriptor"); - } - } - - ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this); - if (!cd) - throw std::runtime_error ("no connection allocated"); - - cd->SetConnectPending (true); - cd->SetNotifyReadable (notify_readable); - cd->SetNotifyWritable (notify_writable); - - Add (cd); - - const char *out = NULL; - out = cd->GetBinding().c_str(); - if (out == NULL) - closesocket (fd); - return out; -} - -/************************ -EventMachine_t::DetachFD -************************/ - -int EventMachine_t::DetachFD (EventableDescriptor *ed) -{ - if (!ed) - throw std::runtime_error ("detaching bad descriptor"); - - #ifdef HAVE_EPOLL - if (bEpoll) { - if (ed->GetSocket() != INVALID_SOCKET) { - assert (bEpoll); // wouldn't be in this method otherwise. - assert (epfd != -1); - int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent()); - // ENOENT or EBADF are not errors because the socket may be already closed when we get here. - if (e && (errno != ENOENT) && (errno != EBADF)) { - char buf [200]; - snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno)); - throw std::runtime_error (buf); - } - } - } - #endif - - #ifdef HAVE_KQUEUE - if (bKqueue) { - struct kevent k; - EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_DELETE, 0, 0, ed); - int t = kevent (kqfd, &k, 1, NULL, 0, NULL); - assert (t == 0); - } - #endif - - { // remove descriptor from lists - int i, j; - int nSockets = Descriptors.size(); - for (i=0, j=0; i < nSockets; i++) { - EventableDescriptor *ted = Descriptors[i]; - assert (ted); - if (ted != ed) - Descriptors [j++] = ted; - } - while ((size_t)j < Descriptors.size()) - Descriptors.pop_back(); - - ModifiedDescriptors.erase (ed); - } - - int fd = ed->GetSocket(); - - // We depend on ~EventableDescriptor not calling close() if the socket is invalid - ed->SetSocketInvalid(); - delete ed; - - return fd; -} - -/************ -name2address -************/ - -struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size) -{ - // THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed. - // Check the more-common cases first. - // Return NULL if no resolution. - - static struct sockaddr_in in4; - #ifndef __CYGWIN__ - static struct sockaddr_in6 in6; - #endif - struct hostent *hp; - - if (!server || !*server) - server = "0.0.0.0"; - - memset (&in4, 0, sizeof(in4)); - if ( (in4.sin_addr.s_addr = inet_addr (server)) != INADDR_NONE) { - if (family) - *family = AF_INET; - if (bind_size) - *bind_size = sizeof(in4); - in4.sin_family = AF_INET; - in4.sin_port = htons (port); - return (struct sockaddr*)&in4; - } - - #if defined(OS_UNIX) && !defined(__CYGWIN__) - memset (&in6, 0, sizeof(in6)); - if (inet_pton (AF_INET6, server, in6.sin6_addr.s6_addr) > 0) { - if (family) - *family = AF_INET6; - if (bind_size) - *bind_size = sizeof(in6); - in6.sin6_family = AF_INET6; - in6.sin6_port = htons (port); - return (struct sockaddr*)&in6; - } - #endif - - #ifdef OS_WIN32 - // TODO, must complete this branch. Windows doesn't have inet_pton. - // A possible approach is to make a getaddrinfo call with the supplied - // server address, constraining the hints to ipv6 and seeing if we - // get any addresses. - // For the time being, Ipv6 addresses aren't supported on Windows. - #endif - - hp = gethostbyname ((char*)server); // Windows requires the cast. - if (hp) { - in4.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr; - if (family) - *family = AF_INET; - if (bind_size) - *bind_size = sizeof(in4); - in4.sin_family = AF_INET; - in4.sin_port = htons (port); - return (struct sockaddr*)&in4; - } - - return NULL; -} - - -/******************************* -EventMachine_t::CreateTcpServer -*******************************/ - -const char *EventMachine_t::CreateTcpServer (const char *server, int port) -{ - /* Create a TCP-acceptor (server) socket and add it to the event machine. - * Return the binding of the new acceptor to the caller. - * This binding will be referenced when the new acceptor sends events - * to indicate accepted connections. - */ - - - int family, bind_size; - struct sockaddr *bind_here = name2address (server, port, &family, &bind_size); - if (!bind_here) - return NULL; - - const char *output_binding = NULL; - - //struct sockaddr_in sin; - - int sd_accept = socket (family, SOCK_STREAM, 0); - if (sd_accept == INVALID_SOCKET) { - goto fail; - } - - /* - memset (&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons (port); - - if (server && *server) { - sin.sin_addr.s_addr = inet_addr (server); - if (sin.sin_addr.s_addr == INADDR_NONE) { - hostent *hp = gethostbyname ((char*)server); // Windows requires the cast. - if (hp == NULL) { - //__warning ("hostname not resolved: ", server); - goto fail; - } - sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr; - } - } - */ - - { // set reuseaddr to improve performance on restarts. - int oval = 1; - if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) { - //__warning ("setsockopt failed while creating listener",""); - goto fail; - } - } - - { // set CLOEXEC. Only makes sense on Unix - #ifdef OS_UNIX - int cloexec = fcntl (sd_accept, F_GETFD, 0); - assert (cloexec >= 0); - cloexec |= FD_CLOEXEC; - fcntl (sd_accept, F_SETFD, cloexec); - #endif - } - - - //if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) { - if (bind (sd_accept, bind_here, bind_size)) { - //__warning ("binding failed"); - goto fail; - } - - if (listen (sd_accept, 100)) { - //__warning ("listen failed"); - goto fail; - } - - { - // Set the acceptor non-blocking. - // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop. - if (!SetSocketNonblocking (sd_accept)) { - //int val = fcntl (sd_accept, F_GETFL, 0); - //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) { - goto fail; - } - } - - { // Looking good. - AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this); - if (!ad) - throw std::runtime_error ("unable to allocate acceptor"); - Add (ad); - output_binding = ad->GetBinding().c_str(); - } - - return output_binding; - - fail: - if (sd_accept != INVALID_SOCKET) - closesocket (sd_accept); - return NULL; -} - - -/********************************** -EventMachine_t::OpenDatagramSocket -**********************************/ - -const char *EventMachine_t::OpenDatagramSocket (const char *address, int port) -{ - const char *output_binding = NULL; - - int sd = socket (AF_INET, SOCK_DGRAM, 0); - if (sd == INVALID_SOCKET) - goto fail; - // from here on, early returns must close the socket! - - - struct sockaddr_in sin; - memset (&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons (port); - - - if (address && *address) { - sin.sin_addr.s_addr = inet_addr (address); - if (sin.sin_addr.s_addr == INADDR_NONE) { - hostent *hp = gethostbyname ((char*)address); // Windows requires the cast. - if (hp == NULL) - goto fail; - sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr; - } - } - else - sin.sin_addr.s_addr = htonl (INADDR_ANY); - - - // Set the new socket nonblocking. - { - if (!SetSocketNonblocking (sd)) - //int val = fcntl (sd, F_GETFL, 0); - //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) - goto fail; - } - - if (bind (sd, (struct sockaddr*)&sin, sizeof(sin)) != 0) - goto fail; - - { // Looking good. - DatagramDescriptor *ds = new DatagramDescriptor (sd, this); - if (!ds) - throw std::runtime_error ("unable to allocate datagram-socket"); - Add (ds); - output_binding = ds->GetBinding().c_str(); - } - - return output_binding; - - fail: - if (sd != INVALID_SOCKET) - closesocket (sd); - return NULL; -} - - - -/******************* -EventMachine_t::Add -*******************/ - -void EventMachine_t::Add (EventableDescriptor *ed) -{ - if (!ed) - throw std::runtime_error ("added bad descriptor"); - ed->SetEventCallback (EventCallback); - NewDescriptors.push_back (ed); -} - - -/******************************* -EventMachine_t::ArmKqueueWriter -*******************************/ - -void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed) -{ - #ifdef HAVE_KQUEUE - if (bKqueue) { - if (!ed) - throw std::runtime_error ("added bad descriptor"); - struct kevent k; - EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, ed); - int t = kevent (kqfd, &k, 1, NULL, 0, NULL); - assert (t == 0); - } - #endif -} - -/******************************* -EventMachine_t::ArmKqueueReader -*******************************/ - -void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed) -{ - #ifdef HAVE_KQUEUE - if (bKqueue) { - if (!ed) - throw std::runtime_error ("added bad descriptor"); - struct kevent k; - EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed); - int t = kevent (kqfd, &k, 1, NULL, 0, NULL); - assert (t == 0); - } - #endif -} - -/********************************** -EventMachine_t::_AddNewDescriptors -**********************************/ - -void EventMachine_t::_AddNewDescriptors() -{ - /* Avoid adding descriptors to the main descriptor list - * while we're actually traversing the list. - * Any descriptors that are added as a result of processing timers - * or acceptors should go on a temporary queue and then added - * while we're not traversing the main list. - * Also, it (rarely) happens that a newly-created descriptor - * is immediately scheduled to close. It might be a good - * idea not to bother scheduling these for I/O but if - * we do that, we might bypass some important processing. - */ - - for (size_t i = 0; i < NewDescriptors.size(); i++) { - EventableDescriptor *ed = NewDescriptors[i]; - if (ed == NULL) - throw std::runtime_error ("adding bad descriptor"); - - #if HAVE_EPOLL - if (bEpoll) { - assert (epfd != -1); - int e = epoll_ctl (epfd, EPOLL_CTL_ADD, ed->GetSocket(), ed->GetEpollEvent()); - if (e) { - char buf [200]; - snprintf (buf, sizeof(buf)-1, "unable to add new descriptor: %s", strerror(errno)); - throw std::runtime_error (buf); - } - } - #endif - - #if HAVE_KQUEUE - /* - if (bKqueue) { - // INCOMPLETE. Some descriptors don't want to be readable. - assert (kqfd != -1); - struct kevent k; - EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed); - int t = kevent (kqfd, &k, 1, NULL, 0, NULL); - assert (t == 0); - } - */ - #endif - - Descriptors.push_back (ed); - } - NewDescriptors.clear(); -} - - -/********************************** -EventMachine_t::_ModifyDescriptors -**********************************/ - -void EventMachine_t::_ModifyDescriptors() -{ - /* For implementations which don't level check every descriptor on - * every pass through the machine, as select does. - * If we're not selecting, then descriptors need a way to signal to the - * machine that their readable or writable status has changed. - * That's what the ::Modify call is for. We do it this way to avoid - * modifying descriptors during the loop traversal, where it can easily - * happen that an object (like a UDP socket) gets data written on it by - * the application during #post_init. That would take place BEFORE the - * descriptor even gets added to the epoll descriptor, so the modify - * operation will crash messily. - * Another really messy possibility is for a descriptor to put itself - * on the Modified list, and then get deleted before we get here. - * Remember, deletes happen after the I/O traversal and before the - * next pass through here. So we have to make sure when we delete a - * descriptor to remove it from the Modified list. - */ - - #ifdef HAVE_EPOLL - if (bEpoll) { - set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin(); - while (i != ModifiedDescriptors.end()) { - assert (*i); - _ModifyEpollEvent (*i); - ++i; - } - } - #endif - - ModifiedDescriptors.clear(); -} - - -/********************** -EventMachine_t::Modify -**********************/ - -void EventMachine_t::Modify (EventableDescriptor *ed) -{ - if (!ed) - throw std::runtime_error ("modified bad descriptor"); - ModifiedDescriptors.insert (ed); -} - - -/*********************************** -EventMachine_t::_OpenFileForWriting -***********************************/ - -const char *EventMachine_t::_OpenFileForWriting (const char *filename) -{ - /* - * Return the binding-text of the newly-opened file, - * or NULL if there was a problem. - */ - - if (!filename || !*filename) - return NULL; - - int fd = open (filename, O_CREAT|O_TRUNC|O_WRONLY|O_NONBLOCK, 0644); - - FileStreamDescriptor *fsd = new FileStreamDescriptor (fd, this); - if (!fsd) - throw std::runtime_error ("no file-stream allocated"); - Add (fsd); - return fsd->GetBinding().c_str(); - -} - - -/************************************** -EventMachine_t::CreateUnixDomainServer -**************************************/ - -const char *EventMachine_t::CreateUnixDomainServer (const char *filename) -{ - /* Create a UNIX-domain acceptor (server) socket and add it to the event machine. - * Return the binding of the new acceptor to the caller. - * This binding will be referenced when the new acceptor sends events - * to indicate accepted connections. - * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS. - */ - - #ifdef OS_WIN32 - throw std::runtime_error ("unix-domain server unavailable on this platform"); - #endif - - // The whole rest of this function is only compiled on Unix systems. - #ifdef OS_UNIX - const char *output_binding = NULL; - - struct sockaddr_un s_sun; - - int sd_accept = socket (AF_LOCAL, SOCK_STREAM, 0); - if (sd_accept == INVALID_SOCKET) { - goto fail; - } - - if (!filename || !*filename) - goto fail; - unlink (filename); - - bzero (&s_sun, sizeof(s_sun)); - s_sun.sun_family = AF_LOCAL; - strncpy (s_sun.sun_path, filename, sizeof(s_sun.sun_path)-1); - - // don't bother with reuseaddr for a local socket. - - { // set CLOEXEC. Only makes sense on Unix - #ifdef OS_UNIX - int cloexec = fcntl (sd_accept, F_GETFD, 0); - assert (cloexec >= 0); - cloexec |= FD_CLOEXEC; - fcntl (sd_accept, F_SETFD, cloexec); - #endif - } - - if (bind (sd_accept, (struct sockaddr*)&s_sun, sizeof(s_sun))) { - //__warning ("binding failed"); - goto fail; - } - - if (listen (sd_accept, 100)) { - //__warning ("listen failed"); - goto fail; - } - - { - // Set the acceptor non-blocking. - // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop. - if (!SetSocketNonblocking (sd_accept)) { - //int val = fcntl (sd_accept, F_GETFL, 0); - //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) { - goto fail; - } - } - - { // Looking good. - AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this); - if (!ad) - throw std::runtime_error ("unable to allocate acceptor"); - Add (ad); - output_binding = ad->GetBinding().c_str(); - } - - return output_binding; - - fail: - if (sd_accept != INVALID_SOCKET) - closesocket (sd_accept); - return NULL; - #endif // OS_UNIX -} - - -/********************* -EventMachine_t::Popen -*********************/ -#if OBSOLETE -const char *EventMachine_t::Popen (const char *cmd, const char *mode) -{ - #ifdef OS_WIN32 - throw std::runtime_error ("popen is currently unavailable on this platform"); - #endif - - // The whole rest of this function is only compiled on Unix systems. - // Eventually we need this functionality (or a full-duplex equivalent) on Windows. - #ifdef OS_UNIX - const char *output_binding = NULL; - - FILE *fp = popen (cmd, mode); - if (!fp) - return NULL; - - // From here, all early returns must pclose the stream. - - // According to the pipe(2) manpage, descriptors returned from pipe have both - // CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking. - if (!SetSocketNonblocking (fileno (fp))) { - pclose (fp); - return NULL; - } - - { // Looking good. - PipeDescriptor *pd = new PipeDescriptor (fp, this); - if (!pd) - throw std::runtime_error ("unable to allocate pipe"); - Add (pd); - output_binding = pd->GetBinding().c_str(); - } - - return output_binding; - #endif -} -#endif // OBSOLETE - -/************************** -EventMachine_t::Socketpair -**************************/ - -const char *EventMachine_t::Socketpair (char * const*cmd_strings) -{ - #ifdef OS_WIN32 - throw std::runtime_error ("socketpair is currently unavailable on this platform"); - #endif - - // The whole rest of this function is only compiled on Unix systems. - // Eventually we need this functionality (or a full-duplex equivalent) on Windows. - #ifdef OS_UNIX - // Make sure the incoming array of command strings is sane. - if (!cmd_strings) - return NULL; - int j; - for (j=0; j < 100 && cmd_strings[j]; j++) - ; - if ((j==0) || (j==100)) - return NULL; - - const char *output_binding = NULL; - - int sv[2]; - if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0) - return NULL; - // from here, all early returns must close the pair of sockets. - - // Set the parent side of the socketpair nonblocking. - // We don't care about the child side, and most child processes will expect their - // stdout to be blocking. Thanks to Duane Johnson and Bill Kelly for pointing this out. - // Obviously DON'T set CLOEXEC. - if (!SetSocketNonblocking (sv[0])) { - close (sv[0]); - close (sv[1]); - return NULL; - } - - pid_t f = fork(); - if (f > 0) { - close (sv[1]); - PipeDescriptor *pd = new PipeDescriptor (sv[0], f, this); - if (!pd) - throw std::runtime_error ("unable to allocate pipe"); - Add (pd); - output_binding = pd->GetBinding().c_str(); - } - else if (f == 0) { - close (sv[0]); - dup2 (sv[1], STDIN_FILENO); - close (sv[1]); - dup2 (STDIN_FILENO, STDOUT_FILENO); - execvp (cmd_strings[0], cmd_strings+1); - exit (-1); // end the child process if the exec doesn't work. - } - else - throw std::runtime_error ("no fork"); - - return output_binding; - #endif -} - - -/**************************** -EventMachine_t::OpenKeyboard -****************************/ - -const char *EventMachine_t::OpenKeyboard() -{ - KeyboardDescriptor *kd = new KeyboardDescriptor (this); - if (!kd) - throw std::runtime_error ("no keyboard-object allocated"); - Add (kd); - return kd->GetBinding().c_str(); -} - - - - - -//#endif // OS_UNIX - -/*****************************************************************************
-
-$Id$
-
-File: emwin.cpp
-Date: 05May06
-
-Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
-Gmail: blackhedd
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of either: 1) the GNU General Public License
-as published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version; or 2) Ruby's License.
-
-See the file COPYING for complete licensing information.
-
-*****************************************************************************/
-
-
-// THIS ENTIRE FILE IS FOR WINDOWS BUILDS ONLY
-// INCOMPLETE AND DISABLED FOR NOW.
-#ifdef xOS_WIN32
-
-#include "project.h"
-
-
-// Keep a global variable floating around
-// with the current loop time as set by the Event Machine.
-// This avoids the need for frequent expensive calls to time(NULL);
-time_t gCurrentLoopTime;
-
-
-/******************************
-EventMachine_t::EventMachine_t
-******************************/
-
-EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const char*, int)):
- EventCallback (event_callback),
- NextHeartbeatTime (0)
-{
- gTerminateSignalReceived = false;
- Iocp = NULL;
-}
-
-
-/*******************************
-EventMachine_t::~EventMachine_t
-*******************************/
-
-EventMachine_t::~EventMachine_t()
-{
- cerr << "EM __dt\n";
- if (Iocp)
- CloseHandle (Iocp);
-}
-
-
-/****************************
-EventMachine_t::ScheduleHalt
-****************************/
-
-void EventMachine_t::ScheduleHalt()
-{
- /* This is how we stop the machine.
- * This can be called by clients. Signal handlers will probably
- * set the global flag.
- * For now this means there can only be one EventMachine ever running at a time.
- */
- gTerminateSignalReceived = true;
-}
-
-
-
-/*******************
-EventMachine_t::Run
-*******************/
-
-void EventMachine_t::Run()
-{
- HookControlC (true);
-
- Iocp = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (Iocp == NULL)
- throw std::runtime_error ("no completion port");
-
-
- DWORD nBytes, nCompletionKey;
- LPOVERLAPPED Overlapped;
-
- do {
- gCurrentLoopTime = time(NULL);
- // Have some kind of strategy that will dequeue maybe up to 10 completions
- // without running the timers as long as they are available immediately.
- // Otherwise in a busy server we're calling them every time through the loop.
- if (!_RunTimers())
- break;
- if (GetQueuedCompletionStatus (Iocp, &nBytes, &nCompletionKey, &Overlapped, 1000)) {
- }
- cerr << "+";
- } while (!gTerminateSignalReceived);
-
-
- /*
- while (true) {
- gCurrentLoopTime = time(NULL);
- if (!_RunTimers())
- break;
- _AddNewDescriptors();
- if (!_RunOnce())
- break;
- if (gTerminateSignalReceived)
- break;
- }
- */
-
- HookControlC (false);
-}
-
-
-/**************************
-EventMachine_t::_RunTimers
-**************************/
-
-bool EventMachine_t::_RunTimers()
-{
- // These are caller-defined timer handlers.
- // Return T/F to indicate whether we should continue the main loop.
- // We rely on the fact that multimaps sort by their keys to avoid
- // inspecting the whole list every time we come here.
- // Just keep inspecting and processing the list head until we hit
- // one that hasn't expired yet.
-
- while (true) {
- multimap<time_t,Timer_t>::iterator i = Timers.begin();
- if (i == Timers.end())
- break;
- if (i->first > gCurrentLoopTime)
- break;
- if (EventCallback)
- (*EventCallback) ("", EM_TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length());
- Timers.erase (i);
- }
- return true;
-}
-
-
-/***********************************
-EventMachine_t::InstallOneshotTimer
-***********************************/
-
-const char *EventMachine_t::InstallOneshotTimer (int seconds)
-{
- if (Timers.size() > MaxOutstandingTimers)
- return false;
- // Don't use the global loop-time variable here, because we might
- // get called before the main event machine is running.
-
- Timer_t t;
- Timers.insert (make_pair (time(NULL) + seconds, t));
- return t.GetBinding().c_str();
-}
-
-
-/**********************************
-EventMachine_t::OpenDatagramSocket
-**********************************/
-
-const char *EventMachine_t::OpenDatagramSocket (const char *address, int port)
-{
- cerr << "OPEN DATAGRAM SOCKET\n";
- return "Unimplemented";
-}
-
-
-/*******************************
-EventMachine_t::CreateTcpServer
-*******************************/
-
-const char *EventMachine_t::CreateTcpServer (const char *server, int port)
-{
- /* Create a TCP-acceptor (server) socket and add it to the event machine.
- * Return the binding of the new acceptor to the caller.
- * This binding will be referenced when the new acceptor sends events
- * to indicate accepted connections.
- */
-
- const char *output_binding = NULL;
-
- struct sockaddr_in sin;
-
- SOCKET sd_accept = socket (AF_INET, SOCK_STREAM, 0);
- if (sd_accept == INVALID_SOCKET) {
- goto fail;
- }
-
- memset (&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons (port);
-
- if (server && *server) {
- sin.sin_addr.s_addr = inet_addr (server);
- if (sin.sin_addr.s_addr == INADDR_NONE) {
- hostent *hp = gethostbyname (server);
- if (hp == NULL) {
- //__warning ("hostname not resolved: ", server);
- goto fail;
- }
- sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
- }
- }
-
-
- // No need to set reuseaddr on Windows.
-
-
- if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) {
- //__warning ("binding failed");
- goto fail;
- }
-
- if (listen (sd_accept, 100)) {
- //__warning ("listen failed");
- goto fail;
- }
-
- { // Looking good.
- AcceptorDescriptor *ad = new AcceptorDescriptor (this, sd_accept);
- if (!ad)
- throw std::runtime_error ("unable to allocate acceptor");
- Add (ad);
- output_binding = ad->GetBinding().c_str();
-
- CreateIoCompletionPort ((HANDLE)sd_accept, Iocp, NULL, 0);
- SOCKET sd = socket (AF_INET, SOCK_STREAM, 0);
- CreateIoCompletionPort ((HANDLE)sd, Iocp, NULL, 0);
- AcceptEx (sd_accept, sd,
- }
-
- return output_binding;
-
- fail:
- if (sd_accept != INVALID_SOCKET)
- closesocket (sd_accept);
- return NULL;
-}
-
-
-/*******************************
-EventMachine_t::ConnectToServer
-*******************************/
-
-const char *EventMachine_t::ConnectToServer (const char *server, int port)
-{
- if (!server || !*server || !port)
- return NULL;
-
- sockaddr_in pin;
- unsigned long HostAddr;
-
- HostAddr = inet_addr (server);
- if (HostAddr == INADDR_NONE) {
- hostent *hp = gethostbyname (server);
- if (!hp)
- return NULL;
- HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
- }
-
- memset (&pin, 0, sizeof(pin));
- pin.sin_family = AF_INET;
- pin.sin_addr.s_addr = HostAddr;
- pin.sin_port = htons (port);
-
- int sd = socket (AF_INET, SOCK_STREAM, 0);
- if (sd == INVALID_SOCKET)
- return NULL;
-
-
- LPOVERLAPPED olap = (LPOVERLAPPED) calloc (1, sizeof (OVERLAPPED));
- cerr << "I'm dying now\n";
- throw runtime_error ("UNIMPLEMENTED!!!\n");
-
-}
-
-
-
-/*******************
-EventMachine_t::Add
-*******************/
-
-void EventMachine_t::Add (EventableDescriptor *ed)
-{
- cerr << "ADD\n";
-}
-
-
-
-#endif // OS_WIN32
-
-/***************************************************************************** - -$Id$ - -File: epoll.cpp -Date: 06Jun07 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - - -#ifdef HAVE_EPOLL - -#include "project.h" - -#endif // HAVE_EPOLL - -/***************************************************************************** - -$Id: mapper.cpp 4527 2007-07-04 10:21:34Z francis $ - -File: mapper.cpp -Date: 02Jul07 - -Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved. -Gmail: garbagecat10 - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - - -////////////////////////////////////////////////////////////////////// -// UNIX implementation -////////////////////////////////////////////////////////////////////// - - -#ifdef OS_UNIX - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <fcntl.h> -#include <errno.h> - -#include <iostream> -#include "unistd.h" -#include <string> -#include <cstring> -#include <stdexcept> -using namespace std; - -#include "mapper.h" - -/****************** -Mapper_t::Mapper_t -******************/ - -Mapper_t::Mapper_t (const string &filename) -{ - /* We ASSUME we can open the file. - * (More precisely, we assume someone else checked before we got here.) - */ - - Fd = open (filename.c_str(), O_RDONLY); - if (Fd < 0) - throw runtime_error (strerror (errno)); - - struct stat st; - if (fstat (Fd, &st)) - throw runtime_error (strerror (errno)); - FileSize = st.st_size; - - MapPoint = (const char*) mmap (0, FileSize, PROT_READ, MAP_SHARED, Fd, 0); - if (MapPoint == MAP_FAILED) - throw runtime_error (strerror (errno)); -} - - -/******************* -Mapper_t::~Mapper_t -*******************/ - -Mapper_t::~Mapper_t() -{ - Close(); -} - - -/*************** -Mapper_t::Close -***************/ - -void Mapper_t::Close() -{ - // Can be called multiple times. - // Calls to GetChunk are invalid after a call to Close. - if (MapPoint) { - munmap ((void*)MapPoint, FileSize); - MapPoint = NULL; - } - if (Fd >= 0) { - close (Fd); - Fd = -1; - } -} - -/****************** -Mapper_t::GetChunk -******************/ - -const char *Mapper_t::GetChunk (unsigned start) -{ - return MapPoint + start; -} - - - -#endif // OS_UNIX - - -////////////////////////////////////////////////////////////////////// -// WINDOWS implementation -////////////////////////////////////////////////////////////////////// - -#ifdef OS_WIN32 - -#include <windows.h> - -#include <iostream> -#include <string> -#include <stdexcept> -using namespace std; - -#include "mapper.h" - -/****************** -Mapper_t::Mapper_t -******************/ - -Mapper_t::Mapper_t (const string &filename) -{ - /* We ASSUME we can open the file. - * (More precisely, we assume someone else checked before we got here.) - */ - - hFile = INVALID_HANDLE_VALUE; - hMapping = NULL; - MapPoint = NULL; - FileSize = 0; - - hFile = CreateFile (filename.c_str(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (hFile == INVALID_HANDLE_VALUE) - throw runtime_error ("File not found"); - - BY_HANDLE_FILE_INFORMATION i; - if (GetFileInformationByHandle (hFile, &i)) - FileSize = i.nFileSizeLow; - - hMapping = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, 0, NULL); - if (!hMapping) - throw runtime_error ("File not mapped"); - - MapPoint = (const char*) MapViewOfFile (hMapping, FILE_MAP_WRITE, 0, 0, 0); - if (!MapPoint) - throw runtime_error ("Mappoint not read"); -} - - -/******************* -Mapper_t::~Mapper_t -*******************/ - -Mapper_t::~Mapper_t() -{ - Close(); -} - -/*************** -Mapper_t::Close -***************/ - -void Mapper_t::Close() -{ - // Can be called multiple times. - // Calls to GetChunk are invalid after a call to Close. - if (MapPoint) { - UnmapViewOfFile (MapPoint); - MapPoint = NULL; - } - if (hMapping != NULL) { - CloseHandle (hMapping); - hMapping = NULL; - } - if (hFile != INVALID_HANDLE_VALUE) { - CloseHandle (hFile); - hMapping = INVALID_HANDLE_VALUE; - } -} - - -/****************** -Mapper_t::GetChunk -******************/ - -const char *Mapper_t::GetChunk (unsigned start) -{ - return MapPoint + start; -} - - - -#endif // OS_WINDOWS -/***************************************************************************** - -$Id: rubymain.cpp 4529 2007-07-04 11:32:22Z francis $ - -File: rubymain.cpp -Date: 02Jul07 - -Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved. -Gmail: garbagecat10 - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - - - -#include <iostream> -#include <stdexcept> -using namespace std; - -#include <ruby.h> -#include "mapper.h" - -static VALUE EmModule; -static VALUE FastFileReader; -static VALUE Mapper; - - - -/********* -mapper_dt -*********/ - -static void mapper_dt (void *ptr) -{ - if (ptr) - delete (Mapper_t*) ptr; -} - -/********** -mapper_new -**********/ - -static VALUE mapper_new (VALUE self, VALUE filename) -{ - Mapper_t *m = new Mapper_t (StringValuePtr (filename)); - if (!m) - rb_raise (rb_eException, "No Mapper Object"); - VALUE v = Data_Wrap_Struct (Mapper, 0, mapper_dt, (void*)m); - return v; -} - - -/**************** -mapper_get_chunk -****************/ - -static VALUE mapper_get_chunk (VALUE self, VALUE start, VALUE length) -{ - Mapper_t *m = NULL; - Data_Get_Struct (self, Mapper_t, m); - if (!m) - rb_raise (rb_eException, "No Mapper Object"); - - // TODO, what if some moron sends us a negative start value? - unsigned _start = NUM2INT (start); - unsigned _length = NUM2INT (length); - if ((_start + _length) > m->GetFileSize()) - rb_raise (rb_eException, "Mapper Range Error"); - - const char *chunk = m->GetChunk (_start); - if (!chunk) - rb_raise (rb_eException, "No Mapper Chunk"); - return rb_str_new (chunk, _length); -} - -/************ -mapper_close -************/ - -static VALUE mapper_close (VALUE self) -{ - Mapper_t *m = NULL; - Data_Get_Struct (self, Mapper_t, m); - if (!m) - rb_raise (rb_eException, "No Mapper Object"); - m->Close(); - return Qnil; -} - -/*********** -mapper_size -***********/ - -static VALUE mapper_size (VALUE self) -{ - Mapper_t *m = NULL; - Data_Get_Struct (self, Mapper_t, m); - if (!m) - rb_raise (rb_eException, "No Mapper Object"); - return INT2NUM (m->GetFileSize()); -} - - -/********************** -Init_fastfilereaderext -**********************/ - -extern "C" void Init_fastfilereaderext() -{ - EmModule = rb_define_module ("EventMachine"); - FastFileReader = rb_define_class_under (EmModule, "FastFileReader", rb_cObject); - Mapper = rb_define_class_under (FastFileReader, "Mapper", rb_cObject); - - rb_define_module_function (Mapper, "new", (VALUE(*)(...))mapper_new, 1); - rb_define_method (Mapper, "size", (VALUE(*)(...))mapper_size, 0); - rb_define_method (Mapper, "close", (VALUE(*)(...))mapper_close, 0); - rb_define_method (Mapper, "get_chunk", (VALUE(*)(...))mapper_get_chunk, 2); -} - - - -/***************************************************************************** - -$Id$ - -File: files.cpp -Date: 26Aug06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - - -/****************************************** -FileStreamDescriptor::FileStreamDescriptor -******************************************/ - -FileStreamDescriptor::FileStreamDescriptor (int fd, EventMachine_t *em): - EventableDescriptor (fd, em), - OutboundDataSize (0) -{ -cerr << "#####"; -} - - -/******************************************* -FileStreamDescriptor::~FileStreamDescriptor -*******************************************/ - -FileStreamDescriptor::~FileStreamDescriptor() -{ - // Run down any stranded outbound data. - for (size_t i=0; i < OutboundPages.size(); i++) - OutboundPages[i].Free(); -} - - -/************************** -FileStreamDescriptor::Read -**************************/ - -void FileStreamDescriptor::Read() -{ -} - -/*************************** -FileStreamDescriptor::Write -***************************/ - -void FileStreamDescriptor::Write() -{ -} - - -/******************************* -FileStreamDescriptor::Heartbeat -*******************************/ - -void FileStreamDescriptor::Heartbeat() -{ -} - - -/*********************************** -FileStreamDescriptor::SelectForRead -***********************************/ - -bool FileStreamDescriptor::SelectForRead() -{ - cerr << "R?"; - return false; -} - - -/************************************ -FileStreamDescriptor::SelectForWrite -************************************/ - -bool FileStreamDescriptor::SelectForWrite() -{ - cerr << "W?"; - return false; -} - - -/***************************************************************************** - -$Id$ - -File: kb.cpp -Date: 24Aug07 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - - -/************************************** -KeyboardDescriptor::KeyboardDescriptor -**************************************/ - -KeyboardDescriptor::KeyboardDescriptor (EventMachine_t *parent_em): - EventableDescriptor (0, parent_em), - bReadAttemptedAfterClose (false), - LastIo (gCurrentLoopTime), - InactivityTimeout (0) -{ - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueReader (this); - #endif -} - - -/*************************************** -KeyboardDescriptor::~KeyboardDescriptor -***************************************/ - -KeyboardDescriptor::~KeyboardDescriptor() -{ -} - - -/************************* -KeyboardDescriptor::Write -*************************/ - -void KeyboardDescriptor::Write() -{ - // Why are we here? - throw std::runtime_error ("bad code path in keyboard handler"); -} - - -/***************************** -KeyboardDescriptor::Heartbeat -*****************************/ - -void KeyboardDescriptor::Heartbeat() -{ - // no-op -} - - -/************************ -KeyboardDescriptor::Read -************************/ - -void KeyboardDescriptor::Read() -{ - char c; - read (GetSocket(), &c, 1); - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, &c, 1); -} - - - - -#if 0 -/****************************** -PipeDescriptor::PipeDescriptor -******************************/ - -PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em): - EventableDescriptor (fd, parent_em), - bReadAttemptedAfterClose (false), - LastIo (gCurrentLoopTime), - InactivityTimeout (0), - OutboundDataSize (0), - SubprocessPid (subpid) -{ - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif -} - - -/******************************* -PipeDescriptor::~PipeDescriptor -*******************************/ - -PipeDescriptor::~PipeDescriptor() -{ - // Run down any stranded outbound data. - for (size_t i=0; i < OutboundPages.size(); i++) - OutboundPages[i].Free(); - - /* As a virtual destructor, we come here before the base-class - * destructor that closes our file-descriptor. - * We have to make sure the subprocess goes down (if it's not - * already down) and we have to reap the zombie. - * - * This implementation is PROVISIONAL and will surely be improved. - * The intention here is that we never block, hence the highly - * undesirable sleeps. But if we can't reap the subprocess even - * after sending it SIGKILL, then something is wrong and we - * throw a fatal exception, which is also not something we should - * be doing. - * - * Eventually the right thing to do will be to have the reactor - * core respond to SIGCHLD by chaining a handler on top of the - * one Ruby may have installed, and dealing with a list of dead - * children that are pending cleanup. - * - * Since we want to have a signal processor integrated into the - * client-visible API, let's wait until that is done before cleaning - * this up. - */ - - struct timespec req = {0, 10000000}; - kill (SubprocessPid, SIGTERM); - nanosleep (&req, NULL); - if (waitpid (SubprocessPid, NULL, WNOHANG) == 0) { - kill (SubprocessPid, SIGKILL); - nanosleep (&req, NULL); - if (waitpid (SubprocessPid, NULL, WNOHANG) == 0) - throw std::runtime_error ("unable to reap subprocess"); - } -} - - - -/******************** -PipeDescriptor::Read -********************/ - -void PipeDescriptor::Read() -{ - int sd = GetSocket(); - if (sd == INVALID_SOCKET) { - assert (!bReadAttemptedAfterClose); - bReadAttemptedAfterClose = true; - return; - } - - LastIo = gCurrentLoopTime; - - int total_bytes_read = 0; - char readbuffer [16 * 1024]; - - for (int i=0; i < 10; i++) { - // Don't read just one buffer and then move on. This is faster - // if there is a lot of incoming. - // But don't read indefinitely. Give other sockets a chance to run. - // NOTICE, we're reading one less than the buffer size. - // That's so we can put a guard byte at the end of what we send - // to user code. - // Use read instead of recv, which on Linux gives a "socket operation - // on nonsocket" error. - - - int r = read (sd, readbuffer, sizeof(readbuffer) - 1); - //cerr << "<R:" << r << ">"; - - if (r > 0) { - total_bytes_read += r; - LastRead = gCurrentLoopTime; - - // Add a null-terminator at the the end of the buffer - // that we will send to the callback. - // DO NOT EVER CHANGE THIS. We want to explicitly allow users - // to be able to depend on this behavior, so they will have - // the option to do some things faster. Additionally it's - // a security guard against buffer overflows. - readbuffer [r] = 0; - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r); - } - else if (r == 0) { - break; - } - else { - // Basically a would-block, meaning we've read everything there is to read. - break; - } - - } - - - if (total_bytes_read == 0) { - // If we read no data on a socket that selected readable, - // it generally means the other end closed the connection gracefully. - ScheduleClose (false); - //bCloseNow = true; - } - -} - -/********************* -PipeDescriptor::Write -*********************/ - -void PipeDescriptor::Write() -{ - int sd = GetSocket(); - assert (sd != INVALID_SOCKET); - - LastIo = gCurrentLoopTime; - char output_buffer [16 * 1024]; - size_t nbytes = 0; - - while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) { - OutboundPage *op = &(OutboundPages[0]); - if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) { - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset); - nbytes += (op->Length - op->Offset); - op->Free(); - OutboundPages.pop_front(); - } - else { - int len = sizeof(output_buffer) - nbytes; - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len); - op->Offset += len; - nbytes += len; - } - } - - // We should never have gotten here if there were no data to write, - // so assert that as a sanity check. - // Don't bother to make sure nbytes is less than output_buffer because - // if it were we probably would have crashed already. - assert (nbytes > 0); - - assert (GetSocket() != INVALID_SOCKET); - int bytes_written = write (GetSocket(), output_buffer, nbytes); - - if (bytes_written > 0) { - OutboundDataSize -= bytes_written; - if ((size_t)bytes_written < nbytes) { - int len = nbytes - bytes_written; - char *buffer = (char*) malloc (len + 1); - if (!buffer) - throw std::runtime_error ("bad alloc throwing back data"); - memcpy (buffer, output_buffer + bytes_written, len); - buffer [len] = 0; - OutboundPages.push_front (OutboundPage (buffer, len)); - } - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0)); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - } - else { - #ifdef OS_UNIX - if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR)) - #endif - #ifdef OS_WIN32 - if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK)) - #endif - Close(); - } -} - - -/************************* -PipeDescriptor::Heartbeat -*************************/ - -void PipeDescriptor::Heartbeat() -{ - // If an inactivity timeout is defined, then check for it. - if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout)) - ScheduleClose (false); - //bCloseNow = true; -} - - -/***************************** -PipeDescriptor::SelectForRead -*****************************/ - -bool PipeDescriptor::SelectForRead() -{ - /* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */ - return true; -} - -/****************************** -PipeDescriptor::SelectForWrite -******************************/ - -bool PipeDescriptor::SelectForWrite() -{ - /* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */ - return (GetOutboundDataSize() > 0); -} - - - - -/******************************** -PipeDescriptor::SendOutboundData -********************************/ - -int PipeDescriptor::SendOutboundData (const char *data, int length) -{ - //if (bCloseNow || bCloseAfterWriting) - if (IsCloseScheduled()) - return 0; - - if (!data && (length > 0)) - throw std::runtime_error ("bad outbound data"); - char *buffer = (char *) malloc (length + 1); - if (!buffer) - throw std::runtime_error ("no allocation for outbound data"); - memcpy (buffer, data, length); - buffer [length] = 0; - OutboundPages.push_back (OutboundPage (buffer, length)); - OutboundDataSize += length; - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | EPOLLOUT); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - return length; -} - -/******************************** -PipeDescriptor::GetSubprocessPid -********************************/ - -bool PipeDescriptor::GetSubprocessPid (pid_t *pid) -{ - bool ok = false; - if (pid && (SubprocessPid > 0)) { - *pid = SubprocessPid; - ok = true; - } - return ok; -} - -#endif - -/***************************************************************************** - -$Id$ - -File: page.cpp -Date: 30Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - - -#include "project.h" - - -/****************** -PageList::PageList -******************/ - -PageList::PageList() -{ -} - - -/******************* -PageList::~PageList -*******************/ - -PageList::~PageList() -{ - while (HasPages()) - PopFront(); -} - - -/*************** -PageList::Front -***************/ - -void PageList::Front (const char **page, int *length) -{ - assert (page && length); - - if (HasPages()) { - Page p = Pages.front(); - *page = p.Buffer; - *length = p.Size; - } - else { - *page = NULL; - *length = 0; - } -} - - -/****************** -PageList::PopFront -******************/ - -void PageList::PopFront() -{ - if (HasPages()) { - Page p = Pages.front(); - Pages.pop_front(); - if (p.Buffer) - free ((void*)p.Buffer); - } -} - - -/****************** -PageList::HasPages -******************/ - -bool PageList::HasPages() -{ - return (Pages.size() > 0) ? true : false; -} - - -/************** -PageList::Push -**************/ - -void PageList::Push (const char *buf, int size) -{ - if (buf && (size > 0)) { - char *copy = (char*) malloc (size); - if (!copy) - throw runtime_error ("no memory in pagelist"); - memcpy (copy, buf, size); - Pages.push_back (Page (copy, size)); - } -} - - - - - -/***************************************************************************** - -$Id$ - -File: pipe.cpp -Date: 30May07 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - - -#ifdef OS_UNIX -// THIS ENTIRE FILE IS ONLY COMPILED ON UNIX-LIKE SYSTEMS. - -/****************************** -PipeDescriptor::PipeDescriptor -******************************/ - -PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em): - EventableDescriptor (fd, parent_em), - bReadAttemptedAfterClose (false), - LastIo (gCurrentLoopTime), - InactivityTimeout (0), - OutboundDataSize (0), - SubprocessPid (subpid) -{ - #ifdef HAVE_EPOLL - EpollEvent.events = EPOLLIN; - #endif - #ifdef HAVE_KQUEUE - MyEventMachine->ArmKqueueReader (this); - #endif -} - - -/******************************* -PipeDescriptor::~PipeDescriptor -*******************************/ - -PipeDescriptor::~PipeDescriptor() -{ - // Run down any stranded outbound data. - for (size_t i=0; i < OutboundPages.size(); i++) - OutboundPages[i].Free(); - - /* As a virtual destructor, we come here before the base-class - * destructor that closes our file-descriptor. - * We have to make sure the subprocess goes down (if it's not - * already down) and we have to reap the zombie. - * - * This implementation is PROVISIONAL and will surely be improved. - * The intention here is that we never block, hence the highly - * undesirable sleeps. But if we can't reap the subprocess even - * after sending it SIGKILL, then something is wrong and we - * throw a fatal exception, which is also not something we should - * be doing. - * - * Eventually the right thing to do will be to have the reactor - * core respond to SIGCHLD by chaining a handler on top of the - * one Ruby may have installed, and dealing with a list of dead - * children that are pending cleanup. - * - * Since we want to have a signal processor integrated into the - * client-visible API, let's wait until that is done before cleaning - * this up. - * - * Added a very ugly hack to support passing the subprocess's exit - * status to the user. It only makes logical sense for user code to access - * the subprocess exit status in the unbind callback. But unbind is called - * back during the EventableDescriptor destructor. So by that time there's - * no way to call back this object through an object binding, because it's - * already been cleaned up. We might have added a parameter to the unbind - * callback, but that would probably break a huge amount of existing code. - * So the hack-solution is to define an instance variable in the EventMachine - * object and stick the exit status in there, where it can easily be accessed - * with an accessor visible to user code. - * User code should ONLY access the exit status from within the unbind callback. - * Otherwise there's no guarantee it'll be valid. - * This hack won't make it impossible to run multiple EventMachines in a single - * process, but it will make it impossible to reliably nest unbind calls - * within other unbind calls. (Not sure if that's even possible.) - */ - - assert (MyEventMachine); - - // check if the process is already dead - if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0) { - kill (SubprocessPid, SIGTERM); - // wait 0.25s for process to die - struct timespec req = {0, 250000000}; - nanosleep (&req, NULL); - if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0) { - kill (SubprocessPid, SIGKILL); - // wait 0.5s for process to die - struct timespec req = {0, 500000000}; - nanosleep (&req, NULL); - if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0) - throw std::runtime_error ("unable to reap subprocess"); - } - } -} - - - -/******************** -PipeDescriptor::Read -********************/ - -void PipeDescriptor::Read() -{ - int sd = GetSocket(); - if (sd == INVALID_SOCKET) { - assert (!bReadAttemptedAfterClose); - bReadAttemptedAfterClose = true; - return; - } - - LastIo = gCurrentLoopTime; - - int total_bytes_read = 0; - char readbuffer [16 * 1024]; - - for (int i=0; i < 10; i++) { - // Don't read just one buffer and then move on. This is faster - // if there is a lot of incoming. - // But don't read indefinitely. Give other sockets a chance to run. - // NOTICE, we're reading one less than the buffer size. - // That's so we can put a guard byte at the end of what we send - // to user code. - // Use read instead of recv, which on Linux gives a "socket operation - // on nonsocket" error. - - - int r = read (sd, readbuffer, sizeof(readbuffer) - 1); - //cerr << "<R:" << r << ">"; - - if (r > 0) { - total_bytes_read += r; - LastRead = gCurrentLoopTime; - - // Add a null-terminator at the the end of the buffer - // that we will send to the callback. - // DO NOT EVER CHANGE THIS. We want to explicitly allow users - // to be able to depend on this behavior, so they will have - // the option to do some things faster. Additionally it's - // a security guard against buffer overflows. - readbuffer [r] = 0; - if (EventCallback) - (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r); - } - else if (r == 0) { - break; - } - else { - // Basically a would-block, meaning we've read everything there is to read. - break; - } - - } - - - if (total_bytes_read == 0) { - // If we read no data on a socket that selected readable, - // it generally means the other end closed the connection gracefully. - ScheduleClose (false); - //bCloseNow = true; - } - -} - -/********************* -PipeDescriptor::Write -*********************/ - -void PipeDescriptor::Write() -{ - int sd = GetSocket(); - assert (sd != INVALID_SOCKET); - - LastIo = gCurrentLoopTime; - char output_buffer [16 * 1024]; - size_t nbytes = 0; - - while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) { - OutboundPage *op = &(OutboundPages[0]); - if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) { - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset); - nbytes += (op->Length - op->Offset); - op->Free(); - OutboundPages.pop_front(); - } - else { - int len = sizeof(output_buffer) - nbytes; - memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len); - op->Offset += len; - nbytes += len; - } - } - - // We should never have gotten here if there were no data to write, - // so assert that as a sanity check. - // Don't bother to make sure nbytes is less than output_buffer because - // if it were we probably would have crashed already. - assert (nbytes > 0); - - assert (GetSocket() != INVALID_SOCKET); - int bytes_written = write (GetSocket(), output_buffer, nbytes); - - if (bytes_written > 0) { - OutboundDataSize -= bytes_written; - if ((size_t)bytes_written < nbytes) { - int len = nbytes - bytes_written; - char *buffer = (char*) malloc (len + 1); - if (!buffer) - throw std::runtime_error ("bad alloc throwing back data"); - memcpy (buffer, output_buffer + bytes_written, len); - buffer [len] = 0; - OutboundPages.push_front (OutboundPage (buffer, len)); - } - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0)); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - } - else { - #ifdef OS_UNIX - if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR)) - #endif - #ifdef OS_WIN32 - if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK)) - #endif - Close(); - } -} - - -/************************* -PipeDescriptor::Heartbeat -*************************/ - -void PipeDescriptor::Heartbeat() -{ - // If an inactivity timeout is defined, then check for it. - if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout)) - ScheduleClose (false); - //bCloseNow = true; -} - - -/***************************** -PipeDescriptor::SelectForRead -*****************************/ - -bool PipeDescriptor::SelectForRead() -{ - /* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */ - return true; -} - -/****************************** -PipeDescriptor::SelectForWrite -******************************/ - -bool PipeDescriptor::SelectForWrite() -{ - /* Pipe descriptors, being local by definition, don't have - * a pending state, so this is simpler than for the - * ConnectionDescriptor object. - */ - return (GetOutboundDataSize() > 0); -} - - - - -/******************************** -PipeDescriptor::SendOutboundData -********************************/ - -int PipeDescriptor::SendOutboundData (const char *data, int length) -{ - //if (bCloseNow || bCloseAfterWriting) - if (IsCloseScheduled()) - return 0; - - if (!data && (length > 0)) - throw std::runtime_error ("bad outbound data"); - char *buffer = (char *) malloc (length + 1); - if (!buffer) - throw std::runtime_error ("no allocation for outbound data"); - memcpy (buffer, data, length); - buffer [length] = 0; - OutboundPages.push_back (OutboundPage (buffer, length)); - OutboundDataSize += length; - #ifdef HAVE_EPOLL - EpollEvent.events = (EPOLLIN | EPOLLOUT); - assert (MyEventMachine); - MyEventMachine->Modify (this); - #endif - return length; -} - -/******************************** -PipeDescriptor::GetSubprocessPid -********************************/ - -bool PipeDescriptor::GetSubprocessPid (pid_t *pid) -{ - bool ok = false; - if (pid && (SubprocessPid > 0)) { - *pid = SubprocessPid; - ok = true; - } - return ok; -} - - -#endif // OS_UNIX - -/***************************************************************************** - -$Id$ - -File: rubymain.cpp -Date: 06Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" -#include "eventmachine.h" -#include <ruby.h> - - - -/******* -Statics -*******/ - -static VALUE EmModule; -static VALUE EmConnection; - -static VALUE Intern_at_signature; -static VALUE Intern_at_timers; -static VALUE Intern_at_conns; -static VALUE Intern_event_callback; -static VALUE Intern_run_deferred_callbacks; -static VALUE Intern_delete; -static VALUE Intern_call; -static VALUE Intern_receive_data; - -static VALUE Intern_notify_readable; -static VALUE Intern_notify_writable; - -/**************** -t_event_callback -****************/ - -static void event_callback (const char *a1, int a2, const char *a3, int a4) -{ - if (a2 == EM_CONNECTION_READ) { - VALUE t = rb_ivar_get (EmModule, Intern_at_conns); - VALUE q = rb_hash_aref (t, rb_str_new2(a1)); - if (q == Qnil) - rb_raise (rb_eRuntimeError, "no connection"); - rb_funcall (q, Intern_receive_data, 1, rb_str_new (a3, a4)); - } - else if (a2 == EM_CONNECTION_NOTIFY_READABLE) { - VALUE t = rb_ivar_get (EmModule, Intern_at_conns); - VALUE q = rb_hash_aref (t, rb_str_new2(a1)); - if (q == Qnil) - rb_raise (rb_eRuntimeError, "no connection"); - rb_funcall (q, Intern_notify_readable, 0); - } - else if (a2 == EM_CONNECTION_NOTIFY_WRITABLE) { - VALUE t = rb_ivar_get (EmModule, Intern_at_conns); - VALUE q = rb_hash_aref (t, rb_str_new2(a1)); - if (q == Qnil) - rb_raise (rb_eRuntimeError, "no connection"); - rb_funcall (q, Intern_notify_writable, 0); - } - else if (a2 == EM_LOOPBREAK_SIGNAL) { - rb_funcall (EmModule, Intern_run_deferred_callbacks, 0); - } - else if (a2 == EM_TIMER_FIRED) { - VALUE t = rb_ivar_get (EmModule, Intern_at_timers); - VALUE q = rb_funcall (t, Intern_delete, 1, rb_str_new(a3, a4)); - if (q == Qnil) - rb_raise (rb_eRuntimeError, "no timer"); - rb_funcall (q, Intern_call, 0); - } - else - rb_funcall (EmModule, Intern_event_callback, 3, rb_str_new2(a1), (a2 << 1) | 1, rb_str_new(a3,a4)); -} - - - -/************************** -t_initialize_event_machine -**************************/ - -static VALUE t_initialize_event_machine (VALUE self) -{ - evma_initialize_library (event_callback); - return Qnil; -} - - - -/***************************** -t_run_machine_without_threads -*****************************/ - -static VALUE t_run_machine_without_threads (VALUE self) -{ - evma_run_machine(); - return Qnil; -} - - -/******************* -t_add_oneshot_timer -*******************/ - -static VALUE t_add_oneshot_timer (VALUE self, VALUE interval) -{ - const char *f = evma_install_oneshot_timer (FIX2INT (interval)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no timer"); - return rb_str_new2 (f); -} - - -/************** -t_start_server -**************/ - -static VALUE t_start_server (VALUE self, VALUE server, VALUE port) -{ - const char *f = evma_create_tcp_server (StringValuePtr(server), FIX2INT(port)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no acceptor"); - return rb_str_new2 (f); -} - -/************* -t_stop_server -*************/ - -static VALUE t_stop_server (VALUE self, VALUE signature) -{ - evma_stop_tcp_server (StringValuePtr (signature)); - return Qnil; -} - - -/******************* -t_start_unix_server -*******************/ - -static VALUE t_start_unix_server (VALUE self, VALUE filename) -{ - const char *f = evma_create_unix_domain_server (StringValuePtr(filename)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no unix-domain acceptor"); - return rb_str_new2 (f); -} - - - -/*********** -t_send_data -***********/ - -static VALUE t_send_data (VALUE self, VALUE signature, VALUE data, VALUE data_length) -{ - int b = evma_send_data_to_connection (StringValuePtr (signature), StringValuePtr (data), FIX2INT (data_length)); - return INT2NUM (b); -} - - -/*********** -t_start_tls -***********/ - -static VALUE t_start_tls (VALUE self, VALUE signature) -{ - evma_start_tls (StringValuePtr (signature)); - return Qnil; -} - -/*************** -t_set_tls_parms -***************/ - -static VALUE t_set_tls_parms (VALUE self, VALUE signature, VALUE privkeyfile, VALUE certchainfile) -{ - /* set_tls_parms takes a series of positional arguments for specifying such things - * as private keys and certificate chains. - * It's expected that the parameter list will grow as we add more supported features. - * ALL of these parameters are optional, and can be specified as empty or NULL strings. - */ - evma_set_tls_parms (StringValuePtr (signature), StringValuePtr (privkeyfile), StringValuePtr (certchainfile) ); - return Qnil; -} - -/************** -t_get_peername -**************/ - -static VALUE t_get_peername (VALUE self, VALUE signature) -{ - struct sockaddr s; - if (evma_get_peername (StringValuePtr (signature), &s)) { - return rb_str_new ((const char*)&s, sizeof(s)); - } - - return Qnil; -} - -/************** -t_get_sockname -**************/ - -static VALUE t_get_sockname (VALUE self, VALUE signature) -{ - struct sockaddr s; - if (evma_get_sockname (StringValuePtr (signature), &s)) { - return rb_str_new ((const char*)&s, sizeof(s)); - } - - return Qnil; -} - -/******************** -t_get_subprocess_pid -********************/ - -static VALUE t_get_subprocess_pid (VALUE self, VALUE signature) -{ - pid_t pid; - if (evma_get_subprocess_pid (StringValuePtr (signature), &pid)) { - return INT2NUM (pid); - } - - return Qnil; -} - -/*********************** -t_get_subprocess_status -***********************/ - -static VALUE t_get_subprocess_status (VALUE self, VALUE signature) -{ - int status; - if (evma_get_subprocess_status (StringValuePtr (signature), &status)) { - return INT2NUM (status); - } - - return Qnil; -} - -/***************************** -t_get_comm_inactivity_timeout -*****************************/ - -static VALUE t_get_comm_inactivity_timeout (VALUE self, VALUE signature) -{ - int timeout; - if (evma_get_comm_inactivity_timeout (StringValuePtr (signature), &timeout)) - return INT2FIX (timeout); - return Qnil; -} - -/***************************** -t_set_comm_inactivity_timeout -*****************************/ - -static VALUE t_set_comm_inactivity_timeout (VALUE self, VALUE signature, VALUE timeout) -{ - int ti = FIX2INT (timeout); - if (evma_set_comm_inactivity_timeout (StringValuePtr (signature), &ti)); - return Qtrue; - return Qnil; -} - - -/*************** -t_send_datagram -***************/ - -static VALUE t_send_datagram (VALUE self, VALUE signature, VALUE data, VALUE data_length, VALUE address, VALUE port) -{ - int b = evma_send_datagram (StringValuePtr (signature), StringValuePtr (data), FIX2INT (data_length), StringValuePtr(address), FIX2INT(port)); - return INT2NUM (b); -} - - -/****************** -t_close_connection -******************/ - -static VALUE t_close_connection (VALUE self, VALUE signature, VALUE after_writing) -{ - evma_close_connection (StringValuePtr (signature), ((after_writing == Qtrue) ? 1 : 0)); - return Qnil; -} - -/******************************** -t_report_connection_error_status -********************************/ - -static VALUE t_report_connection_error_status (VALUE self, VALUE signature) -{ - int b = evma_report_connection_error_status (StringValuePtr (signature)); - return INT2NUM (b); -} - - - -/**************** -t_connect_server -****************/ - -static VALUE t_connect_server (VALUE self, VALUE server, VALUE port) -{ - // Avoid FIX2INT in this case, because it doesn't deal with type errors properly. - // Specifically, if the value of port comes in as a string rather than an integer, - // NUM2INT will throw a type error, but FIX2INT will generate garbage. - - const char *f = evma_connect_to_server (StringValuePtr(server), NUM2INT(port)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no connection"); - return rb_str_new2 (f); -} - -/********************* -t_connect_unix_server -*********************/ - -static VALUE t_connect_unix_server (VALUE self, VALUE serversocket) -{ - const char *f = evma_connect_to_unix_server (StringValuePtr(serversocket)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no connection"); - return rb_str_new2 (f); -} - -/*********** -t_attach_fd -***********/ - -static VALUE t_attach_fd (VALUE self, VALUE file_descriptor, VALUE read_mode, VALUE write_mode) -{ - const char *f = evma_attach_fd (NUM2INT(file_descriptor), (read_mode == Qtrue) ? 1 : 0, (write_mode == Qtrue) ? 1 : 0); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no connection"); - return rb_str_new2 (f); -} - -/*********** -t_detach_fd -***********/ - -static VALUE t_detach_fd (VALUE self, VALUE signature) -{ - return INT2NUM(evma_detach_fd (StringValuePtr(signature))); -} - -/***************** -t_open_udp_socket -*****************/ - -static VALUE t_open_udp_socket (VALUE self, VALUE server, VALUE port) -{ - const char *f = evma_open_datagram_socket (StringValuePtr(server), FIX2INT(port)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no datagram socket"); - return rb_str_new2 (f); -} - - - -/***************** -t_release_machine -*****************/ - -static VALUE t_release_machine (VALUE self) -{ - evma_release_library(); - return Qnil; -} - - -/****** -t_stop -******/ - -static VALUE t_stop (VALUE self) -{ - evma_stop_machine(); - return Qnil; -} - -/****************** -t_signal_loopbreak -******************/ - -static VALUE t_signal_loopbreak (VALUE self) -{ - evma_signal_loopbreak(); - return Qnil; -} - -/************** -t_library_type -**************/ - -static VALUE t_library_type (VALUE self) -{ - return rb_eval_string (":extension"); -} - - - -/******************* -t_set_timer_quantum -*******************/ - -static VALUE t_set_timer_quantum (VALUE self, VALUE interval) -{ - evma_set_timer_quantum (FIX2INT (interval)); - return Qnil; -} - -/******************** -t_set_max_timer_count -********************/ - -static VALUE t_set_max_timer_count (VALUE self, VALUE ct) -{ - evma_set_max_timer_count (FIX2INT (ct)); - return Qnil; -} - -/*************** -t_setuid_string -***************/ - -static VALUE t_setuid_string (VALUE self, VALUE username) -{ - evma_setuid_string (StringValuePtr (username)); - return Qnil; -} - - - -/************* -t__write_file -*************/ - -static VALUE t__write_file (VALUE self, VALUE filename) -{ - const char *f = evma__write_file (StringValuePtr (filename)); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "file not opened"); - return rb_str_new2 (f); -} - -/************** -t_invoke_popen -**************/ - -static VALUE t_invoke_popen (VALUE self, VALUE cmd) -{ - // 1.8.7+ - #ifdef RARRAY_LEN - int len = RARRAY_LEN(cmd); - #else - int len = RARRAY (cmd)->len; - #endif - if (len > 98) - rb_raise (rb_eRuntimeError, "too many arguments to popen"); - char *strings [100]; - for (int i=0; i < len; i++) { - VALUE ix = INT2FIX (i); - VALUE s = rb_ary_aref (1, &ix, cmd); - strings[i] = StringValuePtr (s); - } - strings[len] = NULL; - - const char *f = evma_popen (strings); - if (!f || !*f) { - char *err = strerror (errno); - char buf[100]; - memset (buf, 0, sizeof(buf)); - snprintf (buf, sizeof(buf)-1, "no popen: %s", (err?err:"???")); - rb_raise (rb_eRuntimeError, buf); - } - return rb_str_new2 (f); -} - - -/*************** -t_read_keyboard -***************/ - -static VALUE t_read_keyboard (VALUE self) -{ - const char *f = evma_open_keyboard(); - if (!f || !*f) - rb_raise (rb_eRuntimeError, "no keyboard reader"); - return rb_str_new2 (f); -} - - -/******** -t__epoll -********/ - -static VALUE t__epoll (VALUE self) -{ - // Temporary. - evma__epoll(); - return Qnil; -} - -/********** -t__epoll_p -**********/ - -static VALUE t__epoll_p (VALUE self) -{ - #ifdef HAVE_EPOLL - return Qtrue; - #else - return Qfalse; - #endif -} - - -/********* -t__kqueue -*********/ - -static VALUE t__kqueue (VALUE self) -{ - // Temporary. - evma__kqueue(); - return Qnil; -} - -/*********** -t__kqueue_p -***********/ - -static VALUE t__kqueue_p (VALUE self) -{ - #ifdef HAVE_KQUEUE - return Qtrue; - #else - return Qfalse; - #endif -} - - -/**************** -t_send_file_data -****************/ - -static VALUE t_send_file_data (VALUE self, VALUE signature, VALUE filename) -{ - - /* The current implementation of evma_send_file_data_to_connection enforces a strict - * upper limit on the file size it will transmit (currently 32K). The function returns - * zero on success, -1 if the requested file exceeds its size limit, and a positive - * number for other errors. - * TODO: Positive return values are actually errno's, which is probably the wrong way to - * do this. For one thing it's ugly. For another, we can't be sure zero is never a real errno. - */ - - int b = evma_send_file_data_to_connection (StringValuePtr(signature), StringValuePtr(filename)); - if (b == -1) - rb_raise(rb_eRuntimeError, "File too large. send_file_data() supports files under 32k."); - if (b > 0) { - char *err = strerror (b); - char buf[1024]; - memset (buf, 0, sizeof(buf)); - snprintf (buf, sizeof(buf)-1, ": %s %s", StringValuePtr(filename),(err?err:"???")); - - rb_raise (rb_eIOError, buf); - } - - return INT2NUM (0); -} - - -/******************* -t_set_rlimit_nofile -*******************/ - -static VALUE t_set_rlimit_nofile (VALUE self, VALUE arg) -{ - arg = (NIL_P(arg)) ? -1 : NUM2INT (arg); - return INT2NUM (evma_set_rlimit_nofile (arg)); -} - -/*************************** -conn_get_outbound_data_size -***************************/ - -static VALUE conn_get_outbound_data_size (VALUE self) -{ - VALUE sig = rb_ivar_get (self, Intern_at_signature); - return INT2NUM (evma_get_outbound_data_size (StringValuePtr(sig))); -} - - -/****************************** -conn_associate_callback_target -******************************/ - -static VALUE conn_associate_callback_target (VALUE self, VALUE sig) -{ - // No-op for the time being. - return Qnil; -} - - -/*************** -t_get_loop_time -****************/ - -static VALUE t_get_loop_time (VALUE self) -{ - VALUE cTime = rb_path2class("Time"); - if (gCurrentLoopTime != 0) { - return rb_funcall(cTime, - rb_intern("at"), - 1, - INT2NUM(gCurrentLoopTime)); - } - return Qnil; -} - - -/********************* -Init_rubyeventmachine -*********************/ - -extern "C" void Init_rubyeventmachine() -{ - // Tuck away some symbol values so we don't have to look 'em up every time we need 'em. - Intern_at_signature = rb_intern ("@signature"); - Intern_at_timers = rb_intern ("@timers"); - Intern_at_conns = rb_intern ("@conns"); - - Intern_event_callback = rb_intern ("event_callback"); - Intern_run_deferred_callbacks = rb_intern ("run_deferred_callbacks"); - Intern_delete = rb_intern ("delete"); - Intern_call = rb_intern ("call"); - Intern_receive_data = rb_intern ("receive_data"); - - Intern_notify_readable = rb_intern ("notify_readable"); - Intern_notify_writable = rb_intern ("notify_writable"); - - // INCOMPLETE, we need to define class Connections inside module EventMachine - // run_machine and run_machine_without_threads are now identical. - // Must deprecate the without_threads variant. - EmModule = rb_define_module ("EventMachine"); - EmConnection = rb_define_class_under (EmModule, "Connection", rb_cObject); - - rb_define_class_under (EmModule, "ConnectionNotBound", rb_eException); - rb_define_class_under (EmModule, "NoHandlerForAcceptedConnection", rb_eException); - rb_define_class_under (EmModule, "UnknownTimerFired", rb_eException); - - rb_define_module_function (EmModule, "initialize_event_machine", (VALUE(*)(...))t_initialize_event_machine, 0); - rb_define_module_function (EmModule, "run_machine", (VALUE(*)(...))t_run_machine_without_threads, 0); - rb_define_module_function (EmModule, "run_machine_without_threads", (VALUE(*)(...))t_run_machine_without_threads, 0); - rb_define_module_function (EmModule, "add_oneshot_timer", (VALUE(*)(...))t_add_oneshot_timer, 1); - rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2); - rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1); - rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1); - rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 3); - rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1); - rb_define_module_function (EmModule, "send_data", (VALUE(*)(...))t_send_data, 3); - rb_define_module_function (EmModule, "send_datagram", (VALUE(*)(...))t_send_datagram, 5); - rb_define_module_function (EmModule, "close_connection", (VALUE(*)(...))t_close_connection, 2); - rb_define_module_function (EmModule, "report_connection_error_status", (VALUE(*)(...))t_report_connection_error_status, 1); - rb_define_module_function (EmModule, "connect_server", (VALUE(*)(...))t_connect_server, 2); - rb_define_module_function (EmModule, "connect_unix_server", (VALUE(*)(...))t_connect_unix_server, 1); - - rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 3); - rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1); - - rb_define_module_function (EmModule, "current_time", (VALUE(*)(...))t_get_loop_time, 0); - - rb_define_module_function (EmModule, "open_udp_socket", (VALUE(*)(...))t_open_udp_socket, 2); - rb_define_module_function (EmModule, "read_keyboard", (VALUE(*)(...))t_read_keyboard, 0); - rb_define_module_function (EmModule, "release_machine", (VALUE(*)(...))t_release_machine, 0); - rb_define_module_function (EmModule, "stop", (VALUE(*)(...))t_stop, 0); - rb_define_module_function (EmModule, "signal_loopbreak", (VALUE(*)(...))t_signal_loopbreak, 0); - rb_define_module_function (EmModule, "library_type", (VALUE(*)(...))t_library_type, 0); - rb_define_module_function (EmModule, "set_timer_quantum", (VALUE(*)(...))t_set_timer_quantum, 1); - rb_define_module_function (EmModule, "set_max_timer_count", (VALUE(*)(...))t_set_max_timer_count, 1); - rb_define_module_function (EmModule, "setuid_string", (VALUE(*)(...))t_setuid_string, 1); - rb_define_module_function (EmModule, "invoke_popen", (VALUE(*)(...))t_invoke_popen, 1); - rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2); - - // Provisional: - rb_define_module_function (EmModule, "_write_file", (VALUE(*)(...))t__write_file, 1); - - rb_define_module_function (EmModule, "get_peername", (VALUE(*)(...))t_get_peername, 1); - rb_define_module_function (EmModule, "get_sockname", (VALUE(*)(...))t_get_sockname, 1); - rb_define_module_function (EmModule, "get_subprocess_pid", (VALUE(*)(...))t_get_subprocess_pid, 1); - rb_define_module_function (EmModule, "get_subprocess_status", (VALUE(*)(...))t_get_subprocess_status, 1); - rb_define_module_function (EmModule, "get_comm_inactivity_timeout", (VALUE(*)(...))t_get_comm_inactivity_timeout, 1); - rb_define_module_function (EmModule, "set_comm_inactivity_timeout", (VALUE(*)(...))t_set_comm_inactivity_timeout, 2); - rb_define_module_function (EmModule, "set_rlimit_nofile", (VALUE(*)(...))t_set_rlimit_nofile, 1); - - // Temporary: - rb_define_module_function (EmModule, "epoll", (VALUE(*)(...))t__epoll, 0); - rb_define_module_function (EmModule, "kqueue", (VALUE(*)(...))t__kqueue, 0); - - rb_define_module_function (EmModule, "epoll?", (VALUE(*)(...))t__epoll_p, 0); - rb_define_module_function (EmModule, "kqueue?", (VALUE(*)(...))t__kqueue_p, 0); - - rb_define_method (EmConnection, "get_outbound_data_size", (VALUE(*)(...))conn_get_outbound_data_size, 0); - rb_define_method (EmConnection, "associate_callback_target", (VALUE(*)(...))conn_associate_callback_target, 1); - - rb_define_const (EmModule, "TimerFired", INT2NUM(100)); - rb_define_const (EmModule, "ConnectionData", INT2NUM(101)); - rb_define_const (EmModule, "ConnectionUnbound", INT2NUM(102)); - rb_define_const (EmModule, "ConnectionAccepted", INT2NUM(103)); - rb_define_const (EmModule, "ConnectionCompleted", INT2NUM(104)); - rb_define_const (EmModule, "LoopbreakSignalled", INT2NUM(105)); - - rb_define_const (EmModule, "ConnectionNotifyReadable", INT2NUM(106)); - rb_define_const (EmModule, "ConnectionNotifyWritable", INT2NUM(107)); - -} - -/***************************************************************************** - -$Id$ - -File: sigs.cpp -Date: 06Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - -#include "project.h" - - -bool gTerminateSignalReceived; - - -/************** -SigtermHandler -**************/ - -void SigtermHandler (int sig) -{ - // This is a signal-handler, don't do anything frisky. Interrupts are disabled. - // Set the terminate flag WITHOUT trying to lock a mutex- otherwise we can easily - // self-deadlock, especially if the event machine is looping quickly. - gTerminateSignalReceived = true; -} - - -/********************* -InstallSignalHandlers -*********************/ - -void InstallSignalHandlers() -{ - #ifdef OS_UNIX - static bool bInstalled = false; - if (!bInstalled) { - bInstalled = true; - signal (SIGINT, SigtermHandler); - signal (SIGTERM, SigtermHandler); - signal (SIGPIPE, SIG_IGN); - } - #endif -} - - - -/******************* -WintelSignalHandler -*******************/ - -#ifdef OS_WIN32 -BOOL WINAPI WintelSignalHandler (DWORD control) -{ - if (control == CTRL_C_EVENT) - gTerminateSignalReceived = true; - return TRUE; -} -#endif - -/************ -HookControlC -************/ - -#ifdef OS_WIN32 -void HookControlC (bool hook) -{ - if (hook) { - // INSTALL hook - SetConsoleCtrlHandler (WintelSignalHandler, TRUE); - } - else { - // UNINSTALL hook - SetConsoleCtrlHandler (WintelSignalHandler, FALSE); - } -} -#endif - - -/***************************************************************************** - -$Id$ - -File: ssl.cpp -Date: 30Apr06 - -Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved. -Gmail: blackhedd - -This program is free software; you can redistribute it and/or modify -it under the terms of either: 1) the GNU General Public License -as published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version; or 2) Ruby's License. - -See the file COPYING for complete licensing information. - -*****************************************************************************/ - - -#ifdef WITH_SSL - -#include "project.h" - - -bool SslContext_t::bLibraryInitialized = false; - - - -static void InitializeDefaultCredentials(); -static EVP_PKEY *DefaultPrivateKey = NULL; -static X509 *DefaultCertificate = NULL; - -static char PrivateMaterials[] = { -"-----BEGIN RSA PRIVATE KEY-----\n" -"MIICXAIBAAKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxwVDWV\n" -"Igdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t39hJ/\n" -"AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQIDAQAB\n" -"AoGALA89gIFcr6BIBo8N5fL3aNHpZXjAICtGav+kTUpuxSiaym9cAeTHuAVv8Xgk\n" -"H2Wbq11uz+6JMLpkQJH/WZ7EV59DPOicXrp0Imr73F3EXBfR7t2EQDYHPMthOA1D\n" -"I9EtCzvV608Ze90hiJ7E3guGrGppZfJ+eUWCPgy8CZH1vRECQQDv67rwV/oU1aDo\n" -"6/+d5nqjeW6mWkGqTnUU96jXap8EIw6B+0cUKskwx6mHJv+tEMM2748ZY7b0yBlg\n" -"w4KDghbFAkEAz2h8PjSJG55LwqmXih1RONSgdN9hjB12LwXL1CaDh7/lkEhq0PlK\n" -"PCAUwQSdM17Sl0Xxm2CZiekTSlwmHrtqXQJAF3+8QJwtV2sRJp8u2zVe37IeH1cJ\n" -"xXeHyjTzqZ2803fnjN2iuZvzNr7noOA1/Kp+pFvUZUU5/0G2Ep8zolPUjQJAFA7k\n" -"xRdLkzIx3XeNQjwnmLlncyYPRv+qaE3FMpUu7zftuZBnVCJnvXzUxP3vPgKTlzGa\n" -"dg5XivDRfsV+okY5uQJBAMV4FesUuLQVEKb6lMs7rzZwpeGQhFDRfywJzfom2TLn\n" -"2RdJQQ3dcgnhdVDgt5o1qkmsqQh8uJrJ9SdyLIaZQIc=\n" -"-----END RSA PRIVATE KEY-----\n" -"-----BEGIN CERTIFICATE-----\n" -"MIID6TCCA1KgAwIBAgIJANm4W/Tzs+s+MA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD\n" -"VQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYw\n" -"FAYDVQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsG\n" -"A1UEAxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2lu\n" -"ZWVyaW5nQHN0ZWFtaGVhdC5uZXQwHhcNMDYwNTA1MTcwNjAzWhcNMjQwMjIwMTcw\n" -"NjAzWjCBqjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQH\n" -"EwhOZXcgWW9yazEWMBQGA1UEChMNU3RlYW1oZWF0Lm5ldDEUMBIGA1UECxMLRW5n\n" -"aW5lZXJpbmcxHTAbBgNVBAMTFG9wZW5jYS5zdGVhbWhlYXQubmV0MSgwJgYJKoZI\n" -"hvcNAQkBFhllbmdpbmVlcmluZ0BzdGVhbWhlYXQubmV0MIGfMA0GCSqGSIb3DQEB\n" -"AQUAA4GNADCBiQKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxw\n" -"VDWVIgdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t3\n" -"9hJ/AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQID\n" -"AQABo4IBEzCCAQ8wHQYDVR0OBBYEFPJvPd1Fcmd8o/Tm88r+NjYPICCkMIHfBgNV\n" -"HSMEgdcwgdSAFPJvPd1Fcmd8o/Tm88r+NjYPICCkoYGwpIGtMIGqMQswCQYDVQQG\n" -"EwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYwFAYD\n" -"VQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsGA1UE\n" -"AxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2luZWVy\n" -"aW5nQHN0ZWFtaGVhdC5uZXSCCQDZuFv087PrPjAMBgNVHRMEBTADAQH/MA0GCSqG\n" -"SIb3DQEBBQUAA4GBAC1CXey/4UoLgJiwcEMDxOvW74plks23090iziFIlGgcIhk0\n" -"Df6hTAs7H3MWww62ddvR8l07AWfSzSP5L6mDsbvq7EmQsmPODwb6C+i2aF3EDL8j\n" -"uw73m4YIGI0Zw2XdBpiOGkx2H56Kya6mJJe/5XORZedh1wpI7zki01tHYbcy\n" -"-----END CERTIFICATE-----\n"}; - -/* These private materials were made with: - * openssl req -new -x509 -keyout cakey.pem -out cacert.pem -nodes -days 6500 - * TODO: We need a full-blown capability to work with user-supplied - * keypairs and properly-signed certificates. - */ - - -/***************** -builtin_passwd_cb -*****************/ - -extern "C" int builtin_passwd_cb (char *buf, int bufsize, int rwflag, void *userdata) -{ - strcpy (buf, "kittycat"); - return 8; -} - -/**************************** -InitializeDefaultCredentials -****************************/ - -static void InitializeDefaultCredentials() -{ - BIO *bio = BIO_new_mem_buf (PrivateMaterials, -1); - assert (bio); - - if (DefaultPrivateKey) { - // we may come here in a restart. - EVP_PKEY_free (DefaultPrivateKey); - DefaultPrivateKey = NULL; - } - PEM_read_bio_PrivateKey (bio, &DefaultPrivateKey, builtin_passwd_cb, 0); - - if (DefaultCertificate) { - // we may come here in a restart. - X509_free (DefaultCertificate); - DefaultCertificate = NULL; - } - PEM_read_bio_X509 (bio, &DefaultCertificate, NULL, 0); - - BIO_free (bio); -} - - - -/************************** -SslContext_t::SslContext_t -**************************/ - -SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile): - pCtx (NULL), - PrivateKey (NULL), - Certificate (NULL) -{ - /* TODO: the usage of the specified private-key and cert-chain filenames only applies to - * client-side connections at this point. Server connections currently use the default materials. - * That needs to be fixed asap. - * Also, in this implementation, server-side connections use statically defined X-509 defaults. - * One thing I'm really not clear on is whether or not you have to explicitly free X509 and EVP_PKEY - * objects when we call our destructor, or whether just calling SSL_CTX_free is enough. - */ - - if (!bLibraryInitialized) { - bLibraryInitialized = true; - SSL_library_init(); - OpenSSL_add_ssl_algorithms(); - OpenSSL_add_all_algorithms(); - SSL_load_error_strings(); - ERR_load_crypto_strings(); - - InitializeDefaultCredentials(); - } - - bIsServer = is_server; - pCtx = SSL_CTX_new (is_server ? SSLv23_server_method() : SSLv23_client_method()); - if (!pCtx) - throw std::runtime_error ("no SSL context"); - - SSL_CTX_set_options (pCtx, SSL_OP_ALL); - //SSL_CTX_set_options (pCtx, (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3)); - - if (is_server) { - // The SSL_CTX calls here do NOT allocate memory. - int e; - if (privkeyfile.length() > 0) - e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM); - else - e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey); - assert (e > 0); - if (certchainfile.length() > 0) - e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str()); - else - e = SSL_CTX_use_certificate (pCtx, DefaultCertificate); - assert (e > 0); - } - - SSL_CTX_set_cipher_list (pCtx, "ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH"); - - if (is_server) { - SSL_CTX_sess_set_cache_size (pCtx, 128); - SSL_CTX_set_session_id_context (pCtx, (unsigned char*)"eventmachine", 12); - } - else { - int e; - if (privkeyfile.length() > 0) { - e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM); - assert (e > 0); - } - if (certchainfile.length() > 0) { - e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str()); - assert (e > 0); - } - } -} - - - -/*************************** -SslContext_t::~SslContext_t -***************************/ - -SslContext_t::~SslContext_t() -{ - if (pCtx) - SSL_CTX_free (pCtx); - if (PrivateKey) - EVP_PKEY_free (PrivateKey); - if (Certificate) - X509_free (Certificate); -} - - - -/****************** -SslBox_t::SslBox_t -******************/ - -SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile): - bIsServer (is_server), - pSSL (NULL), - pbioRead (NULL), - pbioWrite (NULL) -{ - /* TODO someday: make it possible to re-use SSL contexts so we don't have to create - * a new one every time we come here. - */ - - Context = new SslContext_t (bIsServer, privkeyfile, certchainfile); - assert (Context); - - pbioRead = BIO_new (BIO_s_mem()); - assert (pbioRead); - - pbioWrite = BIO_new (BIO_s_mem()); - assert (pbioWrite); - - pSSL = SSL_new (Context->pCtx); - assert (pSSL); - SSL_set_bio (pSSL, pbioRead, pbioWrite); - - if (!bIsServer) - SSL_connect (pSSL); -} - - - -/******************* -SslBox_t::~SslBox_t -*******************/ - -SslBox_t::~SslBox_t() -{ - // Freeing pSSL will also free the associated BIOs, so DON'T free them separately. - if (pSSL) { - if (SSL_get_shutdown (pSSL) & SSL_RECEIVED_SHUTDOWN) - SSL_shutdown (pSSL); - else - SSL_clear (pSSL); - SSL_free (pSSL); - } - - delete Context; -} - - - -/*********************** -SslBox_t::PutCiphertext -***********************/ - -bool SslBox_t::PutCiphertext (const char *buf, int bufsize) -{ - assert (buf && (bufsize > 0)); - - assert (pbioRead); - int n = BIO_write (pbioRead, buf, bufsize); - - return (n == bufsize) ? true : false; -} - - -/********************** -SslBox_t::GetPlaintext -**********************/ - -int SslBox_t::GetPlaintext (char *buf, int bufsize) -{ - if (!SSL_is_init_finished (pSSL)) { - int e = bIsServer ? SSL_accept (pSSL) : SSL_connect (pSSL); - if (e < 0) { - int er = SSL_get_error (pSSL, e); - if (er != SSL_ERROR_WANT_READ) { - // Return -1 for a nonfatal error, -2 for an error that should force the connection down. - return (er == SSL_ERROR_SSL) ? (-2) : (-1); - } - else - return 0; - } - // If handshake finished, FALL THROUGH and return the available plaintext. - } - - if (!SSL_is_init_finished (pSSL)) { - // We can get here if a browser abandons a handshake. - // The user can see a warning dialog and abort the connection. - cerr << "<SSL_incomp>"; - return 0; - } - - //cerr << "CIPH: " << SSL_get_cipher (pSSL) << endl; - - int n = SSL_read (pSSL, buf, bufsize); - if (n >= 0) { - return n; - } - else { - if (SSL_get_error (pSSL, n) == SSL_ERROR_WANT_READ) { - return 0; - } - else { - return -1; - } - } - - return 0; -} - - - -/************************** -SslBox_t::CanGetCiphertext -**************************/ - -bool SslBox_t::CanGetCiphertext() -{ - assert (pbioWrite); - return BIO_pending (pbioWrite) ? true : false; -} - - - -/*********************** -SslBox_t::GetCiphertext -***********************/ - -int SslBox_t::GetCiphertext (char *buf, int bufsize) -{ - assert (pbioWrite); - assert (buf && (bufsize > 0)); - - return BIO_read (pbioWrite, buf, bufsize); -} - - - -/********************** -SslBox_t::PutPlaintext -**********************/ - -int SslBox_t::PutPlaintext (const char *buf, int bufsize) -{ - // The caller will interpret the return value as the number of bytes written. - // WARNING WARNING WARNING, are there any situations in which a 0 or -1 return - // from SSL_write means we should immediately retry? The socket-machine loop - // will probably wait for a time-out cycle (perhaps a second) before re-trying. - // THIS WOULD CAUSE A PERCEPTIBLE DELAY! - - /* We internally queue any outbound plaintext that can't be dispatched - * because we're in the middle of a handshake or something. - * When we get called, try to send any queued data first, and then - * send the caller's data (or queue it). We may get called with no outbound - * data, which means we try to send the outbound queue and that's all. - * - * Return >0 if we wrote any data, 0 if we didn't, and <0 for a fatal error. - * Note that if we return 0, the connection is still considered live - * and we are signalling that we have accepted the outbound data (if any). - */ - - OutboundQ.Push (buf, bufsize); - - if (!SSL_is_init_finished (pSSL)) - return 0; - - bool fatal = false; - bool did_work = false; - - while (OutboundQ.HasPages()) { - const char *page; - int length; - OutboundQ.Front (&page, &length); - assert (page && (length > 0)); - int n = SSL_write (pSSL, page, length); - if (n > 0) { - did_work = true; - OutboundQ.PopFront(); - } - else { - int er = SSL_get_error (pSSL, n); - if ((er != SSL_ERROR_WANT_READ) && (er != SSL_ERROR_WANT_WRITE)) - fatal = true; - break; - } - } - - - if (did_work) - return 1; - else if (fatal) - return -1; - else - return 0; -} - - -#endif // WITH_SSL - diff --git a/test/scanners/cpp/pleac.expected.raydebug b/test/scanners/cpp/pleac.expected.raydebug deleted file mode 100644 index 62426ec..0000000 --- a/test/scanners/cpp/pleac.expected.raydebug +++ /dev/null @@ -1,2041 +0,0 @@ -comment(// -*- c++ -*-) - -comment(// @@PLEAC@@_NAME) -comment(// @@SKIP@@ C++/STL/Boost) - - -comment(// @@PLEAC@@_WEB) -comment(// @@SKIP@@ http://www.research.att.com/~bs/C++.html) -comment(// @@SKIP@@ http://www.boost.org/) - - -comment(// @@PLEAC@@_1.0) -comment(// NOTE: Whilst it is perfectly valid to use Standard C Library, or GNU) -comment(// C Library, routines in C++ programs, the code examples here will, as) -comment(// far as possible, avoid doing so, instead using C++-specific functionality) -comment(// and idioms. In general:) -comment(// * I/O will be iostream-based [i.e. no 'scanf', 'printf', 'fgets' etc]) -comment(// * Container / iterator idioms based on the Standard Template Library [STL]) -comment(// will replace the built-in array / raw pointer idioms typically used in C) -comment(// * Boost Library functionality utilised wherever possible [the reason for) -comment(// this is that much of this functionality is likely to appear in the next) -comment(// C++ standard]) -comment(// * Error detection/handling will generally be exception-based [this is done) -comment(// to keep examples simple. Exception use is optional in C++, and is not as) -comment(// pervasive as it is in other languages like Java or C#]) -comment(// C-based solution(s\) to problem(s\) will be found in the corresponding section) -comment(// of PLEAC-C/Posix/GNU.) - -comment(// In C++, one can use the builtin 'char *' type or the 'string' type) -comment(// to represent strings. In this section, we will work with the C++) -comment(// library 'string' class.) - -comment(// Characteristics of 'string' types:) -comment(// - may be of any length) -comment(// - are defined within the std namespace) -comment(// - can be converted to a 'const char *' using std::string::c_str(\)) -comment(// - can be subscripted to access individual characters (e.g., str[3]) -comment(// returns the 4th character of the string) -comment(// - memory associated with strings is reclaimed automatically as strings) -comment(// go out of scope) -comment(// - strings cannot be used as true/false values (i.e., the following is not) -comment(// allowed: string s; if (s\) {}\)) - -comment(//-----------------------------) -comment(// Before using strings, you must include the <string> header file) -preprocessor(#include) include(<string>) - -comment(//-----------------------------) -comment(// To create a literal strings, you must use double quotes ("\). You cannot) -comment(// use single quotes. ) - -comment(//-----------------------------) -comment(// String variables must be declared -- if no value is given it's) -comment(// value is the empty string (""\). ) -ident(std)operator(::)pre_type(string) ident(s)operator(;) - -comment(//-----------------------------) -comment(// To insert special characters, quote the character with \\ -std::string s1 = "\\\\n"; // Two characters, \\ and n) -ident(std)operator(::)pre_type(string) ident(s2) operator(=) string<delimiter(")content(Jon )char(\\")content(Maddog)char(\\")content( Orwant)delimiter(")>operator(;) comment(// Literal double quotes) - -comment(//-----------------------------) -comment(// Strings can be declared in one of two ways) -ident(std)operator(::)pre_type(string) ident(s1) operator(=) string<delimiter(")content(assignment syntax)delimiter(")>operator(;) -ident(std)operator(::)pre_type(string) ident(s2)operator(()string<delimiter(")content(constructor syntax)delimiter(")>operator(\);) - -comment(//-----------------------------) -comment(// Multi-line strings.) -comment(// There is no equivalent to perl's "here" documents in c++) -ident(std)operator(::)pre_type(string) ident(s1) operator(=) string<delimiter(")content( -This is a multiline string started and finished with double -quotes that spans 4 lines (it contains 3 newline characters\). -)delimiter(")>operator(;) - -ident(std)operator(::)pre_type(string) ident(s2) operator(=) string<delimiter(")content(This is a multiline string started and finished with double -quotes that spans 2 lines (it contains 1 newline character\).)delimiter(")>operator(;) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.1) -ident(std)operator(::)pre_type(string) ident(s) operator(=) string<delimiter(")content(some string)delimiter(")>operator(;) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(value1) operator(=) ident(s)operator(.)ident(substr)operator(()ident(offset)operator(,) ident(length)operator(\);) -ident(std)operator(::)pre_type(string) ident(value2) operator(=) ident(s)operator(.)ident(substr)operator(()ident(offset)operator(\);) - -comment(// Unlike perl, the substr function returns a copy of the substring) -comment(// rather than a reference to the existing substring, thus using substr) -comment(// on the left hand side of an assignment statement will not modify ) -comment(// the original string. To get this functionality, you can use the) -comment(// std::string::replace function.) - -comment(// Using offsets and lengths) -ident(s)operator(.)ident(replace)operator(()ident(offset)operator(,) ident(length)operator(,) ident(newstring)operator(\);) -ident(s)operator(.)ident(replace)operator(()ident(offset)operator(,) ident(s)operator(.)ident(size)operator((\)-)ident(offset)operator(,) ident(newtail)operator(\);) - -comment(//-----------------------------) -comment(// The C++ string class doesn't have anything equivalent to perl's unpack.) -comment(// Instead, one can use C structures to import/export binary data) - -comment(//-----------------------------) -preprocessor(#include) include(<string>) -pre_type(string) ident(s) operator(=) string<delimiter(")content(This is what you have)delimiter(")>operator(;) - -ident(std)operator(::)pre_type(string) ident(first) operator(=) ident(s)operator(.)ident(substr)operator(()integer(0)operator(,) integer(1)operator(\);) comment(// "T") -ident(std)operator(::)pre_type(string) ident(second) operator(=) ident(s)operator(.)ident(substr)operator(()integer(5)operator(,) integer(2)operator(\);) comment(// "is") -ident(std)operator(::)pre_type(string) ident(rest) operator(=) ident(s)operator(.)ident(substr)operator(()integer(13)operator(\);) comment(// "you have") - -comment(// C++ strings do not support backwards indexing as perl does but ) -comment(// you can fake it out by subtracting the negative index from the) -comment(// string length) -ident(std)operator(::)pre_type(string) ident(last) operator(=) ident(s)operator(.)ident(substr)operator(()ident(s)operator(.)ident(size)operator((\)-)integer(1)operator(\);) comment(// "e") -ident(std)operator(::)pre_type(string) ident(end) operator(=) ident(s)operator(.)ident(substr)operator(()ident(s)operator(.)ident(size)operator((\)-)integer(4)operator(\);) comment(// "have") -ident(std)operator(::)pre_type(string) ident(piece) operator(=) ident(s)operator(.)ident(substr)operator(()ident(s)operator(.)ident(size)operator((\)-)integer(8)operator(,) integer(3)operator(\);) comment(// "you") - -comment(//-----------------------------) -preprocessor(#include) include(<string>) -preprocessor(#include) include(<iostream>) - -pre_type(string) ident(s)operator(()string<delimiter(")content(This is what you have)delimiter(")>operator(\);) -ident(std)operator(::)ident(cout) operator(<<) ident(s) operator(<<) ident(std)operator(::)ident(endl)operator(;) -comment(// This is what you have) - -ident(s)operator(.)ident(replace)operator(()integer(5)operator(,)integer(2)operator(,)string<delimiter(")content(wasn't)delimiter(")>operator(\);) comment(// change "is to "wasn't") -comment(// This wasn't what you have) - -ident(s)operator(.)ident(replace)operator(()ident(s)operator(.)ident(size)operator((\)-)integer(12)operator(,) integer(12)operator(,) string<delimiter(")content(ondrous)delimiter(")>operator(\);) comment(// "This wasn't wondrous") -comment(// This wasn't wonderous) - -ident(s)operator(.)ident(replace)operator(()integer(0)operator(,) integer(1)operator(,) string<delimiter(")delimiter(")>operator(\);) comment(// delete first character) -comment(// his wasn't wondrous) - -ident(s)operator(.)ident(replace)operator(()ident(s)operator(.)ident(size)operator((\)-)integer(10)operator(,) integer(10)operator(,) string<delimiter(")delimiter(")>operator(\);) comment(// delete last 10 characters) -comment(// his wasn') - -comment(//-----------------------------) -comment(// C++ does not have built-in support for the perl s///, m//, and tr/// ) -comment(// operators; however, similar results can be achieved in at least ) -comment(// two ways:) -comment(// - string operations such as string::find, string::rfind, etc.) -comment(// - the boost regular expression library (regex++\) supports perl) -comment(// regular expression syntax.) -comment(// TODO: Add examples of each.) - -comment(// MISSING: if (substr($string, -10\) =~ /pattern/\) {) -comment(// print "Pattern matches in last 10 characters\\n";) -comment(// }) - -comment(// MISSING: substr($string, 0, 5\) =~ s/is/at/g;) - -comment(//-----------------------------) -comment(// exchange the first and last letters in a string using substr and replace) -pre_type(string) ident(a) operator(=) string<delimiter(")content(make a hat)delimiter(")>operator(;) - -ident(std)operator(::)pre_type(string) ident(first) operator(=) ident(a)operator(.)ident(substr)operator(()integer(0)operator(,)integer(1)operator(\);) -ident(std)operator(::)pre_type(string) ident(last) operator(=) ident(a)operator(.)ident(substr)operator(()ident(a)operator(.)ident(size)operator((\)-)integer(1)operator(\);) - -ident(a)operator(.)ident(replace)operator(()integer(0)operator(,)integer(1)operator(,) ident(last)operator(\);) -ident(a)operator(.)ident(replace)operator(()ident(a)operator(.)ident(size)operator((\)-)integer(1)operator(,) integer(1)operator(,) ident(first)operator(\);) - -comment(// exchange the first and last letters in a string using indexing and swap) -preprocessor(#include) include(<algorithm>) -ident(std)operator(::)ident(swap)operator(()ident(a)operator([)integer(0)operator(],) ident(a)operator([)ident(a)operator(.)ident(size)operator((\)-)integer(1)operator(]\);) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.2) -comment(//-----------------------------) -comment(// C++ doesn't have functionality equivalent to the || and ||=. ) -comment(// If statements and trigraphs can be used instead.) -comment(//-----------------------------) -comment(// C++ doesn't have anything equivalent "defined". C++ variables) -comment(// cannot be used at all if they have not previously been defined.) - -comment(//-----------------------------) -comment(// Use b if b is not empty, else c) -ident(a) operator(=) ident(b)operator(.)ident(size)operator((\)) operator(?) ident(b) operator(:) ident(c)operator(;) - -comment(// Set x to y unless x is not empty) -reserved(if) operator(()ident(x)operator(.)ident(is_empty)operator((\)\)) ident(x) operator(=) ident(y)operator(;) - -comment(//-----------------------------) -ident(foo) operator(=) operator((!)ident(bar)operator(.)ident(is_empty)operator((\)\)) operator(?) ident(bar) operator(:) string<delimiter(")content(DEFAULT VALUE)delimiter(")>operator(;) - -comment(//-----------------------------) -comment(// NOTE: argv is declared as char *argv[] in C/C++. We assume) -comment(// the following code surrounds the following examples that deal) -comment(// with argv. Also, arguments to a program start at argv[1] -- argv[0]) -comment(// is the name of the executable that's running.) -preprocessor(#include) include(<string.h>) -pre_type(int) ident(main)operator(()pre_type(int) ident(argc)operator(,) pre_type(char) operator(*)ident(argv)operator([]\)) operator({) - pre_type(char) operator(**)ident(args) operator(=) ident(argv)operator(+)integer(1)operator(;) comment(// +1 skips argv[0], the name of the executable) - comment(// examples) -operator(}) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(dir) operator(=) operator((*)ident(args)operator(\)) operator(?) operator(*)ident(argv)operator(++) operator(:) string<delimiter(")content(/tmp)delimiter(")>operator(;) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(dir) operator(=) ident(argv)operator([)integer(1)operator(]) operator(?) ident(argv)operator([)integer(1)operator(]) operator(:) string<delimiter(")content(/tmp)delimiter(")>operator(;) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(dir) operator(=) operator(()ident(argc)operator(-)integer(1)operator(\)) operator(?) ident(argv)operator([)integer(1)operator(]) operator(:) string<delimiter(")content(/tmp)delimiter(")>operator(;) - -comment(//-----------------------------) -preprocessor(#include) include(<map>) -ident(std)operator(::)ident(map)operator(<)ident(std)operator(::)pre_type(string)operator(,)pre_type(int)operator(>) ident(count)operator(;) - -ident(count)operator([)ident(shell)operator(.)ident(size)operator((\)) operator(?) ident(shell) operator(:) string<delimiter(")content(/bin/sh)delimiter(")>operator(]++;) - -comment(//-----------------------------) -comment(// find the user name on Unix systems) -comment(// TODO: Simplify. This is too ugly and complex) -preprocessor(#include) include(<sys/types.h>) -preprocessor(#include) include(<unistd.h>) -preprocessor(#include) include(<pwd.h>) -preprocessor(#include) include("boost/lexical_cast.hpp") - -ident(std)operator(::)pre_type(string) ident(user)operator(;) -pre_type(char) operator(*)ident(msg) operator(=) integer(0)operator(;) -ident(passwd) operator(*)ident(pwd) operator(=) integer(0)operator(;) - -reserved(if) operator(() operator(()ident(msg) operator(=) ident(getenv)operator(()string<delimiter(")content(USER)delimiter(")>operator(\)\)) operator(||) - operator(()ident(msg) operator(=) ident(getenv)operator(()string<delimiter(")content(LOGNAME)delimiter(")>operator(\)\)) operator(||) - operator(()ident(msg) operator(=) ident(getlogin)operator((\)\)) operator(\)) - ident(user) operator(=) ident(msg)operator(;) -reserved(else) reserved(if) operator(()ident(pwd) operator(=) ident(getpwuid)operator(()ident(getuid)operator((\)\)\)) - ident(user) operator(=) ident(pwd)operator(->)ident(pw_name)operator(;) -reserved(else) - ident(user) operator(=) string<delimiter(")content(Unknown uid number )delimiter(")> operator(+) ident(boost)operator(::)ident(lexical_cast)operator(<)ident(std)operator(::)pre_type(string)operator(>()ident(getuid)operator((\)\);) - -comment(//-----------------------------) -reserved(if) operator(()ident(starting_point)operator(.)ident(is_empty)operator((\)\)) ident(starting_point) operator(=) string<delimiter(")content(Greenwich)delimiter(")>operator(;) - -comment(//-----------------------------) -comment(// Example using list. Other C++ STL containers work similarly.) -preprocessor(#include) include(<list>) -ident(list)operator(<)pre_type(int)operator(>) ident(a)operator(,) ident(b)operator(;) -reserved(if) operator(()ident(a)operator(.)ident(is_empty)operator((\)\)) ident(a) operator(=) ident(b)operator(;) comment(// copy only if a is empty) -ident(a) operator(=) operator((!)ident(b)operator(.)ident(is_empty)operator((\)\)) operator(?) ident(b) operator(:) ident(c)operator(;) comment(// asign b if b nonempty, else c) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.3) -comment(//-----------------------------) -preprocessor(#include) include(<algorithm>) -ident(std)operator(::)ident(swap)operator(()ident(a)operator(,) ident(b)operator(\);) - -comment(//-----------------------------) -ident(temp) operator(=) ident(a)operator(;) -ident(a) operator(=) ident(b)operator(;) -ident(b) operator(=) ident(temp)operator(;) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(a)operator(()string<delimiter(")content(alpha)delimiter(")>operator(\);) -ident(std)operator(::)pre_type(string) ident(b)operator(()string<delimiter(")content(omega)delimiter(")>operator(\);) -ident(std)operator(::)ident(swap)operator(()ident(a)operator(,)ident(b)operator(\);) - -comment(//-----------------------------) -comment(// The ability to exchange more than two variables at once is not ) -comment(// built into the C++ language or C++ standard libraries. However, you) -comment(// can use the boost tuple library to accomplish this.) -preprocessor(#include) include(<boost/tuple/tuple.hpp>) - -ident(boost)operator(::)ident(tie)operator(()ident(alpha)operator(,)ident(beta)operator(,)ident(production)operator(\)) - operator(=) ident(boost)operator(::)ident(make_tuple)operator(()string<delimiter(")content(January)delimiter(")>operator(,) string<delimiter(")content(March)delimiter(")>operator(,) string<delimiter(")content(August)delimiter(")>operator(\);) -comment(// move beta to alpha,) -comment(// move production to beta,) -comment(// move alpha to production) -ident(boost)operator(::)ident(tie)operator(()ident(alpha)operator(,) ident(beta)operator(,) ident(production)operator(\)) - operator(=) ident(boost)operator(::)ident(make_tuple)operator(()ident(beta)operator(,) ident(production)operator(,) ident(alpha)operator(\);) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.4) -comment(//-----------------------------) -comment(// There are several ways to convert between characters) -comment(// and integers. The examples assume the following declarations:) -pre_type(char) ident(ch)operator(;) -pre_type(int) ident(num)operator(;) - -comment(//-----------------------------) -comment(// Using implicit conversion) -ident(num) operator(=) ident(ch)operator(;) -ident(ch) operator(=) ident(num)operator(;) - -comment(//-----------------------------) -comment(// New-style C++ casts) -ident(ch) operator(=) reserved(static_cast)operator(<)pre_type(char)operator(>()ident(num)operator(\);) -ident(num) operator(=) reserved(static_cast)operator(<)pre_type(int)operator(>()ident(ch)operator(\);) - -comment(//-----------------------------) -comment(// Old-style C casts) -ident(ch) operator(=) operator(()pre_type(char)operator(\))ident(num)operator(;) -ident(num) operator(=) operator(()pre_type(int)operator(\))ident(ch)operator(;) - -comment(//-----------------------------) -comment(// Using the C++ stringstream class) -preprocessor(#include) include(<sstream>) comment(// On some older compilers, use <strstream>) -ident(std)operator(::)ident(stringstream) ident(a)operator(;) comment(// On some older compilers, use std::strstream) - -ident(a) operator(<<) ident(ch)operator(;) comment(// Append character to a string) -ident(a) operator(>>) ident(num)operator(;) comment(// Output character as a number) - -ident(a) operator(<<) ident(num)operator(;) comment(// Append number to a string) -ident(a) operator(>>) ident(ch)operator(;) comment(// Output number as a character) - -comment(//-----------------------------) -comment(// Using sprintf, printf) -pre_type(char) ident(str)operator([)integer(2)operator(];) comment(// Has to be length 2 to have room for NULL character) -ident(sprintf)operator(()ident(str)operator(,) string<delimiter(")content(%c)delimiter(")>operator(,) ident(num)operator(\);) -ident(printf)operator(()string<delimiter(")content(Number %d is character %c)char(\\n)delimiter(")>operator(,) ident(num)operator(,) ident(num)operator(\);) - -comment(//-----------------------------) -pre_type(int) ident(ascii_value) operator(=) char('e')operator(;) comment(// now 101) -pre_type(char) ident(character) operator(=) integer(101)operator(;) comment(// now 'e') - -comment(//-----------------------------) -ident(printf)operator(()string<delimiter(")content(Number %d is character %c)char(\\n)delimiter(")>operator(,) integer(101)operator(,) integer(101)operator(\);) - -comment(//-----------------------------) -comment(// Convert from HAL to IBM, character by character) -preprocessor(#include) include(<string>) -preprocessor(#include) include(<iostream>) - -ident(std)operator(::)pre_type(string) ident(ibm)operator(,) ident(hal) operator(=) string<delimiter(")content(HAL)delimiter(")>operator(;) -reserved(for) operator(()pre_type(unsigned) pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i)operator(<)ident(hal)operator(.)ident(size)operator((\);) operator(++)ident(i)operator(\)) - ident(ibm) operator(+=) ident(hal)operator([)ident(i)operator(]+)integer(1)operator(;) comment(// Add one to each ascii value) -ident(std)operator(::)ident(cout) operator(<<) ident(ibm) operator(<<) ident(std)operator(::)ident(endl)operator(;) comment(// prints "IBM") - -comment(//-----------------------------) -comment(// Convert hal from HAL to IBM) -preprocessor(#include) include(<string>) -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<functional>) comment(// For bind1st and plus<>) -preprocessor(#include) include(<algorithm>) comment(// For transform ) - -ident(std)operator(::)pre_type(string) ident(hal) operator(=) string<delimiter(")content(HAL)delimiter(")>operator(;) -ident(transform)operator(()ident(hal)operator(.)ident(begin)operator((\),) ident(hal)operator(.)ident(end)operator((\),) ident(hal)operator(.)ident(begin)operator((\),) - ident(bind1st)operator(()ident(plus)operator(<)pre_type(char)operator(>(\),)integer(1)operator(\)\);) -ident(std)operator(::)ident(cout) operator(<<) ident(hal) operator(<<) ident(std)operator(::)ident(endl)operator(;) comment(// prints "IBM") -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.5) -comment(//-----------------------------) -comment(// Since C++ strings can be accessed one character at a time,) -comment(// there's no need to do any processing on the string to convert) -comment(// it into an array of characters. ) -preprocessor(#include) include(<string>) -ident(std)operator(::)pre_type(string) ident(s)operator(;) - -comment(// Accessing characters using for loop and integer offsets) -reserved(for) operator(()pre_type(unsigned) pre_type(int) ident(i)operator(=)integer(0)operator(;) ident(i)operator(<)ident(s)operator(.)ident(size)operator((\);) operator(++)ident(i)operator(\)) operator({) - comment(// do something with s[i]) -operator(}) - -comment(// Accessing characters using iterators) -reserved(for) operator(()ident(std)operator(::)pre_type(string)operator(::)ident(iterator) ident(i)operator(=)ident(s)operator(.)ident(begin)operator((\);) ident(i)operator(!=)ident(s)operator(.)ident(end)operator((\);) operator(++)ident(i)operator(\)) operator({) - comment(// do something with *i) -operator(}) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(str) operator(=) string<delimiter(")content(an apple a day)delimiter(")>operator(;) -ident(std)operator(::)ident(map)operator(<)pre_type(char)operator(,)pre_type(int)operator(>) ident(seen)operator(;) - -reserved(for) operator(()ident(std)operator(::)pre_type(string)operator(::)ident(iterator) ident(i)operator(=)ident(str)operator(.)ident(begin)operator((\);) ident(i)operator(!=)ident(str)operator(.)ident(end)operator((\);) operator(++)ident(i)operator(\)) - ident(seen)operator([*)ident(i)operator(]++;) - -ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(unique chars are: )delimiter(")>operator(;) -reserved(for) operator(()ident(std)operator(::)ident(map)operator(<)pre_type(char)operator(,)pre_type(int)operator(>::)ident(iterator) ident(i)operator(=)ident(seen)operator(.)ident(begin)operator((\);) ident(i)operator(!=)ident(seen)operator(.)ident(end)operator((\);) operator(++)ident(i)operator(\)) - ident(std)operator(::)ident(cout) operator(<<) ident(i)operator(->)ident(first)operator(;) -ident(std)operator(::)ident(cout) operator(<<) ident(std)operator(::)ident(endl)operator(;) -comment(// unique chars are: adelnpy) - -comment(//-----------------------------) -pre_type(int) ident(sum) operator(=) integer(0)operator(;) -reserved(for) operator(()ident(std)operator(::)pre_type(string)operator(::)ident(iterator) ident(i)operator(=)ident(str)operator(.)ident(begin)operator((\);) ident(i)operator(!=)ident(str)operator(.)ident(end)operator((\);) operator(++)ident(i)operator(\)) - ident(sum) operator(+=) operator(*)ident(i)operator(;) -ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(sum is )delimiter(")> operator(<<) ident(sum) operator(<<) ident(std)operator(::)ident(endl)operator(;) -comment(// prints "sum is 1248" if str was "an appla a day") - - -comment(//-----------------------------) -comment(// MISSING: sysv-like checksum program) - -comment(//-----------------------------) -comment(// slowcat, emulate a slow line printer) -preprocessor(#include) include(<sys/time.h>) -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<fstream>) - -pre_type(int) ident(main)operator(()pre_type(int) ident(argc)operator(,) pre_type(char) operator(*)ident(argv)operator([]\)) operator({) - ident(timeval) ident(delay) operator(=) operator({) integer(0)operator(,) integer(50000) operator(};) comment(// Delay in { seconds, nanoseconds }) - pre_type(char) operator(**)ident(arg) operator(=) ident(argv)operator(+)integer(1)operator(;) - reserved(while) operator((*)ident(arg)operator(\)) operator({) comment(// For each file) - ident(std)operator(::)ident(ifstream) ident(file)operator((*)ident(arg)operator(++\);) - pre_type(char) ident(c)operator(;) - reserved(while) operator(()ident(file)operator(.)ident(get)operator(()ident(c)operator(\)\)) operator({) - ident(std)operator(::)ident(cout)operator(.)ident(put)operator(()ident(c)operator(\);) - ident(std)operator(::)ident(cout)operator(.)ident(flush)operator((\);) - ident(select)operator(()integer(0)operator(,) integer(0)operator(,) integer(0)operator(,) integer(0)operator(,) operator(&)ident(delay)operator(\);) - operator(}) - operator(}) -operator(}) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.6) -comment(//-----------------------------) -preprocessor(#include) include(<string>) -preprocessor(#include) include(<algorithm>) comment(// For reverse) -ident(std)operator(::)pre_type(string) ident(s)operator(;) - -ident(reverse)operator(()ident(s)operator(.)ident(begin)operator((\),) ident(s)operator(.)ident(end)operator((\)\);) - -comment(//-----------------------------) -preprocessor(#include) include(<vector>) comment(// For std::vector) -preprocessor(#include) include(<sstream>) comment(// On older compilers, use <strstream>) -preprocessor(#include) include("boost/regex.hpp") comment(// For boost::regex_split) - -ident(std)operator(::)pre_type(string) ident(str)operator(;) -ident(std)operator(::)ident(vector)operator(<)ident(std)operator(::)pre_type(string)operator(>) ident(words)operator(;) -ident(boost)operator(::)ident(regex_split)operator(()ident(std)operator(::)ident(back_inserter)operator(()ident(words)operator(\),) ident(str)operator(\);) -ident(reverse)operator(()ident(words)operator(.)ident(begin)operator((\),) ident(words)operator(.)ident(end)operator((\)\);) comment(// Reverse the order of the words) - -ident(std)operator(::)ident(stringstream) ident(revwords)operator(;) comment(// On older compilers, use strstream) -ident(copy)operator(()ident(words)operator(.)ident(begin)operator((\),) ident(words)operator(.)ident(end)operator((\),) ident(ostream_inserter)operator(<)pre_type(string)operator(>()ident(revwords)operator(,)string<delimiter(")content( )delimiter(")>operator(\);) -ident(std)operator(::)ident(cout) operator(<<) ident(revwards)operator(.)ident(str)operator((\)) operator(<<) ident(std)operator(::)ident(endl)operator(;) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(rts) operator(=) ident(str)operator(;) -ident(reverse)operator(()ident(rts)operator(.)ident(begin)operator((\),) ident(rts)operator(.)ident(end)operator((\)\);) comment(// Reverses letters in rts) - -comment(//-----------------------------) -ident(std)operator(::)ident(vector)operator(<)pre_type(string)operator(>) ident(words)operator(;) -ident(reverse)operator(()ident(words)operator(.)ident(begin)operator((\),) ident(words)operator(.)ident(end)operator((\)\);) comment(// Reverses words in container) - -comment(//-----------------------------) -comment(// Reverse word order) -ident(std)operator(::)pre_type(string) ident(s) operator(=) string<delimiter(")content(Yoda said, 'can you see this?')delimiter(")>operator(;) - -ident(std)operator(::)ident(vector)operator(<)ident(std)operator(::)pre_type(string)operator(>) ident(allwords)operator(;) -ident(boost)operator(::)ident(regex_split)operator(()ident(std)operator(::)ident(back_inserter)operator(()ident(allwords)operator(\),) ident(s)operator(\);) - -ident(reverse)operator(()ident(allwords)operator(.)ident(begin)operator((\),) ident(allwords)operator(.)ident(end)operator((\)\);) - -ident(std)operator(::)ident(stringstream) ident(revwords)operator(;) comment(// On older compilers, use strstream) -ident(copy)operator(()ident(allwords)operator(.)ident(begin)operator((\),) ident(allwords)operator(.)ident(end)operator((\),) ident(ostream_inserter)operator(<)pre_type(string)operator(>()ident(revwords)operator(,)string<delimiter(")content( )delimiter(")>operator(\)\);) -ident(std)operator(::)ident(cout) operator(<<) ident(revwards)operator(.)ident(str)operator((\)) operator(<<) ident(std)operator(::)ident(endl)operator(;) -comment(// this?' see you 'can said, Yoda) - -comment(//-----------------------------) -ident(std)operator(::)pre_type(string) ident(word) operator(=) string<delimiter(")content(reviver)delimiter(")>operator(;) -pre_type(bool) ident(is_palindrome) operator(=) ident(equal)operator(()ident(word)operator(.)ident(begin)operator((\),) ident(word)operator(.)ident(end)operator((\),) ident(word)operator(.)ident(rbegin)operator((\)\);) - -comment(//-----------------------------) -preprocessor(#include) include(<ifstream>) - -ident(std)operator(::)ident(ifstream) ident(dict)operator(()string<delimiter(")content(/usr/dict/words)delimiter(")>operator(\);) -ident(std)operator(::)pre_type(string) ident(word)operator(;) -reserved(while)operator(()ident(getline)operator(()ident(dict)operator(,)ident(word)operator(\)\)) operator({) - reserved(if) operator(()ident(equal)operator(()ident(word)operator(.)ident(begin)operator((\),) ident(word)operator(.)ident(end)operator((\),) ident(word)operator(.)ident(rbegin)operator((\)\)) operator(&&) - ident(word)operator(.)ident(size)operator((\)) operator(>) integer(5)operator(\)) - ident(std)operator(::)ident(cout) operator(<<) ident(word) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.7) -comment(//-----------------------------) -preprocessor(#include) include(<string>) - -ident(std)operator(::)pre_type(string)operator(::)ident(size_type) ident(pos)operator(;) -reserved(while) operator((()ident(pos) operator(=) ident(str)operator(.)ident(find)operator(()string<delimiter(")char(\\t)delimiter(")>operator(\)\)) operator(!=) ident(std)operator(::)pre_type(string)operator(::)ident(npos)operator(\)) - ident(str)operator(.)ident(replace)operator(()ident(pos)operator(,) integer(1)operator(,) pre_type(string)operator(()char(' ')operator(,)integer(8)operator(-)ident(pos)operator(%)integer(8)operator(\)\);) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.8) -comment(//-----------------------------) -comment(// Not applicable to C++) -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.9) -comment(//-----------------------------) -comment(// TODO: Fix to be more like cookbook) -comment(// TODO: Modify/add code to do this with locales) -preprocessor(#include) include(<string>) -preprocessor(#include) include(<algorithm>) - -ident(std)operator(::)pre_type(string) ident(phrase) operator(=) string<delimiter(")content(bo peep)delimiter(")>operator(;) -ident(transform)operator(()ident(phrase)operator(.)ident(begin)operator((\),) ident(phrase)operator(.)ident(end)operator((\),) ident(phrase)operator(.)ident(begin)operator((\),) ident(toupper)operator(\);) -comment(// "BO PEEP") -ident(transform)operator(()ident(phrase)operator(.)ident(begin)operator((\),) ident(phrase)operator(.)ident(end)operator((\),) ident(phrase)operator(.)ident(begin)operator((\),) ident(tolower)operator(\);) -comment(// "bo peep") -comment(//-----------------------------) - - -comment(// @@PLEAC@@_1.10) -comment(//-----------------------------) -comment(// C++ does not provide support for perl-like in-string interpolation,) -comment(// concatenation must be used instead.) - -preprocessor(#include) include(<string>) - -ident(std)operator(::)pre_type(string) ident(var1)operator(,) ident(var2)operator(;) -ident(std)operator(::)pre_type(string) ident(answer) operator(=) ident(var1) operator(+) ident(func)operator((\)) operator(+) ident(var2)operator(;) comment(// func returns string or char *) - -comment(//-----------------------------) -preprocessor(#include) include("boost/lexical_cast.hpp") - -pre_type(int) ident(n) operator(=) integer(4)operator(;) -ident(std)operator(::)pre_type(string) ident(phrase) operator(=) string<delimiter(")content(I have )delimiter(")> operator(+) ident(boost)operator(::)ident(lexical_cast)operator(<)pre_type(string)operator(>()ident(n)operator(+)integer(1)operator(\)) operator(+) string<delimiter(")content( guanacos.)delimiter(")>operator(;) - -comment(//-----------------------------) -ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(I have )delimiter(")> operator(+) ident(boost)operator(::)ident(lexical_cast)operator(<)pre_type(string)operator(>()ident(n)operator(+)integer(1)operator(\)) operator(+) string<delimiter(")content( guanacos.)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) - - -comment(// @@PLEAC@@_1.11) -comment(//-----------------------------) -comment(// C++ does not have "here documents".) -comment(// TODO: Lots more.) -preprocessor(#include) include(<string>) -preprocessor(#include) include("boost/regex.hpp") - -ident(std)operator(::)pre_type(string) ident(var) operator(=) string<delimiter(")content( - your text - goes here. -)delimiter(")>operator(;) - -ident(boost)operator(::)ident(regex) ident(ex)operator(()string<delimiter(")content(^)char(\\\\)content(s+)delimiter(")>operator(\);) -ident(var) operator(=) ident(boost)operator(::)ident(regex_merge)operator(()ident(var)operator(,) ident(ex)operator(,) string<delimiter(")delimiter(")>operator(\);) - -comment(// @@PLEAC@@_10.0) -comment(// NOTE: Whilst it is perfectly valid to use Standard C Library, or GNU C Library, routines in) -comment(// C++ programs, the code examples here will, as far as possible, avoid doing so, instead using) -comment(// C++-specific functionality and idioms. In general:) -comment(// * I/O will be iostream-based [i.e. no 'scanf', 'printf', 'fgets' etc]) -comment(// * Container / iterator idioms based on the Standard Template Library [STL]) -comment(// will replace the built-in array / raw pointer idioms typically used in C) -comment(// * Boost Library functionality utilised wherever possible [the reason for) -comment(// this is that much of this functionality is likely to appear in the next) -comment(// C++ standard]) -comment(// * Error detection/handling will generally be exception-based [this is done) -comment(// to keep examples simple. Exception use is optional in C++, and is not as) -comment(// pervasive as it is in other languages like Java or C#]) -comment(// C-based solution(s\) to problem(s\) will be found in the corresponding section of PLEAC-C/Posix/GNU.) - -preprocessor(#include) include(<iostream>) - -comment(// 'greeted' defined outside of any namespace, class or function, so is part of the) -comment(// global namespace, and will be visible throughout the entire executable. Should it) -comment(// be necessary to restrict the visibility of this global identifier to the current) -comment(// 'compilation unit' [i.e. current source file] then the following may be used:) -comment(//) -comment(// namespace { int greeted = 0; }) -comment(//) -comment(// The effect is similar to using the 'static' keyword, in this same context, in the C) -comment(// language.) - -pre_type(int) ident(greeted) operator(=) integer(0)operator(;) - -pre_type(int) ident(howManyGreetings)operator((\);) -directive(void) ident(hello)operator((\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - ident(hello)operator((\);) - - pre_type(int) ident(greetings) operator(=) ident(howManyGreetings)operator((\);) - - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(bye there!, there have been )delimiter(")> - operator(<<) ident(greetings) - operator(<<) string<delimiter(")content( greetings so far)delimiter(")> - operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ----) - -pre_type(int) ident(howManyGreetings)operator((\)) -operator({) - comment(// Access 'greeted' identifier in the global namespace using the scope resolution) - comment(// operator. Use of this operator is only necessary if a similarly-named identifier) - comment(// exists in a ) - reserved(return) operator(::)ident(greeted)operator(;) -operator(}) - -directive(void) ident(hello)operator((\)) -operator({) - comment(// Here 'greeted' is accessed without additional qualification. Since a 'greeted' identifier) - comment(// exists only in the global namespace, it is that identifier that is used) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(high there!, this function has been called )delimiter(")> - operator(<<) operator(++)ident(greeted) - operator(<<) string<delimiter(")content( times)delimiter(")> - operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// @@PLEAC@@_10.1) -comment(// Standard C++ requires that a function be prototyped, hence the name and type of parameters) -comment(// must be specified, and the argumemt list in any calls to that function must match the) -comment(// parameter list, as shown here ) - -preprocessor(#include) include(<cmath>) - -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) pre_type(double) ident(side2)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - pre_type(double) ident(diag) operator(=) ident(hypotenuse)operator(()float(3)float(.0)operator(,) float(4)float(.0)operator(\);) -operator(}) - -comment(// ----) - -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) pre_type(double) ident(side2)operator(\)) -operator({) - reserved(return) ident(std)operator(::)ident(sqrt)operator(()ident(std)operator(::)ident(pow)operator(()ident(side1)operator(,) float(2)float(.0)operator(\)) operator(+) ident(std)operator(::)ident(pow)operator(()ident(side2)operator(,) float(2)float(.0)operator(\)\);) -operator(}) - -comment(// ----------------------------) - -comment(// Variable length argument list functions, via the C Language derived 'va_...' macros,) -comment(// are also supported. However use of this facility is particularly discouraged in C++) -comment(// because:) -comment(// * It is an inherently type-unsafe facility; type safety is a core C++ concern) -comment(// * Other facilities, such as overloaded functions, and default arguments [neither of which) -comment(// are available in C] can sometimes obviate the need for variable length argument lists) -comment(// * OOP techniques can also lessen the need for variable length argument lists. The most) -comment(// obvious example here is the Iostream library where repeated calls of I/O operators replace) -comment(// the format string / variable arguments of 'printf') - -preprocessor(#include) include(<cmath>) -preprocessor(#include) include(<cstdarg>) - -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) operator(.)operator(.)operator(.)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - pre_type(double) ident(diag) operator(=) ident(hypotenuse)operator(()float(3)float(.0)operator(,) float(4)float(.0)operator(\);) -operator(}) - -comment(// ----) - -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) operator(.)operator(.)operator(.)operator(\)) -operator({) - comment(// More details available in the corresponding section of PLEAC-C/Posix/GNU) - ident(va_list) ident(ap)operator(;) - ident(va_start)operator(()ident(ap)operator(,) ident(side1)operator(\);) - pre_type(double) ident(side2) operator(=) ident(va_arg)operator(()ident(ap)operator(,) pre_type(double)operator(\);) - ident(va_end)operator(()ident(ap)operator(\);) - - reserved(return) ident(std)operator(::)ident(sqrt)operator(()ident(std)operator(::)ident(pow)operator(()ident(side1)operator(,) float(2)float(.0)operator(\)) operator(+) ident(std)operator(::)ident(pow)operator(()ident(side2)operator(,) float(2)float(.0)operator(\)\);) -operator(}) - -comment(// ----------------------------) - -comment(// An example using default arguments appears below) - -preprocessor(#include) include(<cmath>) - -comment(// Specify default argument values in declaration) -comment(// Note: This may be done in either of the declaration or the definition [not both], but it) -comment(// makes more sense to do so in the declaration since these are usually placed in header files) -comment(// which may be included in several source files. The default argument values would need to be) -comment(// known in all those locations) -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1) operator(=) float(3)float(.0)operator(,) pre_type(double) ident(side2) operator(=) float(4)float(.0)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// All arguments specified) - pre_type(double) ident(diag) operator(=) ident(hypotenuse)operator(()float(3)float(.0)operator(,) float(4)float(.0)operator(\);) - - comment(// Both calls utilise default argument value(s\)) - ident(diag) operator(=) ident(hypotenuse)operator(()float(3)float(.0)operator(\);) - - ident(diag) operator(=) ident(hypotenuse)operator((\);) -operator(}) - -comment(// ----) - -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) pre_type(double) ident(side2)operator(\)) -operator({) - reserved(return) ident(std)operator(::)ident(sqrt)operator(()ident(std)operator(::)ident(pow)operator(()ident(side1)operator(,) float(2)float(.0)operator(\)) operator(+) ident(std)operator(::)ident(pow)operator(()ident(side2)operator(,) float(2)float(.0)operator(\)\);) -operator(}) - -comment(// ----------------------------) - -comment(// A [very contrived, not very practical] example using function overloading appears below) - -preprocessor(#include) include(<cmath>) - -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) pre_type(double) ident(side2)operator(\);) -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(\);) -pre_type(double) ident(hypotenuse)operator((\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Call version (1\)) - pre_type(double) ident(diag) operator(=) ident(hypotenuse)operator(()float(3)float(.0)operator(,) float(4)float(.0)operator(\);) - - comment(// Call version (2\)) - ident(diag) operator(=) ident(hypotenuse)operator(()float(3)float(.0)operator(\);) - - comment(// Call version (3\)) - ident(diag) operator(=) ident(hypotenuse)operator((\);) -operator(}) - -comment(// ----) - -comment(// (1\)) -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(,) pre_type(double) ident(side2)operator(\)) -operator({) - reserved(return) ident(std)operator(::)ident(sqrt)operator(()ident(std)operator(::)ident(pow)operator(()ident(side1)operator(,) float(2)float(.0)operator(\)) operator(+) ident(std)operator(::)ident(pow)operator(()ident(side2)operator(,) float(2)float(.0)operator(\)\);) -operator(}) - -comment(// (2\)) -pre_type(double) ident(hypotenuse)operator(()pre_type(double) ident(side1)operator(\)) -operator({) - reserved(return) ident(std)operator(::)ident(sqrt)operator(()ident(std)operator(::)ident(pow)operator(()ident(side1)operator(,) float(2)float(.0)operator(\)) operator(+) ident(std)operator(::)ident(pow)operator(()float(4)float(.0)operator(,) float(2)float(.0)operator(\)\);) -operator(}) - -comment(// (3\)) -pre_type(double) ident(hypotenuse)operator((\)) -operator({) - reserved(return) ident(std)operator(::)ident(sqrt)operator(()ident(std)operator(::)ident(pow)operator(()float(3)float(.0)operator(,) float(2)float(.0)operator(\)) operator(+) ident(std)operator(::)ident(pow)operator(()float(4)float(.0)operator(,) float(2)float(.0)operator(\)\);) -operator(}) - -comment(// ----------------------------) - -preprocessor(#include) include(<cstddef>) -preprocessor(#include) include(<vector>) - -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(int_all)operator(()directive(const) pre_type(double) ident(arr)operator([],) ident(size_t) ident(arrsize)operator(\);) -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(int_all)operator(()directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(double)operator(>&) ident(arr)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Load vectors from built-in arrays, or use Boost 'assign' library) - directive(const) pre_type(double) ident(nums)operator([]) operator(=) operator({)float(1)float(.4)operator(,) float(3)float(.5)operator(,) float(6)float(.7)operator(};) - directive(const) ident(size_t) ident(arrsize) operator(=) reserved(sizeof)operator(()ident(nums)operator(\)) operator(/) reserved(sizeof)operator(()ident(nums)operator([)integer(0)operator(]\);) - - comment(// Conversion effected at vector creation time) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(ints) operator(=) ident(int_all)operator(()ident(nums)operator(,) ident(arrsize)operator(\);) - - comment(// Vector -> vector copy / conversion ) - ident(ints) operator(=) ident(int_all)operator(()ident(std)operator(::)ident(vector)operator(<)pre_type(double)operator(>()ident(nums)operator(,) ident(nums) operator(+) ident(arrsize)operator(\)\);) -operator(}) - -comment(// ----) - -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(int_all)operator(()directive(const) pre_type(double) ident(arr)operator([],) ident(size_t) ident(arrsize)operator(\)) -operator({) - reserved(return) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>()ident(arr)operator(,) ident(arr) operator(+) ident(arrsize)operator(\);) -operator(}) - -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(int_all)operator(()directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(double)operator(>&) ident(arr)operator(\)) -operator({) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(r)operator(;) - ident(r)operator(.)ident(assign)operator(()ident(arr)operator(.)ident(begin)operator((\),) ident(arr)operator(.)ident(end)operator((\)\);) comment(// Type safe element copying ) - reserved(return) ident(r)operator(;) -operator(}) - -comment(// ----------------------------) - -preprocessor(#include) include(<algorithm>) -preprocessor(#include) include(<vector>) - -preprocessor(#include) include(<cmath>) -preprocessor(#include) include(<cstddef>) - -directive(void) ident(trunc_em)operator(()ident(std)operator(::)ident(vector)operator(<)pre_type(double)operator(>&) ident(arr)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Load vectors from built-in arrays, or use Boost 'assign' library) - directive(const) pre_type(double) ident(nums)operator([]) operator(=) operator({)float(1)float(.4)operator(,) float(3)float(.5)operator(,) float(6)float(.7)operator(};) - directive(const) ident(size_t) ident(arrsize) operator(=) reserved(sizeof)operator(()ident(nums)operator(\)) operator(/) reserved(sizeof)operator(()ident(nums)operator([)integer(0)operator(]\);) - - ident(std)operator(::)ident(vector)operator(<)pre_type(double)operator(>) ident(numsv)operator(()ident(nums)operator(,) ident(nums) operator(+) ident(arrsize)operator(\);) - - ident(trunc_em)operator(()ident(numsv)operator(\);) -operator(}) - -comment(// ----) - -directive(void) ident(trunc_em)operator(()ident(std)operator(::)ident(vector)operator(<)pre_type(double)operator(>&) ident(arr)operator(\)) -operator({) - comment(// Replace each element with the value returned by applying 'floor' to that element) - ident(std)operator(::)ident(transform)operator(()ident(arr)operator(.)ident(begin)operator((\),) ident(arr)operator(.)ident(end)operator((\),) ident(arr)operator(.)ident(begin)operator((\),) ident(floor)operator(\);) -operator(}) - -comment(// @@PLEAC@@_10.2) -comment(// Variables declared within a function body are local to that function, and those declared) -comment(// outside a function body [and not as part of a class / struct definition, or enclosed within) -comment(// a namespace] are global, that is, are visible throughout the executable unless their) -comment(// visibility has been restricted to the source file in which they are defined via enclosing) -comment(// them within an anonymous namespace [which has the same effect as using the 'static' keyword,) -comment(// in this same context, in the C language]) - -preprocessor(#include) include(<vector>) - -directive(void) ident(somefunc)operator((\)) -operator({) - comment(// All these variables are local to this function) - pre_type(int) ident(variable)operator(,) ident(another)operator(;) - - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(vec)operator(()integer(5)operator(\);) - - operator(;) comment(// ...) -operator(}) - -comment(// ----------------------------) - -comment(// A couple of generic, type-safe type conversion helpers. The Boost Library sports a conversion) -comment(// library at: http://www.boost.org/libs/conversion/index.html) - -preprocessor(#include) include(<sstream>) -preprocessor(#include) include(<string>) - -reserved(class) class(bad_conversion) operator({};) - -reserved(template)operator(<)reserved(typename) ident(T)operator(>) ident(T) ident(fromString)operator(()directive(const) ident(std)operator(::)pre_type(string)operator(&) ident(s)operator(\)) -operator({) - ident(std)operator(::)ident(istringstream) ident(iss)operator(()ident(s)operator(\);) - ident(T) ident(t)operator(;) ident(iss) operator(>>) ident(t)operator(;) - reserved(if) operator((!)ident(iss)operator(\)) reserved(throw) ident(bad_conversion)operator((\);) - reserved(return) ident(t)operator(;) -operator(}) - -reserved(template)operator(<)reserved(typename) ident(T)operator(>) ident(std)operator(::)pre_type(string) ident(toString)operator(()directive(const) ident(T)operator(&) ident(t)operator(\)) -operator({) - ident(std)operator(::)ident(ostringstream) ident(oss)operator(;) - ident(oss) operator(<<) ident(t) operator(<<) ident(std)operator(::)ident(ends)operator(;) - reserved(if) operator((!)ident(oss)operator(\)) reserved(throw) ident(bad_conversion)operator((\);) - reserved(return) ident(std)operator(::)pre_type(string)operator(()ident(oss)operator(.)ident(str)operator((\)\);) -operator(}) - -comment(// ------------) - -preprocessor(#include) include(<string>) - -comment(// File scope variables) -reserved(namespace) -operator({) - ident(std)operator(::)pre_type(string) ident(name)operator(;) - pre_type(int) ident(age)operator(,) ident(c)operator(,) ident(condition)operator(;) -operator(}) - -directive(void) ident(run_check)operator((\);) -directive(void) ident(check_x)operator(()pre_type(int) ident(x)operator(\);) - -comment(// ----) - -comment(// An alternative, C++-specific approach, to command-line handling and type conversion) -comment(// may be seen at: http://www.boost.org/libs/conversion/lexical_cast.htm) - -pre_type(int) ident(main)operator(()pre_type(int) ident(argc)operator(,) pre_type(char)operator(*) ident(argv)operator([]\)) -operator({) - ident(name)operator(.)ident(assign)operator(()ident(argv)operator([)integer(1)operator(]\);) - - reserved(try) - operator({) - ident(age) operator(=) ident(fromString)operator(<)pre_type(int)operator(>()ident(argv)operator([)integer(2)operator(]\);) - operator(}) - - reserved(catch) operator(()directive(const) ident(bad_conversion)operator(&) ident(e)operator(\)) - operator({) - operator(;) comment(// ... handle conversion error ...) - operator(}) - - ident(check_x)operator(()ident(age)operator(\);) -operator(}) - -comment(// ------------) - -directive(void) ident(run_check)operator((\)) -operator({) - comment(// Full access to file scope variables) - ident(condition) operator(=) integer(1)operator(;) - comment(// ...) -operator(}) - -directive(void) ident(check_x)operator(()pre_type(int) ident(x)operator(\)) -operator({) - comment(// Full access to file scope variables) - ident(std)operator(::)pre_type(string) ident(y)operator(()string<delimiter(")content(whatever)delimiter(")>operator(\);) - - ident(run_check)operator((\);) - - comment(// 'condition' updated by 'run_check') - reserved(if) operator(()ident(condition)operator(\)) - operator({) - operator(;) comment(// ...) - operator(}) -operator(}) - -comment(// @@PLEAC@@_10.3) -comment(// Standard C++, owing to its C heritage, allows the creation of 'persistent private variables',) -comment(// via use of the 'static' keyword. For more details about this, and illustrative code examples,) -comment(// refer to this same section in PLEAC-C/Posix/GNU. Standard C++-specific methods of perfoming) -comment(// this task involve use of the 'namespace' facility, or creating a class containing 'static') -comment(// members and using access specifiers to restrict access) - -comment(// This example replaces the 'static' keyword with use of an anonymous namespace to force) -comment(// 'variable' to have file scope, and be visible only within the 'mysubs.cpp file. It is) -comment(// therefore both persistant [because it is a global variable] and private [because it is) -comment(// visible only to functions defined within the same source file]) - -comment(// File: 'mysubs.h') -directive(void) ident(mysub)operator(()directive(void)operator(\);) -directive(void) ident(reset)operator(()directive(void)operator(\);) - -comment(// ----) - -comment(// File: 'mysubs.cpp') -reserved(namespace) -operator({) - pre_type(int) ident(variable) operator(=) integer(1)operator(;) -operator(}) - -directive(void) ident(mysub)operator(()directive(void)operator(\)) -operator({) - operator(;) comment(// ... do something with 'variable' ...) -operator(}) - -directive(void) ident(reset)operator(()directive(void)operator(\)) operator({) ident(variable) operator(=) integer(1)operator(;) operator(}) - -comment(// ----) - -comment(// File: 'test.cpp') -preprocessor(#include) include("mysubs.h") - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// 'variable' is not accessable here) - - comment(// Call 'mysub', which can access 'variable') - ident(mysub)operator((\);) - - comment(// Call 'reset' which sets 'variable' to 1 ) - ident(reset)operator((\);) -operator(}) - -comment(// ------------) - -comment(// This example is similar to the previous one in using an anonymous namespace to restrict) -comment(// variable visibility. It goes further, hoewever, grouping logically related items within) -comment(// a named namespace, thus ensuring access to those items is controlled [i.e. requires) -comment(// qualification, or a 'using' declaration or directive]) - -comment(// File: 'counter.h') -reserved(namespace) ident(cnt) -operator({) - pre_type(int) ident(increment)operator((\);) - pre_type(int) ident(decrement)operator((\);) -operator(}) - -comment(// ----) - -comment(// File: 'counter.cpp') -reserved(namespace) ident(cnt) -operator({) - comment(// Ensures 'counter' is visible only within the current source file) - reserved(namespace) operator({) pre_type(int) ident(counter) operator(=) integer(0)operator(;) operator(}) - - directive(void) ident(reset)operator(()pre_type(int) ident(v) operator(=) integer(0)operator(\)) operator({) ident(counter) operator(=) ident(v)operator(;) operator(}) - - pre_type(int) ident(increment)operator((\)) operator({) reserved(return) operator(++)ident(counter)operator(;) operator(}) - pre_type(int) ident(decrement)operator((\)) operator({) reserved(return) operator(--)ident(counter)operator(;) operator(}) -operator(}) - -comment(// ----) - -comment(// File: 'test.cpp') -preprocessor(#include) include(<iostream>) -preprocessor(#include) include("counter.h") - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Following line is illegal because 'cnt::counter' is private to the 'counter.cpp' file) - comment(// int c = cnt::counter;) - - pre_type(int) ident(a) operator(=) ident(cnt)operator(::)ident(increment)operator((\);) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) ident(std)operator(::)ident(endl)operator(;) - - ident(a) operator(=) ident(cnt)operator(::)ident(decrement)operator((\);) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ------------) - -comment(// This example sees a class containing 'static' members and using access specifiers to) -comment(// restrict access to those members. Since all the members are static, this class is not) -comment(// meant to be instantiated [i.e. objects created from it - it can be done, but they would) -comment(// all be the exact same object :\)], but merely uses the 'class' facility to encapsulate) -comment(// [i.e. group together] and allow selective access [i.e. hide some parts, allow access to) -comment(// others]. For Design Pattern afficiandos, this is a crude example of the Singleton Pattern) - -comment(// File: 'counter.h') -reserved(class) class(Counter) -operator({) -directive(public)operator(:) - directive(static) pre_type(int) ident(increment)operator((\);) - directive(static) pre_type(int) ident(decrement)operator((\);) -directive(private)operator(:) - directive(static) pre_type(int) ident(counter)operator(;) -operator(};) - -comment(// ----) - -comment(// File: 'counter.cpp') -preprocessor(#include) include("counter.h") - -pre_type(int) ident(Counter)operator(::)ident(increment)operator((\)) operator({) reserved(return) operator(++)ident(counter)operator(;) operator(}) -pre_type(int) ident(Counter)operator(::)ident(decrement)operator((\)) operator({) reserved(return) operator(--)ident(counter)operator(;) operator(}) - -pre_type(int) ident(Counter)operator(::)ident(counter) operator(=) integer(0)operator(;) - -comment(// ----) - -comment(// File: 'test.cpp') -preprocessor(#include) include(<iostream>) -preprocessor(#include) include("counter.h") - -pre_type(int) ident(main)operator((\)) -operator({) - pre_type(int) ident(a) operator(=) ident(Counter)operator(::)ident(increment)operator((\);) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) ident(std)operator(::)ident(endl)operator(;) - - ident(a) operator(=) ident(Counter)operator(::)ident(decrement)operator((\);) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// @@PLEAC@@_10.4) -comment(// Standard C++ offers no facility for performing adhoc, runtime stack inspection; therefore,) -comment(// information such as the currently-executing function name, cannot be obtained. Now, this) -comment(// isn't to say that such facilities don't exist [since, after all, a symbolic debugger works) -comment(// by doing just this - stack inspection, among other things], but that such features are, for) -comment(// native code compiled languages like C++, 'extra-language' and development tool-specific) - -comment(// @@PLEAC@@_10.5) -comment(// Standard C++ supports both) -comment(// * 'pass-by-value': a copy of an argument is passed when calling a function; in this way) -comment(// the original is safe from modification, but a copying overhead is incurred which may) -comment(// adversely affect performance) -comment(// * 'pass-by-reference': the address of an argument is passed when calling a function;) -comment(// allows the original to be modified, and incurrs no performance penalty from copying) -comment(//) -comment(// The 'pass-by-value' mechanism works in the same way as in the Standard C language [see) -comment(// corresponding section in PLEAC-C/Posix/GNU]. The 'pass-by-reference' mechanism provides) -comment(// the same functionality as passing a pointer-to-a-pointer-to-an-argument, but without the) -comment(// complications arising from having to correctly dereference. Using a reference to a non-const) -comment(// item allows:) -comment(// * The item's state to be modified i.e. if an object was passed, it can be mutated [effect) -comment(// can be mimiced by passing a pointer to the item]) -comment(// * The item, itself, can be replaced with a new item i.e. the memory location to which the) -comment(// reference refers is updated [effect can be mimiced by passing a pointer-to-a-pointer to) -comment(// the item]) - -preprocessor(#include) include(<cstddef>) -preprocessor(#include) include(<vector>) - -comment(// 'pass-by-value': a copy of each vector is passed as an argument) -comment(// void array_diff(const std::vector<int> arr1, const std::vector<int> arr2\);) - -comment(// 'pass-by-reference': the address of each vector is passed as an argument. Some variants:) -comment(// * Disallow both vector replacement and alteration of its contents) -comment(// void array_diff(const std::vector<const int>& arr1, const std::vector<const int>& arr2\);) -comment(// * Disallow vector replacement only) -comment(// void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2\);) -comment(// * Disallow alteration of vector contents only) -comment(// void array_diff(std::vector<const int>& arr1, std::vector<const int>& arr2\);) -comment(// * Allow replacement / alteration) -comment(// void array_diff(std::vector<int>& arr1, std::vector<int>& arr2\);) - -directive(void) ident(array_diff)operator(()directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr1)operator(,) directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr2)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Load vectors from built-in arrays, or use Boost 'assign' library) - directive(const) pre_type(int) ident(arr1)operator([]) operator(=) operator({)integer(1)operator(,) integer(2)operator(,) integer(3)operator(},) ident(arr2)operator([]) operator(=) operator({)integer(4)operator(,) integer(5)operator(,) integer(6)operator(};) - directive(const) ident(size_t) ident(arrsize) operator(=) integer(3)operator(;) - - comment(// Function call is the same whether 'array_diff' is declared to be 'pass-by-value') - comment(// or 'pass-by-reference') - ident(array_diff)operator(()ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>()ident(arr1)operator(,) ident(arr1) operator(+) ident(arrsize)operator(\),) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>()ident(arr2)operator(,) ident(arr2) operator(+) ident(arrsize)operator(\)\);) -operator(}) - -comment(// ----) - -comment(// void array_diff(const std::vector<int> arr1, const std::vector<int> arr2\)) -comment(// {) -comment(// ; // 'arr1' and 'arr2' are copies of the originals) -comment(// }) - -directive(void) ident(array_diff)operator(()directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr1)operator(,) directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr2)operator(\)) -operator({) - operator(;) comment(// 'arr1' and 'arr2' are references to the originals) -operator(}) - -comment(// ----------------------------) - -preprocessor(#include) include(<cstddef>) - -preprocessor(#include) include(<algorithm>) -preprocessor(#include) include(<functional>) -preprocessor(#include) include(<vector>) - -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(add_vecpair)operator(()directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr1)operator(,) directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr2)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Load vectors from built-in arrays, or use Boost 'assign' library) - directive(const) pre_type(int) ident(aa)operator([]) operator(=) operator({)integer(1)operator(,) integer(2)operator(},) ident(ba)operator([]) operator(=) operator({)integer(5)operator(,) integer(8)operator(};) - ident(size_t) ident(arrsize) operator(=) integer(2)operator(;) - - directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(a)operator(()ident(aa)operator(,) ident(aa) operator(+) ident(arrsize)operator(\),) ident(b)operator(()ident(ba)operator(,) ident(ba) operator(+) ident(arrsize)operator(\);) - - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(c) operator(=) ident(add_vecpair)operator(()ident(a)operator(,) ident(b)operator(\);) -operator(}) - -comment(// ----) - -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(add_vecpair)operator(()directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr1)operator(,) directive(const) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>&) ident(arr2)operator(\)) -operator({) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(retvec)operator(;) ident(retvec)operator(.)ident(reserve)operator(()ident(arr1)operator(.)ident(size)operator((\)\);) - ident(std)operator(::)ident(transform)operator(()ident(arr1)operator(.)ident(begin)operator((\),) ident(arr1)operator(.)ident(end)operator((\),) ident(arr2)operator(.)ident(begin)operator((\),) ident(back_inserter)operator(()ident(retvec)operator(\),) ident(std)operator(::)ident(plus)operator(<)pre_type(int)operator(>(\)\);) - reserved(return) ident(retvec)operator(;) -operator(}) - -comment(// @@PLEAC@@_10.6) -comment(// Please refer to the corresponding section in PLEAC-C/Posix/GNU since the points raised there) -comment(// apply to C++ also. Examples here don't so much illustrate C++'s handling of 'return context') -comment(// as much as how disparate types might be handled in a reasonably uniform manner) - -comment(// Here, 'mysub' is implemented as a function template, and its return type varies with the) -comment(// argument type. In most cases the compiler is able to infer the return type from the ) -comment(// argument, however, it is possible to pass the type as a template parameter. Note this) -comment(// code operates at compile-time, as does any template-only code) - -preprocessor(#include) include(<cstddef>) - -preprocessor(#include) include(<string>) -preprocessor(#include) include(<vector>) - -reserved(template) operator(<)reserved(typename) ident(T)operator(>) ident(T) ident(mysub)operator(()directive(const) ident(T)operator(&) ident(t)operator(\)) operator({) reserved(return) ident(t)operator(;) operator(}) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// 1. Type information inferred by compiler) - pre_type(int) ident(i) operator(=) ident(mysub)operator(()integer(5)operator(\);) - - pre_type(double) ident(d) operator(=) ident(mysub)operator(()float(7)float(.6)operator(\);) - - directive(const) pre_type(int) ident(arr)operator([]) operator(=) operator({)integer(1)operator(,) integer(2)operator(,) integer(3)operator(};) - directive(const) ident(size_t) ident(arrsize) operator(=) reserved(sizeof)operator(()ident(arr)operator(\)) operator(/) reserved(sizeof)operator(()ident(arr)operator([)integer(0)operator(]\);) - - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(v) operator(=) ident(mysub)operator(()ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>()ident(arr)operator(,) ident(arr) operator(+) ident(arrsize)operator(\)\);) - - comment(// 2. Type information provided by user) - comment(// Pass a 'const char*' argument and specify type information in the call) - ident(std)operator(::)pre_type(string) ident(s) operator(=) ident(mysub)operator(<)ident(std)operator(::)pre_type(string)operator(>()string<delimiter(")content(xyz)delimiter(")>operator(\);) - - comment(// Could avoid specifying type information by passing a 'std::string' argument ) - comment(// std::string s = mysub(std::string("xyz"\)\);) -operator(}) - -comment(// ----------------------------) - -comment(// This is a variant on the previous example that uses the Boost Library's 'any' type as a) -comment(// generic 'stub' type) - -preprocessor(#include) include(<string>) -preprocessor(#include) include(<vector>) - -preprocessor(#include) include(<boost/any.hpp>) - -reserved(template) operator(<)reserved(typename) ident(T)operator(>) ident(boost)operator(::)ident(any) ident(mysub)operator(()directive(const) ident(T)operator(&) ident(t)operator(\)) operator({) reserved(return) ident(boost)operator(::)ident(any)operator(()ident(t)operator(\);) operator(}) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - ident(std)operator(::)ident(vector)operator(<)ident(boost)operator(::)ident(any)operator(>) ident(any)operator(;) - - comment(// Add various types [encapsulated in 'any' objects] to the container) - ident(any)operator(.)ident(push_back)operator(()ident(mysub)operator(()integer(5)operator(\)\);) - ident(any)operator(.)ident(push_back)operator(()ident(mysub)operator(()float(7)float(.6)operator(\)\);) - ident(any)operator(.)ident(push_back)operator(()ident(mysub)operator(()ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>()integer(5)operator(,) integer(5)operator(\)\)\);) - ident(any)operator(.)ident(push_back)operator(()ident(mysub)operator(()ident(std)operator(::)pre_type(string)operator(()string<delimiter(")content(xyz)delimiter(")>operator(\)\)\);) - - comment(// Extract the various types from the container by appropriately casting the relevant) - comment(// 'any' object) - pre_type(int) ident(i) operator(=) ident(boost)operator(::)ident(any_cast)operator(<)pre_type(int)operator(>()ident(any)operator([)integer(0)operator(]\);) - pre_type(double) ident(d) operator(=) ident(boost)operator(::)ident(any_cast)operator(<)pre_type(double)operator(>()ident(any)operator([)integer(1)operator(]\);) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(v) operator(=) ident(boost)operator(::)ident(any_cast)operator(<) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) operator(>()ident(any)operator([)integer(2)operator(]\);) - ident(std)operator(::)pre_type(string) ident(s) operator(=) ident(boost)operator(::)ident(any_cast)operator(<)ident(std)operator(::)pre_type(string)operator(>()ident(any)operator([)integer(3)operator(]\);) -operator(}) - -comment(// @@PLEAC@@_10.7) -comment(// Just like the C language, C++ offers no support for named / keyword parameters. It is of) -comment(// course possible to mimic such functionality the same way it is done in C [see corresponding) -comment(// section in PLEAC-C/Posix/GNU], the most obvious means being by passing a set of key/value) -comment(// pairs in a std::map. This will not be shown here. Instead, two quite C++-specific examples) -comment(// will be provided, based on:) -comment(//) -comment(// * Named Parameter Idiom [see: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18]) -comment(// * Boost 'parameter' Library [see: http://www.boost.org/libs/parameter/doc/html/index.html]) - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<map>) - -reserved(class) class(TimeEntry) -operator({) -directive(public)operator(:) - directive(explicit) ident(TimeEntry)operator(()pre_type(int) ident(value) operator(=) integer(0)operator(,) pre_type(char) ident(dim) operator(=) char('s')operator(\);) - - pre_type(bool) directive(operator)operator(<()directive(const) ident(TimeEntry)operator(&) ident(right)operator(\)) directive(const)operator(;) - - directive(friend) ident(std)operator(::)ident(ostream)operator(&) directive(operator)operator(<<()ident(std)operator(::)ident(ostream)operator(&) ident(out)operator(,) directive(const) ident(TimeEntry)operator(&) ident(t)operator(\);) - -directive(private)operator(:) - pre_type(int) ident(value_)operator(;) - pre_type(char) ident(dim_)operator(;) -operator(};) - -reserved(typedef) ident(std)operator(::)ident(pair)operator(<)directive(const) pre_type(int)operator(,) ident(TimeEntry)operator(>) ident(TENTRY)operator(;) -reserved(typedef) ident(std)operator(::)ident(map)operator(<)directive(const) pre_type(int)operator(,) ident(TimeEntry)operator(>) ident(TIMETBL)operator(;) - -reserved(class) class(RaceTime) -operator({) -directive(public)operator(:) - directive(const) directive(static) pre_type(int) ident(START_TIME)operator(,) ident(FINISH_TIME)operator(,) ident(INCR_TIME)operator(;) - -directive(public)operator(:) - directive(explicit) ident(RaceTime)operator((\);) - - ident(RaceTime)operator(&) ident(start_time)operator(()directive(const) ident(TimeEntry)operator(&) ident(time)operator(\);) - ident(RaceTime)operator(&) ident(finish_time)operator(()directive(const) ident(TimeEntry)operator(&) ident(time)operator(\);) - ident(RaceTime)operator(&) ident(incr_time)operator(()directive(const) ident(TimeEntry)operator(&) ident(time)operator(\);) - - directive(friend) ident(std)operator(::)ident(ostream)operator(&) directive(operator)operator(<<()ident(std)operator(::)ident(ostream)operator(&) ident(out)operator(,) directive(const) ident(RaceTime)operator(&) ident(r)operator(\);) - -directive(private)operator(:) - ident(TIMETBL) ident(timetbl_)operator(;) -operator(};) - -directive(const) pre_type(int) ident(RaceTime)operator(::)ident(START_TIME) operator(=) integer(0)operator(,) ident(RaceTime)operator(::)ident(FINISH_TIME) operator(=) integer(1)operator(,) ident(RaceTime)operator(::)ident(INCR_TIME) operator(=) integer(2)operator(;) - -directive(void) ident(the_func)operator(()directive(const) ident(RaceTime)operator(&) ident(r)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - ident(the_func)operator(()ident(RaceTime)operator((\))operator(.)ident(start_time)operator(()ident(TimeEntry)operator(()integer(20)operator(,) char('s')operator(\)\))operator(.)ident(finish_time)operator(()ident(TimeEntry)operator(()integer(5)operator(,) char('m')operator(\)\))operator(.)ident(incr_time)operator(()ident(TimeEntry)operator(()integer(5)operator(,) char('s')operator(\)\)\);) - - ident(the_func)operator(()ident(RaceTime)operator((\))operator(.)ident(start_time)operator(()ident(TimeEntry)operator(()integer(5)operator(,) char('m')operator(\)\))operator(.)ident(finish_time)operator(()ident(TimeEntry)operator(()integer(30)operator(,) char('m')operator(\)\)\);) - - ident(the_func)operator(()ident(RaceTime)operator((\))operator(.)ident(start_time)operator(()ident(TimeEntry)operator(()integer(30)operator(,) char('m')operator(\)\)\);) -operator(}) - -comment(// ----) - -ident(std)operator(::)ident(ostream)operator(&) directive(operator)operator(<<()ident(std)operator(::)ident(ostream)operator(&) ident(out)operator(,) directive(const) ident(TimeEntry)operator(&) ident(t)operator(\)) -operator({) - ident(out) operator(<<) ident(t)operator(.)ident(value_) operator(<<) ident(t)operator(.)ident(dim_)operator(;) reserved(return) ident(out)operator(;) -operator(}) - -ident(std)operator(::)ident(ostream)operator(&) directive(operator)operator(<<()ident(std)operator(::)ident(ostream)operator(&) ident(out)operator(,) directive(const) ident(RaceTime)operator(&) ident(r)operator(\)) -operator({) - ident(RaceTime)operator(&) ident(r_) operator(=) reserved(const_cast)operator(<)ident(RaceTime)operator(&>()ident(r)operator(\);) - - ident(out) operator(<<) string<delimiter(")content(start_time: )delimiter(")> operator(<<) ident(r_)operator(.)ident(timetbl_)operator([)ident(RaceTime)operator(::)ident(START_TIME)operator(]) - operator(<<) string<delimiter(")char(\\n)content(finish_time: )delimiter(")> operator(<<) ident(r_)operator(.)ident(timetbl_)operator([)ident(RaceTime)operator(::)ident(FINISH_TIME)operator(]) - operator(<<) string<delimiter(")char(\\n)content(incr_time: )delimiter(")> operator(<<) ident(r_)operator(.)ident(timetbl_)operator([)ident(RaceTime)operator(::)ident(INCR_TIME)operator(];) - - reserved(return) ident(out)operator(;) -operator(}) - -ident(TimeEntry)operator(::)ident(TimeEntry)operator(()pre_type(int) ident(value)operator(,) pre_type(char) ident(dim)operator(\)) operator(:) ident(value_)operator(()ident(value)operator(\),) ident(dim_)operator(()ident(dim)operator(\)) operator({}) - -pre_type(bool) ident(TimeEntry)operator(::)directive(operator)operator(<()directive(const) ident(TimeEntry)operator(&) ident(right)operator(\)) directive(const) -operator({) - reserved(return) operator(()ident(dim_) operator(==) ident(right)operator(.)ident(dim_)operator(\)) operator(?) operator(()ident(value_) operator(<) ident(right)operator(.)ident(value_)operator(\)) operator(:) operator(!()ident(dim_) operator(<) ident(right)operator(.)ident(dim_)operator(\);) -operator(}) - -ident(RaceTime)operator(::)ident(RaceTime)operator((\)) -operator({) - ident(timetbl_)operator(.)ident(insert)operator(()ident(TENTRY)operator(()ident(START_TIME)operator(,) ident(TimeEntry)operator(()integer(0)operator(,) char('s')operator(\)\)\);) - ident(timetbl_)operator(.)ident(insert)operator(()ident(TENTRY)operator(()ident(FINISH_TIME)operator(,) ident(TimeEntry)operator(()integer(0)operator(,) char('s')operator(\)\)\);) - ident(timetbl_)operator(.)ident(insert)operator(()ident(TENTRY)operator(()ident(INCR_TIME)operator(,) ident(TimeEntry)operator(()integer(0)operator(,) char('s')operator(\)\)\);) -operator(}) - -ident(RaceTime)operator(&) ident(RaceTime)operator(::)ident(start_time)operator(()directive(const) ident(TimeEntry)operator(&) ident(time)operator(\)) -operator({) - ident(timetbl_)operator([)ident(START_TIME)operator(]) operator(=) ident(time)operator(;) reserved(return) operator(*)local_variable(this)operator(;) -operator(}) - -ident(RaceTime)operator(&) ident(RaceTime)operator(::)ident(finish_time)operator(()directive(const) ident(TimeEntry)operator(&) ident(time)operator(\)) -operator({) - ident(timetbl_)operator([)ident(FINISH_TIME)operator(]) operator(=) ident(time)operator(;) reserved(return) operator(*)local_variable(this)operator(;) -operator(}) - -ident(RaceTime)operator(&) ident(RaceTime)operator(::)ident(incr_time)operator(()directive(const) ident(TimeEntry)operator(&) ident(time)operator(\)) -operator({) - ident(timetbl_)operator([)ident(INCR_TIME)operator(]) operator(=) ident(time)operator(;) reserved(return) operator(*)local_variable(this)operator(;) -operator(}) - -directive(void) ident(the_func)operator(()directive(const) ident(RaceTime)operator(&) ident(r)operator(\)) -operator({) - ident(std)operator(::)ident(cout) operator(<<) ident(r) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ----------------------------) - -comment(// The Boost 'parameter' library requires a significant amount of setup code to be written,) -comment(// much more than this section warrants. My recommendation is to read carefully through the) -comment(// tutorial to determine whether a problem for which it is being considered justifies all) -comment(// the setup.) - -comment(// @@PLEAC@@_10.8) -comment(// The Boost 'tuple' Library also allows multiple assignment to variables, including the) -comment(// selective skipping of return values) - -preprocessor(#include) include(<iostream>) - -preprocessor(#include) include(<boost/tuple/tuple.hpp>) - -reserved(typedef) ident(boost)operator(::)ident(tuple)operator(<)pre_type(int)operator(,) pre_type(int)operator(,) pre_type(int)operator(>) ident(T3)operator(;) - -ident(T3) ident(func)operator((\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - pre_type(int) ident(a) operator(=) integer(6)operator(,) ident(b) operator(=) integer(7)operator(,) ident(c) operator(=) integer(8)operator(;) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) char(',') operator(<<) ident(b) operator(<<) char(',') operator(<<) ident(c) operator(<<) ident(std)operator(::)ident(endl)operator(;) - - comment(// A tuple of references to the referred variables is created; the values) - comment(// captured from the returned tuple are thus multiply-assigned to them) - ident(boost)operator(::)ident(tie)operator(()ident(a)operator(,) ident(b)operator(,) ident(c)operator(\)) operator(=) ident(func)operator((\);) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) char(',') operator(<<) ident(b) operator(<<) char(',') operator(<<) ident(c) operator(<<) ident(std)operator(::)ident(endl)operator(;) - - comment(// Variables can still be individually referenced) - ident(a) operator(=) integer(11)operator(;) ident(b) operator(=) integer(23)operator(;) ident(c) operator(=) integer(56)operator(;) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) char(',') operator(<<) ident(b) operator(<<) char(',') operator(<<) ident(c) operator(<<) ident(std)operator(::)ident(endl)operator(;) - - comment(// Return values may be ignored; affected variables retain existing values) - ident(boost)operator(::)ident(tie)operator(()ident(a)operator(,) ident(boost)operator(::)ident(tuples)operator(::)ident(ignore)operator(,) ident(c)operator(\)) operator(=) ident(func)operator((\);) - ident(std)operator(::)ident(cout) operator(<<) ident(a) operator(<<) char(',') operator(<<) ident(b) operator(<<) char(',') operator(<<) ident(c) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ----) - -ident(T3) ident(func)operator((\)) operator({) reserved(return) ident(T3)operator(()integer(3)operator(,) integer(6)operator(,) integer(9)operator(\);) operator(}) - -comment(// @@PLEAC@@_10.9) -comment(// Like Standard C, C++ allows only the return of a single value. The return of multiple values) -comment(// *can*, however, be simulated by packaging them within an aggregate type [as in C], or a) -comment(// custom class, or one of the STL containers like std::vector. Probably the most robust, and) -comment(// [pseudo]-standardised, approach is to use the Boost 'tuple' Library, as will be done in this) -comment(// section. Notes:) -comment(// * Use made of Boost 'assign' Library to simplify container loading; this is a *very* handy) -comment(// library) -comment(// * Use made of Boost 'any' Library to make containers heterogenous; 'variant' Library is) -comment(// similar, and is more appropriate where type-safe container traversal is envisaged e.g.) -comment(// for printing ) - -preprocessor(#include) include(<string>) -preprocessor(#include) include(<vector>) -preprocessor(#include) include(<map>) - -preprocessor(#include) include(<boost/any.hpp>) -preprocessor(#include) include(<boost/tuple/tuple.hpp>) - -preprocessor(#include) include(<boost/assign/std/vector.hpp>) -preprocessor(#include) include(<boost/assign/list_inserter.hpp>) - -reserved(typedef) ident(std)operator(::)ident(vector)operator(<)ident(boost)operator(::)ident(any)operator(>) ident(ARRAY)operator(;) -reserved(typedef) ident(std)operator(::)ident(map)operator(<)ident(std)operator(::)pre_type(string)operator(,) ident(boost)operator(::)ident(any)operator(>) ident(HASH)operator(;) -reserved(typedef) ident(boost)operator(::)ident(tuple)operator(<)ident(ARRAY)operator(,) ident(HASH)operator(>) ident(ARRAY_HASH)operator(;) - -ident(ARRAY_HASH) ident(some_func)operator(()directive(const) ident(ARRAY)operator(&) ident(array)operator(,) directive(const) ident(HASH)operator(&) ident(hash)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Load containers using Boost 'assign' Library ) - directive(using) reserved(namespace) ident(boost)operator(::)ident(assign)operator(;) - ident(ARRAY) ident(array)operator(;) ident(array) operator(+=) integer(1)operator(,) integer(2)operator(,) integer(3)operator(,) integer(4)operator(,) integer(5)operator(;) - ident(HASH) ident(hash)operator(;) ident(insert)operator(()ident(hash)operator(\)) operator(()string<delimiter(")content(k1)delimiter(")>operator(,) integer(1)operator(\)) operator(()string<delimiter(")content(k2)delimiter(")>operator(,) integer(2)operator(\)) operator(()string<delimiter(")content(k3)delimiter(")>operator(,) integer(3)operator(\);) - - comment(// Pass arguments to 'somefunc' and retrieve them as members of a tuple) - ident(ARRAY_HASH) ident(refs) operator(=) ident(some_func)operator(()ident(array)operator(,) ident(hash)operator(\);) - - comment(// Retrieve copy of 'array' from tuple) - ident(ARRAY) ident(ret_array) operator(=) ident(boost)operator(::)ident(get)operator(<)integer(0)operator(>()ident(refs)operator(\);) - - comment(// Retrieve copy of 'hash' from tuple) - ident(HASH) ident(ret_hash) operator(=) ident(boost)operator(::)ident(get)operator(<)integer(1)operator(>()ident(refs)operator(\);) -operator(}) - -comment(// ----) - -ident(ARRAY_HASH) ident(some_func)operator(()directive(const) ident(ARRAY)operator(&) ident(array)operator(,) directive(const) ident(HASH)operator(&) ident(hash)operator(\)) -operator({) - operator(;) comment(// ... do something with 'array' and 'hash') - - reserved(return) ident(ARRAY_HASH)operator(()ident(array)operator(,) ident(hash)operator(\);) -operator(}) - -comment(// @@PLEAC@@_10.10) -comment(// Like function calls in Standard C, function calls in C++ need to conform to signature) -comment(// requirements; a function call must match its declaration with the same number, and type,) -comment(// of arguments passed [includes implicitly-passed default arguments], and the same return) -comment(// value type. Thus, unlike Perl, a function declared to return a value *must* do so, thus) -comment(// cannot 'return nothing' to indicate failure. ) -comment(// Whilst in Standard C certain conventions like returning NULL pointers, or returning -1, to) -comment(// indicate the 'failure' of a task [i.e. function return codes are checked, and control) -comment(// proceeds conditionally] are used, Standard C++ sports facilities which lessen the need for) -comment(// dong the same. Specifically, C++ offers:) -comment(// * Built-in exception handling which can be used to detect [and perhaps recover from],) -comment(// all manner of unusual, or erroneous / problematic situations. One recommended use is) -comment(// to avoid writing code that performs a lot of return code checking) -comment(// * Native OOP support allows use of the Null Object Design Pattern. Put simply, rather than) -comment(// than checking return codes then deciding on an action, an object with some predefined) -comment(// default behaviour is returned / used where an unusual / erroneous / problematic situation) -comment(// is encountered. This approach could be as simple as having some sort of default base) -comment(// class member function behaviour, or as complex as having a diagnostic-laden object created) -comment(// * Functions can still return 'error-indicating entities', but rather than primitive types) -comment(// like 'int's or NULL pointers, complex objects can be returned. For example, the Boost) -comment(// Library sports a number of such types:) -comment(// - 'tuple') -comment(// - 'any', 'variant' and 'optional') -comment(// - 'tribool' [true, false, indeterminate]) - -comment(// Exception Handling Example) - -reserved(class) class(XYZ_exception) operator({};) - -pre_type(int) ident(func)operator((\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - pre_type(int) ident(valid_value) operator(=) integer(0)operator(;) - - reserved(try) - operator({) - operator(;) comment(// ...) - - ident(valid_value) operator(=) ident(func)operator((\);) - - operator(;) comment(// ...) - operator(}) - - reserved(catch)operator(()directive(const) ident(XYZ_exception)operator(&) ident(e)operator(\)) - operator({) - operator(;) comment(// ...) - operator(}) -operator(}) - -comment(// ----) - -pre_type(int) ident(func)operator((\)) -operator({) - pre_type(bool) ident(error_detected) operator(=) pre_constant(false)operator(;) - pre_type(int) ident(valid_value)operator(;) - - operator(;) comment(// ...) - - reserved(if) operator(()ident(error_detected)operator(\)) reserved(throw) ident(XYZ_exception)operator((\);) - - operator(;) comment(// ...) - - reserved(return) ident(valid_value)operator(;) -operator(}) - -comment(// ------------) - -comment(// Null Object Design Pattern Example) - -preprocessor(#include) include(<iostream>) - -reserved(class) class(Value) -operator({) -directive(public)operator(:) - directive(virtual) directive(void) ident(do_something)operator((\)) operator(=) integer(0)operator(;) -operator(};) - -reserved(class) class(NullValue) operator(:) directive(public) ident(Value) -operator({) -directive(public)operator(:) - directive(virtual) directive(void) ident(do_something)operator((\);) -operator(};) - -reserved(class) class(ValidValue) operator(:) directive(public) ident(Value) -operator({) -directive(public)operator(:) - directive(virtual) directive(void) ident(do_something)operator((\);) -operator(};) - -ident(Value)operator(*) ident(func)operator((\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Error checking is performed within 'func'. However, regardless of the outcome, an) - comment(// object of 'Value' type is returned which possesses similar behaviour, though appropriate) - comment(// to whether processing was successful or not. In this way no error checking is needed) - comment(// outside of 'func') - ident(Value)operator(*) ident(v) operator(=) ident(func)operator((\);) - - ident(v)operator(->)ident(do_something)operator((\);) - - reserved(delete) ident(v)operator(;) -operator(}) - -comment(// ----) - -directive(void) ident(NullValue)operator(::)ident(do_something)operator((\)) -operator({) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(*null*)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -directive(void) ident(ValidValue)operator(::)ident(do_something)operator((\)) -operator({) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(valid)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -ident(Value)operator(*) ident(func)operator((\)) -operator({) - pre_type(bool) ident(error_detected) operator(=) pre_constant(true)operator(;) - - operator(;) comment(// ...) - - reserved(if) operator(()ident(error_detected)operator(\)) reserved(return) reserved(new) ident(NullValue)operator(;) - - operator(;) comment(// ...) - - reserved(return) reserved(new) ident(ValidValue)operator(;) -operator(}) - -comment(// ----------------------------) - -comment(// The Boost 'optional' library has many uses, but in the current context, one is of particular) -comment(// use: returning a specified type [thus satisfying language requirements], but whose value) -comment(// may be 'set' [if the function succeeded] or 'unset' [if it failed], and this condition very) -comment(// easily checked) - -preprocessor(#include) include(<iostream>) - -preprocessor(#include) include(<cstdlib>) - -preprocessor(#include) include(<string>) -preprocessor(#include) include(<vector>) -preprocessor(#include) include(<map>) - -preprocessor(#include) include(<boost/optional/optional.hpp>) - -reserved(class) class(func_fail) -operator({) -directive(public)operator(:) - directive(explicit) ident(func_fail)operator(()directive(const) ident(std)operator(::)pre_type(string)operator(&) ident(msg)operator(\)) operator(:) ident(msg_)operator(()ident(msg)operator(\)) operator({}) - directive(const) ident(std)operator(::)pre_type(string)operator(&) ident(msg)operator((\)) directive(const) operator({) reserved(return) ident(msg_)operator(;) operator(}) -directive(private)operator(:) - directive(const) ident(std)operator(::)pre_type(string) ident(msg_)operator(;) -operator(};) - -comment(// ----) - -directive(void) ident(die)operator(()directive(const) ident(std)operator(::)pre_type(string)operator(&) ident(msg)operator(\);) - -ident(boost)operator(::)ident(optional)operator(<)pre_type(int)operator(>) ident(sfunc)operator((\);) -ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) operator(>) ident(afunc)operator((\);) -ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(map)operator(<)ident(std)operator(::)pre_type(string)operator(,) pre_type(int)operator(>) operator(>) ident(hfunc)operator((\);) - -comment(// ------------) - -pre_type(int) ident(main)operator((\)) -operator({) - reserved(try) - operator({) - ident(boost)operator(::)ident(optional)operator(<)pre_type(int)operator(>) ident(s)operator(;) - ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) operator(>) ident(a)operator(;) - ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(map)operator(<)ident(std)operator(::)pre_type(string)operator(,) pre_type(int)operator(>) operator(>) ident(h)operator(;) - - reserved(if) operator((!()ident(s) operator(=) ident(sfunc)operator((\)\)\)) reserved(throw) ident(func_fail)operator(()string<delimiter(")content('sfunc' failed)delimiter(")>operator(\);) - reserved(if) operator((!()ident(a) operator(=) ident(afunc)operator((\)\)\)) reserved(throw) ident(func_fail)operator(()string<delimiter(")content('afunc' failed)delimiter(")>operator(\);) - reserved(if) operator((!()ident(h) operator(=) ident(hfunc)operator((\)\)\)) reserved(throw) ident(func_fail)operator(()string<delimiter(")content('hfunc' failed)delimiter(")>operator(\);) - - operator(;) comment(// ... do stuff with 's', 'a', and 'h' ...) - pre_type(int) ident(scalar) operator(=) operator(*)ident(s)operator(;) - - operator(;) comment(// ...) - operator(}) - - reserved(catch) operator(()directive(const) ident(func_fail)operator(&) ident(e)operator(\)) - operator({) - ident(die)operator(()ident(e)operator(.)ident(msg)operator((\)\);) - operator(}) - - operator(;) comment(// ... other code executed if no error above ...) -operator(}) - -comment(// ------------) - -directive(void) ident(die)operator(()directive(const) ident(std)operator(::)pre_type(string)operator(&) ident(msg)operator(\)) -operator({) - ident(std)operator(::)ident(cerr) operator(<<) ident(msg) operator(<<) ident(std)operator(::)ident(endl)operator(;) - - comment(// Should only be used if all objects in the originating local scope have been destroyed) - ident(std)operator(::)ident(exit)operator(()ident(EXIT_FAILURE)operator(\);) -operator(}) - -comment(// ----) - -ident(boost)operator(::)ident(optional)operator(<)pre_type(int)operator(>) ident(sfunc)operator((\)) -operator({) - pre_type(bool) ident(error_detected) operator(=) pre_constant(true)operator(;) - - pre_type(int) ident(valid_int_value)operator(;) - - operator(;) comment(// ...) - - reserved(if) operator(()ident(error_detected)operator(\)) reserved(return) ident(boost)operator(::)ident(optional)operator(<)pre_type(int)operator(>(\);) - - operator(;) comment(// ...) - - reserved(return) ident(boost)operator(::)ident(optional)operator(<)pre_type(int)operator(>()ident(valid_int_value)operator(\);) -operator(}) - -ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) operator(>) ident(afunc)operator((\)) -operator({) - comment(// ... code not shown ...) - - reserved(return) ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) operator(>(\);) - - comment(// ... code not shown) -operator(}) - -ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(map)operator(<)ident(std)operator(::)pre_type(string)operator(,) pre_type(int)operator(>) operator(>) ident(hfunc)operator((\)) -operator({) - comment(// ... code not shown ...) - - reserved(return) ident(boost)operator(::)ident(optional)operator(<) ident(std)operator(::)ident(map)operator(<)ident(std)operator(::)pre_type(string)operator(,) pre_type(int)operator(>) operator(>(\);) - - comment(// ... code not shown ...) -operator(}) - -comment(// @@PLEAC@@_10.11) -comment(// Whilst in Perl function prototyping is optional, this is not the case in C++, where it is) -comment(// necessary to:) -comment(// * Declare a function before use; this could either be a function declaration separate from) -comment(// the function definition, or the function definition itself which serves as its own) -comment(// declaration) -comment(// * Specify both parameter positional and type information; parameter names are optional in) -comment(// declarations, mandatory in definitions) -comment(// * Specify return type) - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<vector>) - -comment(// Function Declaration) -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(myfunc)operator(()pre_type(int) ident(arg1)operator(,) pre_type(int) ident(arg2)operator(\);) comment(// Also possible: std::vector<int> myfunc(int, int\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Call function with all required arguments; this is the only calling method) - comment(// [except for calling via function pointer which still needs all arguments supplied]) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(results) operator(=) ident(myfunc)operator(()integer(3)operator(,) integer(5)operator(\);) - - comment(// Let's look at our return array's contents) - ident(std)operator(::)ident(cout) operator(<<) ident(results)operator([)integer(0)operator(]) operator(<<) char(':') operator(<<) ident(results)operator([)integer(1)operator(]) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ----) - -comment(// Function Definition) -ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(myfunc)operator(()pre_type(int) ident(arg1)operator(,) pre_type(int) ident(arg2)operator(\)) -operator({) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(r)operator(;) - - ident(std)operator(::)ident(back_inserter)operator(()ident(r)operator(\)) operator(=) ident(arg1)operator(;) - ident(std)operator(::)ident(back_inserter)operator(()ident(r)operator(\)) operator(=) ident(arg2)operator(;) - - reserved(return) ident(r)operator(;) -operator(}) - -comment(// ------------) - -comment(// A version on the above code that is generic, that is, making use of the C++ template) -comment(// mechanism to work with any type) - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<vector>) - -comment(// Function Declaration) -reserved(template) operator(<)reserved(class) class(T)operator(>) ident(std)operator(::)ident(vector)operator(<)ident(T)operator(>) ident(myfunc)operator(()directive(const) ident(T)operator(&) ident(arg1)operator(,) directive(const) ident(T)operator(&) ident(arg2)operator(\);) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - ident(std)operator(::)ident(vector)operator(<)pre_type(int)operator(>) ident(results) operator(=) ident(myfunc)operator(()integer(3)operator(,) integer(5)operator(\);) - - ident(std)operator(::)ident(cout) operator(<<) ident(results)operator([)integer(0)operator(]) operator(<<) char(':') operator(<<) ident(results)operator([)integer(1)operator(]) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ----) - -comment(// Function Definition) -reserved(template) operator(<)reserved(class) class(T)operator(>) ident(std)operator(::)ident(vector)operator(<)ident(T)operator(>) ident(myfunc)operator(()directive(const) ident(T)operator(&) ident(arg1)operator(,) directive(const) ident(T)operator(&) ident(arg2)operator(\)) -operator({) - ident(std)operator(::)ident(vector)operator(<)ident(T)operator(>) ident(r)operator(;) - - ident(std)operator(::)ident(back_inserter)operator(()ident(r)operator(\)) operator(=) ident(arg1)operator(;) - ident(std)operator(::)ident(back_inserter)operator(()ident(r)operator(\)) operator(=) ident(arg2)operator(;) - - reserved(return) ident(r)operator(;) -operator(}) - -comment(// ------------) - -comment(// Other Perl examples are omitted since there is no variation in C++ function calling or) -comment(// parameter handling) - -comment(// @@PLEAC@@_10.12) -comment(// One of the key, non-object oriented features of Standard C++ is its built-in support for) -comment(// exceptions / exception handling. The feature is well-integrated into the language, including) -comment(// a set of predefined exception classes included in, and used by, the Standard Library, is) -comment(// quite easy to use, and helps the programmer write robust code provided certain conventions) -comment(// are followed. On the downside, the C++ exception handling system is criticised for imposing) -comment(// significant runtime overhead, as well as increasing executable code size [though this) -comment(// varies considerably between CPU's, OS's, and compilers]. Please refer to the corresponding) -comment(// section in PLEAC-C/Posix/GNU for pertinent reading references.) -comment(//) -comment(// The example code below matches the PLEAC-C/Posix/GNU example rather than the Perl code. Note:) -comment(// * A very minimal, custom exception class is implemented; a more complex class, one richer in) -comment(// diagnostic information, could have been implemented, or perhaps one based on a standard) -comment(// exception class like 'std::exception') -comment(// * Ordinarily error / exception messages are directed to 'std::cerr' or 'std::clog') -comment(// * General recommendation is to throw 'temporaries' [via invoking a constructor],) -comment(// and to 'catch' as const reference(s\)) -comment(// * Proper 'cleanup' is very important; consult a suitable book for guidance on writing) -comment(// 'exception safe' code) - -preprocessor(#include) include(<iostream>) -preprocessor(#include) include(<string>) - -reserved(class) class(FullmoonException) -operator({) -directive(public)operator(:) - directive(explicit) ident(FullmoonException)operator(()directive(const) ident(std)operator(::)pre_type(string)operator(&) ident(msg)operator(\)) operator(:) ident(msg_)operator(()ident(msg)operator(\)) operator({}) - - directive(friend) ident(std)operator(::)ident(ostream)operator(&) directive(operator)operator(<<()ident(std)operator(::)ident(ostream)operator(&) ident(out)operator(,) directive(const) ident(FullmoonException)operator(&) ident(e)operator(\)) - operator({) - ident(out) operator(<<) ident(e)operator(.)ident(msg_)operator(;) reserved(return) ident(out)operator(;) - operator(}) -directive(private)operator(:) - directive(const) ident(std)operator(::)pre_type(string) ident(msg_)operator(;) -operator(};) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(main - entry)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) - - reserved(try) - operator({) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(try block - entry)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(... doing stuff ...)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) - - comment(// if (... error condition detected ...\)) - reserved(throw) ident(FullmoonException)operator(()string<delimiter(")content(... the problem description ...)delimiter(")>operator(\);) - - comment(// Control never gets here ...) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(try block - end)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) - operator(}) - - reserved(catch)operator(()directive(const) ident(FullmoonException)operator(&) ident(e)operator(\)) - operator({) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(Caught a'Fullmoon' exception. Message: )delimiter(")> - operator(<<) string<delimiter(")content([)delimiter(")> operator(<<) ident(e) operator(<<) string<delimiter(")content(])delimiter(")> - operator(<<) ident(std)operator(::)ident(endl)operator(;) - operator(}) - - reserved(catch)operator(()operator(.)operator(.)operator(.)operator(\)) - operator({) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(Caught an unknown exceptione)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) - operator(}) - - comment(// Control gets here regardless of whether an exception is thrown or not) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(main - end)delimiter(")> operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// @@PLEAC@@_10.13) -comment(// Standard C++ sports a namespace facility which allows an application to be divided into) -comment(// logical sub-systems, each of which operates within its own scope. Put very simply, the same) -comment(// identifiers [i.e. name of types, objects, and functions] may be each used in a namespace) -comment(// without fear of a nameclash occurring when logical sub-systems are variously combined as) -comment(// an application. The name-clash problem is inherent in single-namespace languages like C; it) -comment(// often occurs when several third-party libraries are used [a common occurrence in C], or) -comment(// when an application scales up. The remedy is to rename identifiers, or, in the case of ) -comment(// functions that cannot be renamed, to wrap them up in other functions in a separate source) -comment(// file. Of course the problem may be minimised via strict adherence to naming conventions. ) -comment(//) -comment(// The C++ namespace facility is important, too, because it avoids the need to utilise certain) -comment(// C language practices, in particular:) -comment(// * Use of, possibly, 'clumsy' naming conventions [as described above]) -comment(// * Partition an application by separating logically-related items into separate source) -comment(// files. Namespaces cross file boundaries, so items may reside in several source files) -comment(// and still comprise a single, logical sub-system) -comment(// * Anonymous namespaces avoid use of the 'static' keyword in creating file scope globals) - -comment(// Global variable) -pre_type(int) ident(age) operator(=) integer(18)operator(;) - -comment(// ----) - -directive(void) ident(print_age)operator((\)) -operator({) - comment(// Global value, 'age', is accessed) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(Age is )delimiter(")> operator(<<) ident(age) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ------------) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// A local variable named, 'age' will act to 'shadow' the globally) - comment(// defined version, thus any changes to, 'age', will not affect) - comment(// the global version) - pre_type(int) ident(age) operator(=) integer(5)operator(;) - - comment(// Prints 18, the current value of the global version) - ident(print_age)operator((\);) - - comment(// Local version is altered, *not* global version) - ident(age) operator(=) integer(23)operator(;) - - comment(// Prints 18, the current value of the global version) - ident(print_age)operator((\);) -operator(}) - -comment(// ----------------------------) - -comment(// Global variable) -pre_type(int) ident(age) operator(=) integer(18)operator(;) - -comment(// ----) - -directive(void) ident(print_age)operator((\)) -operator({) - comment(// Global value, 'age', is accessed) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(Age is )delimiter(")> operator(<<) ident(age) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ------------) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Here no local version declared: any changes affect global version) - ident(age) operator(=) integer(5)operator(;) - - comment(// Prints 5, the new value of the global version) - ident(print_age)operator((\);) - - comment(// Global version again altered) - ident(age) operator(=) integer(23)operator(;) - - comment(// Prints 23, the new value of the global version) - ident(print_age)operator((\);) -operator(}) - -comment(// ----------------------------) - -comment(// Global variable) -pre_type(int) ident(age) operator(=) integer(18)operator(;) - -comment(// ----) - -directive(void) ident(print_age)operator((\)) -operator({) - comment(// Global value, 'age', is accessed) - ident(std)operator(::)ident(cout) operator(<<) string<delimiter(")content(Age is )delimiter(")> operator(<<) ident(age) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ------------) - -pre_type(int) ident(main)operator((\)) -operator({) - comment(// Global version value saved into local version) - pre_type(int) ident(age) operator(=) operator(::)ident(age)operator(;) - - comment(// Prints 18, the new value of the global version) - ident(print_age)operator((\);) - - comment(// Global version this time altered) - operator(::)ident(age) operator(=) integer(23)operator(;) - - comment(// Prints 23, the new value of the global version) - ident(print_age)operator((\);) - - comment(// Global version value restored from saved local version) - operator(::)ident(age) operator(=) ident(age)operator(;) - - comment(// Prints 18, the restored value of the global version) - ident(print_age)operator((\);) -operator(}) - -comment(// @@PLEAC@@_10.14) -comment(// Please refer to the corresponding section in PLEAC-C/Posix/GNU since the points raised there) -comment(// about functions and function pointers apply equally to Standard C++ [briefly: functions) -comment(// cannot be redefined; several same-signature functions may be called via the same function) -comment(// pointer variable; code cannot be generated 'on-the-fly' (well, not without the use of) -comment(// several external tools, making it an extra-language, not integral, feature\)].) -comment(// @@INCOMPLETE@@) - -comment(// @@PLEAC@@_10.15) -comment(// Please refer to the corresponding section in PLEAC-C/Posix/GNU since all the points raised) -comment(// there apply equally to Standard C++ [briefly: undefined function calls are compiler-detected) -comment(// errors; function-pointer-based calls can't be checked for integrity].) -comment(// @@INCOMPLETE@@) - -comment(// @@PLEAC@@_10.16) -comment(// Standard C++ does not support either simple nested functions or closures, therefore the) -comment(// example cannot be implemented exactly as per the Perl code) - -comment(/* === -int outer(int arg\) -{ - int x = arg + 35; - - // *** wrong - illegal C++ *** - int inner(\) { return x * 19; } - - return x + inner(\); -} -=== */) - -comment(// The problem may, of course, be solved by defining two functions using parameter passing) -comment(// where appropriate, but this is contrary to the intent of the original Perl code) -pre_type(int) ident(inner)operator(()pre_type(int) ident(x)operator(\)) -operator({) - reserved(return) ident(x) operator(*) integer(19)operator(;) -operator(}) - -pre_type(int) ident(outer)operator(()pre_type(int) ident(arg)operator(\)) -operator({) - pre_type(int) ident(x) operator(=) ident(arg) operator(+) integer(35)operator(;) - reserved(return) ident(x) operator(+) ident(inner)operator(()ident(x)operator(\);) -operator(}) - -comment(// An arguably better [but far more complicated] approach is to encapsulate all items within) -comment(// a namespace, but again, is an approach that is counter the intent of the original Perl code) -preprocessor(#include) include(<iostream>) - -reserved(namespace) ident(nst) -operator({) - pre_type(int) ident(x)operator(;) - pre_type(int) ident(inner)operator((\);) - pre_type(int) ident(outer)operator(()pre_type(int) ident(arg)operator(\);) -operator(}) - -comment(// ----) - -pre_type(int) ident(main)operator((\)) -operator({) - ident(std)operator(::)ident(cout) operator(<<) ident(nst)operator(::)ident(outer)operator(()integer(3)operator(\)) operator(<<) ident(std)operator(::)ident(endl)operator(;) -operator(}) - -comment(// ----) - -pre_type(int) ident(nst)operator(::)ident(inner)operator((\)) -operator({) - reserved(return) ident(nst)operator(::)ident(x) operator(*) integer(19)operator(;) -operator(}) - -pre_type(int) ident(nst)operator(::)ident(outer)operator(()pre_type(int) ident(arg)operator(\)) -operator({) - ident(nst)operator(::)ident(x) operator(=) ident(arg) operator(+) integer(35)operator(;) - reserved(return) ident(nst)operator(::)ident(x) operator(+) ident(nst)operator(::)ident(inner)operator((\);) -operator(}) - -comment(// Another way to solve this problem and avoiding the use of an external function, is to) -comment(// create a local type and instantiate an object passing any required environment context) -comment(// to the constructor. Then, what appears as a parameterless nested function call, can be) -comment(// effected using 'operator(\)'. This approach most closely matches the original Perl code) - -pre_type(int) ident(outer)operator(()pre_type(int) ident(arg)operator(\)) -operator({) - pre_type(int) ident(x) operator(=) ident(arg) operator(+) integer(35)operator(;) - - comment(// 'Inner' is what is known as a Functor or Function Object [or Command Design Pattern]; it) - comment(// allows objects that capture state / context to be instantiated, and that state / context) - comment(// used / retained / altered at multiple future times. Both the STL and Boost Libraries) - comment(// provide extensive support these constructs) - reserved(struct) ident(Inner) - operator({) - pre_type(int) ident(n_)operator(;) - directive(explicit) ident(Inner)operator(()pre_type(int) ident(n)operator(\)) operator(:) ident(n_)operator(()ident(n)operator(\)) operator({}) - pre_type(int) directive(operator)operator((\)(\)) directive(const) operator({) reserved(return) ident(n_) operator(*) integer(19)operator(;) operator(}) - operator(}) ident(inner)operator(()ident(x)operator(\);) - - reserved(return) ident(x) operator(+) ident(inner)operator((\);) -operator(}) - -comment(// @@PLEAC@@_10.17) -comment(// @@INCOMPLETE@@) -comment(// @@INCOMPLETE@@) - diff --git a/test/scanners/cpp/pleac.in.cpp b/test/scanners/cpp/pleac.in.cpp deleted file mode 100644 index 5a09e8c..0000000 --- a/test/scanners/cpp/pleac.in.cpp +++ /dev/null @@ -1,2041 +0,0 @@ -// -*- c++ -*-
-
-// @@PLEAC@@_NAME
-// @@SKIP@@ C++/STL/Boost
-
-
-// @@PLEAC@@_WEB
-// @@SKIP@@ http://www.research.att.com/~bs/C++.html
-// @@SKIP@@ http://www.boost.org/
-
-
-// @@PLEAC@@_1.0
-// NOTE: Whilst it is perfectly valid to use Standard C Library, or GNU
-// C Library, routines in C++ programs, the code examples here will, as
-// far as possible, avoid doing so, instead using C++-specific functionality
-// and idioms. In general:
-// * I/O will be iostream-based [i.e. no 'scanf', 'printf', 'fgets' etc]
-// * Container / iterator idioms based on the Standard Template Library [STL]
-// will replace the built-in array / raw pointer idioms typically used in C
-// * Boost Library functionality utilised wherever possible [the reason for
-// this is that much of this functionality is likely to appear in the next
-// C++ standard]
-// * Error detection/handling will generally be exception-based [this is done
-// to keep examples simple. Exception use is optional in C++, and is not as
-// pervasive as it is in other languages like Java or C#]
-// C-based solution(s) to problem(s) will be found in the corresponding section
-// of PLEAC-C/Posix/GNU.
-
-// In C++, one can use the builtin 'char *' type or the 'string' type
-// to represent strings. In this section, we will work with the C++
-// library 'string' class.
-
-// Characteristics of 'string' types:
-// - may be of any length
-// - are defined within the std namespace
-// - can be converted to a 'const char *' using std::string::c_str()
-// - can be subscripted to access individual characters (e.g., str[3]
-// returns the 4th character of the string
-// - memory associated with strings is reclaimed automatically as strings
-// go out of scope
-// - strings cannot be used as true/false values (i.e., the following is not
-// allowed: string s; if (s) {})
-
-//-----------------------------
-// Before using strings, you must include the <string> header file
-#include <string>
-
-//-----------------------------
-// To create a literal strings, you must use double quotes ("). You cannot
-// use single quotes.
-
-//-----------------------------
-// String variables must be declared -- if no value is given it's
-// value is the empty string ("").
-std::string s;
-
-//-----------------------------
-// To insert special characters, quote the character with \
-std::string s1 = "\\n"; // Two characters, \ and n
-std::string s2 = "Jon \"Maddog\" Orwant"; // Literal double quotes
-
-//-----------------------------
-// Strings can be declared in one of two ways
-std::string s1 = "assignment syntax";
-std::string s2("constructor syntax");
-
-//-----------------------------
-// Multi-line strings.
-// There is no equivalent to perl's "here" documents in c++
-std::string s1 = "
-This is a multiline string started and finished with double
-quotes that spans 4 lines (it contains 3 newline characters).
-";
-
-std::string s2 = "This is a multiline string started and finished with double
-quotes that spans 2 lines (it contains 1 newline character).";
-//-----------------------------
-
-
-// @@PLEAC@@_1.1
-std::string s = "some string";
-
-//-----------------------------
-std::string value1 = s.substr(offset, length);
-std::string value2 = s.substr(offset);
-
-// Unlike perl, the substr function returns a copy of the substring
-// rather than a reference to the existing substring, thus using substr
-// on the left hand side of an assignment statement will not modify
-// the original string. To get this functionality, you can use the
-// std::string::replace function.
-
-// Using offsets and lengths
-s.replace(offset, length, newstring);
-s.replace(offset, s.size()-offset, newtail);
-
-//-----------------------------
-// The C++ string class doesn't have anything equivalent to perl's unpack.
-// Instead, one can use C structures to import/export binary data
-
-//-----------------------------
-#include <string>
-string s = "This is what you have";
-
-std::string first = s.substr(0, 1); // "T"
-std::string second = s.substr(5, 2); // "is"
-std::string rest = s.substr(13); // "you have"
-
-// C++ strings do not support backwards indexing as perl does but
-// you can fake it out by subtracting the negative index from the
-// string length
-std::string last = s.substr(s.size()-1); // "e"
-std::string end = s.substr(s.size()-4); // "have"
-std::string piece = s.substr(s.size()-8, 3); // "you"
-
-//-----------------------------
-#include <string>
-#include <iostream>
-
-string s("This is what you have");
-std::cout << s << std::endl;
-// This is what you have
-
-s.replace(5,2,"wasn't"); // change "is to "wasn't"
-// This wasn't what you have
-
-s.replace(s.size()-12, 12, "ondrous"); // "This wasn't wondrous"
-// This wasn't wonderous
-
-s.replace(0, 1, ""); // delete first character
-// his wasn't wondrous
-
-s.replace(s.size()-10, 10, ""); // delete last 10 characters
-// his wasn'
-
-//-----------------------------
-// C++ does not have built-in support for the perl s///, m//, and tr///
-// operators; however, similar results can be achieved in at least
-// two ways:
-// - string operations such as string::find, string::rfind, etc.
-// - the boost regular expression library (regex++) supports perl
-// regular expression syntax.
-// TODO: Add examples of each.
-
-// MISSING: if (substr($string, -10) =~ /pattern/) {
-// print "Pattern matches in last 10 characters\n";
-// }
-
-// MISSING: substr($string, 0, 5) =~ s/is/at/g;
-
-//-----------------------------
-// exchange the first and last letters in a string using substr and replace
-string a = "make a hat";
-
-std::string first = a.substr(0,1);
-std::string last = a.substr(a.size()-1);
-
-a.replace(0,1, last);
-a.replace(a.size()-1, 1, first);
-
-// exchange the first and last letters in a string using indexing and swap
-#include <algorithm>
-std::swap(a[0], a[a.size()-1]);
-//-----------------------------
-
-
-// @@PLEAC@@_1.2
-//-----------------------------
-// C++ doesn't have functionality equivalent to the || and ||=.
-// If statements and trigraphs can be used instead.
-//-----------------------------
-// C++ doesn't have anything equivalent "defined". C++ variables
-// cannot be used at all if they have not previously been defined.
-
-//-----------------------------
-// Use b if b is not empty, else c
-a = b.size() ? b : c;
-
-// Set x to y unless x is not empty
-if (x.is_empty()) x = y;
-
-//-----------------------------
-foo = (!bar.is_empty()) ? bar : "DEFAULT VALUE";
-
-//-----------------------------
-// NOTE: argv is declared as char *argv[] in C/C++. We assume
-// the following code surrounds the following examples that deal
-// with argv. Also, arguments to a program start at argv[1] -- argv[0]
-// is the name of the executable that's running.
-#include <string.h>
-int main(int argc, char *argv[]) {
- char **args = argv+1; // +1 skips argv[0], the name of the executable
- // examples
-}
-
-//-----------------------------
-std::string dir = (*args) ? *argv++ : "/tmp";
-
-//-----------------------------
-std::string dir = argv[1] ? argv[1] : "/tmp";
-
-//-----------------------------
-std::string dir = (argc-1) ? argv[1] : "/tmp";
-
-//-----------------------------
-#include <map>
-std::map<std::string,int> count;
-
-count[shell.size() ? shell : "/bin/sh"]++;
-
-//-----------------------------
-// find the user name on Unix systems
-// TODO: Simplify. This is too ugly and complex
-#include <sys/types.h>
-#include <unistd.h>
-#include <pwd.h>
-#include "boost/lexical_cast.hpp"
-
-std::string user;
-char *msg = 0;
-passwd *pwd = 0;
-
-if ( (msg = getenv("USER")) ||
- (msg = getenv("LOGNAME")) ||
- (msg = getlogin()) )
- user = msg;
-else if (pwd = getpwuid(getuid()))
- user = pwd->pw_name;
-else
- user = "Unknown uid number " + boost::lexical_cast<std::string>(getuid());
-
-//-----------------------------
-if (starting_point.is_empty()) starting_point = "Greenwich";
-
-//-----------------------------
-// Example using list. Other C++ STL containers work similarly.
-#include <list>
-list<int> a, b;
-if (a.is_empty()) a = b; // copy only if a is empty
-a = (!b.is_empty()) ? b : c; // asign b if b nonempty, else c
-//-----------------------------
-
-
-// @@PLEAC@@_1.3
-//-----------------------------
-#include <algorithm>
-std::swap(a, b);
-
-//-----------------------------
-temp = a;
-a = b;
-b = temp;
-
-//-----------------------------
-std::string a("alpha");
-std::string b("omega");
-std::swap(a,b);
-
-//-----------------------------
-// The ability to exchange more than two variables at once is not
-// built into the C++ language or C++ standard libraries. However, you
-// can use the boost tuple library to accomplish this.
-#include <boost/tuple/tuple.hpp>
-
-boost::tie(alpha,beta,production)
- = boost::make_tuple("January", "March", "August");
-// move beta to alpha,
-// move production to beta,
-// move alpha to production
-boost::tie(alpha, beta, production)
- = boost::make_tuple(beta, production, alpha);
-//-----------------------------
-
-
-// @@PLEAC@@_1.4
-//-----------------------------
-// There are several ways to convert between characters
-// and integers. The examples assume the following declarations:
-char ch;
-int num;
-
-//-----------------------------
-// Using implicit conversion
-num = ch;
-ch = num;
-
-//-----------------------------
-// New-style C++ casts
-ch = static_cast<char>(num);
-num = static_cast<int>(ch);
-
-//-----------------------------
-// Old-style C casts
-ch = (char)num;
-num = (int)ch;
-
-//-----------------------------
-// Using the C++ stringstream class
-#include <sstream> // On some older compilers, use <strstream>
-std::stringstream a; // On some older compilers, use std::strstream
-
-a << ch; // Append character to a string
-a >> num; // Output character as a number
-
-a << num; // Append number to a string
-a >> ch; // Output number as a character
-
-//-----------------------------
-// Using sprintf, printf
-char str[2]; // Has to be length 2 to have room for NULL character
-sprintf(str, "%c", num);
-printf("Number %d is character %c\n", num, num);
-
-//-----------------------------
-int ascii_value = 'e'; // now 101
-char character = 101; // now 'e'
-
-//-----------------------------
-printf("Number %d is character %c\n", 101, 101);
-
-//-----------------------------
-// Convert from HAL to IBM, character by character
-#include <string>
-#include <iostream>
-
-std::string ibm, hal = "HAL";
-for (unsigned int i=0; i<hal.size(); ++i)
- ibm += hal[i]+1; // Add one to each ascii value
-std::cout << ibm << std::endl; // prints "IBM"
-
-//-----------------------------
-// Convert hal from HAL to IBM
-#include <string>
-#include <iostream>
-#include <functional> // For bind1st and plus<>
-#include <algorithm> // For transform
-
-std::string hal = "HAL";
-transform(hal.begin(), hal.end(), hal.begin(),
- bind1st(plus<char>(),1));
-std::cout << hal << std::endl; // prints "IBM"
-//-----------------------------
-
-
-// @@PLEAC@@_1.5
-//-----------------------------
-// Since C++ strings can be accessed one character at a time,
-// there's no need to do any processing on the string to convert
-// it into an array of characters.
-#include <string>
-std::string s;
-
-// Accessing characters using for loop and integer offsets
-for (unsigned int i=0; i<s.size(); ++i) {
- // do something with s[i]
-}
-
-// Accessing characters using iterators
-for (std::string::iterator i=s.begin(); i!=s.end(); ++i) {
- // do something with *i
-}
-
-//-----------------------------
-std::string str = "an apple a day";
-std::map<char,int> seen;
-
-for (std::string::iterator i=str.begin(); i!=str.end(); ++i)
- seen[*i]++;
-
-std::cout << "unique chars are: ";
-for (std::map<char,int>::iterator i=seen.begin(); i!=seen.end(); ++i)
- std::cout << i->first;
-std::cout << std::endl;
-// unique chars are: adelnpy
-
-//-----------------------------
-int sum = 0;
-for (std::string::iterator i=str.begin(); i!=str.end(); ++i)
- sum += *i;
-std::cout << "sum is " << sum << std::endl;
-// prints "sum is 1248" if str was "an appla a day"
-
-
-//-----------------------------
-// MISSING: sysv-like checksum program
-
-//-----------------------------
-// slowcat, emulate a slow line printer
-#include <sys/time.h>
-#include <iostream>
-#include <fstream>
-
-int main(int argc, char *argv[]) {
- timeval delay = { 0, 50000 }; // Delay in { seconds, nanoseconds }
- char **arg = argv+1;
- while (*arg) { // For each file
- std::ifstream file(*arg++);
- char c;
- while (file.get(c)) {
- std::cout.put(c);
- std::cout.flush();
- select(0, 0, 0, 0, &delay);
- }
- }
-}
-//-----------------------------
-
-
-// @@PLEAC@@_1.6
-//-----------------------------
-#include <string>
-#include <algorithm> // For reverse
-std::string s;
-
-reverse(s.begin(), s.end());
-
-//-----------------------------
-#include <vector> // For std::vector
-#include <sstream> // On older compilers, use <strstream>
-#include "boost/regex.hpp" // For boost::regex_split
-
-std::string str;
-std::vector<std::string> words;
-boost::regex_split(std::back_inserter(words), str);
-reverse(words.begin(), words.end()); // Reverse the order of the words
-
-std::stringstream revwords; // On older compilers, use strstream
-copy(words.begin(), words.end(), ostream_inserter<string>(revwords," ");
-std::cout << revwards.str() << std::endl;
-
-//-----------------------------
-std::string rts = str;
-reverse(rts.begin(), rts.end()); // Reverses letters in rts
-
-//-----------------------------
-std::vector<string> words;
-reverse(words.begin(), words.end()); // Reverses words in container
-
-//-----------------------------
-// Reverse word order
-std::string s = "Yoda said, 'can you see this?'";
-
-std::vector<std::string> allwords;
-boost::regex_split(std::back_inserter(allwords), s);
-
-reverse(allwords.begin(), allwords.end());
-
-std::stringstream revwords; // On older compilers, use strstream
-copy(allwords.begin(), allwords.end(), ostream_inserter<string>(revwords," "));
-std::cout << revwards.str() << std::endl;
-// this?' see you 'can said, Yoda
-
-//-----------------------------
-std::string word = "reviver";
-bool is_palindrome = equal(word.begin(), word.end(), word.rbegin());
-
-//-----------------------------
-#include <ifstream>
-
-std::ifstream dict("/usr/dict/words");
-std::string word;
-while(getline(dict,word)) {
- if (equal(word.begin(), word.end(), word.rbegin()) &&
- word.size() > 5)
- std::cout << word << std::endl;
-}
-//-----------------------------
-
-
-// @@PLEAC@@_1.7
-//-----------------------------
-#include <string>
-
-std::string::size_type pos;
-while ((pos = str.find("\t")) != std::string::npos)
- str.replace(pos, 1, string(' ',8-pos%8));
-//-----------------------------
-
-
-// @@PLEAC@@_1.8
-//-----------------------------
-// Not applicable to C++
-//-----------------------------
-
-
-// @@PLEAC@@_1.9
-//-----------------------------
-// TODO: Fix to be more like cookbook
-// TODO: Modify/add code to do this with locales
-#include <string>
-#include <algorithm>
-
-std::string phrase = "bo peep";
-transform(phrase.begin(), phrase.end(), phrase.begin(), toupper);
-// "BO PEEP"
-transform(phrase.begin(), phrase.end(), phrase.begin(), tolower);
-// "bo peep"
-//-----------------------------
-
-
-// @@PLEAC@@_1.10
-//-----------------------------
-// C++ does not provide support for perl-like in-string interpolation,
-// concatenation must be used instead.
-
-#include <string>
-
-std::string var1, var2;
-std::string answer = var1 + func() + var2; // func returns string or char *
-
-//-----------------------------
-#include "boost/lexical_cast.hpp"
-
-int n = 4;
-std::string phrase = "I have " + boost::lexical_cast<string>(n+1) + " guanacos.";
-
-//-----------------------------
-std::cout << "I have " + boost::lexical_cast<string>(n+1) + " guanacos." << std::endl;
-
-
-// @@PLEAC@@_1.11
-//-----------------------------
-// C++ does not have "here documents".
-// TODO: Lots more.
-#include <string>
-#include "boost/regex.hpp"
-
-std::string var = "
- your text
- goes here.
-";
-
-boost::regex ex("^\\s+");
-var = boost::regex_merge(var, ex, "");
-
-// @@PLEAC@@_10.0
-// NOTE: Whilst it is perfectly valid to use Standard C Library, or GNU C Library, routines in
-// C++ programs, the code examples here will, as far as possible, avoid doing so, instead using
-// C++-specific functionality and idioms. In general:
-// * I/O will be iostream-based [i.e. no 'scanf', 'printf', 'fgets' etc]
-// * Container / iterator idioms based on the Standard Template Library [STL]
-// will replace the built-in array / raw pointer idioms typically used in C
-// * Boost Library functionality utilised wherever possible [the reason for
-// this is that much of this functionality is likely to appear in the next
-// C++ standard]
-// * Error detection/handling will generally be exception-based [this is done
-// to keep examples simple. Exception use is optional in C++, and is not as
-// pervasive as it is in other languages like Java or C#]
-// C-based solution(s) to problem(s) will be found in the corresponding section of PLEAC-C/Posix/GNU.
-
-#include <iostream>
-
-// 'greeted' defined outside of any namespace, class or function, so is part of the
-// global namespace, and will be visible throughout the entire executable. Should it
-// be necessary to restrict the visibility of this global identifier to the current
-// 'compilation unit' [i.e. current source file] then the following may be used:
-//
-// namespace { int greeted = 0; }
-//
-// The effect is similar to using the 'static' keyword, in this same context, in the C
-// language.
-
-int greeted = 0;
-
-int howManyGreetings();
-void hello();
-
-// ----
-
-int main()
-{
- hello();
-
- int greetings = howManyGreetings();
-
- std::cout << "bye there!, there have been "
- << greetings
- << " greetings so far"
- << std::endl;
-}
-
-// ----
-
-int howManyGreetings()
-{
- // Access 'greeted' identifier in the global namespace using the scope resolution
- // operator. Use of this operator is only necessary if a similarly-named identifier
- // exists in a
- return ::greeted;
-}
-
-void hello()
-{
- // Here 'greeted' is accessed without additional qualification. Since a 'greeted' identifier
- // exists only in the global namespace, it is that identifier that is used
- std::cout << "high there!, this function has been called "
- << ++greeted
- << " times"
- << std::endl;
-}
-
-// @@PLEAC@@_10.1
-// Standard C++ requires that a function be prototyped, hence the name and type of parameters
-// must be specified, and the argumemt list in any calls to that function must match the
-// parameter list, as shown here
-
-#include <cmath>
-
-double hypotenuse(double side1, double side2);
-
-// ----
-
-int main()
-{
- double diag = hypotenuse(3.0, 4.0);
-}
-
-// ----
-
-double hypotenuse(double side1, double side2)
-{
- return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
-}
-
-// ----------------------------
-
-// Variable length argument list functions, via the C Language derived 'va_...' macros,
-// are also supported. However use of this facility is particularly discouraged in C++
-// because:
-// * It is an inherently type-unsafe facility; type safety is a core C++ concern
-// * Other facilities, such as overloaded functions, and default arguments [neither of which
-// are available in C] can sometimes obviate the need for variable length argument lists
-// * OOP techniques can also lessen the need for variable length argument lists. The most
-// obvious example here is the Iostream library where repeated calls of I/O operators replace
-// the format string / variable arguments of 'printf'
-
-#include <cmath>
-#include <cstdarg>
-
-double hypotenuse(double side1, ...);
-
-// ----
-
-int main()
-{
- double diag = hypotenuse(3.0, 4.0);
-}
-
-// ----
-
-double hypotenuse(double side1, ...)
-{
- // More details available in the corresponding section of PLEAC-C/Posix/GNU
- va_list ap;
- va_start(ap, side1);
- double side2 = va_arg(ap, double);
- va_end(ap);
-
- return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
-}
-
-// ----------------------------
-
-// An example using default arguments appears below
-
-#include <cmath>
-
-// Specify default argument values in declaration
-// Note: This may be done in either of the declaration or the definition [not both], but it
-// makes more sense to do so in the declaration since these are usually placed in header files
-// which may be included in several source files. The default argument values would need to be
-// known in all those locations
-double hypotenuse(double side1 = 3.0, double side2 = 4.0);
-
-// ----
-
-int main()
-{
- // All arguments specified
- double diag = hypotenuse(3.0, 4.0);
-
- // Both calls utilise default argument value(s)
- diag = hypotenuse(3.0);
-
- diag = hypotenuse();
-}
-
-// ----
-
-double hypotenuse(double side1, double side2)
-{
- return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
-}
-
-// ----------------------------
-
-// A [very contrived, not very practical] example using function overloading appears below
-
-#include <cmath>
-
-double hypotenuse(double side1, double side2);
-double hypotenuse(double side1);
-double hypotenuse();
-
-// ----
-
-int main()
-{
- // Call version (1)
- double diag = hypotenuse(3.0, 4.0);
-
- // Call version (2)
- diag = hypotenuse(3.0);
-
- // Call version (3)
- diag = hypotenuse();
-}
-
-// ----
-
-// (1)
-double hypotenuse(double side1, double side2)
-{
- return std::sqrt(std::pow(side1, 2.0) + std::pow(side2, 2.0));
-}
-
-// (2)
-double hypotenuse(double side1)
-{
- return std::sqrt(std::pow(side1, 2.0) + std::pow(4.0, 2.0));
-}
-
-// (3)
-double hypotenuse()
-{
- return std::sqrt(std::pow(3.0, 2.0) + std::pow(4.0, 2.0));
-}
-
-// ----------------------------
-
-#include <cstddef>
-#include <vector>
-
-std::vector<int> int_all(const double arr[], size_t arrsize);
-std::vector<int> int_all(const std::vector<double>& arr);
-
-// ----
-
-int main()
-{
- // Load vectors from built-in arrays, or use Boost 'assign' library
- const double nums[] = {1.4, 3.5, 6.7};
- const size_t arrsize = sizeof(nums) / sizeof(nums[0]);
-
- // Conversion effected at vector creation time
- std::vector<int> ints = int_all(nums, arrsize);
-
- // Vector -> vector copy / conversion
- ints = int_all(std::vector<double>(nums, nums + arrsize));
-}
-
-// ----
-
-std::vector<int> int_all(const double arr[], size_t arrsize)
-{
- return std::vector<int>(arr, arr + arrsize);
-}
-
-std::vector<int> int_all(const std::vector<double>& arr)
-{
- std::vector<int> r;
- r.assign(arr.begin(), arr.end()); // Type safe element copying
- return r;
-}
-
-// ----------------------------
-
-#include <algorithm>
-#include <vector>
-
-#include <cmath>
-#include <cstddef>
-
-void trunc_em(std::vector<double>& arr);
-
-// ----
-
-int main()
-{
- // Load vectors from built-in arrays, or use Boost 'assign' library
- const double nums[] = {1.4, 3.5, 6.7};
- const size_t arrsize = sizeof(nums) / sizeof(nums[0]);
-
- std::vector<double> numsv(nums, nums + arrsize);
-
- trunc_em(numsv);
-}
-
-// ----
-
-void trunc_em(std::vector<double>& arr)
-{
- // Replace each element with the value returned by applying 'floor' to that element
- std::transform(arr.begin(), arr.end(), arr.begin(), floor);
-}
-
-// @@PLEAC@@_10.2
-// Variables declared within a function body are local to that function, and those declared
-// outside a function body [and not as part of a class / struct definition, or enclosed within
-// a namespace] are global, that is, are visible throughout the executable unless their
-// visibility has been restricted to the source file in which they are defined via enclosing
-// them within an anonymous namespace [which has the same effect as using the 'static' keyword,
-// in this same context, in the C language]
-
-#include <vector>
-
-void somefunc()
-{
- // All these variables are local to this function
- int variable, another;
-
- std::vector<int> vec(5);
-
- ; // ...
-}
-
-// ----------------------------
-
-// A couple of generic, type-safe type conversion helpers. The Boost Library sports a conversion
-// library at: http://www.boost.org/libs/conversion/index.html
-
-#include <sstream>
-#include <string>
-
-class bad_conversion {};
-
-template<typename T> T fromString(const std::string& s)
-{
- std::istringstream iss(s);
- T t; iss >> t;
- if (!iss) throw bad_conversion();
- return t;
-}
-
-template<typename T> std::string toString(const T& t)
-{
- std::ostringstream oss;
- oss << t << std::ends;
- if (!oss) throw bad_conversion();
- return std::string(oss.str());
-}
-
-// ------------
-
-#include <string>
-
-// File scope variables
-namespace
-{
- std::string name;
- int age, c, condition;
-}
-
-void run_check();
-void check_x(int x);
-
-// ----
-
-// An alternative, C++-specific approach, to command-line handling and type conversion
-// may be seen at: http://www.boost.org/libs/conversion/lexical_cast.htm
-
-int main(int argc, char* argv[])
-{
- name.assign(argv[1]);
-
- try
- {
- age = fromString<int>(argv[2]);
- }
-
- catch (const bad_conversion& e)
- {
- ; // ... handle conversion error ...
- }
-
- check_x(age);
-}
-
-// ------------
-
-void run_check()
-{
- // Full access to file scope variables
- condition = 1;
- // ...
-}
-
-void check_x(int x)
-{
- // Full access to file scope variables
- std::string y("whatever");
-
- run_check();
-
- // 'condition' updated by 'run_check'
- if (condition)
- {
- ; // ...
- }
-}
-
-// @@PLEAC@@_10.3
-// Standard C++, owing to its C heritage, allows the creation of 'persistent private variables',
-// via use of the 'static' keyword. For more details about this, and illustrative code examples,
-// refer to this same section in PLEAC-C/Posix/GNU. Standard C++-specific methods of perfoming
-// this task involve use of the 'namespace' facility, or creating a class containing 'static'
-// members and using access specifiers to restrict access
-
-// This example replaces the 'static' keyword with use of an anonymous namespace to force
-// 'variable' to have file scope, and be visible only within the 'mysubs.cpp file. It is
-// therefore both persistant [because it is a global variable] and private [because it is
-// visible only to functions defined within the same source file]
-
-// File: 'mysubs.h'
-void mysub(void);
-void reset(void);
-
-// ----
-
-// File: 'mysubs.cpp'
-namespace
-{
- int variable = 1;
-}
-
-void mysub(void)
-{
- ; // ... do something with 'variable' ...
-}
-
-void reset(void) { variable = 1; }
-
-// ----
-
-// File: 'test.cpp'
-#include "mysubs.h"
-
-int main()
-{
- // 'variable' is not accessable here
-
- // Call 'mysub', which can access 'variable'
- mysub();
-
- // Call 'reset' which sets 'variable' to 1
- reset();
-}
-
-// ------------
-
-// This example is similar to the previous one in using an anonymous namespace to restrict
-// variable visibility. It goes further, hoewever, grouping logically related items within
-// a named namespace, thus ensuring access to those items is controlled [i.e. requires
-// qualification, or a 'using' declaration or directive]
-
-// File: 'counter.h'
-namespace cnt
-{
- int increment();
- int decrement();
-}
-
-// ----
-
-// File: 'counter.cpp'
-namespace cnt
-{
- // Ensures 'counter' is visible only within the current source file
- namespace { int counter = 0; }
-
- void reset(int v = 0) { counter = v; }
-
- int increment() { return ++counter; }
- int decrement() { return --counter; }
-}
-
-// ----
-
-// File: 'test.cpp'
-#include <iostream>
-#include "counter.h"
-
-int main()
-{
- // Following line is illegal because 'cnt::counter' is private to the 'counter.cpp' file
- // int c = cnt::counter;
-
- int a = cnt::increment();
- std::cout << a << std::endl;
-
- a = cnt::decrement();
- std::cout << a << std::endl;
-}
-
-// ------------
-
-// This example sees a class containing 'static' members and using access specifiers to
-// restrict access to those members. Since all the members are static, this class is not
-// meant to be instantiated [i.e. objects created from it - it can be done, but they would
-// all be the exact same object :)], but merely uses the 'class' facility to encapsulate
-// [i.e. group together] and allow selective access [i.e. hide some parts, allow access to
-// others]. For Design Pattern afficiandos, this is a crude example of the Singleton Pattern
-
-// File: 'counter.h'
-class Counter
-{
-public:
- static int increment();
- static int decrement();
-private:
- static int counter;
-};
-
-// ----
-
-// File: 'counter.cpp'
-#include "counter.h"
-
-int Counter::increment() { return ++counter; }
-int Counter::decrement() { return --counter; }
-
-int Counter::counter = 0;
-
-// ----
-
-// File: 'test.cpp'
-#include <iostream>
-#include "counter.h"
-
-int main()
-{
- int a = Counter::increment();
- std::cout << a << std::endl;
-
- a = Counter::decrement();
- std::cout << a << std::endl;
-}
-
-// @@PLEAC@@_10.4
-// Standard C++ offers no facility for performing adhoc, runtime stack inspection; therefore,
-// information such as the currently-executing function name, cannot be obtained. Now, this
-// isn't to say that such facilities don't exist [since, after all, a symbolic debugger works
-// by doing just this - stack inspection, among other things], but that such features are, for
-// native code compiled languages like C++, 'extra-language' and development tool-specific
-
-// @@PLEAC@@_10.5
-// Standard C++ supports both
-// * 'pass-by-value': a copy of an argument is passed when calling a function; in this way
-// the original is safe from modification, but a copying overhead is incurred which may
-// adversely affect performance
-// * 'pass-by-reference': the address of an argument is passed when calling a function;
-// allows the original to be modified, and incurrs no performance penalty from copying
-//
-// The 'pass-by-value' mechanism works in the same way as in the Standard C language [see
-// corresponding section in PLEAC-C/Posix/GNU]. The 'pass-by-reference' mechanism provides
-// the same functionality as passing a pointer-to-a-pointer-to-an-argument, but without the
-// complications arising from having to correctly dereference. Using a reference to a non-const
-// item allows:
-// * The item's state to be modified i.e. if an object was passed, it can be mutated [effect
-// can be mimiced by passing a pointer to the item]
-// * The item, itself, can be replaced with a new item i.e. the memory location to which the
-// reference refers is updated [effect can be mimiced by passing a pointer-to-a-pointer to
-// the item]
-
-#include <cstddef>
-#include <vector>
-
-// 'pass-by-value': a copy of each vector is passed as an argument
-// void array_diff(const std::vector<int> arr1, const std::vector<int> arr2);
-
-// 'pass-by-reference': the address of each vector is passed as an argument. Some variants:
-// * Disallow both vector replacement and alteration of its contents
-// void array_diff(const std::vector<const int>& arr1, const std::vector<const int>& arr2);
-// * Disallow vector replacement only
-// void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2);
-// * Disallow alteration of vector contents only
-// void array_diff(std::vector<const int>& arr1, std::vector<const int>& arr2);
-// * Allow replacement / alteration
-// void array_diff(std::vector<int>& arr1, std::vector<int>& arr2);
-
-void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2);
-
-// ----
-
-int main()
-{
- // Load vectors from built-in arrays, or use Boost 'assign' library
- const int arr1[] = {1, 2, 3}, arr2[] = {4, 5, 6};
- const size_t arrsize = 3;
-
- // Function call is the same whether 'array_diff' is declared to be 'pass-by-value'
- // or 'pass-by-reference'
- array_diff(std::vector<int>(arr1, arr1 + arrsize), std::vector<int>(arr2, arr2 + arrsize));
-}
-
-// ----
-
-// void array_diff(const std::vector<int> arr1, const std::vector<int> arr2)
-// {
-// ; // 'arr1' and 'arr2' are copies of the originals
-// }
-
-void array_diff(const std::vector<int>& arr1, const std::vector<int>& arr2)
-{
- ; // 'arr1' and 'arr2' are references to the originals
-}
-
-// ----------------------------
-
-#include <cstddef>
-
-#include <algorithm>
-#include <functional>
-#include <vector>
-
-std::vector<int> add_vecpair(const std::vector<int>& arr1, const std::vector<int>& arr2);
-
-// ----
-
-int main()
-{
- // Load vectors from built-in arrays, or use Boost 'assign' library
- const int aa[] = {1, 2}, ba[] = {5, 8};
- size_t arrsize = 2;
-
- const std::vector<int> a(aa, aa + arrsize), b(ba, ba + arrsize);
-
- std::vector<int> c = add_vecpair(a, b);
-}
-
-// ----
-
-std::vector<int> add_vecpair(const std::vector<int>& arr1, const std::vector<int>& arr2)
-{
- std::vector<int> retvec; retvec.reserve(arr1.size());
- std::transform(arr1.begin(), arr1.end(), arr2.begin(), back_inserter(retvec), std::plus<int>());
- return retvec;
-}
-
-// @@PLEAC@@_10.6
-// Please refer to the corresponding section in PLEAC-C/Posix/GNU since the points raised there
-// apply to C++ also. Examples here don't so much illustrate C++'s handling of 'return context'
-// as much as how disparate types might be handled in a reasonably uniform manner
-
-// Here, 'mysub' is implemented as a function template, and its return type varies with the
-// argument type. In most cases the compiler is able to infer the return type from the
-// argument, however, it is possible to pass the type as a template parameter. Note this
-// code operates at compile-time, as does any template-only code
-
-#include <cstddef>
-
-#include <string>
-#include <vector>
-
-template <typename T> T mysub(const T& t) { return t; }
-
-// ----
-
-int main()
-{
- // 1. Type information inferred by compiler
- int i = mysub(5);
-
- double d = mysub(7.6);
-
- const int arr[] = {1, 2, 3};
- const size_t arrsize = sizeof(arr) / sizeof(arr[0]);
-
- std::vector<int> v = mysub(std::vector<int>(arr, arr + arrsize));
-
- // 2. Type information provided by user
- // Pass a 'const char*' argument and specify type information in the call
- std::string s = mysub<std::string>("xyz");
-
- // Could avoid specifying type information by passing a 'std::string' argument
- // std::string s = mysub(std::string("xyz"));
-}
-
-// ----------------------------
-
-// This is a variant on the previous example that uses the Boost Library's 'any' type as a
-// generic 'stub' type
-
-#include <string>
-#include <vector>
-
-#include <boost/any.hpp>
-
-template <typename T> boost::any mysub(const T& t) { return boost::any(t); }
-
-// ----
-
-int main()
-{
- std::vector<boost::any> any;
-
- // Add various types [encapsulated in 'any' objects] to the container
- any.push_back(mysub(5));
- any.push_back(mysub(7.6));
- any.push_back(mysub(std::vector<int>(5, 5)));
- any.push_back(mysub(std::string("xyz")));
-
- // Extract the various types from the container by appropriately casting the relevant
- // 'any' object
- int i = boost::any_cast<int>(any[0]);
- double d = boost::any_cast<double>(any[1]);
- std::vector<int> v = boost::any_cast< std::vector<int> >(any[2]);
- std::string s = boost::any_cast<std::string>(any[3]);
-}
-
-// @@PLEAC@@_10.7
-// Just like the C language, C++ offers no support for named / keyword parameters. It is of
-// course possible to mimic such functionality the same way it is done in C [see corresponding
-// section in PLEAC-C/Posix/GNU], the most obvious means being by passing a set of key/value
-// pairs in a std::map. This will not be shown here. Instead, two quite C++-specific examples
-// will be provided, based on:
-//
-// * Named Parameter Idiom [see: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18]
-// * Boost 'parameter' Library [see: http://www.boost.org/libs/parameter/doc/html/index.html]
-
-#include <iostream>
-#include <map>
-
-class TimeEntry
-{
-public:
- explicit TimeEntry(int value = 0, char dim = 's');
-
- bool operator<(const TimeEntry& right) const;
-
- friend std::ostream& operator<<(std::ostream& out, const TimeEntry& t);
-
-private:
- int value_;
- char dim_;
-};
-
-typedef std::pair<const int, TimeEntry> TENTRY;
-typedef std::map<const int, TimeEntry> TIMETBL;
-
-class RaceTime
-{
-public:
- const static int START_TIME, FINISH_TIME, INCR_TIME;
-
-public:
- explicit RaceTime();
-
- RaceTime& start_time(const TimeEntry& time);
- RaceTime& finish_time(const TimeEntry& time);
- RaceTime& incr_time(const TimeEntry& time);
-
- friend std::ostream& operator<<(std::ostream& out, const RaceTime& r);
-
-private:
- TIMETBL timetbl_;
-};
-
-const int RaceTime::START_TIME = 0, RaceTime::FINISH_TIME = 1, RaceTime::INCR_TIME = 2;
-
-void the_func(const RaceTime& r);
-
-// ----
-
-int main()
-{
- the_func(RaceTime().start_time(TimeEntry(20, 's')).finish_time(TimeEntry(5, 'm')).incr_time(TimeEntry(5, 's')));
-
- the_func(RaceTime().start_time(TimeEntry(5, 'm')).finish_time(TimeEntry(30, 'm')));
-
- the_func(RaceTime().start_time(TimeEntry(30, 'm')));
-}
-
-// ----
-
-std::ostream& operator<<(std::ostream& out, const TimeEntry& t)
-{
- out << t.value_ << t.dim_; return out;
-}
-
-std::ostream& operator<<(std::ostream& out, const RaceTime& r)
-{
- RaceTime& r_ = const_cast<RaceTime&>(r);
-
- out << "start_time: " << r_.timetbl_[RaceTime::START_TIME]
- << "\nfinish_time: " << r_.timetbl_[RaceTime::FINISH_TIME]
- << "\nincr_time: " << r_.timetbl_[RaceTime::INCR_TIME];
-
- return out;
-}
-
-TimeEntry::TimeEntry(int value, char dim) : value_(value), dim_(dim) {}
-
-bool TimeEntry::operator<(const TimeEntry& right) const
-{
- return (dim_ == right.dim_) ? (value_ < right.value_) : !(dim_ < right.dim_);
-}
-
-RaceTime::RaceTime()
-{
- timetbl_.insert(TENTRY(START_TIME, TimeEntry(0, 's')));
- timetbl_.insert(TENTRY(FINISH_TIME, TimeEntry(0, 's')));
- timetbl_.insert(TENTRY(INCR_TIME, TimeEntry(0, 's')));
-}
-
-RaceTime& RaceTime::start_time(const TimeEntry& time)
-{
- timetbl_[START_TIME] = time; return *this;
-}
-
-RaceTime& RaceTime::finish_time(const TimeEntry& time)
-{
- timetbl_[FINISH_TIME] = time; return *this;
-}
-
-RaceTime& RaceTime::incr_time(const TimeEntry& time)
-{
- timetbl_[INCR_TIME] = time; return *this;
-}
-
-void the_func(const RaceTime& r)
-{
- std::cout << r << std::endl;
-}
-
-// ----------------------------
-
-// The Boost 'parameter' library requires a significant amount of setup code to be written,
-// much more than this section warrants. My recommendation is to read carefully through the
-// tutorial to determine whether a problem for which it is being considered justifies all
-// the setup.
-
-// @@PLEAC@@_10.8
-// The Boost 'tuple' Library also allows multiple assignment to variables, including the
-// selective skipping of return values
-
-#include <iostream>
-
-#include <boost/tuple/tuple.hpp>
-
-typedef boost::tuple<int, int, int> T3;
-
-T3 func();
-
-// ----
-
-int main()
-{
- int a = 6, b = 7, c = 8;
- std::cout << a << ',' << b << ',' << c << std::endl;
-
- // A tuple of references to the referred variables is created; the values
- // captured from the returned tuple are thus multiply-assigned to them
- boost::tie(a, b, c) = func();
- std::cout << a << ',' << b << ',' << c << std::endl;
-
- // Variables can still be individually referenced
- a = 11; b = 23; c = 56;
- std::cout << a << ',' << b << ',' << c << std::endl;
-
- // Return values may be ignored; affected variables retain existing values
- boost::tie(a, boost::tuples::ignore, c) = func();
- std::cout << a << ',' << b << ',' << c << std::endl;
-}
-
-// ----
-
-T3 func() { return T3(3, 6, 9); }
-
-// @@PLEAC@@_10.9
-// Like Standard C, C++ allows only the return of a single value. The return of multiple values
-// *can*, however, be simulated by packaging them within an aggregate type [as in C], or a
-// custom class, or one of the STL containers like std::vector. Probably the most robust, and
-// [pseudo]-standardised, approach is to use the Boost 'tuple' Library, as will be done in this
-// section. Notes:
-// * Use made of Boost 'assign' Library to simplify container loading; this is a *very* handy
-// library
-// * Use made of Boost 'any' Library to make containers heterogenous; 'variant' Library is
-// similar, and is more appropriate where type-safe container traversal is envisaged e.g.
-// for printing
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include <boost/any.hpp>
-#include <boost/tuple/tuple.hpp>
-
-#include <boost/assign/std/vector.hpp>
-#include <boost/assign/list_inserter.hpp>
-
-typedef std::vector<boost::any> ARRAY;
-typedef std::map<std::string, boost::any> HASH;
-typedef boost::tuple<ARRAY, HASH> ARRAY_HASH;
-
-ARRAY_HASH some_func(const ARRAY& array, const HASH& hash);
-
-// ----
-
-int main()
-{
- // Load containers using Boost 'assign' Library
- using namespace boost::assign;
- ARRAY array; array += 1, 2, 3, 4, 5;
- HASH hash; insert(hash) ("k1", 1) ("k2", 2) ("k3", 3);
-
- // Pass arguments to 'somefunc' and retrieve them as members of a tuple
- ARRAY_HASH refs = some_func(array, hash);
-
- // Retrieve copy of 'array' from tuple
- ARRAY ret_array = boost::get<0>(refs);
-
- // Retrieve copy of 'hash' from tuple
- HASH ret_hash = boost::get<1>(refs);
-}
-
-// ----
-
-ARRAY_HASH some_func(const ARRAY& array, const HASH& hash)
-{
- ; // ... do something with 'array' and 'hash'
-
- return ARRAY_HASH(array, hash);
-}
-
-// @@PLEAC@@_10.10
-// Like function calls in Standard C, function calls in C++ need to conform to signature
-// requirements; a function call must match its declaration with the same number, and type,
-// of arguments passed [includes implicitly-passed default arguments], and the same return
-// value type. Thus, unlike Perl, a function declared to return a value *must* do so, thus
-// cannot 'return nothing' to indicate failure.
-// Whilst in Standard C certain conventions like returning NULL pointers, or returning -1, to
-// indicate the 'failure' of a task [i.e. function return codes are checked, and control
-// proceeds conditionally] are used, Standard C++ sports facilities which lessen the need for
-// dong the same. Specifically, C++ offers:
-// * Built-in exception handling which can be used to detect [and perhaps recover from],
-// all manner of unusual, or erroneous / problematic situations. One recommended use is
-// to avoid writing code that performs a lot of return code checking
-// * Native OOP support allows use of the Null Object Design Pattern. Put simply, rather than
-// than checking return codes then deciding on an action, an object with some predefined
-// default behaviour is returned / used where an unusual / erroneous / problematic situation
-// is encountered. This approach could be as simple as having some sort of default base
-// class member function behaviour, or as complex as having a diagnostic-laden object created
-// * Functions can still return 'error-indicating entities', but rather than primitive types
-// like 'int's or NULL pointers, complex objects can be returned. For example, the Boost
-// Library sports a number of such types:
-// - 'tuple'
-// - 'any', 'variant' and 'optional'
-// - 'tribool' [true, false, indeterminate]
-
-// Exception Handling Example
-
-class XYZ_exception {};
-
-int func();
-
-// ----
-
-int main()
-{
- int valid_value = 0;
-
- try
- {
- ; // ...
-
- valid_value = func();
-
- ; // ...
- }
-
- catch(const XYZ_exception& e)
- {
- ; // ...
- }
-}
-
-// ----
-
-int func()
-{
- bool error_detected = false;
- int valid_value;
-
- ; // ...
-
- if (error_detected) throw XYZ_exception();
-
- ; // ...
-
- return valid_value;
-}
-
-// ------------
-
-// Null Object Design Pattern Example
-
-#include <iostream>
-
-class Value
-{
-public:
- virtual void do_something() = 0;
-};
-
-class NullValue : public Value
-{
-public:
- virtual void do_something();
-};
-
-class ValidValue : public Value
-{
-public:
- virtual void do_something();
-};
-
-Value* func();
-
-// ----
-
-int main()
-{
- // Error checking is performed within 'func'. However, regardless of the outcome, an
- // object of 'Value' type is returned which possesses similar behaviour, though appropriate
- // to whether processing was successful or not. In this way no error checking is needed
- // outside of 'func'
- Value* v = func();
-
- v->do_something();
-
- delete v;
-}
-
-// ----
-
-void NullValue::do_something()
-{
- std::cout << "*null*" << std::endl;
-}
-
-void ValidValue::do_something()
-{
- std::cout << "valid" << std::endl;
-}
-
-Value* func()
-{
- bool error_detected = true;
-
- ; // ...
-
- if (error_detected) return new NullValue;
-
- ; // ...
-
- return new ValidValue;
-}
-
-// ----------------------------
-
-// The Boost 'optional' library has many uses, but in the current context, one is of particular
-// use: returning a specified type [thus satisfying language requirements], but whose value
-// may be 'set' [if the function succeeded] or 'unset' [if it failed], and this condition very
-// easily checked
-
-#include <iostream>
-
-#include <cstdlib>
-
-#include <string>
-#include <vector>
-#include <map>
-
-#include <boost/optional/optional.hpp>
-
-class func_fail
-{
-public:
- explicit func_fail(const std::string& msg) : msg_(msg) {}
- const std::string& msg() const { return msg_; }
-private:
- const std::string msg_;
-};
-
-// ----
-
-void die(const std::string& msg);
-
-boost::optional<int> sfunc();
-boost::optional< std::vector<int> > afunc();
-boost::optional< std::map<std::string, int> > hfunc();
-
-// ------------
-
-int main()
-{
- try
- {
- boost::optional<int> s;
- boost::optional< std::vector<int> > a;
- boost::optional< std::map<std::string, int> > h;
-
- if (!(s = sfunc())) throw func_fail("'sfunc' failed");
- if (!(a = afunc())) throw func_fail("'afunc' failed");
- if (!(h = hfunc())) throw func_fail("'hfunc' failed");
-
- ; // ... do stuff with 's', 'a', and 'h' ...
- int scalar = *s;
-
- ; // ...
- }
-
- catch (const func_fail& e)
- {
- die(e.msg());
- }
-
- ; // ... other code executed if no error above ...
-}
-
-// ------------
-
-void die(const std::string& msg)
-{
- std::cerr << msg << std::endl;
-
- // Should only be used if all objects in the originating local scope have been destroyed
- std::exit(EXIT_FAILURE);
-}
-
-// ----
-
-boost::optional<int> sfunc()
-{
- bool error_detected = true;
-
- int valid_int_value;
-
- ; // ...
-
- if (error_detected) return boost::optional<int>();
-
- ; // ...
-
- return boost::optional<int>(valid_int_value);
-}
-
-boost::optional< std::vector<int> > afunc()
-{
- // ... code not shown ...
-
- return boost::optional< std::vector<int> >();
-
- // ... code not shown
-}
-
-boost::optional< std::map<std::string, int> > hfunc()
-{
- // ... code not shown ...
-
- return boost::optional< std::map<std::string, int> >();
-
- // ... code not shown ...
-}
-
-// @@PLEAC@@_10.11
-// Whilst in Perl function prototyping is optional, this is not the case in C++, where it is
-// necessary to:
-// * Declare a function before use; this could either be a function declaration separate from
-// the function definition, or the function definition itself which serves as its own
-// declaration
-// * Specify both parameter positional and type information; parameter names are optional in
-// declarations, mandatory in definitions
-// * Specify return type
-
-#include <iostream>
-#include <vector>
-
-// Function Declaration
-std::vector<int> myfunc(int arg1, int arg2); // Also possible: std::vector<int> myfunc(int, int);
-
-// ----
-
-int main()
-{
- // Call function with all required arguments; this is the only calling method
- // [except for calling via function pointer which still needs all arguments supplied]
- std::vector<int> results = myfunc(3, 5);
-
- // Let's look at our return array's contents
- std::cout << results[0] << ':' << results[1] << std::endl;
-}
-
-// ----
-
-// Function Definition
-std::vector<int> myfunc(int arg1, int arg2)
-{
- std::vector<int> r;
-
- std::back_inserter(r) = arg1;
- std::back_inserter(r) = arg2;
-
- return r;
-}
-
-// ------------
-
-// A version on the above code that is generic, that is, making use of the C++ template
-// mechanism to work with any type
-
-#include <iostream>
-#include <vector>
-
-// Function Declaration
-template <class T> std::vector<T> myfunc(const T& arg1, const T& arg2);
-
-// ----
-
-int main()
-{
- std::vector<int> results = myfunc(3, 5);
-
- std::cout << results[0] << ':' << results[1] << std::endl;
-}
-
-// ----
-
-// Function Definition
-template <class T> std::vector<T> myfunc(const T& arg1, const T& arg2)
-{
- std::vector<T> r;
-
- std::back_inserter(r) = arg1;
- std::back_inserter(r) = arg2;
-
- return r;
-}
-
-// ------------
-
-// Other Perl examples are omitted since there is no variation in C++ function calling or
-// parameter handling
-
-// @@PLEAC@@_10.12
-// One of the key, non-object oriented features of Standard C++ is its built-in support for
-// exceptions / exception handling. The feature is well-integrated into the language, including
-// a set of predefined exception classes included in, and used by, the Standard Library, is
-// quite easy to use, and helps the programmer write robust code provided certain conventions
-// are followed. On the downside, the C++ exception handling system is criticised for imposing
-// significant runtime overhead, as well as increasing executable code size [though this
-// varies considerably between CPU's, OS's, and compilers]. Please refer to the corresponding
-// section in PLEAC-C/Posix/GNU for pertinent reading references.
-//
-// The example code below matches the PLEAC-C/Posix/GNU example rather than the Perl code. Note:
-// * A very minimal, custom exception class is implemented; a more complex class, one richer in
-// diagnostic information, could have been implemented, or perhaps one based on a standard
-// exception class like 'std::exception'
-// * Ordinarily error / exception messages are directed to 'std::cerr' or 'std::clog'
-// * General recommendation is to throw 'temporaries' [via invoking a constructor],
-// and to 'catch' as const reference(s)
-// * Proper 'cleanup' is very important; consult a suitable book for guidance on writing
-// 'exception safe' code
-
-#include <iostream>
-#include <string>
-
-class FullmoonException
-{
-public:
- explicit FullmoonException(const std::string& msg) : msg_(msg) {}
-
- friend std::ostream& operator<<(std::ostream& out, const FullmoonException& e)
- {
- out << e.msg_; return out;
- }
-private:
- const std::string msg_;
-};
-
-// ----
-
-int main()
-{
- std::cout << "main - entry" << std::endl;
-
- try
- {
- std::cout << "try block - entry" << std::endl;
- std::cout << "... doing stuff ..." << std::endl;
-
- // if (... error condition detected ...)
- throw FullmoonException("... the problem description ...");
-
- // Control never gets here ...
- std::cout << "try block - end" << std::endl;
- }
-
- catch(const FullmoonException& e)
- {
- std::cout << "Caught a'Fullmoon' exception. Message: "
- << "[" << e << "]"
- << std::endl;
- }
-
- catch(...)
- {
- std::cout << "Caught an unknown exceptione" << std::endl;
- }
-
- // Control gets here regardless of whether an exception is thrown or not
- std::cout << "main - end" << std::endl;
-}
-
-// @@PLEAC@@_10.13
-// Standard C++ sports a namespace facility which allows an application to be divided into
-// logical sub-systems, each of which operates within its own scope. Put very simply, the same
-// identifiers [i.e. name of types, objects, and functions] may be each used in a namespace
-// without fear of a nameclash occurring when logical sub-systems are variously combined as
-// an application. The name-clash problem is inherent in single-namespace languages like C; it
-// often occurs when several third-party libraries are used [a common occurrence in C], or
-// when an application scales up. The remedy is to rename identifiers, or, in the case of
-// functions that cannot be renamed, to wrap them up in other functions in a separate source
-// file. Of course the problem may be minimised via strict adherence to naming conventions.
-//
-// The C++ namespace facility is important, too, because it avoids the need to utilise certain
-// C language practices, in particular:
-// * Use of, possibly, 'clumsy' naming conventions [as described above]
-// * Partition an application by separating logically-related items into separate source
-// files. Namespaces cross file boundaries, so items may reside in several source files
-// and still comprise a single, logical sub-system
-// * Anonymous namespaces avoid use of the 'static' keyword in creating file scope globals
-
-// Global variable
-int age = 18;
-
-// ----
-
-void print_age()
-{
- // Global value, 'age', is accessed
- std::cout << "Age is " << age << std::endl;
-}
-
-// ------------
-
-int main()
-{
- // A local variable named, 'age' will act to 'shadow' the globally
- // defined version, thus any changes to, 'age', will not affect
- // the global version
- int age = 5;
-
- // Prints 18, the current value of the global version
- print_age();
-
- // Local version is altered, *not* global version
- age = 23;
-
- // Prints 18, the current value of the global version
- print_age();
-}
-
-// ----------------------------
-
-// Global variable
-int age = 18;
-
-// ----
-
-void print_age()
-{
- // Global value, 'age', is accessed
- std::cout << "Age is " << age << std::endl;
-}
-
-// ------------
-
-int main()
-{
- // Here no local version declared: any changes affect global version
- age = 5;
-
- // Prints 5, the new value of the global version
- print_age();
-
- // Global version again altered
- age = 23;
-
- // Prints 23, the new value of the global version
- print_age();
-}
-
-// ----------------------------
-
-// Global variable
-int age = 18;
-
-// ----
-
-void print_age()
-{
- // Global value, 'age', is accessed
- std::cout << "Age is " << age << std::endl;
-}
-
-// ------------
-
-int main()
-{
- // Global version value saved into local version
- int age = ::age;
-
- // Prints 18, the new value of the global version
- print_age();
-
- // Global version this time altered
- ::age = 23;
-
- // Prints 23, the new value of the global version
- print_age();
-
- // Global version value restored from saved local version
- ::age = age;
-
- // Prints 18, the restored value of the global version
- print_age();
-}
-
-// @@PLEAC@@_10.14
-// Please refer to the corresponding section in PLEAC-C/Posix/GNU since the points raised there
-// about functions and function pointers apply equally to Standard C++ [briefly: functions
-// cannot be redefined; several same-signature functions may be called via the same function
-// pointer variable; code cannot be generated 'on-the-fly' (well, not without the use of
-// several external tools, making it an extra-language, not integral, feature)].
-// @@INCOMPLETE@@
-
-// @@PLEAC@@_10.15
-// Please refer to the corresponding section in PLEAC-C/Posix/GNU since all the points raised
-// there apply equally to Standard C++ [briefly: undefined function calls are compiler-detected
-// errors; function-pointer-based calls can't be checked for integrity].
-// @@INCOMPLETE@@
-
-// @@PLEAC@@_10.16
-// Standard C++ does not support either simple nested functions or closures, therefore the
-// example cannot be implemented exactly as per the Perl code
-
-/* ===
-int outer(int arg)
-{
- int x = arg + 35;
-
- // *** wrong - illegal C++ ***
- int inner() { return x * 19; }
-
- return x + inner();
-}
-=== */
-
-// The problem may, of course, be solved by defining two functions using parameter passing
-// where appropriate, but this is contrary to the intent of the original Perl code
-int inner(int x)
-{
- return x * 19;
-}
-
-int outer(int arg)
-{
- int x = arg + 35;
- return x + inner(x);
-}
-
-// An arguably better [but far more complicated] approach is to encapsulate all items within
-// a namespace, but again, is an approach that is counter the intent of the original Perl code
-#include <iostream>
-
-namespace nst
-{
- int x;
- int inner();
- int outer(int arg);
-}
-
-// ----
-
-int main()
-{
- std::cout << nst::outer(3) << std::endl;
-}
-
-// ----
-
-int nst::inner()
-{
- return nst::x * 19;
-}
-
-int nst::outer(int arg)
-{
- nst::x = arg + 35;
- return nst::x + nst::inner();
-}
-
-// Another way to solve this problem and avoiding the use of an external function, is to
-// create a local type and instantiate an object passing any required environment context
-// to the constructor. Then, what appears as a parameterless nested function call, can be
-// effected using 'operator()'. This approach most closely matches the original Perl code
-
-int outer(int arg)
-{
- int x = arg + 35;
-
- // 'Inner' is what is known as a Functor or Function Object [or Command Design Pattern]; it
- // allows objects that capture state / context to be instantiated, and that state / context
- // used / retained / altered at multiple future times. Both the STL and Boost Libraries
- // provide extensive support these constructs
- struct Inner
- {
- int n_;
- explicit Inner(int n) : n_(n) {}
- int operator()() const { return n_ * 19; }
- } inner(x);
-
- return x + inner();
-}
-
-// @@PLEAC@@_10.17
-// @@INCOMPLETE@@
-// @@INCOMPLETE@@
-
diff --git a/test/scanners/cpp/suite.rb b/test/scanners/cpp/suite.rb deleted file mode 100644 index 7389d40..0000000 --- a/test/scanners/cpp/suite.rb +++ /dev/null @@ -1,2 +0,0 @@ -class Cpp < CodeRay::TestCase -end diff --git a/test/scanners/cpp/wedekind.expected.raydebug b/test/scanners/cpp/wedekind.expected.raydebug deleted file mode 100644 index e85226f..0000000 --- a/test/scanners/cpp/wedekind.expected.raydebug +++ /dev/null @@ -1,12 +0,0 @@ -reserved(template)operator(<) reserved(typename) ident(T) operator(>) -ident(T) ident(plus)operator(() directive(const) operator(&)ident(T) ident(x) operator(\)) -operator({) - reserved(return) operator(-)ident(x)operator(;) -operator(}) - -reserved(template)operator(<) reserved(typename) ident(T) operator(>) -reserved(class) class(image) -operator({) -directive(public)operator(:) - ident(image)operator(() directive(const) ident(image)operator(<) ident(T) operator(>) operator(&)ident(_image) operator(\)) operator({}) -operator(};) diff --git a/test/scanners/cpp/wedekind.in.cpp b/test/scanners/cpp/wedekind.in.cpp deleted file mode 100644 index 68b0dba..0000000 --- a/test/scanners/cpp/wedekind.in.cpp +++ /dev/null @@ -1,12 +0,0 @@ -template< typename T > -T plus( const &T x ) -{ - return -x; -} - -template< typename T > -class image -{ -public: - image( const image< T > &_image ) {} -}; |