32 #include <arpa/inet.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
55#define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
68#define RECOGNIZE_DISCO \
69 _client_bind = false; \
70 _was_connected = false
73#define ENSURE_HEALTH(retval) \
74 if (!was_connected()) return retval; \
75 if (!_socket) { RECOGNIZE_DISCO; return retval; }
77#define CHECK_BOGUS(retval) \
78 if (is_bogus()) { return retval; }
103 _was_connected(false),
109 _select_lock(new
mutex),
115 if ( (_type == BROADCAST) || (_type == UNICAST) ) {
118 }
else if ( (type == CONNECTED) || (type == BOGUS_SOCK) ) {
122 LOG(
a_sprintf(
"unknown socket type %d; failing out.", _type));
140 WHACK(_last_resolve);
142 _client_bind =
false;
159 to_return +=
" spocket: ";
161 to_return +=
"connected, ";
163 if (
was_connected()) to_return +=
"unconnected (was once), ";
164 else to_return +=
"never-connected, ";
166 to_return +=
a_sprintf(
"socket=%u, ", _socket);
168 to_return +=
a_sprintf(
"root-socket=%u, ", _server_socket);
182 switch (to_name.
value()) {
183 case NOT_SERVER:
return "NOT_SERVER";
196 _socks->
close(_socket);
199 if (_server_socket) {
201 LOG(
a_sprintf(
"closing server socket %d", _server_socket));
203 _socks->
close(_server_socket);
216 if (!_socket)
return false;
223 int ret = _socks->
select(_socket, sel_mode);
233 LOG(
"caught exception thrown from select, returning false.");
245 int ret = _socks->
select(_socket, mode, timeout);
263 int ret = _socks->
select(_socket, mode, timeout);
282 LOG(
"this object was already opened as a server!");
287 _was_connected =
false;
297 int sock_type = SOCK_STREAM;
298 int proto = IPPROTO_TCP;
301 sock_type = SOCK_DGRAM;
304 _socket = int(::socket(AF_INET, sock_type, proto));
307 LOG(
"Failed to open the client's connecting spocket.");
332 LOG(
"couldn't set watchdog timer on socket.");
359 sockaddr sock = _stack->
convert(*_cli_bind);
363 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
367 if (
negative(bind(_socket, &sock,
sizeof(sock)))) {
369 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
378 sockaddr sock = _stack->
convert(*_where);
382 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
386 if (
negative(bind(_socket, &sock,
sizeof(sock)))) {
388 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
392 _was_connected =
true;
398 sockaddr sock = _stack->
convert(*_where);
410 int sock_len =
sizeof(sock);
414 int ret =
::connect(_socket, &sock, sock_len);
433 LOG(
a_sprintf(
"Connect failed (error %s or %d) on address:",
450 LOG(
a_sprintf(
"socket %d connected to server.", _socket));
453 _was_connected =
true;
472 LOG(
"tried to accept on a client spocket.");
478 if (!_server_socket) {
479 _server_socket = int(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
486 LOG(
"Failed to open the serving spocket.");
492 LOG(
"Failed to mark the socket for re-use.");
495 sockaddr sock = _stack->
convert(*_where);
498 int sock_len =
sizeof(sock);
499 if (bind(_server_socket, (sockaddr *)&sock, sock_len) < 0) {
501 _socks->
close(_server_socket);
509 _socks->
close(_server_socket);
527 socklen_t sock_len =
sizeof(new_sock);
533 LOG(
astring(
"Accept got no client, with an error of ")
544 if (setsockopt(accepted, SOL_SOCKET, SO_KEEPALIVE, (
char *)&
sock_hop,
547 LOG(
"couldn't set watchdog timer on socket.");
561 *sock->_remote = _stack->
convert(new_sock);
562 sock->_socket = accepted;
563 sock->_server_socket = 0;
564 sock->_was_connected =
true;
581 len_sent =
::send(_socket, (
char *)buffer, size, 0);
585 LOG(
"No data went out on the spocket.");
592 LOG(
"would block, will try later...");
594 LOG(
"HEY HEY! some was sent but we were not counting it!!!");
600 +
" occurred during the send!");
604 LOG(
a_sprintf(
"forcing disconnect on socket %d.", _socket));
611 if (len_sent != size) {
614 LOG(
a_sprintf(
"sent %d bytes out of %d.", len_sent, size));
629 int size,
int &len_sent)
634 sockaddr dest = _stack->
convert(where_to);
635 int ret = sendto(_socket, (
char *)to_send, size, 0, &dest,
sizeof(dest));
659 if (to_return ==
OKAY)
660 buffer.
zap(size, buffer.
last());
674 int len = recv(_socket, (
char *)buffer, expected, 0);
684 }
else if (len < 0) {
687 LOG(
astring(
"The receive failed with an error ")
708 if (to_return ==
OKAY)
709 buffer.
zap(size, buffer.
last());
726 socklen_t fromlen =
sizeof(from);
727 int len = recvfrom(_socket, (
char *)buffer, expected, 0, &from, &fromlen);
740 LOG(
astring(
"The recvfrom failed with an error ")
746 where_from = _stack->
convert(from);
a_sprintf is a specialization of astring that provides printf style support.
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
const contents * observe() const
Returns a pointer to the underlying C array of data.
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".
outcome stuff(int length, contents *to_stuff) const
Copies at most "length" elements from this into the array "to_stuff".
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.
A very common template for a dynamic array of bytes.
Outcomes describe the state of completion for an operation.
static basis::astring system_error_text(basis::un_int error_to_show)
returns the OS's string form of the "error_to_show".
static basis::un_int system_error()
gets the most recent system error reported on this thread.
static const char * outcome_name(const basis::outcome &to_name)
this type of address describes a destination out on the internet.
basis::astring text_form() const
char hostname[MAXIMUM_HOSTNAME_LENGTH]
int close(basis::un_int &socket)
int select(basis::un_int socket, int selection_mode, int timeout=0) const
bool set_reuse_address(basis::un_int socket, bool reuse=true)
bool set_keep_alive(basis::un_int socket, bool keep_alive=true)
bool set_broadcast(basis::un_int socket, bool broadcasting=true)
bool set_non_blocking(basis::un_int socket, bool non_blocking=true)
Abstraction for a higher-level BSD socket that is platform independent.
basis::outcome await_writable(int timeout)
bool was_connected() const
tcpip_stack & stack() const
basis::outcome send(const basis::abyte *buffer, int size, int &len_sent)
basis::astring text_form()
basis::outcome connect(int communication_wait=20 *basis::SECOND_ms)
static const char * outcome_name(const basis::outcome &to_name)
basis::outcome receive_from(basis::abyte *buffer, int &size, internet_address &where_from)
bool is_root_server() const
basis::outcome send_to(const internet_address &where_to, const basis::abyte *buffer, int size, int &len_sent)
basis::outcome accept(spocket *&sock, bool wait)
const internet_address & remote() const
void bind_client(const internet_address &source)
when a client calls connect, this forces it to bind to "source".
basis::outcome disconnect()
basis::outcome await_readable(int timeout)
const internet_address & where() const
basis::outcome receive(basis::abyte *buffer, int &size)
Helpful functions for interacting with TCP/IP stacks.
static basis::astring tcpip_error_name(int error_value)
basis::byte_array full_resolve(const basis::astring &hostname, basis::astring &full_host) const
static sockaddr convert(const internet_address &to_convert)
static void sleep_ms(basis::un_int msec)
a system independent name for a forced snooze measured in milliseconds.
Represents a point in time relative to the operating system startup time.
#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 char abyte
A fairly important unit which is seldom defined...
unsigned int un_int
Abbreviated name for unsigned integers.
bool negative(const type &a)
negative returns true if "a" is less than zero.
A logger that sends to the console screen using the standard output device.
Provides access to the operating system's socket methods.
const int RESOLVE_INTERVAL
const int PENDING_CONNECTIONS_ALLOWED
A dynamic container class that holds any kind of object via pointers.
#define CHECK_BOGUS(retval)
#define ENSURE_HEALTH(retval)
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
#define SOCK_ECONNREFUSED