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 
44 using namespace basis;
45 using namespace loggers;
46 using namespace structures;
47 using namespace timely;
48 
49 namespace 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 
62 const 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 
128 spocket::~spocket()
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.
147 const internet_address &spocket::where() const { return *_where; }
148 const internet_address &spocket::remote() const { return *_remote; }
149 
150 tcpip_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.
154 astring spocket::text_form()
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 
174 void spocket::bind_client(const internet_address &addr)
175 {
176  _client_bind = true;
177  *_cli_bind = addr;
178 }
179 
180 const 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 
188 outcome spocket::disconnect()
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 
209 bool spocket::connected()
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 
238 outcome spocket::await_readable(int timeout)
239 {
240  FUNCDEF("await_readable");
241  CHECK_BOGUS(NO_CONNECTION);
242  ENSURE_HEALTH(NO_CONNECTION);
243  GRAB_LOCK;
244  int mode = raw_socket::SELECTING_JUST_READ;
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 
256 outcome spocket::await_writable(int timeout)
257 {
258  FUNCDEF("await_writable");
259  CHECK_BOGUS(NO_CONNECTION);
260  ENSURE_HEALTH(NO_CONNECTION);
261  GRAB_LOCK;
262  int mode = raw_socket::SELECTING_JUST_WRITE;
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 
274 outcome spocket::connect(int communication_wait)
275 {
276  FUNCDEF("connect");
277  CHECK_BOGUS(NO_CONNECTION);
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()) {
351  ip_addr.stuff(internet_address::ADDRESS_SIZE, _where->ip_address);
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 
421  basis::un_int last_error = critical_events::system_error();
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.
445  time_control::sleep_ms(10);
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 
460 outcome spocket::accept(spocket * &sock, bool wait)
461 {
462  FUNCDEF("accept");
463  CHECK_BOGUS(NO_CONNECTION);
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) {
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;
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 ")
508  + critical_events::system_error_text(critical_events::system_error()));
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 ")
534  + critical_events::system_error_text(error));
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 
568 outcome spocket::send(const byte_array &to_send, int &len_sent)
569 {
570  return send(to_send.observe(), to_send.length(), len_sent);
571 }
572 
573 outcome spocket::send(const abyte *buffer, int size, int &len_sent)
574 {
575  FUNCDEF("send");
576  CHECK_BOGUS(OKAY);
577  if (_type != CONNECTED) return BAD_INPUT;
578  GRAB_LOCK;
579  ENSURE_HEALTH(NO_CONNECTION);
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 
622 outcome spocket::send_to(const internet_address &where_to,
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 
628 outcome spocket::send_to(const internet_address &where_to, const abyte *to_send,
629  int size, int &len_sent)
630 {
631  FUNCDEF("send_to");
632  CHECK_BOGUS(OKAY);
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 
650 outcome spocket::receive(byte_array &buffer, int &size)
651 {
652  FUNCDEF("receive");
653  CHECK_BOGUS(NONE_READY);
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 
664 outcome spocket::receive(abyte *buffer, int &size)
665 {
666  FUNCDEF("receive");
667  CHECK_BOGUS(NONE_READY);
668  if (_type != CONNECTED) return BAD_INPUT;
669  ENSURE_HEALTH(NO_CONNECTION);
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) {
685  if (critical_events::system_error() == SOCK_EWOULDBLOCK) return NONE_READY;
686 #ifdef DEBUG_SPOCKET
687  LOG(astring("The receive failed with an error ")
688  + critical_events::system_error_text(critical_events::system_error()));
689 #endif
690  if (!connected()) return NO_CONNECTION;
691  return ACCESS_DENIED;
692  }
693  size = len;
694  return OKAY;
695 }
696 
697 outcome spocket::receive_from(byte_array &buffer, int &size,
698  internet_address &where_from)
699 {
700  FUNCDEF("receive_from");
701  where_from = internet_address();
702  CHECK_BOGUS(NONE_READY);
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 
713 outcome spocket::receive_from(abyte *buffer, int &size,
714  internet_address &where_from)
715 {
716  FUNCDEF("receive_from");
717  where_from = internet_address();
718  CHECK_BOGUS(NONE_READY);
719  if (_type == CONNECTED) return BAD_INPUT;
720  ENSURE_HEALTH(NO_CONNECTION);
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);
728  int err = critical_events::system_error();
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 ")
741  + critical_events::system_error_text(err));
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 
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
const contents * observe() const
Returns a pointer to the underlying C array of data.
Definition: array.h:172
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition: array.h:175
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
virtual void text_form(base_string &state_fill) const
Provides a text view of all the important info owned by this object.
Definition: astring.cpp:130
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
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.
Definition: spocket.h:40
Helpful functions for interacting with TCP/IP stacks.
Definition: tcpip_stack.h:38
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:57
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.
Definition: base_address.h:26
@ 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>
Definition: earth_time.cpp:37
#define GRAB_LOCK
Definition: spocket.cpp:92
#define CHECK_BOGUS(retval)
Definition: spocket.cpp:77
#define ENSURE_HEALTH(retval)
Definition: spocket.cpp:73
#define RECOGNIZE_DISCO
Definition: spocket.cpp:68
#define LOG(to_print)
Definition: spocket.cpp:55
#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