36 #include <arpa/inet.h>
37 #include <sys/socket.h>
40 using namespace basis;
53 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
74 class socket_data_amorph :
public amorph<socket_data> {};
78 class socket_minder_prompter :
public ethread
81 socket_minder_prompter(socket_minder &parent)
88 ~socket_minder_prompter() {
92 virtual void perform_activity(
void *
formal(ptr)) { _parent.snoozy_select(); }
95 socket_minder &_parent;
101 int event_type,
int message)
103 _parent_route(parent_route),
104 _event_type(event_type),
106 _socket_list(new socket_data_amorph),
111 _prompter(new socket_minder_prompter(*this))
137 for (
int i = 0; i < _socket_list->elements(); i++) {
140 if (i != _socket_list->elements() - 1)
141 to_return += parser_bits::platform_eol_to_chars();
157 for (
int p = 0; p < pending.
length(); p++) {
166 if (!ret || (!read_sox.
length() && !write_sox.
length()) ) {
175 for (
int r = 0; r < read_sox.
length(); r++) {
176 const int sock = read_sox[r];
188 for (
int w = 0; w < write_sox.
length(); w++) {
189 const int sock = write_sox[w];
205 for (
int i = 0; i < _socket_list->elements(); i++) {
223 for (
int i = 0; i < _socket_list->elements(); i++) {
224 if (_socket_list->borrow(i)->_socket == socket)
return true;
232 for (
int i = 0; i < _socket_list->elements(); i++)
233 if (_socket_list->borrow(i)->_socket == socket)
234 return _socket_list->borrow(i);
242 if (!to_unlock)
return;
248 bool connected_mode,
bool connection_pending)
262 _socket_list->append(new_data);
270 for (
int i = 0; i < _socket_list->elements(); i++) {
271 if (_socket_list->borrow(i)->_socket == socket) {
274 _socket_list->zap(i, i);
284 #ifdef DEBUG_SOCKET_MINDER
288 #ifdef DEBUG_SOCKET_MINDER
289 LOG(
astring(astring::SPRINTF,
"registering interest of %d for socket "
290 "%d.", interests, socket));
292 if (!harpo)
return false;
301 if (!harpo)
return false;
310 if (!harpo)
return false;
316 void socket_minder::fire_event(
int to_fire,
int at_whom,
327 _pending_sox->
insert(0, 1);
328 (*_pending_sox)[0] = to_put;
330 *_pending_sox += to_put;
337 if (!_pending_sox->
member(socket))
return false;
338 _pending_sox->
remove(socket);
345 if (!_pending_sox->
length())
return 0;
346 int to_return = _pending_sox->
get(0);
347 _pending_sox->
zap(0, 0);
353 FUNCDEF(
"handle_pending_connecters");
367 #ifdef DEBUG_SOCKET_MINDER
368 LOG(
a_sprintf(
"sending client SI_CONNECTED event on parent %d",
377 socklen_t sock_len =
sizeof(sock_addr);
378 int new_sock = int(::accept(to_peek.
_socket, &sock_addr, &sock_len));
381 LOG(
a_sprintf(
"accept got a client socket %d.", new_sock));
382 if (_pending_sox->
member(new_sock)) {
383 LOG(
a_sprintf(
"already have seen socket %d in pending!", new_sock));
385 *_pending_sox += new_sock;
386 #ifdef DEBUG_SOCKET_MINDER
387 LOG(
a_sprintf(
"sending server SI_CONNECTED event on parent %d",
392 }
else if (_pending_sox->
length()) {
432 fire_event(_message, _parent_route, to_peek.
_socket,
444 LOG(
"not supposed to try this when not connected yet...");
447 #ifdef DEBUG_SOCKET_MINDER
466 error_code = critical_events::system_error();
468 #ifdef DEBUG_SOCKET_MINDER
469 LOG(
a_sprintf(
"updating that %d bytes got sent out of %d to send.",
470 len_sent, to_send.
length()));
471 if (to_send.
length() != len_sent)
472 LOG(
a_sprintf(
"size to send (%d) not same as size sent (%d).",
473 to_send.
length(), len_sent));
476 to_send.
zap(0, len_sent - 1);
483 LOG(
astring(astring::SPRINTF,
"error on socket %d is %s.",
486 switch (error_code) {
491 LOG(
a_sprintf(
"due to %s condition, closing socket %d.",
493 fire_event(_message, _parent_route, to_poke.
_socket,
506 LOG(
"not supposed to try this when not connected yet...");
509 #ifdef DEBUG_SOCKET_MINDER
520 bool got_something =
true;
525 got_something =
false;
529 #ifdef DEBUG_SOCKET_MINDER
533 got_something =
true;
542 error_code = critical_events::system_error();
554 _socks->
close(deader);
562 #ifdef DEBUG_SOCKET_MINDER
569 fire_event(_message, _parent_route, to_poke.
_socket,
576 LOG(
astring(astring::SPRINTF,
"error on socket %d is %s.",
579 switch (error_code) {
584 LOG(
a_sprintf(
"due to %s condition, closing socket %d.",
586 fire_event(_message, _parent_route, to_poke.
_socket,
589 _socks->
close(deader);
a_sprintf is a specialization of astring that provides printf style support.
outcome insert(int index, int new_indices)
Adds "new_indices" new positions for objects into the array at "index".
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
const contents * observe() const
Returns a pointer to the underlying C array of data.
const contents & get(int index) const
Accesses individual objects stored in "this" at the "index" position.
int length() const
Returns the current reported length of the allocated C array.
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
int last() const
Returns the last valid element in the array.
Provides a dynamically resizable ASCII character string.
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
auto_synchronizer simplifies concurrent code by automatically unlocking.
A very common template for a dynamic array of bytes.
A simple object that wraps a templated array of ints.
void lock()
Clamps down on the mutex, if possible.
void unlock()
Gives up the possession of the mutex.
Models an OS-level event so we can represent activities occurring there.
Provides a platform-independent object for adding threads to a program.
Manages a collection of mailboxes and implements delivery routes for mail.
void drop_off(const structures::unique_int &id, letter *package)
sends a "package" on its way to the "id" via the registered route.
int close(basis::un_int &socket)
int select(basis::un_int socket, int selection_mode, int timeout=0) const
bool set_non_blocking(basis::un_int socket, bool non_blocking=true)
basis::astring text_form() const
basis::byte_array _receive_buffer
basis::byte_array _partially_received
timely::time_stamp _last_conn_alert
int _registered_interests
basis::byte_array _partially_sent
void get_sockets(basis::int_array &read_sox, basis::int_array &write_sox, basis::int_array &pending) const
bool is_connection_pending(int socket)
bool handle_pending_connecters(socket_data &to_peek)
void put_pending_server(int to_put, bool at_head)
bool set_connection_pending(int socket, bool pending)
bool remove_socket_data(int socket)
bool register_interest(int socket, int interests)
virtual bool evaluate_interest(socket_data &to_examine)
bool zap_pending_server(int socket)
socket_data * lock_socket_data(int socket)
void push_sends(socket_data &to_poke, int states)
bool add_socket_data(int socket, bool server, int server_socket, bool connected_mode, bool connection_pending)
void push_receives(socket_data &to_poke, int states)
basis::astring text_form() const
bool owns_socket(int socket) const
void unlock_socket_data(socket_data *to_unlock)
Helpful functions for interacting with TCP/IP stacks.
static basis::astring tcpip_error_name(int error_value)
A simple object that wraps a templated set of ints.
bool member(const contents &to_test) const
Returns true if the item "to_test" is a member of this set.
bool remove(const contents &to_remove)
Removes the item "to_remove" from the set.
Represents a point in time relative to the operating system startup time.
void reset()
sets the stamp time back to now.
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
#define NULL_POINTER
The value representing a pointer to nothing.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
unsigned int un_int
Abbreviated name for unsigned integers.
const int KILOBYTE
Number of bytes in a kilobyte.
A logger that sends to the console screen using the standard output device.
Provides access to the operating system's socket methods.
const int SOCKMIND_MAXIMUM_RECEIVES
const int MAXIMUM_TRANSFER_CHUNK
const int CONN_ALERT_INTERVAL
const int MULTI_SELECT_TIMEOUT
const int SOCKET_CHECK_INTERVAL
A dynamic container class that holds any kind of object via pointers.
#define SOCK_ECONNABORTED