1 /*****************************************************************************\
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2001-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "internet_address.h"
16 #include "raw_socket.h"
18 #include "tcpip_stack.h"
20 #include <basis/byte_array.h>
21 #include <basis/functions.h>
22 #include <basis/astring.h>
23 #include <basis/mutex.h>
24 #include <loggers/critical_events.h>
25 #include <loggers/program_wide_logger.h>
26 #include <structures/static_memory_gremlin.h>
27 #include <timely/time_control.h>
28 #include <timely/time_stamp.h>
31 #include <arpa/inet.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #include <sys/types.h>
43 using namespace basis;
44 using namespace loggers;
45 using namespace structures;
46 using namespace timely;
50 //#define DEBUG_SPOCKET
51 // uncomment for noisy version.
54 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
56 const int PENDING_CONNECTIONS_ALLOWED = 14;
57 // we allow this many connections to queue up before they get rejected.
58 // if the OS is windoze, this number is ignored if it's greater than the
59 // hardcoded maximum of like 5.
61 const int RESOLVE_INTERVAL = 300;
62 // we'll re-resolve the ip address at this rate. this mainly comes into
63 // play for the connect call, since the address passed in could have changed
64 // or been invalid to start with. we're not losing much by trying to
65 // resolve the address again during connection time.
67 #define RECOGNIZE_DISCO \
68 _client_bind = false; \
69 _was_connected = false
71 // ensure that the socket is in a good state.
72 #define ENSURE_HEALTH(retval) \
73 if (!_was_connected) return retval; /* never has been. */ \
74 if (!_socket) { RECOGNIZE_DISCO; return retval; /* not set. */ }
76 #define CHECK_BOGUS(retval) \
77 if (is_bogus()) { return retval; /* this spocket is junk. */ }
81 // win32 seems to trip over selects unless we protect them.
82 #define GRAB_LOCK auto_synchronizer l(*_select_lock)
83 // and in truth, the locking turns out to be needed on win32 if we're
84 // going to allow sharing a spocket across threads. this is one of the
85 // design goals so we're honor bound to support that.
91 SAFE_STATIC(mutex, __broken_pipe_synch, )
94 spocket::spocket(const internet_address &where, sock_types type)
98 _was_connected(false),
100 _where(new internet_address(where)),
101 _remote(new internet_address),
102 _socks(new raw_socket),
103 _stack(new tcpip_stack),
104 _select_lock(new mutex),
105 _last_resolve(new time_stamp), // don't force an immediate resolve.
107 _cli_bind(new internet_address)
109 FUNCDEF("constructor");
110 if ( (_type == BROADCAST) || (_type == UNICAST) ) {
111 // casting types are never servers.
113 } else if ( (type == CONNECTED) || (type == BOGUS_SOCK) ) {
114 // nothing special here currently.
116 // this is an unknown type.
117 LOG(a_sprintf("unknown socket type %d; failing out.", _type));
118 //hmmm: without a validity flag of some sort, this doesn't mean much.
126 FUNCDEF("destructor");
127 LOG(a_sprintf("closing spocket: ") + text_form());
135 WHACK(_last_resolve);
137 _client_bind = false;
140 // where and remote don't need to be protected unless we revise the design of
141 // the class and allow a reset or re-open kind of method.
142 const internet_address &spocket::where() const { return *_where; }
143 const internet_address &spocket::remote() const { return *_remote; }
145 tcpip_stack &spocket::stack() const { return *_stack; }
147 // doesn't need to be protected since the sockets are being treated as simple
148 // ints and since _where currently does not get destroyed.
149 astring spocket::text_form()
151 a_sprintf sock_string("socket=%d", _socket);
152 if (is_root_server())
153 sock_string += a_sprintf("root-socket=%d", _server_socket);
155 return a_sprintf("%s spocket: %s, %s, %s",
156 (is_client()? "client" :
157 (is_root_server()? "root-server" : "server") ),
158 (connected()? "connected" :
159 (was_connected()? "unconnected (was once)" : "never-connected") ),
161 _where->text_form().s());
164 void spocket::bind_client(const internet_address &addr)
170 const char *spocket::outcome_name(const outcome &to_name)
172 switch (to_name.value()) {
173 case NOT_SERVER: return "NOT_SERVER";
174 default: return communication_commons::outcome_name(to_name);
178 outcome spocket::disconnect()
181 FUNCDEF("disconnect");
186 LOG(a_sprintf("closing socket %d", _socket));
188 _socks->close(_socket);
191 if (_server_socket) {
193 LOG(a_sprintf("closing server socket %d", _server_socket));
195 _socks->close(_server_socket);
201 bool spocket::connected()
204 FUNCDEF("connected");
206 ENSURE_HEALTH(false);
208 if (_type != CONNECTED) return _was_connected;
210 // do examination on spocket.
213 int ret = _socks->select(_socket, sel_mode);
216 return true; // we are happy.
218 if ( (ret & SI_DISCONNECTED) || (ret & SI_ERRONEOUS) ) {
225 outcome spocket::await_readable(int timeout)
228 FUNCDEF("await_readable");
230 CHECK_BOGUS(NO_CONNECTION);
231 ENSURE_HEALTH(NO_CONNECTION);
233 int mode = raw_socket::SELECTING_JUST_READ;
234 int ret = _socks->select(_socket, mode, timeout);
235 if (ret & SI_READABLE) return OKAY;
236 // we found something to report.
237 if (ret & SI_DISCONNECTED) {
239 return NO_CONNECTION;
241 return _socket? NONE_READY : NO_CONNECTION;
242 // nothing is ready currently.
245 outcome spocket::await_writable(int timeout)
248 FUNCDEF("await_writable");
250 CHECK_BOGUS(NO_CONNECTION);
251 ENSURE_HEALTH(NO_CONNECTION);
253 int mode = raw_socket::SELECTING_JUST_WRITE;
254 int ret = _socks->select(_socket, mode, timeout);
255 if (ret & SI_WRITABLE) return OKAY;
256 // we found something to report.
257 if (ret & SI_DISCONNECTED) {
259 return NO_CONNECTION;
261 return _socket? NONE_READY : NO_CONNECTION;
262 // nothing is ready currently.
265 outcome spocket::connect(int communication_wait)
268 CHECK_BOGUS(NO_CONNECTION);
270 GRAB_LOCK; // short lock.
271 if ( (_was_connected && !_client) || _server_socket) {
273 LOG("this object was already opened as a server!");
277 _client = true; // set our state now that we're sure this is okay.
278 _was_connected = false; // reset this, since we're connecting now.
282 // the socket was never created (or was cleaned up previously). this is
283 // where we create the socket so we can communicate.
285 LOG(astring("creating socket now for ") + _where->text_form());
288 int sock_type = SOCK_STREAM;
289 int proto = IPPROTO_TCP;
291 if ( (_type == BROADCAST) || (_type == UNICAST) ) {
292 sock_type = SOCK_DGRAM;
295 _socket = int(::socket(AF_INET, sock_type, proto));
296 if ( (_socket == basis::un_int(INVALID_SOCKET)) || !_socket) {
298 LOG("Failed to open the client's connecting spocket.");
299 return ACCESS_DENIED;
302 // mark the spocket for _blocking_ I/O. we want connect to sit there
303 // until it's connected or returns with an error.
304 _socks->set_non_blocking(_socket, false);
306 if (_type == BROADCAST) {
307 if (!_socks->set_broadcast(_socket)) return ACCESS_DENIED;
308 // mark the socket for broadcast capability.
311 if (!_socks->set_reuse_address(_socket)) return ACCESS_DENIED;
312 // mark the socket so we don't get bind errors on in-use conditions.
315 if (_type == CONNECTED) {
317 // turn on the keepalive timer so that loss of the connection will
318 // eventually be detected by the OS. the duration that is allowed to
319 // elapse before a dead connection is noticed varies with the operating
320 // system and is not configured at this level.
321 if (!_socks->set_keep_alive(_socket)) {
323 LOG("couldn't set watchdog timer on socket.");
327 //hmmm: doesn't this need to be done for bcast too?
329 // create the spocket address that we will connect to.
330 if (strlen(_where->hostname)
331 // && (_where->is_nil_address()
332 // || (*_last_resolve < time_stamp(-RESOLVE_INTERVAL) ) ) ) {
334 //moving to always re-resolving before a connect. otherwise we have somewhat
335 //hard to predict behavior about when the re-resolve will happen.
337 // we know we need to resolve if the address is NIL or if the re-resolve
338 // interval has elapsed.
340 byte_array ip_addr = _stack->full_resolve(_where->hostname, full_host);
341 if (ip_addr.length()) {
342 ip_addr.stuff(internet_address::ADDRESS_SIZE, _where->ip_address);
343 LOG(astring("successfully re-resolved address--") + _where->text_form());
345 *_last_resolve = time_stamp(); // reset since we just resolved.
348 // special code for forcing a client to bind.
350 sockaddr sock = _stack->convert(*_cli_bind);
353 LOG(a_sprintf("binding client socket %d to ", _socket)
354 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
357 // now, the socket address is bound to our socket.
358 if (negative(bind(_socket, &sock, sizeof(sock)))) {
359 LOG(a_sprintf("error binding socket %d to ", _socket)
360 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
364 } else if ( (_type == BROADCAST) || (_type == UNICAST) ) {
365 // this is the last piece of preparation for a broadcast or unicast socket.
366 // there's no real connection, so we just need to get it bound and ready
369 sockaddr sock = _stack->convert(*_where);
372 LOG(a_sprintf("binding socket %d to ", _socket)
373 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
376 // now, the socket address is bound to our socket.
377 if (negative(bind(_socket, &sock, sizeof(sock)))) {
378 LOG(a_sprintf("error binding socket %d to ", _socket)
379 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
382 // that's it for broadcast preparation. we should be ready.
383 _was_connected = true;
387 // the following is for connected mode only.
389 sockaddr sock = _stack->convert(*_where);
391 // attempt the connection now.
393 //hmmm: error returns are done differently on bsd, right?
394 //hmmm: perhaps hide the base connect in a func that sets our internal
395 // error variable and then allows comparison to enums we provide.
397 time_stamp abort_time(communication_wait);
399 bool connected = false; // did we connect.
401 int sock_len = sizeof(sock);
403 while (time_stamp() < abort_time) {
404 // make the low-level socket connection.
405 int ret = ::connect(_socket, &sock, sock_len);
406 if (ret != SOCKET_ERROR) {
408 _socks->set_non_blocking(_socket, true);
412 basis::un_int last_error = critical_events::system_error();
414 // if we're already done, then make this look like a normal connect.
415 if (last_error == SOCK_EISCONN) {
420 if ( (last_error != SOCK_EWOULDBLOCK)
421 && (last_error != SOCK_EINPROGRESS) ) {
422 // this seems like a real error here.
424 LOG(a_sprintf("Connect failed (error %s or %d) on address:",
425 critical_events::system_error_text(last_error).s(), last_error)
426 + _where->text_form());
428 if (last_error == SOCK_ECONNREFUSED) return NO_ANSWER;
429 //hmmm: fix more of the possibilities to be sensible outcomes?
430 return ACCESS_DENIED;
433 if (time_stamp() >= abort_time) break; // skip before sleeping if T.O.
435 // snooze for a bit before trying again.
436 time_control::sleep_ms(10);
441 LOG(a_sprintf("socket %d connected to server.", _socket));
443 GRAB_LOCK; // short lock.
444 _was_connected = true;
451 outcome spocket::accept(spocket * &sock, bool wait)
454 CHECK_BOGUS(NO_CONNECTION);
455 if (_type != CONNECTED) return BAD_INPUT;
457 // we don't lock in here; we should not be locking on the server socket.
459 sock = NIL; // reset.
463 LOG("tried to accept on a client spocket.");
469 if (!_server_socket) {
470 _server_socket = int(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
472 LOG(a_sprintf("srv sock is %d", _server_socket));
476 LOG(astring("creating server socket now for ") + _where->text_form());
479 if (_server_socket == basis::un_int(INVALID_SOCKET)) {
480 LOG("Failed to open the serving spocket.");
484 // mark the socket so we don't get bind errors on in-use conditions.
485 if (!_socks->set_reuse_address(_server_socket))
486 LOG("Failed to mark the socket for re-use.");
488 // create the spocket address for where we exist.
489 sockaddr sock = _stack->convert(*_where);
491 // now, the spocket address is bound to our spocket.
492 int sock_len = sizeof(sock);
493 if (bind(_server_socket, (sockaddr *)&sock, sock_len) < 0) {
494 LOG(astring("Error on bind of ") + critical_events::system_error_text(critical_events::system_error()));
495 _socks->close(_server_socket);
496 return ACCESS_DENIED;
499 // now listen for a connection on our spocket.
500 if (listen(_server_socket, PENDING_CONNECTIONS_ALLOWED) < 0) {
501 LOG(astring("Listen failed with error of ")
502 + critical_events::system_error_text(critical_events::system_error()));
503 _socks->close(_server_socket);
504 return ACCESS_DENIED;
508 // do the kind of accept they want; either block on it or don't.
509 // since our server socket is never used for sends or receives, we pretty
510 // much control it completely and this is safe.
512 _socks->set_non_blocking(_server_socket, true);
513 // mark our socket as non-blocking so we don't get stuck in accepts.
515 _socks->set_non_blocking(_server_socket, false);
516 // mark our socket as blocking; we will be paused until accept occurs.
519 // now try accepting a connection on the spocket.
521 socklen_t sock_len = sizeof(new_sock);
522 int accepted = int(::accept(_server_socket, &new_sock, &sock_len));
523 int error = critical_events::system_error();
524 if (accepted == INVALID_SOCKET) {
525 if (error == SOCK_EWOULDBLOCK) return NO_CONNECTION;
527 LOG(astring("Accept got no client, with an error of ")
528 + critical_events::system_error_text(error));
530 return ACCESS_DENIED;
533 // mark the new spocket for non-blocking I/O.
534 _socks->set_non_blocking(accepted, true);
536 //move to socks object!
538 if (setsockopt(accepted, SOL_SOCKET, SO_KEEPALIVE, (char *)&sock_hop,
539 sizeof(sock_hop)) < 0) {
541 LOG("couldn't set watchdog timer on socket.");
545 // create the spocket address that we will connect to.
547 LOG(astring("accepted a client socket for ") + _where->text_form());
550 // NOTE: normally, our network code sets the spocket to be kept alive (using
551 // keep alives), but we are trying to have a minimal spocket usage and
552 // a minimal network load for this test scenario.
554 sock = new spocket(*_where);
555 *sock->_remote = _stack->convert(new_sock);
556 sock->_socket = accepted;
557 sock->_server_socket = 0; // reset to avoid whacking.
558 sock->_was_connected = true;
562 outcome spocket::send(const byte_array &to_send, int &len_sent)
564 return send(to_send.observe(), to_send.length(), len_sent);
567 outcome spocket::send(const abyte *buffer, int size, int &len_sent)
573 if (_type != CONNECTED) return BAD_INPUT;
575 ENSURE_HEALTH(NO_CONNECTION);
577 len_sent = ::send(_socket, (char *)buffer, size, 0);
578 int error_code = critical_events::system_error();
581 LOG("No data went out on the spocket.");
585 if (len_sent == SOCKET_ERROR) {
586 if (error_code == SOCK_EWOULDBLOCK) {
588 LOG("would block, will try later...");
590 LOG("HEY HEY! some was sent but we were not counting it!!!");
595 LOG(astring("Error ") + critical_events::system_error_text(error_code)
596 + " occurred during the send!");
598 if (!connected()) return NO_CONNECTION;
600 LOG(a_sprintf("forcing disconnect on socket %d.", _socket));
602 // we're trying this new approach here... we found that the socket doesn't
603 // really know that it got disconnected in some circumstances.
605 return ACCESS_DENIED;
607 if (len_sent != size) {
608 // only sent part of the buffer.
610 LOG(a_sprintf("sent %d bytes out of %d.", len_sent, size));
618 outcome spocket::send_to(const internet_address &where_to,
619 const byte_array &to_send, int &len_sent)
621 return send_to(where_to, to_send.observe(), to_send.length(), len_sent);
624 outcome spocket::send_to(const internet_address &where_to, const abyte *to_send,
625 int size, int &len_sent)
629 if (_type == CONNECTED) return BAD_INPUT;
630 sockaddr dest = _stack->convert(where_to);
631 int ret = sendto(_socket, (char *)to_send, size, 0, &dest, sizeof(dest));
632 int error = critical_events::system_error();
634 if (error == SOCK_EWOULDBLOCK) return NONE_READY; // no buffer space?
635 LOG(astring("failed to send packet; error ")
636 + _stack->tcpip_error_name(error));
637 return ACCESS_DENIED;
640 LOG(astring("didn't send whole datagram!"));
646 outcome spocket::receive(byte_array &buffer, int &size)
651 CHECK_BOGUS(NONE_READY);
652 if (_type != CONNECTED) return BAD_INPUT;
653 if (size <= 0) return BAD_INPUT;
655 outcome to_return = receive(buffer.access(), size);
656 // trim the buffer to the actual received size.
657 if (to_return == OKAY)
658 buffer.zap(size, buffer.last());
662 outcome spocket::receive(abyte *buffer, int &size)
667 CHECK_BOGUS(NONE_READY);
668 if (_type != CONNECTED) return BAD_INPUT;
669 ENSURE_HEALTH(NO_CONNECTION);
672 if (expected <= 0) return BAD_INPUT;
674 int len = recv(_socket, (char *)buffer, expected, 0);
676 // check to make sure we're not disconnected.
677 int ret = _socks->select(_socket, raw_socket::SELECTING_JUST_READ);
678 if (ret & SI_DISCONNECTED) {
680 return NO_CONNECTION;
682 // seems like more normal absence of data.
684 } else if (len < 0) {
685 if (critical_events::system_error() == SOCK_EWOULDBLOCK) return NONE_READY;
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;
697 outcome spocket::receive_from(byte_array &buffer, int &size,
698 internet_address &where_from)
701 FUNCDEF("receive_from");
703 where_from = internet_address();
704 CHECK_BOGUS(NONE_READY);
705 if (_type == CONNECTED) return BAD_INPUT;
706 if (size <= 0) return BAD_INPUT;
708 outcome to_return = receive_from(buffer.access(), size, where_from);
709 // trim the buffer to the actual received size.
710 if (to_return == OKAY)
711 buffer.zap(size, buffer.last());
715 outcome spocket::receive_from(abyte *buffer, int &size,
716 internet_address &where_from)
719 FUNCDEF("receive_from");
721 where_from = internet_address();
722 CHECK_BOGUS(NONE_READY);
723 if (_type == CONNECTED) return BAD_INPUT;
724 ENSURE_HEALTH(NO_CONNECTION);
727 if (expected <= 0) return BAD_INPUT;
730 socklen_t fromlen = sizeof(from);
731 int len = recvfrom(_socket, (char *)buffer, expected, 0, &from, &fromlen);
732 int err = critical_events::system_error();
733 if (!len) return NONE_READY;
736 LOG(a_sprintf("actual sys err value=%d", err));
738 if (err == SOCK_EWOULDBLOCK) return NONE_READY;
739 if (err == SOCK_ECONNRESET) return NONE_READY;
740 // this seems to be a necessary windoze kludge; we're not connected
741 // and never were but it says this idiotic garbage about the connection
744 LOG(astring("The recvfrom failed with an error ")
745 + critical_events::system_error_text(err));
747 if (!connected()) return NO_CONNECTION;
748 return ACCESS_DENIED;
750 where_from = _stack->convert(from);