feisty meow concerns codebase 2.140
spocket.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : spocket *
4* Author : Chris Koeritz *
5* *
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\*****************************************************************************/
14
15#include "internet_address.h"
16#include "raw_socket.h"
17#include "spocket.h"
18#include "tcpip_stack.h"
19
20#include <basis/byte_array.h>
21#include <basis/functions.h>
22#include <basis/astring.h>
23#include <basis/mutex.h>
27#include <timely/time_control.h>
28#include <timely/time_stamp.h>
29
30//hmmm: put this bag o headers into a similar thing to windoze helper. maybe just have an os_helper file that combines both?
31//#ifdef __UNIX__
32 #include <arpa/inet.h>
33 #include <errno.h>
34 #include <netdb.h>
35 #include <signal.h>
36 #include <string.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
40 #include <termios.h>
41 #include <unistd.h>
42//#endif
43
44using namespace basis;
45using namespace loggers;
46using namespace structures;
47using namespace timely;
48
49namespace sockets {
50
51//#define DEBUG_SPOCKET
52 // uncomment for noisy version.
53
54#undef LOG
55#define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
56
58 // we allow this many connections to queue up before they get rejected.
59 // if the OS is windoze, this number is ignored if it's greater than the
60 // hardcoded maximum of like 5.
61
62const int RESOLVE_INTERVAL = 300;
63 // we'll re-resolve the ip address at this rate. this mainly comes into
64 // play for the connect call, since the address passed in could have changed
65 // or been invalid to start with. we're not losing much by trying to
66 // resolve the address again during connection time.
67
68#define RECOGNIZE_DISCO \
69 _client_bind = false; \
70 _was_connected = false
71
72// ensure that the socket is in a good state.
73#define ENSURE_HEALTH(retval) \
74 if (!was_connected()) return retval; /* never has been. */ \
75 if (!_socket) { RECOGNIZE_DISCO; return retval; /* not set. */ }
76
77#define CHECK_BOGUS(retval) \
78 if (is_bogus()) { return retval; /* this spocket is junk. */ }
79
80/*
81#undef GRAB_LOCK
82#ifdef __WIN32__
83 // win32 seems to trip over selects unless we protect them.
84 #define GRAB_LOCK auto_synchronizer l(*_select_lock)
85 // and in truth, the locking turns out to be needed on win32 if we're
86 // going to allow sharing a spocket across threads. this is one of the
87 // design goals so we're honor bound to support that.
88#else
89 #define GRAB_LOCK
90#endif
91*/
92 #define GRAB_LOCK
93
94
95//#ifdef __UNIX__
96 SAFE_STATIC(mutex, __broken_pipe_synch, )
97//#endif
98
100: _type(type),
101 _socket(0),
102 _server_socket(0),
103 _was_connected(false),
104 _client(false),
105 _where(new internet_address(where)),
106 _remote(new internet_address),
107 _socks(new raw_socket),
108 _stack(new tcpip_stack),
109 _select_lock(new mutex),
110 _last_resolve(new time_stamp), // don't force an immediate resolve.
111 _client_bind(false),
112 _cli_bind(new internet_address)
113{
114 FUNCDEF("constructor");
115 if ( (_type == BROADCAST) || (_type == UNICAST) ) {
116 // casting types are never servers.
117 _client = true;
118 } else if ( (type == CONNECTED) || (type == BOGUS_SOCK) ) {
119 // nothing special here currently.
120 } else {
121 // this is an unknown type.
122 LOG(a_sprintf("unknown socket type %d; failing out.", _type));
123//hmmm: without a validity flag of some sort, this doesn't mean much.
124 return;
125 }
126}
127
129{
130 FUNCDEF("destructor");
131#ifdef DEBUG_SPOCKET
132 LOG(a_sprintf("closing spocket: ") + text_form());
133#endif
134 disconnect();
135 WHACK(_where);
136 WHACK(_socks);
137 WHACK(_stack);
138 WHACK(_remote);
139 WHACK(_select_lock);
140 WHACK(_last_resolve);
141 WHACK(_cli_bind);
142 _client_bind = false;
143}
144
145// where and remote don't need to be protected unless we revise the design of
146// the class and allow a reset or re-open kind of method.
147const internet_address &spocket::where() const { return *_where; }
148const internet_address &spocket::remote() const { return *_remote; }
149
150tcpip_stack &spocket::stack() const { return *_stack; }
151
152// doesn't need to be protected since the sockets are being treated as simple
153// ints and since _where currently does not get destroyed.
155{
156 FUNCDEF("text_form");
157 astring to_return = is_client()? "client" :
158 (is_root_server()? "root-server" : "server");
159 to_return += " spocket: ";
160 if (connected()) {
161 to_return += "connected, ";
162 } else {
163 if (was_connected()) to_return += "unconnected (was once), ";
164 else to_return += "never-connected, ";
165 }
166 to_return += a_sprintf("socket=%u, ", _socket);
167 if (is_root_server()) {
168 to_return += a_sprintf("root-socket=%u, ", _server_socket);
169 }
170 to_return += _where->text_form().s();
171 return to_return;
172}
173
175{
176 _client_bind = true;
177 *_cli_bind = addr;
178}
179
180const char *spocket::outcome_name(const outcome &to_name)
181{
182 switch (to_name.value()) {
183 case NOT_SERVER: return "NOT_SERVER";
184 default: return communication_commons::outcome_name(to_name);
185 }
186}
187
189{
190 FUNCDEF("disconnect");
192 if (_socket) {
193#ifdef DEBUG_SPOCKET
194 LOG(a_sprintf("closing socket %d", _socket));
195#endif
196 _socks->close(_socket);
197 _socket = 0;
198 }
199 if (_server_socket) {
200#ifdef DEBUG_SPOCKET
201 LOG(a_sprintf("closing server socket %d", _server_socket));
202#endif
203 _socks->close(_server_socket);
204 _server_socket = 0;
205 }
206 return OKAY;
207}
208
210{
211 FUNCDEF("connected");
212 ENSURE_HEALTH(false);
213
214 if (_type != CONNECTED) return was_connected();
215
216 if (!_socket) return false;
217
218 // do examination on spocket.
219 int sel_mode = 0;
220 GRAB_LOCK;
221
222 try {
223 int ret = _socks->select(_socket, sel_mode);
224 if (ret == 0) {
225 return true; // we are happy.
226 }
227 if ( (ret & SI_DISCONNECTED) || (ret & SI_ERRONEOUS) ) {
229 return false;
230 }
231 return true;
232 } catch (...) {
233 LOG("caught exception thrown from select, returning false.");
234 return false;
235 }
236}
237
239{
240 FUNCDEF("await_readable");
243 GRAB_LOCK;
245 int ret = _socks->select(_socket, mode, timeout);
246 if (ret & SI_READABLE) return OKAY;
247 // we found something to report.
248 if (ret & SI_DISCONNECTED) {
250 return NO_CONNECTION;
251 }
252 return _socket? NONE_READY : NO_CONNECTION;
253 // nothing is ready currently.
254}
255
257{
258 FUNCDEF("await_writable");
261 GRAB_LOCK;
263 int ret = _socks->select(_socket, mode, timeout);
264 if (ret & SI_WRITABLE) return OKAY;
265 // we found something to report.
266 if (ret & SI_DISCONNECTED) {
268 return NO_CONNECTION;
269 }
270 return _socket? NONE_READY : NO_CONNECTION;
271 // nothing is ready currently.
272}
273
274outcome spocket::connect(int communication_wait)
275{
276 FUNCDEF("connect");
278 {
279 GRAB_LOCK; // short lock.
280 if ( (was_connected() && !_client) || _server_socket) {
281#ifdef DEBUG_SPOCKET
282 LOG("this object was already opened as a server!");
283#endif
284 return BAD_INPUT;
285 }
286 _client = true; // set our state now that we're sure this is okay.
287 _was_connected = false; // reset this, since we're connecting now.
288 }
289
290 if (!_socket) {
291 // the socket was never created (or was cleaned up previously). this is
292 // where we create the socket so we can communicate.
293#ifdef DEBUG_SPOCKET
294 LOG(astring("creating socket now for ") + _where->text_form());
295#endif
296 GRAB_LOCK;
297 int sock_type = SOCK_STREAM;
298 int proto = IPPROTO_TCP;
299
300 if ( (_type == BROADCAST) || (_type == UNICAST) ) {
301 sock_type = SOCK_DGRAM;
302 proto = IPPROTO_IP;
303 }
304 _socket = int(::socket(AF_INET, sock_type, proto));
305 if ( (_socket == basis::un_int(INVALID_SOCKET)) || !_socket) {
306 _socket = 0;
307 LOG("Failed to open the client's connecting spocket.");
308 return ACCESS_DENIED;
309 }
310
311 // mark the spocket for _blocking_ I/O. we want connect to sit there
312 // until it's connected or returns with an error.
313 _socks->set_non_blocking(_socket, false);
314
315 if (_type == BROADCAST) {
316 if (!_socks->set_broadcast(_socket)) return ACCESS_DENIED;
317 // mark the socket for broadcast capability.
318 }
319
320 if (!_socks->set_reuse_address(_socket)) return ACCESS_DENIED;
321 // mark the socket so we don't get bind errors on in-use conditions.
322 }
323
324 if (_type == CONNECTED) {
325 GRAB_LOCK;
326 // turn on the keepalive timer so that loss of the connection will
327 // eventually be detected by the OS. the duration that is allowed to
328 // elapse before a dead connection is noticed varies with the operating
329 // system and is not configured at this level.
330 if (!_socks->set_keep_alive(_socket)) {
331#ifdef DEBUG_SPOCKET
332 LOG("couldn't set watchdog timer on socket.");
333#endif
334 }
335
336//hmmm: doesn't this need to be done for bcast too?
337
338 // create the spocket address that we will connect to.
339 if (strlen(_where->hostname)
340// && (_where->is_nil_address()
341// || (*_last_resolve < time_stamp(-RESOLVE_INTERVAL) ) ) ) {
342//
343//moving to always re-resolving before a connect. otherwise we have somewhat
344//hard to predict behavior about when the re-resolve will happen.
345 ) {
346 // we know we need to resolve if the address is NULL_POINTER or if the re-resolve
347 // interval has elapsed.
348 astring full_host;
349 byte_array ip_addr = _stack->full_resolve(_where->hostname, full_host);
350 if (ip_addr.length()) {
352 LOG(astring("successfully re-resolved address--") + _where->text_form());
353 }
354 *_last_resolve = time_stamp(); // reset since we just resolved.
355 }
356
357 // special code for forcing a client to bind.
358 if (_client_bind) {
359 sockaddr sock = _stack->convert(*_cli_bind);
360
361#ifdef DEBUG_SPOCKET
362 LOG(a_sprintf("binding client socket %d to ", _socket)
363 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
364#endif
365
366 // now, the socket address is bound to our socket.
367 if (negative(bind(_socket, &sock, sizeof(sock)))) {
368 LOG(a_sprintf("error binding socket %d to ", _socket)
369 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
370 }
371 }
372
373 } else if ( (_type == BROADCAST) || (_type == UNICAST) ) {
374 // this is the last piece of preparation for a broadcast or unicast socket.
375 // there's no real connection, so we just need to get it bound and ready
376 // to fling packets.
377 GRAB_LOCK;
378 sockaddr sock = _stack->convert(*_where);
379
380#ifdef DEBUG_SPOCKET
381 LOG(a_sprintf("binding socket %d to ", _socket)
382 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
383#endif
384
385 // now, the socket address is bound to our socket.
386 if (negative(bind(_socket, &sock, sizeof(sock)))) {
387 LOG(a_sprintf("error binding socket %d to ", _socket)
388 + inet_ntoa(((sockaddr_in *)&sock)->sin_addr));
389 }
390
391 // that's it for broadcast preparation. we should be ready.
392 _was_connected = true;
393 return OKAY;
394 }
395
396 // the following is for connected mode only.
397
398 sockaddr sock = _stack->convert(*_where);
399
400 // attempt the connection now.
401
402//hmmm: error returns are done differently on bsd, right?
403//hmmm: perhaps hide the base connect in a func that sets our internal
404// error variable and then allows comparison to enums we provide.
405
406 time_stamp abort_time(communication_wait);
407
408 bool connected = false; // did we connect.
409
410 int sock_len = sizeof(sock);
411
412 while (time_stamp() < abort_time) {
413 // make the low-level socket connection.
414 int ret = ::connect(_socket, &sock, sock_len);
415 if (ret != SOCKET_ERROR) {
416 connected = true;
417 _socks->set_non_blocking(_socket, true);
418 break;
419 }
420
422
423 // if we're already done, then make this look like a normal connect.
424 if (last_error == SOCK_EISCONN) {
425 connected = true;
426 break;
427 }
428
429 if ( (last_error != SOCK_EWOULDBLOCK)
430 && (last_error != SOCK_EINPROGRESS) ) {
431 // this seems like a real error here.
432#ifdef DEBUG_SPOCKET
433 LOG(a_sprintf("Connect failed (error %s or %d) on address:",
434 critical_events::system_error_text(last_error).s(), last_error)
435 + _where->text_form());
436#endif
437 if (last_error == SOCK_ECONNREFUSED) return NO_ANSWER;
438//hmmm: fix more of the possibilities to be sensible outcomes?
439 return ACCESS_DENIED;
440 }
441
442 if (time_stamp() >= abort_time) break; // skip before sleeping if T.O.
443
444 // snooze for a bit before trying again.
446 }
447
448 if (connected) {
449#ifdef DEBUG_SPOCKET
450 LOG(a_sprintf("socket %d connected to server.", _socket));
451#endif
452 GRAB_LOCK; // short lock.
453 _was_connected = true;
454 return OKAY;
455 }
456
457 return TIMED_OUT;
458}
459
460outcome spocket::accept(spocket * &sock, bool wait)
461{
462 FUNCDEF("accept");
464 if (_type != CONNECTED) return BAD_INPUT;
465
466 // we don't lock in here; we should not be locking on the server socket.
467
468 sock = NULL_POINTER; // reset.
469
470 if (_socket) {
471#ifdef DEBUG_SPOCKET
472 LOG("tried to accept on a client spocket.");
473#endif
474 return NOT_SERVER;
475 }
476 _client = false;
477
478 if (!_server_socket) {
479 _server_socket = int(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
480#ifdef DEBUG_SPOCKET
481 LOG(a_sprintf("srv sock is %d", _server_socket));
482 LOG(astring("creating server socket now for ") + _where->text_form());
483#endif
484
485 if (_server_socket == basis::un_int(INVALID_SOCKET)) {
486 LOG("Failed to open the serving spocket.");
487 return BAD_INPUT;
488 }
489
490 // mark the socket so we don't get bind errors on in-use conditions.
491 if (!_socks->set_reuse_address(_server_socket))
492 LOG("Failed to mark the socket for re-use.");
493
494 // create the spocket address for where we exist.
495 sockaddr sock = _stack->convert(*_where);
496
497 // now, the spocket address is bound to our spocket.
498 int sock_len = sizeof(sock);
499 if (bind(_server_socket, (sockaddr *)&sock, sock_len) < 0) {
501 _socks->close(_server_socket);
502 return ACCESS_DENIED;
503 }
504
505 // now listen for a connection on our spocket.
506 if (listen(_server_socket, PENDING_CONNECTIONS_ALLOWED) < 0) {
507 LOG(astring("Listen failed with error of ")
509 _socks->close(_server_socket);
510 return ACCESS_DENIED;
511 }
512 }
513
514 // do the kind of accept they want; either block on it or don't.
515 // since our server socket is never used for sends or receives, we pretty
516 // much control it completely and this is safe.
517 if (!wait) {
518 _socks->set_non_blocking(_server_socket, true);
519 // mark our socket as non-blocking so we don't get stuck in accepts.
520 } else {
521 _socks->set_non_blocking(_server_socket, false);
522 // mark our socket as blocking; we will be paused until accept occurs.
523 }
524
525 // now try accepting a connection on the spocket.
526 sockaddr new_sock;
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();
530 if (!accepted || (accepted == INVALID_SOCKET)) {
531 if (error == SOCK_EWOULDBLOCK) return NO_CONNECTION;
532#ifdef DEBUG_SPOCKET
533 LOG(astring("Accept got no client, with an error of ")
535#endif
536 return ACCESS_DENIED;
537 }
538
539 // mark the new spocket for non-blocking I/O.
540 _socks->set_non_blocking(accepted, true);
541
542//move to socks object!
543 int sock_hop = 1;
544 if (setsockopt(accepted, SOL_SOCKET, SO_KEEPALIVE, (char *)&sock_hop,
545 sizeof(sock_hop)) < 0) {
546#ifdef DEBUG_SPOCKET
547 LOG("couldn't set watchdog timer on socket.");
548#endif
549 }
550
551#ifdef DEBUG_SPOCKET
552 LOG(astring("accepted a client on our socket: ") + _where->text_form());
553#endif
554
555// NOTE: normally, our network code sets the spocket to be kept alive (using
556// keep alives), but we are trying to have a minimal spocket usage and
557// a minimal network load for this test scenario.
558
559 // create the spocket address that we will connect to.
560 sock = new spocket(*_where);
561 *sock->_remote = _stack->convert(new_sock);
562 sock->_socket = accepted;
563 sock->_server_socket = 0; // reset to avoid whacking.
564 sock->_was_connected = true;
565 return OKAY;
566}
567
568outcome spocket::send(const byte_array &to_send, int &len_sent)
569{
570 return send(to_send.observe(), to_send.length(), len_sent);
571}
572
573outcome spocket::send(const abyte *buffer, int size, int &len_sent)
574{
575 FUNCDEF("send");
577 if (_type != CONNECTED) return BAD_INPUT;
578 GRAB_LOCK;
580
581 len_sent = ::send(_socket, (char *)buffer, size, 0);
582 int error_code = critical_events::system_error();
583 if (!len_sent) {
584#ifdef DEBUG_SPOCKET
585 LOG("No data went out on the spocket.");
586#endif
587 return PARTIAL;
588 }
589 if (len_sent == SOCKET_ERROR) {
590 if (error_code == SOCK_EWOULDBLOCK) {
591#ifdef DEBUG_SPOCKET
592 LOG("would block, will try later...");
593 if (len_sent > 0)
594 LOG("HEY HEY! some was sent but we were not counting it!!!");
595#endif
596 return NONE_READY;
597 }
598#ifdef DEBUG_SPOCKET
599 LOG(astring("Error ") + critical_events::system_error_text(error_code)
600 + " occurred during the send!");
601#endif
602 if (!connected()) return NO_CONNECTION;
603#ifdef DEBUG_SPOCKET
604 LOG(a_sprintf("forcing disconnect on socket %d.", _socket));
605#endif
606 // we're trying this new approach here... we found that the socket doesn't
607 // really know that it got disconnected in some circumstances.
608 disconnect();
609 return ACCESS_DENIED;
610 }
611 if (len_sent != size) {
612 // only sent part of the buffer.
613#ifdef DEBUG_SPOCKET
614 LOG(a_sprintf("sent %d bytes out of %d.", len_sent, size));
615#endif
616 return PARTIAL;
617 }
618
619 return OKAY;
620}
621
623 const byte_array &to_send, int &len_sent)
624{
625 return send_to(where_to, to_send.observe(), to_send.length(), len_sent);
626}
627
628outcome spocket::send_to(const internet_address &where_to, const abyte *to_send,
629 int size, int &len_sent)
630{
631 FUNCDEF("send_to");
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();
637 if (ret < 0) {
638 if (error == SOCK_EWOULDBLOCK) return NONE_READY; // no buffer space?
639 LOG(astring("failed to send packet; error ")
640 + _stack->tcpip_error_name(error));
641 return ACCESS_DENIED;
642 }
643 if (ret != size) {
644 LOG(astring("didn't send whole datagram!"));
645 }
646 len_sent = ret;
647 return OKAY;
648}
649
651{
652 FUNCDEF("receive");
654 if (_type != CONNECTED) return BAD_INPUT;
655 if (size <= 0) return BAD_INPUT;
656 buffer.reset(size);
657 outcome to_return = receive(buffer.access(), size);
658 // trim the buffer to the actual received size.
659 if (to_return == OKAY)
660 buffer.zap(size, buffer.last());
661 return to_return;
662}
663
664outcome spocket::receive(abyte *buffer, int &size)
665{
666 FUNCDEF("receive");
668 if (_type != CONNECTED) return BAD_INPUT;
670 int expected = size;
671 size = 0;
672 if (expected <= 0) return BAD_INPUT;
673 GRAB_LOCK;
674 int len = recv(_socket, (char *)buffer, expected, 0);
675 if (!len) {
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;
681 }
682 // seems like more normal absence of data.
683 return NONE_READY;
684 } else if (len < 0) {
686#ifdef DEBUG_SPOCKET
687 LOG(astring("The receive failed with an error ")
689#endif
690 if (!connected()) return NO_CONNECTION;
691 return ACCESS_DENIED;
692 }
693 size = len;
694 return OKAY;
695}
696
698 internet_address &where_from)
699{
700 FUNCDEF("receive_from");
701 where_from = internet_address();
703 if (_type == CONNECTED) return BAD_INPUT;
704 if (size <= 0) return BAD_INPUT;
705 buffer.reset(size);
706 outcome to_return = receive_from(buffer.access(), size, where_from);
707 // trim the buffer to the actual received size.
708 if (to_return == OKAY)
709 buffer.zap(size, buffer.last());
710 return to_return;
711}
712
714 internet_address &where_from)
715{
716 FUNCDEF("receive_from");
717 where_from = internet_address();
719 if (_type == CONNECTED) return BAD_INPUT;
721 int expected = size;
722 size = 0;
723 if (expected <= 0) return BAD_INPUT;
724 GRAB_LOCK;
725 sockaddr from;
726 socklen_t fromlen = sizeof(from);
727 int len = recvfrom(_socket, (char *)buffer, expected, 0, &from, &fromlen);
729 if (!len) return NONE_READY;
730 else if (len < 0) {
731#ifdef DEBUG_SPOCKET
732 LOG(a_sprintf("actual sys err value=%d", err));
733#endif
734 if (err == SOCK_EWOULDBLOCK) return NONE_READY;
735 if (err == SOCK_ECONNRESET) return NONE_READY;
736 // this seems to be a necessary windoze kludge; we're not connected
737 // and never were but it says this idiotic garbage about the connection
738 // being reset.
739#ifdef DEBUG_SPOCKET
740 LOG(astring("The recvfrom failed with an error ")
742#endif
743 if (!connected()) return NO_CONNECTION;
744 return ACCESS_DENIED;
745 }
746 where_from = _stack->convert(from);
747 size = len;
748 return OKAY;
749}
750
751} //namespace.
752
#define LOG(s)
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition array.h:349
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition array.h:175
const contents * observe() const
Returns a pointer to the underlying C array of data.
Definition array.h:172
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition array.h:769
outcome stuff(int length, contents *to_stuff) const
Copies at most "length" elements from this into the array "to_stuff".
Definition array.h:476
int last() const
Returns the last valid element in the array.
Definition array.h:118
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
Outcomes describe the state of completion for an operation.
Definition outcome.h:31
int value() const
Definition outcome.h:51
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.
Definition spocket.h:40
basis::outcome await_writable(int timeout)
Definition spocket.cpp:256
bool was_connected() const
Definition spocket.h:94
tcpip_stack & stack() const
Definition spocket.cpp:150
basis::outcome send(const basis::abyte *buffer, int size, int &len_sent)
Definition spocket.cpp:573
basis::astring text_form()
Definition spocket.cpp:154
basis::outcome connect(int communication_wait=20 *basis::SECOND_ms)
Definition spocket.cpp:274
static const char * outcome_name(const basis::outcome &to_name)
Definition spocket.cpp:180
basis::outcome receive_from(basis::abyte *buffer, int &size, internet_address &where_from)
Definition spocket.cpp:713
bool is_root_server() const
Definition spocket.h:106
basis::outcome send_to(const internet_address &where_to, const basis::abyte *buffer, int size, int &len_sent)
Definition spocket.cpp:628
basis::outcome accept(spocket *&sock, bool wait)
Definition spocket.cpp:460
const internet_address & remote() const
Definition spocket.cpp:148
void bind_client(const internet_address &source)
when a client calls connect, this forces it to bind to "source".
Definition spocket.cpp:174
basis::outcome disconnect()
Definition spocket.cpp:188
basis::outcome await_readable(int timeout)
Definition spocket.cpp:238
const internet_address & where() const
Definition spocket.cpp:147
basis::outcome receive(basis::abyte *buffer, int &size)
Definition spocket.cpp:664
bool is_client() const
Definition spocket.h:104
Helpful functions for interacting with TCP/IP stacks.
Definition tcpip_stack.h:38
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.
Definition time_stamp.h:38
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
#define GRAB_LOCK
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
unsigned char abyte
A fairly important unit which is seldom defined...
Definition definitions.h:51
unsigned int un_int
Abbreviated name for unsigned integers.
Definition definitions.h:62
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition functions.h:43
A logger that sends to the console screen using the standard output device.
Provides access to the operating system's socket methods.
@ SI_DISCONNECTED
Definition raw_socket.h:46
@ SI_ERRONEOUS
Definition raw_socket.h:47
@ SI_READABLE
Definition raw_socket.h:43
@ SI_WRITABLE
Definition raw_socket.h:44
const int RESOLVE_INTERVAL
Definition spocket.cpp:62
const int PENDING_CONNECTIONS_ALLOWED
Definition spocket.cpp:57
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#include <time.h>
#define CHECK_BOGUS(retval)
Definition spocket.cpp:77
#define ENSURE_HEALTH(retval)
Definition spocket.cpp:73
#define RECOGNIZE_DISCO
Definition spocket.cpp:68
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
#define INVALID_SOCKET
#define SOCK_ECONNRESET
#define SOCKET_ERROR
#define SOCK_EINPROGRESS
#define SOCK_ECONNREFUSED
#define SOCK_EWOULDBLOCK
#define SOCK_EISCONN
void sock_hop