summaryrefslogtreecommitdiff
path: root/test/scanners/cpp
diff options
context:
space:
mode:
authormurphy <murphy@rubychan.de>2010-04-14 23:59:03 +0000
committermurphy <murphy@rubychan.de>2010-04-14 23:59:03 +0000
commit200144dd009d33ff8334be24d0fb2cc91b3a87ab (patch)
treef46c939cd01b8d4165b5d9f3444c20e072b51408 /test/scanners/cpp
parent612a14e17bdae5dbb5b13cdceec797523725cbbe (diff)
downloadcoderay-200144dd009d33ff8334be24d0fb2cc91b3a87ab.tar.gz
Moving scanner tests into separate repository. The repository can be reached at http://svn.rubychan.de/coderay-scanner-tests/trunk.
Diffstat (limited to 'test/scanners/cpp')
-rw-r--r--test/scanners/cpp/elvis.expected.raydebug26
-rw-r--r--test/scanners/cpp/elvis.in.cpp26
-rw-r--r--test/scanners/cpp/eventmachine.expected.raydebug7035
-rw-r--r--test/scanners/cpp/eventmachine.in.cpp7035
-rw-r--r--test/scanners/cpp/pleac.expected.raydebug2041
-rw-r--r--test/scanners/cpp/pleac.in.cpp2041
-rw-r--r--test/scanners/cpp/suite.rb2
-rw-r--r--test/scanners/cpp/wedekind.expected.raydebug12
-rw-r--r--test/scanners/cpp/wedekind.in.cpp12
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 ) {}
-};