Panda3D
connectionManager.cxx
1 // Filename: connectionManager.cxx
2 // Created by: jns (07Feb00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "connectionManager.h"
16 #include "connection.h"
17 #include "connectionReader.h"
18 #include "connectionWriter.h"
19 #include "netAddress.h"
20 #include "config_net.h"
21 #include "socket_udp.h"
22 #include "socket_tcp_listen.h"
23 #include "lightMutexHolder.h"
24 #include "trueClock.h"
25 
26 #if defined(WIN32_VC) || defined(WIN64_VC)
27 #include <winsock2.h> // For gethostname()
28 #include <Iphlpapi.h> // For GetAdaptersAddresses()
29 #elif defined(ANDROID)
30 #include <net/if.h>
31 #else
32 #include <net/if.h>
33 #include <ifaddrs.h>
34 #endif
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: ConnectionManager::Constructor
38 // Access: Published
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 ConnectionManager::
42 ConnectionManager() : _set_mutex("ConnectionManager::_set_mutex")
43 {
44  _interfaces_scanned = false;
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: ConnectionManager::Destructor
49 // Access: Published, Virtual
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 ConnectionManager::
53 ~ConnectionManager() {
54  // Notify all of our associated readers and writers that we're gone.
55  Readers::iterator ri;
56  for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
57  (*ri)->clear_manager();
58  }
59  Writers::iterator wi;
60  for (wi = _writers.begin(); wi != _writers.end(); ++wi) {
61  (*wi)->clear_manager();
62  }
63 }
64 
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: ConnectionManager::open_UDP_connection
68 // Access: Published
69 // Description: Opens a socket for sending and/or receiving UDP
70 // packets. If the port number is greater than zero,
71 // the UDP connection will be opened for listening on
72 // the indicated port; otherwise, it will be useful only
73 // for sending.
74 //
75 // Use a ConnectionReader and ConnectionWriter to handle
76 // the actual communication.
77 ////////////////////////////////////////////////////////////////////
78 PT(Connection) ConnectionManager::
79 open_UDP_connection(int port) {
80  return open_UDP_connection("", port);
81 }
82 
83 ////////////////////////////////////////////////////////////////////
84 // Function: ConnectionManager::open_UDP_connection
85 // Access: Published
86 // Description: Opens a socket for sending and/or receiving UDP
87 // packets. If the port number is greater than zero,
88 // the UDP connection will be opened for listening on
89 // the indicated port; otherwise, it will be useful only
90 // for sending.
91 //
92 // This variant accepts both a hostname and port to
93 // listen on a particular interface; if the hostname is
94 // empty, all interfaces will be available.
95 //
96 // If for_broadcast is true, this UDP connection will be
97 // configured to send and/or receive messages on the
98 // broadcast address (255.255.255.255); otherwise, these
99 // messages may be automatically filtered by the OS.
100 //
101 // Use a ConnectionReader and ConnectionWriter to handle
102 // the actual communication.
103 ////////////////////////////////////////////////////////////////////
104 PT(Connection) ConnectionManager::
105 open_UDP_connection(const string &hostname, int port, bool for_broadcast) {
106  Socket_UDP *socket = new Socket_UDP;
107 
108  if (port > 0) {
109  NetAddress address;
110  if (hostname.empty()) {
111  address.set_any(port);
112  } else {
113  address.set_host(hostname, port);
114  }
115 
116  if (!socket->OpenForInput(address.get_addr())) {
117  if (hostname.empty()) {
118  net_cat.error()
119  << "Unable to bind to port " << port << " for UDP.\n";
120  } else {
121  net_cat.error()
122  << "Unable to bind to " << hostname << ":" << port << " for UDP.\n";
123  }
124  delete socket;
125  return PT(Connection)();
126  }
127 
128  const char *broadcast_note = "";
129  if (for_broadcast) {
130  socket->SetToBroadCast();
131  broadcast_note = "broadcast ";
132  }
133 
134  if (hostname.empty()) {
135  net_cat.info()
136  << "Creating UDP " << broadcast_note << "connection for port " << port << "\n";
137  } else {
138  net_cat.info()
139  << "Creating UDP " << broadcast_note << "connection for " << hostname << ":" << port << "\n";
140  }
141 
142  } else {
143  if (!socket->InitNoAddress()) {
144  net_cat.error()
145  << "Unable to initialize outgoing UDP.\n";
146  delete socket;
147  return PT(Connection)();
148  }
149 
150  const char *broadcast_note = "";
151  if (for_broadcast) {
152  socket->SetToBroadCast();
153  broadcast_note = "broadcast ";
154  }
155 
156  net_cat.info()
157  << "Creating outgoing UDP " << broadcast_note << "connection\n";
158  }
159 
160  PT(Connection) connection = new Connection(this, socket);
161  new_connection(connection);
162  return connection;
163 }
164 
165 
166 
167 ////////////////////////////////////////////////////////////////////
168 // Function: ConnectionManager::open_TCP_server_rendezvous
169 // Access: Published
170 // Description: Creates a socket to be used as a rendezvous socket
171 // for a server to listen for TCP connections. The
172 // socket returned by this call should only be added to
173 // a ConnectionListener (not to a generic
174 // ConnectionReader).
175 //
176 // This variant of this method accepts a single port,
177 // and will listen to that port on all available
178 // interfaces.
179 //
180 // backlog is the maximum length of the queue of pending
181 // connections.
182 ////////////////////////////////////////////////////////////////////
183 PT(Connection) ConnectionManager::
184 open_TCP_server_rendezvous(int port, int backlog) {
185  NetAddress address;
186  address.set_any(port);
187  return open_TCP_server_rendezvous(address, backlog);
188 }
189 
190 ////////////////////////////////////////////////////////////////////
191 // Function: ConnectionManager::open_TCP_server_rendezvous
192 // Access: Published
193 // Description: Creates a socket to be used as a rendezvous socket
194 // for a server to listen for TCP connections. The
195 // socket returned by this call should only be added to
196 // a ConnectionListener (not to a generic
197 // ConnectionReader).
198 //
199 // This variant of this method accepts a "hostname",
200 // which is usually just an IP address in dotted
201 // notation, and a port number. It will listen on the
202 // interface indicated by the IP address. If the IP
203 // address is empty string, it will listen on all
204 // interfaces.
205 //
206 // backlog is the maximum length of the queue of pending
207 // connections.
208 ////////////////////////////////////////////////////////////////////
209 PT(Connection) ConnectionManager::
210 open_TCP_server_rendezvous(const string &hostname, int port, int backlog) {
211  NetAddress address;
212  if (hostname.empty()) {
213  address.set_any(port);
214  } else {
215  address.set_host(hostname, port);
216  }
217  return open_TCP_server_rendezvous(address, backlog);
218 }
219 
220 ////////////////////////////////////////////////////////////////////
221 // Function: ConnectionManager::open_TCP_server_rendezvous
222 // Access: Published
223 // Description: Creates a socket to be used as a rendezvous socket
224 // for a server to listen for TCP connections. The
225 // socket returned by this call should only be added to
226 // a ConnectionListener (not to a generic
227 // ConnectionReader).
228 //
229 // This variant of this method accepts a NetAddress,
230 // which allows you to specify a specific interface to
231 // listen to.
232 //
233 // backlog is the maximum length of the queue of pending
234 // connections.
235 ////////////////////////////////////////////////////////////////////
236 PT(Connection) ConnectionManager::
237 open_TCP_server_rendezvous(const NetAddress &address, int backlog) {
238  ostringstream strm;
239  if (address.get_ip() == 0) {
240  strm << "port " << address.get_port();
241  } else {
242  strm << address.get_ip_string() << ":" << address.get_port();
243  }
244 
245  Socket_TCP_Listen *socket = new Socket_TCP_Listen;
246  bool okflag = socket->OpenForListen(address.get_addr(), backlog);
247  if (!okflag) {
248  net_cat.info()
249  << "Unable to listen to " << strm.str() << " for TCP.\n";
250  delete socket;
251  return PT(Connection)();
252  }
253 
254  net_cat.info()
255  << "Listening for TCP connections on " << strm.str() << "\n";
256 
257  PT(Connection) connection = new Connection(this, socket);
258  new_connection(connection);
259  return connection;
260 }
261 
262 ////////////////////////////////////////////////////////////////////
263 // Function: ConnectionManager::open_TCP_client_connection
264 // Access: Published
265 // Description: Attempts to establish a TCP client connection to a
266 // server at the indicated address. If the connection
267 // is not established within timeout_ms milliseconds, a
268 // null connection is returned.
269 ////////////////////////////////////////////////////////////////////
270 PT(Connection) ConnectionManager::
271 open_TCP_client_connection(const NetAddress &address, int timeout_ms) {
272  Socket_TCP *socket = new Socket_TCP;
273 
274  // We always open the connection with non-blocking mode first, so we
275  // can implement the timeout.
276  bool okflag = socket->ActiveOpenNonBlocking(address.get_addr());
277  if (okflag && socket->GetLastError() == LOCAL_CONNECT_BLOCKING) {
278  // Now wait for the socket to connect.
280  double start = clock->get_short_time();
282  Socket_fdset fset;
283  fset.setForSocket(*socket);
284  int ready = fset.WaitForWrite(true, 0);
285  while (ready == 0) {
286  double elapsed = clock->get_short_time() - start;
287  if (elapsed * 1000.0 > timeout_ms) {
288  // Timeout.
289  okflag = false;
290  break;
291  }
293  fset.setForSocket(*socket);
294  ready = fset.WaitForWrite(true, 0);
295  }
296  }
297 
298  if (okflag) {
299  // So, the connect() operation finished, but did it succeed or fail?
300  if (socket->GetPeerName().GetIPAddressRaw() == 0) {
301  // No peer means it failed.
302  okflag = false;
303  }
304  }
305 
306  if (!okflag) {
307  net_cat.error()
308  << "Unable to open TCP connection to server "
309  << address.get_ip_string() << " on port " << address.get_port() << "\n";
310  delete socket;
311  return PT(Connection)();
312  }
313 
314 #if !defined(HAVE_THREADS) || !defined(SIMPLE_THREADS)
315  // Now we have opened the socket in nonblocking mode. Unless we're
316  // using SIMPLE_THREADS, though, we really want the socket in
317  // blocking mode (since that's what we support here). Change it.
318  socket->SetBlocking();
319 
320 #endif // SIMPLE_THREADS
321 
322  net_cat.info()
323  << "Opened TCP connection to server " << address.get_ip_string()
324  << " on port " << address.get_port() << "\n";
325 
326  PT(Connection) connection = new Connection(this, socket);
327  new_connection(connection);
328  return connection;
329 }
330 
331 ////////////////////////////////////////////////////////////////////
332 // Function: ConnectionManager::open_TCP_client_connection
333 // Access: Published
334 // Description: This is a shorthand version of the function to
335 // directly establish communications to a named host and
336 // port.
337 ////////////////////////////////////////////////////////////////////
338 PT(Connection) ConnectionManager::
339 open_TCP_client_connection(const string &hostname, int port,
340  int timeout_ms) {
341  NetAddress address;
342  if (!address.set_host(hostname, port)) {
343  return PT(Connection)();
344  }
345 
346  return open_TCP_client_connection(address, timeout_ms);
347 }
348 
349 ////////////////////////////////////////////////////////////////////
350 // Function: ConnectionManager::close_connection
351 // Access: Published
352 // Description: Terminates a UDP or TCP socket previously opened.
353 // This also removes it from any associated
354 // ConnectionReader or ConnectionListeners.
355 //
356 // The socket itself may not be immediately closed--it
357 // will not be closed until all outstanding pointers to
358 // it are cleared, including any pointers remaining in
359 // NetDatagrams recently received from the socket.
360 //
361 // The return value is true if the connection was marked
362 // to be closed, or false if close_connection() had
363 // already been called (or the connection did not belong
364 // to this ConnectionManager). In neither case can you
365 // infer anything about whether the connection has
366 // *actually* been closed yet based on the return value.
367 ////////////////////////////////////////////////////////////////////
369 close_connection(const PT(Connection) &connection) {
370  if (connection != (Connection *)NULL) {
371  connection->flush();
372  }
373 
374  {
375  LightMutexHolder holder(_set_mutex);
376  Connections::iterator ci = _connections.find(connection);
377  if (ci == _connections.end()) {
378  // Already closed, or not part of this ConnectionManager.
379  return false;
380  }
381  _connections.erase(ci);
382 
383  Readers::iterator ri;
384  for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
385  (*ri)->remove_connection(connection);
386  }
387  }
388 
389  Socket_IP *socket = connection->get_socket();
390 
391  // We can't *actually* close the connection right now, because
392  // there might be outstanding pointers to it. But we can at least
393  // shut it down. It will be eventually closed when all the
394  // pointers let go.
395 
396  net_cat.info()
397  << "Shutting down connection " << (void *)connection
398  << " locally.\n";
399  socket->Close();
400 
401  return true;
402 }
403 
404 
405 ////////////////////////////////////////////////////////////////////
406 // Function: ConnectionManager::wait_for_readers
407 // Access: Published
408 // Description: Blocks the process for timeout number of seconds, or
409 // until any data is available on any of the
410 // non-threaded ConnectionReaders or
411 // ConnectionListeners, whichever comes first. The
412 // return value is true if there is data available (but
413 // you have to iterate through all readers to find it),
414 // or false if the timeout occurred without any data.
415 //
416 // If the timeout value is negative, this will block
417 // forever or until data is available.
418 //
419 // This only works if all ConnectionReaders and
420 // ConnectionListeners are non-threaded. If any
421 // threaded ConnectionReaders are part of the
422 // ConnectionManager, the timeout value is implicitly
423 // treated as 0.
424 ////////////////////////////////////////////////////////////////////
426 wait_for_readers(double timeout) {
427  bool block_forever = false;
428  if (timeout < 0.0) {
429  block_forever = true;
430  timeout = 0.0;
431  }
432 
434  double now = clock->get_short_time();
435  double stop = now + timeout;
436  do {
437  Socket_fdset fdset;
438  fdset.clear();
439  bool any_threaded = false;
440 
441  {
442  LightMutexHolder holder(_set_mutex);
443 
444  Readers::iterator ri;
445  for (ri = _readers.begin(); ri != _readers.end(); ++ri) {
446  ConnectionReader *reader = (*ri);
447  if (reader->is_polling()) {
448  // If it's a polling reader, we can wait for its socket.
449  // (If it's a threaded reader, we can't do anything here.)
450  reader->accumulate_fdset(fdset);
451  } else {
452  any_threaded = true;
453  stop = now;
454  block_forever = false;
455  }
456  }
457  }
458 
459  double wait_timeout = get_net_max_block();
460  if (!block_forever) {
461  wait_timeout = min(wait_timeout, stop - now);
462  }
463 
464  PN_uint32 wait_timeout_ms = (PN_uint32)(wait_timeout * 1000.0);
465  if (any_threaded) {
466  // If there are any threaded ConnectionReaders, we can't block
467  // at all.
468  wait_timeout_ms = 0;
469  }
470 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
471  // In the presence of SIMPLE_THREADS, we never wait at all,
472  // but rather we yield the thread if we come up empty (so that
473  // we won't block the entire process).
474  wait_timeout_ms = 0;
475 #endif
476  int num_results = fdset.WaitForRead(false, wait_timeout_ms);
477  if (num_results != 0) {
478  // If we got an answer (or an error), return success. The
479  // caller can then figure out what happened.
480  if (num_results < 0) {
481  // Go ahead and yield the timeslice if we got an error.
483  }
484  return true;
485  }
486 
487  // No answer yet, so yield and wait some more. We don't actually
488  // block forever, even in the threaded case, so we can detect
489  // ConnectionReaders being added and removed and such.
491 
492  now = clock->get_short_time();
493  } while (now < stop || block_forever);
494 
495  // Timeout occurred; no data.
496  return false;
497 }
498 
499 ////////////////////////////////////////////////////////////////////
500 // Function: ConnectionManager::get_host_name
501 // Access: Published, Static
502 // Description: Returns the name of this particular machine on the
503 // network, if available, or the empty string if the
504 // hostname cannot be determined.
505 ////////////////////////////////////////////////////////////////////
506 string ConnectionManager::
508  char temp_buff[1024];
509  if (gethostname(temp_buff, 1024) == 0) {
510  return string(temp_buff);
511  }
512 
513  return string();
514 }
515 
516 ////////////////////////////////////////////////////////////////////
517 // Function: ConnectionManager::scan_interfaces
518 // Access: Published
519 // Description: Repopulates the list reported by
520 // get_num_interface()/get_interface(). It is not
521 // necessary to call this explicitly, unless you want to
522 // re-determine the connected interfaces (for instance,
523 // if you suspect the hardware has recently changed).
524 ////////////////////////////////////////////////////////////////////
527  LightMutexHolder holder(_set_mutex);
528  _interfaces.clear();
529  _interfaces_scanned = true;
530 
531 #ifdef WIN32_VC
532  int flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
533  ULONG buffer_size = 0;
534  ULONG result = GetAdaptersAddresses(AF_INET, flags, NULL, NULL, &buffer_size);
535  if (result == ERROR_BUFFER_OVERFLOW) {
536  IP_ADAPTER_ADDRESSES *addresses = (IP_ADAPTER_ADDRESSES *)PANDA_MALLOC_ARRAY(buffer_size);
537  result = GetAdaptersAddresses(AF_INET, flags, NULL, addresses, &buffer_size);
538  if (result == ERROR_SUCCESS) {
539  IP_ADAPTER_ADDRESSES *p = addresses;
540  while (p != NULL) {
541  // p->AdapterName appears to be a GUID. Not sure if this is
542  // actually useful to anyone; we'll store the "friendly name"
543  // instead.
544  TextEncoder encoder;
545  encoder.set_wtext(wstring(p->FriendlyName));
546  string friendly_name = encoder.get_text();
547 
548  Interface iface;
549  iface.set_name(friendly_name);
550 
551  if (p->PhysicalAddressLength > 0) {
552  iface.set_mac_address(format_mac_address((const unsigned char *)p->PhysicalAddress, p->PhysicalAddressLength));
553  }
554 
555  if (p->OperStatus == IfOperStatusUp) {
556  // Prefixes are a linked list, in the order Network IP,
557  // Adapter IP, Broadcast IP (plus more).
558  NetAddress addresses[3];
559  IP_ADAPTER_PREFIX *m = p->FirstPrefix;
560  int mc = 0;
561  while (m != NULL && mc < 3) {
562  addresses[mc] = NetAddress(Socket_Address(*(sockaddr_in *)m->Address.lpSockaddr));
563  m = m->Next;
564  ++mc;
565  }
566 
567  if (mc > 1) {
568  iface.set_ip(addresses[1]);
569  }
570 
571  if (mc > 2) {
572  iface.set_broadcast(addresses[2]);
573 
574  // Now, we can infer the netmask by the difference between the
575  // network address (the first address) and the broadcast
576  // address (the last address).
577  PN_uint32 netmask = addresses[0].get_ip() - addresses[2].get_ip() - 1;
578  Socket_Address sa;
579  sa.set_host(netmask, 0);
580  iface.set_netmask(NetAddress(sa));
581  }
582  }
583 
584  _interfaces.push_back(iface);
585  p = p->Next;
586  }
587  }
588  PANDA_FREE_ARRAY(addresses);
589  }
590 
591 #elif defined(ANDROID)
592  // TODO: implementation using netlink_socket?
593 
594 #else // WIN32_VC
595  struct ifaddrs *ifa;
596  if (getifaddrs(&ifa) != 0) {
597  // Failure.
598  net_cat.error()
599  << "Failed to call getifaddrs\n";
600  return;
601  }
602 
603  struct ifaddrs *p = ifa;
604  while (p != NULL) {
605  if (p->ifa_addr->sa_family == AF_INET) {
606  Interface iface;
607  iface.set_name(p->ifa_name);
608  if (p->ifa_addr != NULL) {
609  iface.set_ip(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_addr)));
610  }
611  if (p->ifa_netmask != NULL) {
612  iface.set_netmask(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_netmask)));
613  }
614  if ((p->ifa_flags & IFF_BROADCAST) && p->ifa_broadaddr != NULL) {
615  iface.set_broadcast(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_broadaddr)));
616  } else if ((p->ifa_flags & IFF_POINTOPOINT) && p->ifa_dstaddr != NULL) {
617  iface.set_p2p(NetAddress(Socket_Address(*(sockaddr_in *)p->ifa_dstaddr)));
618  }
619  _interfaces.push_back(iface);
620  }
621 
622  p = p->ifa_next;
623  }
624 
625  freeifaddrs(ifa);
626 
627 #endif // WIN32_VC
628 }
629 
630 ////////////////////////////////////////////////////////////////////
631 // Function: ConnectionManager::get_num_interfaces
632 // Access: Published
633 // Description: This returns the number of usable network interfaces
634 // detected on this machine. (Currently, only IPv4
635 // interfaces are reported.) See scan_interfaces() to
636 // repopulate this list.
637 ////////////////////////////////////////////////////////////////////
640  if (!_interfaces_scanned) {
641  scan_interfaces();
642  }
643  LightMutexHolder holder(_set_mutex);
644  return _interfaces.size();
645 }
646 
647 ////////////////////////////////////////////////////////////////////
648 // Function: ConnectionManager::get_interface
649 // Access: Published
650 // Description: Returns the nth usable network interface detected on
651 // this machine. (Currently, only IPv4 interfaces are
652 // reported.) See scan_interfaces() to repopulate this
653 // list.
654 ////////////////////////////////////////////////////////////////////
657  if (!_interfaces_scanned) {
658  scan_interfaces();
659  }
660  LightMutexHolder holder(_set_mutex);
661  nassertr(n >= 0 && n < (int)_interfaces.size(), _interfaces[0]);
662  return _interfaces[n];
663 }
664 
665 ////////////////////////////////////////////////////////////////////
666 // Function: ConnectionManager::new_connection
667 // Access: Protected
668 // Description: This internal function is called whenever a new
669 // connection is established. It allows the
670 // ConnectionManager to save all of the pointers to open
671 // connections so they can't be inadvertently deleted
672 // until close_connection() is called.
673 ////////////////////////////////////////////////////////////////////
674 void ConnectionManager::
675 new_connection(const PT(Connection) &connection) {
676  LightMutexHolder holder(_set_mutex);
677  _connections.insert(connection);
678 }
679 
680 ////////////////////////////////////////////////////////////////////
681 // Function: ConnectionManager::flush_read_connection
682 // Access: Protected, Virtual
683 // Description: An internal function called by ConnectionWriter only
684 // when a write failure has occurred. This method
685 // ensures that all of the read data has been flushed
686 // from the pipe before the connection is fully removed.
687 ////////////////////////////////////////////////////////////////////
688 void ConnectionManager::
689 flush_read_connection(Connection *connection) {
690  Readers readers;
691  {
692  LightMutexHolder holder(_set_mutex);
693  Connections::iterator ci = _connections.find(connection);
694  if (ci == _connections.end()) {
695  // Already closed, or not part of this ConnectionManager.
696  return;
697  }
698  _connections.erase(ci);
699 
700  // Get a copy first, so we can release the lock before traversing.
701  readers = _readers;
702  }
703  Readers::iterator ri;
704  for (ri = readers.begin(); ri != readers.end(); ++ri) {
705  (*ri)->flush_read_connection(connection);
706  }
707 
708  Socket_IP *socket = connection->get_socket();
709  socket->Close();
710 }
711 
712 ////////////////////////////////////////////////////////////////////
713 // Function: ConnectionManager::connection_reset
714 // Access: Protected, Virtual
715 // Description: An internal function called by the ConnectionReader,
716 // ConnectionWriter, or ConnectionListener when a
717 // connection has been externally reset. This adds the
718 // connection to the queue of those which have recently
719 // been reset.
720 ////////////////////////////////////////////////////////////////////
721 void ConnectionManager::
722 connection_reset(const PT(Connection) &connection, bool okflag) {
723  if (net_cat.is_info()) {
724  if (okflag) {
725  net_cat.info()
726  << "Connection " << (void *)connection
727  << " was closed normally by the other end";
728 
729  } else {
730  net_cat.info()
731  << "Lost connection " << (void *)connection
732  << " unexpectedly\n";
733  }
734  }
735 
736  // Turns out we do need to explicitly mark the connection as closed
737  // immediately, rather than waiting for the user to do it, since
738  // otherwise we'll keep trying to listen for noise on the socket and
739  // we'll always hear a "yes" answer.
740  close_connection(connection);
741 }
742 
743 ////////////////////////////////////////////////////////////////////
744 // Function: ConnectionManager::add_reader
745 // Access: Protected
746 // Description: This internal function is called by ConnectionReader
747 // when it is constructed.
748 ////////////////////////////////////////////////////////////////////
749 void ConnectionManager::
750 add_reader(ConnectionReader *reader) {
751  LightMutexHolder holder(_set_mutex);
752  _readers.insert(reader);
753 }
754 
755 ////////////////////////////////////////////////////////////////////
756 // Function: ConnectionManager::remove_reader
757 // Access: Protected
758 // Description: This internal function is called by ConnectionReader
759 // when it is destructed.
760 ////////////////////////////////////////////////////////////////////
761 void ConnectionManager::
762 remove_reader(ConnectionReader *reader) {
763  LightMutexHolder holder(_set_mutex);
764  _readers.erase(reader);
765 }
766 
767 ////////////////////////////////////////////////////////////////////
768 // Function: ConnectionManager::add_writer
769 // Access: Protected
770 // Description: This internal function is called by ConnectionWriter
771 // when it is constructed.
772 ////////////////////////////////////////////////////////////////////
773 void ConnectionManager::
774 add_writer(ConnectionWriter *writer) {
775  LightMutexHolder holder(_set_mutex);
776  _writers.insert(writer);
777 }
778 
779 ////////////////////////////////////////////////////////////////////
780 // Function: ConnectionManager::remove_writer
781 // Access: Protected
782 // Description: This internal function is called by ConnectionWriter
783 // when it is destructed.
784 ////////////////////////////////////////////////////////////////////
785 void ConnectionManager::
786 remove_writer(ConnectionWriter *writer) {
787  LightMutexHolder holder(_set_mutex);
788  _writers.erase(writer);
789 }
790 
791 ////////////////////////////////////////////////////////////////////
792 // Function: ConnectionManager::format_mac_address
793 // Access: Protected
794 // Description: Formats a device's MAC address into a string.
795 ////////////////////////////////////////////////////////////////////
796 string ConnectionManager::
797 format_mac_address(const unsigned char *data, int data_size) {
798  stringstream strm;
799  for (int di = 0; di < data_size; ++di) {
800  if (di != 0) {
801  strm << "-";
802  }
803  strm << hex << setw(2) << setfill('0') << (unsigned int)data[di];
804  }
805 
806  return strm.str();
807 }
808 
809 ////////////////////////////////////////////////////////////////////
810 // Function: ConnectionManager::Interface::Output
811 // Access: Published
812 // Description:
813 ////////////////////////////////////////////////////////////////////
814 void ConnectionManager::Interface::
815 output(ostream &out) const {
816  out << get_name() << " [";
817  if (has_ip()) {
818  out << " " << get_ip();
819  }
820  if (has_netmask()) {
821  out << " netmask " << get_netmask();
822  }
823  if (has_broadcast()) {
824  out << " broadcast " << get_broadcast();
825  }
826  if (has_p2p()) {
827  out << " p2p " << get_p2p();
828  }
829  out << " ]";
830 }
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:81
Base functionality for a TCP connected socket This class is pretty useless by itself but it does hide...
Definition: socket_tcp.h:15
unsigned long GetIPAddressRaw() const
Return a RAW sockaddr_in.
int get_num_interfaces()
This returns the number of usable network interfaces detected on this machine.
bool set_any(int port)
Sets the address up to refer to a particular port, but not to any particular IP.
Definition: netAddress.cxx:50
Base functionality for a INET domain Socket this call should be the starting point for all other unix...
Definition: socket_ip.h:34
string get_ip_string() const
Returns the IP address to which this address refers, formatted as a string.
Definition: netAddress.cxx:125
bool is_polling() const
Returns true if the reader is a polling reader, i.e.
int SetBlocking()
Set the socket to block on subsequent calls to socket functions that address this socket...
Definition: socket_ip.h:207
This class can be used to convert text between multiple representations, e.g.
Definition: textEncoder.h:37
bool InitNoAddress()
This will set a udp up for targeted sends.
Definition: socket_udp.h:103
void scan_interfaces()
Repopulates the list reported by get_num_interface()/get_interface().
bool ActiveOpenNonBlocking(const Socket_Address &theaddress)
This function will try and set the socket up for active open to a specified address and port provided...
Definition: socket_tcp.h:152
int get_port() const
Returns the port number to which this address refers.
Definition: netAddress.cxx:103
Socket_Address GetPeerName(void) const
Wrapper on berkly getpeername...
Definition: socket_ip.h:257
bool OpenForListen(const Socket_Address &Inaddess, int backlog_size=1024)
This function will initialize a listening Socket.
static void force_yield()
Suspends the current thread for the rest of the current epoch.
Definition: thread.I:248
This is an abstract base class for a family of classes that listen for activity on a socket and respo...
Base functionality for a TCP rendezvous socket.
bool set_host(const string &hostname, int port)
Sets the address up to refer to a particular port on a particular host.
Definition: netAddress.cxx:83
Base functionality for a combination UDP Reader and Writer.
Definition: socket_udp.h:28
Socket_IP * get_socket() const
Returns the internal Socket_IP that defines the connection.
Definition: connection.cxx:107
bool SetToBroadCast()
Ask the OS to let us receive BROADCASt packets on this port.
Definition: socket_udp.h:71
Similar to MutexHolder, but for a light mutex.
PN_uint32 get_ip() const
Returns the IP address to which this address refers, as a 32-bit integer, in host byte order...
Definition: netAddress.cxx:136
This class handles threaded delivery of datagrams to various TCP or UDP sockets.
static string get_host_name()
Returns the name of this particular machine on the network, if available, or the empty string if the ...
An interface to whatever real-time clock we might have available in the current environment.
Definition: trueClock.h:38
A simple place to store and munipulate tcp and port address for communication layer.
bool set_host(const std::string &hostname, int port)
This function will take a port and string-based TCP address and initialize the address with this info...
static int GetLastError()
gets the last errcode from a socket operation
Definition: socket_ip.h:152
void Close()
closes a socket if it is open (allocated)
Definition: socket_ip.h:141
void clear()
Marks the content as empty.
Definition: socket_fdset.h:138
bool wait_for_readers(double timeout)
Blocks the process for timeout number of seconds, or until any data is available on any of the non-th...
const Interface & get_interface(int n)
Returns the nth usable network interface detected on this machine.
const Socket_Address & get_addr() const
Returns the Socket_Address for this address.
Definition: netAddress.cxx:163
bool OpenForInput(const Socket_Address &address)
Starts a UDP socket listening on a port.
void set_wtext(const wstring &wtext)
Changes the text that is stored in the encoder.
Definition: textEncoder.I:516
Represents a single TCP or UDP socket for input or output.
Definition: connection.h:32
bool flush()
Sends the most recently queued TCP datagram(s) now.
Definition: connection.cxx:211
bool close_connection(const PT(Connection) &connection)
Terminates a UDP or TCP socket previously opened.
Represents a network address to which UDP packets may be sent or to which a TCP socket may be bound...
Definition: netAddress.h:27
string get_text() const
Returns the current text, as encoded via the current encoding system.
Definition: textEncoder.I:167
int WaitForWrite(bool zeroFds, PN_uint32 sleep_time=0xffffffff)
This is the function that will wait till one of the sockets is ready for writing. ...
Definition: socket_fdset.h:159