32 #include <arpa/inet.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
44 using namespace basis;
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;
157 astring to_return = is_client()?
"client" :
158 (is_root_server()?
"root-server" :
"server");
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);
167 if (is_root_server()) {
168 to_return +=
a_sprintf(
"root-socket=%u, ", _server_socket);
180 const char *spocket::outcome_name(
const outcome &to_name)
182 switch (to_name.
value()) {
183 case NOT_SERVER:
return "NOT_SERVER";
184 default:
return communication_commons::outcome_name(to_name);
196 _socks->close(_socket);
199 if (_server_socket) {
201 LOG(
a_sprintf(
"closing server socket %d", _server_socket));
203 _socks->close(_server_socket);
209 bool spocket::connected()
214 if (_type != CONNECTED)
return was_connected();
216 if (!_socket)
return false;
223 int ret = _socks->select(_socket, sel_mode);
233 LOG(
"caught exception thrown from select, returning false.");
244 int mode = raw_socket::SELECTING_JUST_READ;
245 int ret = _socks->select(_socket, mode, timeout);
250 return NO_CONNECTION;
252 return _socket? NONE_READY : NO_CONNECTION;
262 int mode = raw_socket::SELECTING_JUST_WRITE;
263 int ret = _socks->select(_socket, mode, timeout);
268 return NO_CONNECTION;
270 return _socket? NONE_READY : NO_CONNECTION;
274 outcome spocket::connect(
int communication_wait)
280 if ( (was_connected() && !_client) || _server_socket) {
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;
300 if ( (_type == BROADCAST) || (_type == UNICAST) ) {
301 sock_type = SOCK_DGRAM;
304 _socket = int(::socket(AF_INET, sock_type, proto));
307 LOG(
"Failed to open the client's connecting spocket.");
308 return ACCESS_DENIED;
313 _socks->set_non_blocking(_socket,
false);
315 if (_type == BROADCAST) {
316 if (!_socks->set_broadcast(_socket))
return ACCESS_DENIED;
320 if (!_socks->set_reuse_address(_socket))
return ACCESS_DENIED;
324 if (_type == CONNECTED) {
330 if (!_socks->set_keep_alive(_socket)) {
332 LOG(
"couldn't set watchdog timer on socket.");
339 if (strlen(_where->hostname)
349 byte_array ip_addr = _stack->full_resolve(_where->hostname, full_host);
351 ip_addr.
stuff(internet_address::ADDRESS_SIZE, _where->ip_address);
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));
373 }
else if ( (_type == BROADCAST) || (_type == UNICAST) ) {
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);
408 bool connected =
false;
410 int sock_len =
sizeof(sock);
414 int ret = ::connect(_socket, &sock, sock_len);
417 _socks->set_non_blocking(_socket,
true);
433 LOG(
a_sprintf(
"Connect failed (error %s or %d) on address:",
434 critical_events::system_error_text(last_error).s(), last_error)
439 return ACCESS_DENIED;
445 time_control::sleep_ms(10);
450 LOG(
a_sprintf(
"socket %d connected to server.", _socket));
453 _was_connected =
true;
464 if (_type != CONNECTED)
return BAD_INPUT;
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.");
491 if (!_socks->set_reuse_address(_server_socket))
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) {
500 LOG(
astring(
"Error on bind of ") + critical_events::system_error_text(critical_events::system_error()));
501 _socks->close(_server_socket);
502 return ACCESS_DENIED;
508 + critical_events::system_error_text(critical_events::system_error()));
509 _socks->close(_server_socket);
510 return ACCESS_DENIED;
518 _socks->set_non_blocking(_server_socket,
true);
521 _socks->set_non_blocking(_server_socket,
false);
527 socklen_t sock_len =
sizeof(new_sock);
528 basis::un_int accepted = int(::accept(_server_socket, &new_sock, &sock_len));
529 int error = critical_events::system_error();
533 LOG(
astring(
"Accept got no client, with an error of ")
534 + critical_events::system_error_text(error));
536 return ACCESS_DENIED;
540 _socks->set_non_blocking(accepted,
true);
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;
577 if (_type != CONNECTED)
return BAD_INPUT;
581 len_sent = ::send(_socket, (
char *)buffer, size, 0);
582 int error_code = critical_events::system_error();
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!!!");
599 LOG(
astring(
"Error ") + critical_events::system_error_text(error_code)
600 +
" occurred during the send!");
602 if (!connected())
return NO_CONNECTION;
604 LOG(
a_sprintf(
"forcing disconnect on socket %d.", _socket));
609 return ACCESS_DENIED;
611 if (len_sent != size) {
614 LOG(
a_sprintf(
"sent %d bytes out of %d.", len_sent, size));
625 return send_to(where_to, to_send.
observe(), to_send.
length(), len_sent);
629 int size,
int &len_sent)
633 if (_type == CONNECTED)
return BAD_INPUT;
634 sockaddr dest = _stack->convert(where_to);
635 int ret = sendto(_socket, (
char *)to_send, size, 0, &dest,
sizeof(dest));
636 int error = critical_events::system_error();
640 + _stack->tcpip_error_name(error));
641 return ACCESS_DENIED;
654 if (_type != CONNECTED)
return BAD_INPUT;
655 if (size <= 0)
return BAD_INPUT;
659 if (to_return == OKAY)
660 buffer.
zap(size, buffer.
last());
668 if (_type != CONNECTED)
return BAD_INPUT;
672 if (expected <= 0)
return BAD_INPUT;
674 int len = recv(_socket, (
char *)buffer, expected, 0);
677 int ret = _socks->select(_socket, raw_socket::SELECTING_JUST_READ);
680 return NO_CONNECTION;
684 }
else if (len < 0) {
687 LOG(
astring(
"The receive failed with an error ")
688 + critical_events::system_error_text(critical_events::system_error()));
690 if (!connected())
return NO_CONNECTION;
691 return ACCESS_DENIED;
703 if (_type == CONNECTED)
return BAD_INPUT;
704 if (size <= 0)
return BAD_INPUT;
706 outcome to_return = receive_from(buffer.
access(), size, where_from);
708 if (to_return == OKAY)
709 buffer.
zap(size, buffer.
last());
719 if (_type == CONNECTED)
return BAD_INPUT;
723 if (expected <= 0)
return BAD_INPUT;
726 socklen_t fromlen =
sizeof(from);
727 int len = recvfrom(_socket, (
char *)buffer, expected, 0, &from, &fromlen);
728 int err = critical_events::system_error();
729 if (!len)
return NONE_READY;
740 LOG(
astring(
"The recvfrom failed with an error ")
741 + critical_events::system_error_text(err));
743 if (!connected())
return NO_CONNECTION;
744 return ACCESS_DENIED;
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.
const contents * observe() const
Returns a pointer to the underlying C array of data.
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
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.
virtual void text_form(base_string &state_fill) const
Provides a text view of all the important info owned by this object.
A very common template for a dynamic array of bytes.
Outcomes describe the state of completion for an operation.
this type of address describes a destination out on the internet.
machine_uid convert() const
Abstraction for a higher-level BSD socket that is platform independent.
Helpful functions for interacting with TCP/IP stacks.
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