vrpn  07.33
Virtual Reality Peripheral Network
vrpn_Connection.C
Go to the documentation of this file.
1 // Must be done before stdio.h to avoid conflict for SEEK_SET, at least for
2 // MPICH2 on
3 // the Windows platform.. Note that this means we cannot include it in
4 // vrpn_Connection.h,
5 // because user code often includes stdio.h before and VRPN includes.
6 #ifdef VRPN_USE_MPI
7 #include <mpi.h>
8 #endif
9 
10 #ifndef _WIN32_WCE
11 #include <errno.h> // for errno, EINTR
12 #endif
13 #include <stddef.h> // for size_t
14 #include <stdio.h> // for fprintf, stderr, NULL, etc
15 #include <string.h> // for strlen, strcpy, memcpy, etc
16 #ifndef _WIN32_WCE
17 #include <signal.h> // for kill, signal, SIGKILL, etc
18 #ifdef sgi
19 #include <ctype.h>
20 #else
21 #include <cctype> // for isalnum
22 #endif
23 #endif
24 
25 // malloc.h is deprecated; all the functionality *should*
26 // be in stdlib.h
27 #include <stdlib.h> // for exit, atoi, getenv, system
28 
29 #include "vrpn_Connection.h"
30 
31 #ifdef VRPN_USE_WINSOCK_SOCKETS
32 // a socket in windows can not be closed like it can in unix-land
33 #define vrpn_closeSocket closesocket
34 #else
35 #define vrpn_closeSocket close
36 #include <arpa/inet.h> // for inet_addr
37 #include <netinet/in.h> // for sockaddr_in, ntohl, in_addr, etc
38 #include <sys/socket.h> // for getsockname, send, AF_INET, etc
39 #include <unistd.h> // for close, read, fork, etc
40 #ifdef _AIX
41 #define _USE_IRS
42 #endif
43 #include <netdb.h> // for hostent, gethostbyname, etc
44 #endif
45 
46 #ifdef sparc
47 #include <arpa/inet.h> // for inet_addr
48 
49 #define INADDR_NONE -1
50 #endif
51 
52 #ifdef sgi
53 #include <bstring.h>
54 #endif
55 
56 #ifdef hpux
57 #include <arpa/nameser.h>
58 #include <resolv.h> // for herror() - but it isn't there?
59 #endif
60 
61 #ifndef VRPN_USE_WINSOCK_SOCKETS
62 #include <sys/wait.h> // for wait, wait3, WNOHANG
63 #ifndef __CYGWIN__
64 #include <netinet/tcp.h> // for TCP_NODELAY
65 #endif /* __CYGWIN__ */
66 #endif /* VRPN_USE_WINSOCK_SOCKETS */
67 
68 // cast fourth argument to setsockopt()
69 #ifdef VRPN_USE_WINSOCK_SOCKETS
70 #define SOCK_CAST (char *)
71 #ifdef _WIN32_WCE
72 #define errno WSAGetLastError()
73 #define EINTR WSAEINTR
74 #endif
75 #else
76 #ifdef sparc
77 #define SOCK_CAST (const char *)
78 #else
79 #define SOCK_CAST
80 #endif
81 #endif
82 
83 #if defined(_AIX) || defined(__APPLE__) || defined(ANDROID) || defined(__linux)
84 #define GSN_CAST (socklen_t *)
85 #else
86 #if defined(FreeBSD)
87 #define GSN_CAST (unsigned int *)
88 #else
89 #define GSN_CAST
90 #endif
91 #endif
92 
93 // NOT SUPPORTED ON SPARC_SOLARIS
94 // gethostname() doesn't seem to want to link out of stdlib
95 #ifdef sparc
96 extern "C" {
97 int gethostname(char *, int);
98 }
99 #endif
100 
101 #include "vrpn_FileConnection.h" // for vrpn_File_Connection
102 #include "vrpn_Log.h" // for vrpn_Log
103 
104 struct timeval;
105 
106 //#define VERBOSE
107 //#define VERBOSE2
108 //#define VERBOSE3
109 
110 // On Win32, this constant is defined as ~0 (sockets are unsigned ints)
111 #ifndef VRPN_USE_WINSOCK_SOCKETS
112 #define INVALID_SOCKET -1
113 #endif
114 
115 // Don't tell us about FD_SET() "conditional expression is constant"
116 #ifdef _WIN32
117 #pragma warning(disable : 4127)
118 #endif
119 
120 // Syntax of vrpn_MAGIC:
121 //
122 // o The minor version number must follow the last period ('.') and be the
123 // only significant thing following the last period in the vrpn_MAGIC string.
124 //
125 // o Minor versions should interoperate. So, when establishing a connection,
126 // vrpn_MAGIC is checked through the last period. If everything up to, and
127 // including, the last period matches, a connection will be made.
128 //
129 // o If everything up to the last period matches, then a second check is
130 // preformed on everything after the last period (the minor version number).
131 // If the minor version numbers differ, a connection is still made, but a
132 // warning is printed to stderr. There is currently no way to suppress this
133 // warning message if the minor versions differ between the server and the
134 // client..
135 //
136 // o The version checking described above is performed by the function
137 // check_vrpn_cookie, found in this file. check_vrpn_cookie returns a
138 // different value for each of these three cases.
139 // -[juliano 2000/08]
140 //
141 // [juliano 2000/08] Suggestion:
142 //
143 // We have the situation today that vrpn5 can read stream files that were
144 // produced by vrpn-4.x. However, the way the library is written, vrpn
145 // doesn't know this. Further, it is difficult to change this quickly,
146 // because vrpn_check_cookie doesn't know if it's being called for a network
147 // or a file connection. The purpose of this comment is to suggest a
148 // solution.
149 //
150 // Our temporary solution is to change the cookie, rebulid the library, and
151 // relink into our app. Then, our app can read stream files produced by
152 // vrpn4.x.
153 //
154 // Vrpn currently knows that live network connections between vrpn-4.x and
155 // vrpn-5.x apps are not possible. But, ideally, it should also know that
156 // it's ok for a vrpn-5.x app to read a vrpn-4.x streamfile. Unfortunately,
157 // coding this is difficult in the current framework.
158 //
159 // I suggest that check_vrpn_cookie should not be a global function, but
160 // should instead be a protected member function of vrpn_Connection. The
161 // default implementation would do what is currently done by the global
162 // check_vrpn_cookie. However, vrpn_FileConnection would override it and
163 // perform a more permissive check.
164 //
165 // This strategy would scale in the future when we move to vrpn-6.x and
166 // higher. It would also be useful if we ever realize after a release that
167 // VRPN-major.minor is actually network incompatible (but not streamfile
168 // incompatible) with VRPN-major.(minor-1). Then, the vrpn_check_cookie
169 // implementation in VRPN-major.(minor-1) could test for this incompatibility
170 // and print an appropriate diagnostic. Similar solution exists if release
171 // n+1 is file-compatible but later found to be network-incompatible with
172 // release n.
173 //
174 // Again, in our current framework, we cannot distinguish between
175 // file-compatible and network-compatible. In the future, we may also have
176 // shared-memory-access-compatible as well as other types of connection. The
177 // proposed strategy handles both partial major version compatibility as well
178 // as accidental partial minor version incompatibility.
179 //
180 const char *vrpn_MAGIC = (const char *)"vrpn: ver. 07.33";
181 const char *vrpn_FILE_MAGIC = (const char *)"vrpn: ver. 04.00";
182 const int vrpn_MAGICLEN = 16; // Must be a multiple of vrpn_ALIGN bytes!
183 
184 const char *vrpn_got_first_connection = "VRPN_Connection_Got_First_Connection";
185 const char *vrpn_got_connection = "VRPN_Connection_Got_Connection";
186 const char *vrpn_dropped_connection = "VRPN_Connection_Dropped_Connection";
188  "VRPN_Connection_Dropped_Last_Connection";
189 
190 const char *vrpn_CONTROL = "VRPN Control";
191 
192 //**********************************************************************
193 //** This section has been pulled from the "SDI" library and had its
194 //** functions renamed to vrpn_ from sdi_. This removes our dependence
195 //** on libsdi.a for VRPN.
196 
197 #ifdef sparc
198 
199 // On capefear and swift, getdtablesize() isn't declared in unistd.h
200 // even though the man page says it should be. Similarly, wait3()
201 // isn't declared in sys/{wait,time,resource}.h.
202 extern "C" {
203 extern int getdtablesize(void);
204 pid_t wait3(int *statusp, int options, struct rusage *rusage);
205 }
206 #endif
207 
208 /* On HP's, this defines how many possible open file descriptors can be
209  * open at once. This is what is returned by the getdtablesize() function
210  * on other architectures. */
211 #ifdef hpux
212 #define getdtablesize() MAXFUPLIM
213 #endif
214 
215 #ifdef __hpux
216 #define getdtablesize() MAXFUPLIM
217 #endif
218 
219 /* The version of rsh in /usr/local/bin is the AFS version that passes tokens
220  * to the remote machine. This will allow remote execution of anything you
221  * can execute locally. This is the default location from which to get rsh.
222  * If the VRPN_RSH environment variable is set, that will be used as the full
223  * path instead. */
224 #ifdef linux
225 #define RSH (char *) "/usr/local/bin/ssh"
226 #else
227 #define RSH (char *) "/usr/local/bin/rsh"
228 #endif
229 
230 /* How long to wait for a UDP packet to cause a callback connection,
231  * and how many times to retry. */
232 #define UDP_CALL_TIMEOUT (2)
233 #define UDP_CALL_RETRIES (5)
234 
235 /* How long to wait for the server to connect, and how many times to wait
236  * this long. The death of the child is checked for between each of the
237  * waits, in order to allow faster exit if the child quits before calling
238  * back. */
239 #define SERVCOUNT (20)
240 #define SERVWAIT (120 / SERVCOUNT)
241 
242 // From vrpn_CONNECTION_MAX_SENDERS and vrpn_CONNECTION_MAX_TYPES
243 // in vrpn_Connection.h.
244 
245 #define vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE 2000
246 
247 /*
248  Major refactoring 18-20 April 2000 T. Hudson
249 
250  Broke two classes (vrpn_Connection, vrpn_OneConnection) into five:
251 
252  vrpn_TranslationTable
253  vrpn_TypeDispatcher
254  vrpn_Log
255  vrpn_Endpoint
256  vrpn_Connection
257 
258  Each Connection manages one Endpoint per Connection that it is
259  communicating with. Each Endpoint has a Log, and at a future date
260  some Connections may have their own logs. Each Endpoint has two
261  TranslationTables to map remote senders and types to their local
262  identifiers; these tables are also used by Logs. The entire system
263  shares a single TypeDispatcher to track local types, senders, and callbacks.
264 
265  This decomposition let me get rid of the circular references between
266  Connection and Endpoint and between Endpoint and Log. It lets us
267  have logs attached to both Endpoints and Connections. It better
268  isolates and identifies some of the functionality we're using.
269 
270  I've always thought the central component of VRPN is the TypeDispatcher,
271  which I've also seen in the (late '80s) commercial database middleware
272  I've hacked the internals of. There isn't an example of it in the
273  Gang-Of-4 "Design Patterns" book, but I'm doing a small Patterns literature
274  search to try to find it.
275 
276  This module's interface still only contains Connection and Endpoint.
277  The only reason Endpoint is visible is so that it can be used by
278  vrpn_FileConnection; unfortunately, it isn't easy to factor it out
279  of there. I'd suggest moving Connection and FileConnection into their
280  own directory; we can then extract all the classes out of this
281  file into their own C files.
282 
283  TypeDispatcher could certainly use a better name.
284 */
285 
293 struct cRemoteMapping {
294  char *name;
295  vrpn_int32 remote_id;
296  vrpn_int32 local_id;
297 };
298 
299 class vrpn_TranslationTable {
300 
301 public:
302  vrpn_TranslationTable(void);
303  ~vrpn_TranslationTable(void);
304 
305  // ACCESSORS
306 
307  vrpn_int32 numEntries(void) const;
308  vrpn_int32 mapToLocalID(vrpn_int32 remote_id) const;
309 
310  // MANIPULATORS
311 
312  void clear(void);
314 
315  vrpn_int32 addRemoteEntry(cName name, vrpn_int32 remote_id,
316  vrpn_int32 local_id);
321  vrpn_bool addLocalID(const char *name, vrpn_int32 local_id);
324 
325 private:
326  vrpn_int32 d_numEntries;
327  cRemoteMapping d_entry[vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE];
328 };
329 
331  : d_numEntries(0)
332 {
333  int i;
334 
335  for (i = 0; i < vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE; i++) {
336  d_entry[i].name = NULL;
337  d_entry[i].remote_id = -1;
338  d_entry[i].local_id = -1;
339  }
340 }
341 
342 vrpn_TranslationTable::~vrpn_TranslationTable(void) { clear(); }
343 
344 vrpn_int32 vrpn_TranslationTable::numEntries(void) const
345 {
346  return d_numEntries;
347 }
348 
349 vrpn_int32 vrpn_TranslationTable::mapToLocalID(vrpn_int32 remote_id) const
350 {
351  if ((remote_id < 0) || (remote_id > d_numEntries)) {
352 
353 #ifdef VERBOSE2
354  // This isn't an error!? It happens regularly!?
355  fprintf(stderr, "vrpn_TranslationTable::mapToLocalID: "
356  "Remote ID %d is illegal!\n",
357  remote_id);
358 #endif
359 
360  return -1;
361  }
362 
363 #ifdef VERBOSE
364  fprintf(stderr, "Remote ID %d maps to local ID %d (%s).\n", remote_id,
365  d_entry[remote_id].local_id, d_entry[remote_id].name);
366 #endif
367 
368  return d_entry[remote_id].local_id;
369 }
370 
371 vrpn_int32 vrpn_TranslationTable::addRemoteEntry(cName name,
372  vrpn_int32 remote_id,
373  vrpn_int32 local_id)
374 {
375  vrpn_int32 useEntry;
376 
377  useEntry = remote_id;
378 
379  if (useEntry >= vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE) {
380  fprintf(stderr, "vrpn_TranslationTable::addRemoteEntry: "
381  "Too many entries in table (%d).\n",
382  d_numEntries);
383  return -1;
384  }
385 
386  // We do not check to see if this entry is already filled in. Such
387  // a check caused problems with vrpn_Control when reading from log files.
388  // Also, it will cause problems with multi-logging, where the connection
389  // may be requested to send all of its IDs again for a log file is opeened
390  // at a time other than connection set-up.
391 
392  if (!d_entry[useEntry].name) {
393  d_entry[useEntry].name = new cName;
394  if (!d_entry[useEntry].name) {
395  fprintf(stderr, "vrpn_TranslationTable::addRemoteEntry: "
396  "Out of memory.\n");
397  return -1;
398  }
399  }
400 
401  memcpy(d_entry[useEntry].name, name, sizeof(cName));
402  d_entry[useEntry].remote_id = remote_id;
403  d_entry[useEntry].local_id = local_id;
404 
405 #ifdef VERBOSE
406  fprintf(stderr, "Set up remote ID %d named %s with local equivalent %d.\n",
407  remote_id, name, local_id);
408 #endif
409 
410  if (d_numEntries <= useEntry) {
411  d_numEntries = useEntry + 1;
412  }
413 
414  return useEntry;
415 }
416 
417 vrpn_bool vrpn_TranslationTable::addLocalID(const char *name,
418  vrpn_int32 local_id)
419 {
420  int i;
421 
422  for (i = 0; i < d_numEntries; i++) {
423  if (d_entry[i].name && !strcmp(d_entry[i].name, name)) {
424  d_entry[i].local_id = local_id;
425  return VRPN_TRUE;
426  }
427  }
428  return VRPN_FALSE;
429 }
430 
431 void vrpn_TranslationTable::clear(void)
432 {
433  int i;
434 
435  for (i = 0; i < d_numEntries; i++) {
436  if (d_entry[i].name) {
437  delete[] d_entry[i].name;
438  d_entry[i].name = NULL;
439  }
440  d_entry[i].local_id = -1;
441  d_entry[i].remote_id = -1;
442  }
443  d_numEntries = 0;
444 }
445 
447  : d_logFileName(NULL)
448  , d_logmode(vrpn_LOG_NONE)
449  , d_logTail(NULL)
450  , d_firstEntry(NULL)
451  , d_file(NULL)
452  , d_magicCookie(NULL)
453  , d_wroteMagicCookie(vrpn_FALSE)
454  , d_filters(NULL)
455  , d_senders(senders)
456  , d_types(types)
457 {
458 
459  d_lastLogTime.tv_sec = 0;
460  d_lastLogTime.tv_usec = 0;
461 
462  // Set up default value for the cookie received from the server
463  // because if we are using a file connection and want to
464  // write a log, we never receive a cookie from the server.
465  d_magicCookie = new char[vrpn_cookie_size() + 1];
466  if (!d_magicCookie) {
467  fprintf(stderr, "vrpn_Log: Out of memory.\n");
468  return;
469  }
471 }
472 
474 {
475  if (d_file) {
476  close();
477  }
478 
479  if (d_filters) {
480  vrpnLogFilterEntry *next;
481  while (d_filters) {
482  next = d_filters->next;
483  delete d_filters;
484  d_filters = next;
485  }
486  }
487 
488  if (d_magicCookie) {
489  delete[] d_magicCookie;
490  }
491 }
492 
494 {
495  if (this->d_logFileName == NULL)
496  return NULL;
497  else {
498  char *s = new char[strlen(this->d_logFileName) + 1];
499  strcpy(s, this->d_logFileName);
500  return s;
501  }
502 }
503 
504 int vrpn_Log::open(void)
505 {
506 
507  if (!d_logFileName) {
508  fprintf(stderr, "vrpn_Log::open: Log file has no name.\n");
509  return -1;
510  }
511  if (d_file) {
512  fprintf(stderr, "vrpn_Log::open: Log file is already open.\n");
513  return 0; // not a catastrophic failure
514  }
515 
516  // If we can open the file for reading, then it already exists. If
517  // so, we don't want to overwrite it.
518  d_file = fopen(d_logFileName, "r");
519  if (d_file) {
520  fprintf(stderr, "vrpn_Log::open: "
521  "Log file \"%s\" already exists.\n",
522  d_logFileName);
523  fclose(d_file);
524  d_file = NULL;
525  }
526  else {
527  d_file = fopen(d_logFileName, "wb");
528  if (d_file == NULL) { // unable to open the file
529  fprintf(stderr, "vrpn_Log::open: "
530  "Couldn't open log file \"%s\": ",
531  d_logFileName);
532  perror(NULL /* no additional string */);
533  }
534  }
535 
536  if (!d_file) { // Try to write to "/tmp/vrpn_emergency_log", unless it
537  // exists!
538  d_file = fopen("/tmp/vrpn_emergency_log", "r");
539  if (d_file) {
540  fclose(d_file);
541  d_file = NULL;
542  perror("vrpn_Log::open_log: "
543  "Emergency log file \"/tmp/vrpn_emergency_log\" "
544  "already exists.\n");
545  }
546  else {
547  d_file = fopen("/tmp/vrpn_emergency_log", "wb");
548  if (d_file == NULL) {
549  perror("vrpn_Log::open: "
550  "Couldn't open emergency log file "
551  "\"/tmp/vrpn_emergency_log\": ");
552  }
553  }
554 
555  if (!d_file) {
556  return -1;
557  }
558  else {
559  fprintf(stderr, "Writing to /tmp/vrpn_emergency_log instead.\n");
560  }
561  }
562 
563  return 0;
564 }
565 
567 {
568  int final_retval = 0;
569  final_retval = saveLogSoFar();
570 
571  if (fclose(d_file)) {
572  fprintf(stderr, "vrpn_Log::close: "
573  "close of log file failed!\n");
574  final_retval = -1;
575  }
576  d_file = NULL;
577 
578  if (d_logFileName) {
579  delete[] d_logFileName;
580  d_logFileName = NULL;
581  }
582 
583  return final_retval;
584 }
585 
587 {
588  vrpn_LOGLIST *lp;
589  int host_len;
590  int final_retval = 0;
591  size_t retval;
592 
593  // If we aren't supposed to be logging, return with no error.
594  if (!logMode()) return 0;
595 
596  // Make sure the file is open. If not, then error.
597  if (!d_file) {
598  fprintf(stderr, "vrpn_Log::saveLogSoFar: "
599  "Log file is not open!\n");
600 
601  // Abort writing out log without destroying data needed to
602  // clean up memory.
603 
604  d_firstEntry = NULL;
605  final_retval = -1;
606  }
607 
608  if (!d_wroteMagicCookie && !final_retval) {
609  // Write out the log header (magic cookie)
610  // TCH 20 May 1999
611 
612  // There's at least one hack here:
613  // What logging mode should a client that plays back the log at a
614  // later time be forced into? I believe NONE, but there might be
615  // arguments the other way? So, you may want to adjust the cookie
616  // to make the log mode 0.
617 
618  retval = fwrite(d_magicCookie, 1, vrpn_cookie_size(), d_file);
619  if (retval != vrpn_cookie_size()) {
620  fprintf(stderr, "vrpn_Log::saveLogSoFar: "
621  "Couldn't write magic cookie to log file "
622  "(got %d, expected %d).\n",
623  static_cast<int>(retval),
624  static_cast<int>(vrpn_cookie_size()));
625  lp = d_logTail;
626  final_retval = -1;
627  }
628  d_wroteMagicCookie = vrpn_TRUE;
629  }
630 
631  // Write out the messages in the log,
632  // starting at d_firstEntry and working backwards
633  for (lp = d_firstEntry; lp && !final_retval; lp = lp->prev) {
634 
635  // This used to be a horrible hack that wrote the size of the
636  // structure (which included a pointer) to the file. This broke on
637  // 64-bit machines, but could also have broken on any architecture
638  // that packed structures differently from the common packing.
639  // Here, we pull out the entries in a way that avoids doing any
640  // sign changes and then write the array of values to disk.
641  // Unfortunately, to remain backward-compatible with earlier log
642  // files, we need to write the empty pointer.
643  vrpn_int32 values[6];
644  vrpn_int32 zero = 0;
645  memcpy(&(values[0]), &lp->data.type, sizeof(vrpn_int32));
646  memcpy(&(values[1]), &lp->data.sender, sizeof(vrpn_int32));
647  memcpy(&(values[2]), &lp->data.msg_time.tv_sec, sizeof(vrpn_int32));
648  memcpy(&(values[3]), &lp->data.msg_time.tv_usec, sizeof(vrpn_int32));
649  memcpy(&(values[4]), &lp->data.payload_len, sizeof(vrpn_int32));
650  memcpy(&(values[5]), &zero, sizeof(vrpn_int32)); // Bogus pointer.
651  retval = fwrite(values, sizeof(vrpn_int32), 6, d_file);
652 
653  if (retval != 6) {
654  fprintf(stderr,
655  "vrpn_Log::saveLogSoFar: "
656  "Couldn't write log file (got %d, expected %lud).\n",
657  static_cast<int>(retval),
658  static_cast<unsigned long>(sizeof(lp->data)));
659  lp = d_logTail;
660  final_retval = -1;
661  continue;
662  }
663 
664  host_len = ntohl(lp->data.payload_len);
665 
666  // fprintf(stderr, "type %d, sender %d, payload length %d\n",
667  // htonl(lp->data.type), htonl(lp->data.sender), host_len);
668 
669  retval = fwrite(lp->data.buffer, 1, host_len, d_file);
670 
671  if (retval != host_len) {
672  fprintf(stderr, "vrpn_Log::saveLogSoFar: "
673  "Couldn't write log file.\n");
674  lp = d_logTail;
675  final_retval = -1;
676  continue;
677  }
678  }
679 
680  // clean up the linked list
681  while (d_logTail) {
682  lp = d_logTail->next;
683  if (d_logTail->data.buffer) {
684  delete[](char *)d_logTail -> data.buffer; // ugly cast
685  }
686  delete d_logTail;
687  d_logTail = lp;
688  }
689 
690  d_firstEntry = NULL;
691 
692  return final_retval;
693 }
694 
695 int vrpn_Log::logIncomingMessage(size_t payloadLen, struct timeval time,
696  vrpn_int32 type, vrpn_int32 sender,
697  const char *buffer)
698 {
699 
700  // Log it the same way, whether it's a User or System message.
701  // (We used to throw away system messages that we didn't have a handler
702  // for, but I believe that was incorrect.)
703 
704  if (logMode() & vrpn_LOG_INCOMING) {
705  // fprintf(stderr, "Logging incoming message of type %d.\n", type);
706  return logMessage(static_cast<vrpn_int32>(payloadLen), time, type,
707  sender, buffer, vrpn_TRUE);
708  }
709  // fprintf(stderr, "Not logging incoming messages (type %d)...\n", type);
710 
711  return 0;
712 }
713 
714 int vrpn_Log::logOutgoingMessage(vrpn_int32 payloadLen, struct timeval time,
715  vrpn_int32 type, vrpn_int32 sender,
716  const char *buffer)
717 {
718  if (logMode() & vrpn_LOG_OUTGOING) {
719  // fprintf(stderr, "Logging outgoing message of type %d.\n", type);
720  return logMessage(payloadLen, time, type, sender, buffer);
721  }
722  // fprintf(stderr, "Not logging outgoing messages (type %d)...\n", type);
723  return 0;
724 }
725 
726 int vrpn_Log::logMessage(vrpn_int32 payloadLen, struct timeval time,
727  vrpn_int32 type, vrpn_int32 sender, const char *buffer,
728  vrpn_bool isRemote)
729 {
730  vrpn_LOGLIST *lp;
731  vrpn_int32 effectiveType;
732  vrpn_int32 effectiveSender;
733 
734  if (isRemote) {
735  effectiveType = d_types->mapToLocalID(type);
736  effectiveSender = d_senders->mapToLocalID(sender);
737  }
738  else {
739  effectiveType = type;
740  effectiveSender = sender;
741  }
742 
743  // Filter user messages
744  if (type >= 0) {
745  if (checkFilters(payloadLen, time, effectiveType, effectiveSender,
746  buffer)) {
747  // This is NOT a failure - do not return nonzero!
748  return 0;
749  }
750  }
751 
752  // Make a log structure for the new message
753  lp = new vrpn_LOGLIST;
754  if (!lp) {
755  fprintf(stderr, "vrpn_Log::logMessage: "
756  "Out of memory!\n");
757  return -1;
758  }
759  lp->data.type = htonl(type);
760  lp->data.sender = htonl(sender);
761 
762  lp->data.msg_time.tv_sec = htonl(time.tv_sec);
763  lp->data.msg_time.tv_usec = htonl(time.tv_usec);
764 
765  d_lastLogTime.tv_sec = time.tv_sec;
766  d_lastLogTime.tv_usec = time.tv_usec;
767 
768  lp->data.payload_len = htonl(payloadLen);
769  lp->data.buffer = NULL;
770 
771  if (payloadLen > 0) {
772  lp->data.buffer = new char[payloadLen];
773  if (!lp->data.buffer) {
774  fprintf(stderr, "vrpn_Log::logMessage: "
775  "Out of memory!\n");
776  delete lp;
777  return -1;
778  }
779 
780  // need to explicitly override the const
781  memcpy((char *)lp->data.buffer, buffer, payloadLen);
782  }
783 
784  // Insert the new message into the log
785  lp->next = d_logTail;
786  lp->prev = NULL;
787  if (d_logTail) {
788  d_logTail->prev = lp;
789  }
790  d_logTail = lp;
791  if (!d_firstEntry) {
792  d_firstEntry = lp;
793  }
794 
795  return 0;
796 }
797 
798 int vrpn_Log::setCompoundName(const char *name, int index)
799 {
800  char newName[2048]; // HACK
801  const char *dot;
802  size_t len;
803 
804  // Change foo.bar, 5 to foo-5.bar
805  // and foo, 5 to foo-5
806 
807  dot = strrchr(name, '.');
808 
809  if (dot) {
810  strncpy(newName, name, dot - name);
811  newName[dot - name] = 0;
812  }
813  else {
814  strcpy(newName, name);
815  }
816  len = strlen(newName);
817  sprintf(newName + len, "-%d", index);
818  if (dot) {
819  strcat(newName, dot);
820  }
821 
822  return setName(newName);
823 }
824 
825 int vrpn_Log::setName(const char *name) { return setName(name, strlen(name)); }
826 
827 int vrpn_Log::setName(const char *name, size_t len)
828 {
829  if (d_logFileName) {
830  delete[] d_logFileName;
831  }
832 
833  d_logFileName = new char[1 + len];
834  if (!d_logFileName) {
835  fprintf(stderr, "vrpn_Log::setName: Out of memory!\n");
836  return -1;
837  }
838  strncpy(d_logFileName, name, len);
839  d_logFileName[len] = '\0';
840 
841  return 0;
842 }
843 
844 int vrpn_Log::setCookie(const char *cookieBuffer)
845 {
846 
847  if (d_magicCookie) {
848  delete[] d_magicCookie;
849  }
850  d_magicCookie = new char[1 + vrpn_cookie_size()];
851  if (!d_magicCookie) {
852  fprintf(stderr, "vrpn_Log::setCookie: Out of memory.\n");
853  return -1;
854  }
855  strncpy(d_magicCookie, cookieBuffer, vrpn_cookie_size());
856 
857  return 0;
858 }
859 
860 long &vrpn_Log::logMode(void) { return d_logmode; }
861 
862 int vrpn_Log::addFilter(vrpn_LOGFILTER filter, void *userdata)
863 {
864  vrpnLogFilterEntry *newEntry;
865 
866  newEntry = new vrpnLogFilterEntry;
867  if (!newEntry) {
868  fprintf(stderr, "vrpn_Log::addFilter: Out of memory.\n");
869  return -1;
870  }
871 
872  newEntry->filter = filter;
873  newEntry->userdata = userdata;
874  newEntry->next = d_filters;
875  d_filters = newEntry;
876 
877  return 0;
878 }
879 
881 
882 int vrpn_Log::checkFilters(vrpn_int32 payloadLen, struct timeval time,
883  vrpn_int32 type, vrpn_int32 sender,
884  const char *buffer)
885 {
886  vrpnLogFilterEntry *next;
887 
889  p.type = type;
890  p.sender = sender;
891  p.msg_time.tv_sec = time.tv_sec;
892  p.msg_time.tv_usec = time.tv_usec;
893  p.payload_len = payloadLen;
894  p.buffer = buffer;
895 
896  for (next = d_filters; next; next = next->next) {
897  if ((*next->filter)(next->userdata, p)) {
898  // Don't log
899  return 1;
900  }
901  }
902 
903  return 0;
904 }
905 
913 class vrpn_TypeDispatcher {
914 
915 public:
916  vrpn_TypeDispatcher(void);
917  ~vrpn_TypeDispatcher(void);
918 
919  // ACCESSORS
920 
921  int numTypes(void) const;
922  const char *typeName(int which) const;
923 
924  vrpn_int32 getTypeID(const char *name);
926 
927  int numSenders(void) const;
928  const char *senderName(int which) const;
929 
930  vrpn_int32 getSenderID(const char *name);
932 
933  // MANIPULATORS
934 
935  vrpn_int32 addType(const char *name);
936  vrpn_int32 addSender(const char *name);
937 
938  vrpn_int32 registerType(const char *name);
942 
943  vrpn_int32 registerSender(const char *name);
947 
948  int addHandler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata,
949  vrpn_int32 sender);
950  int removeHandler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler,
951  void *userdata, vrpn_int32 sender);
952  void setSystemHandler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler);
953 
954  // It'd make a certain amount of sense to unify these next few, but
955  // there are some places in the code that depend on the side effect of
956  // do_callbacks_for() NOT dispatching system messages.
957 
958  int doCallbacksFor(vrpn_int32 type, vrpn_int32 sender, timeval time,
959  vrpn_uint32 len, const char *buffer);
960  int doSystemCallbacksFor(vrpn_int32 type, vrpn_int32 sender, timeval time,
961  vrpn_uint32 len, const char *buffer,
962  void *userdata);
963  int doSystemCallbacksFor(vrpn_HANDLERPARAM p, void *userdata);
964 
965  void clear(void);
966 
967 protected:
968  struct vrpnLocalMapping {
969  char *name; // Name of type
970  vrpnMsgCallbackEntry *who_cares; // Callbacks
971  vrpn_int32 cCares; // TCH 28 Oct 97
972  };
973 
974  int d_numTypes;
975  vrpnLocalMapping d_types[vrpn_CONNECTION_MAX_TYPES];
976 
977  int d_numSenders;
979 
981 
982  vrpnMsgCallbackEntry *d_genericCallbacks;
983 };
984 
986  : d_numTypes(0)
987  , d_numSenders(0)
988  , d_genericCallbacks(NULL)
989 {
990  int i;
991  // Make all of the names NULL pointers so they get allocated later
992  for (i = 0; i < vrpn_CONNECTION_MAX_SENDERS; i++) {
993  d_senders[i] = NULL;
994  }
995 
996  // Clear out any entries in the table.
997  clear();
998 }
999 
1000 vrpn_TypeDispatcher::~vrpn_TypeDispatcher(void)
1001 {
1002  vrpnMsgCallbackEntry *pVMCB, *pVMCB_Del;
1003  int i;
1004 
1005  for (i = 0; i < d_numTypes; i++) {
1006  if (d_types[i].name) {
1007  delete[] d_types[i].name;
1008  }
1009  pVMCB = d_types[i].who_cares;
1010  while (pVMCB) {
1011  pVMCB_Del = pVMCB;
1012  pVMCB = pVMCB_Del->next;
1013  delete pVMCB_Del;
1014  }
1015  }
1016 
1017  pVMCB = d_genericCallbacks;
1018 
1019  while (pVMCB) {
1020  pVMCB_Del = pVMCB;
1021  pVMCB = pVMCB_Del->next;
1022  delete pVMCB_Del;
1023  }
1024 
1025  // Clear out any entries in the table.
1026  clear();
1027 }
1028 
1029 int vrpn_TypeDispatcher::numTypes(void) const { return d_numTypes; }
1030 
1031 const char *vrpn_TypeDispatcher::typeName(int i) const
1032 {
1033  if ((i < 0) || (i >= d_numTypes)) {
1034  return NULL;
1035  }
1036  return d_types[i].name;
1037 }
1038 
1039 vrpn_int32 vrpn_TypeDispatcher::getTypeID(const char *name)
1040 {
1041  vrpn_int32 i;
1042 
1043  for (i = 0; i < d_numTypes; i++) {
1044  if (!strcmp(name, d_types[i].name)) {
1045  return i;
1046  }
1047  }
1048 
1049  return -1;
1050 }
1051 
1052 int vrpn_TypeDispatcher::numSenders(void) const { return d_numSenders; }
1053 
1054 const char *vrpn_TypeDispatcher::senderName(int i) const
1055 {
1056  if ((i < 0) || (i >= d_numSenders)) {
1057  return NULL;
1058  }
1059  return d_senders[i];
1060 }
1061 
1062 vrpn_int32 vrpn_TypeDispatcher::getSenderID(const char *name)
1063 {
1064  vrpn_int32 i;
1065 
1066  for (i = 0; i < d_numSenders; i++) {
1067  if (!strcmp(name, d_senders[i])) {
1068  return i;
1069  }
1070  }
1071 
1072  return -1;
1073 }
1074 
1075 vrpn_int32 vrpn_TypeDispatcher::addType(const char *name)
1076 {
1077 
1078  // See if there are too many on the list. If so, return -1.
1079  if (d_numTypes >= vrpn_CONNECTION_MAX_TYPES) {
1080  fprintf(stderr, "vrpn_TypeDispatcher::addType: "
1081  "Too many! (%d)\n",
1082  d_numTypes);
1083  return -1;
1084  }
1085 
1086  if (!d_types[d_numTypes].name) {
1087  d_types[d_numTypes].name = new cName;
1088  if (!d_types[d_numTypes].name) {
1089  fprintf(stderr, "vrpn_TypeDispatcher::addType: "
1090  "Can't allocate memory for new record.\n");
1091  return -1;
1092  }
1093  }
1094 
1095  // Add this one into the list and return its index
1096  strncpy(d_types[d_numTypes].name, name, sizeof(cName) - 1);
1097  d_types[d_numTypes].who_cares = NULL;
1098  d_types[d_numTypes].cCares = 0;
1099  d_numTypes++;
1100 
1101  return d_numTypes - 1;
1102 }
1103 
1104 vrpn_int32 vrpn_TypeDispatcher::addSender(const char *name)
1105 {
1106 
1107  // See if there are too many on the list. If so, return -1.
1108  if (d_numSenders >= vrpn_CONNECTION_MAX_SENDERS) {
1109  fprintf(stderr, "vrpn_TypeDispatcher::addSender: "
1110  "Too many! (%d).\n",
1111  d_numSenders);
1112  return -1;
1113  }
1114 
1115  if (!d_senders[d_numSenders]) {
1116 
1117  // fprintf(stderr, "Allocating a new name entry\n");
1118 
1119  d_senders[d_numSenders] = new cName;
1120  if (!d_senders[d_numSenders]) {
1121  fprintf(stderr, "vrpn_TypeDispatcher::addSender: "
1122  "Can't allocate memory for new record\n");
1123  return -1;
1124  }
1125  }
1126 
1127  // Add this one into the list
1128  strncpy(d_senders[d_numSenders], name, sizeof(cName) - 1);
1129  d_numSenders++;
1130 
1131  // One more in place -- return its index
1132  return d_numSenders - 1;
1133 }
1134 
1135 vrpn_int32 vrpn_TypeDispatcher::registerType(const char *name)
1136 {
1137  vrpn_int32 retval;
1138 
1139  // See if the name is already in the list. If so, return it.
1140  retval = getTypeID(name);
1141  if (retval != -1) {
1142  return retval;
1143  }
1144 
1145  return addType(name);
1146 }
1147 
1148 vrpn_int32 vrpn_TypeDispatcher::registerSender(const char *name)
1149 {
1150  vrpn_int32 retval;
1151 
1152  // See if the name is already in the list. If so, return it.
1153  retval = getSenderID(name);
1154  if (retval != -1) {
1155  return retval;
1156  }
1157 
1158  return addSender(name);
1159 }
1160 
1161 int vrpn_TypeDispatcher::addHandler(vrpn_int32 type,
1162  vrpn_MESSAGEHANDLER handler, void *userdata,
1163  vrpn_int32 sender)
1164 {
1165  vrpnMsgCallbackEntry *new_entry;
1166  vrpnMsgCallbackEntry **ptr;
1167 
1168  // Ensure that the type is a valid one (one that has been defined)
1169  // OR that it is "any"
1170  if (((type < 0) || (type >= d_numTypes)) && (type != vrpn_ANY_TYPE)) {
1171  fprintf(stderr, "vrpn_TypeDispatcher::addHandler: No such type\n");
1172  return -1;
1173  }
1174 
1175  // Ensure that the sender is a valid one (or "any")
1176  if ((sender != vrpn_ANY_SENDER) &&
1177  ((sender < 0) || (sender >= d_numSenders))) {
1178  fprintf(stderr, "vrpn_TypeDispatcher::addHandler: No such sender\n");
1179  return -1;
1180  }
1181 
1182  // Ensure that the handler is non-NULL
1183  if (handler == NULL) {
1184  fprintf(stderr, "vrpn_TypeDispatcher::addHandler: NULL handler\n");
1185  return -1;
1186  }
1187 
1188  // Allocate and initialize the new entry
1189  new_entry = new vrpnMsgCallbackEntry();
1190  if (new_entry == NULL) {
1191  fprintf(stderr, "vrpn_TypeDispatcher::addHandler: Out of memory\n");
1192  return -1;
1193  }
1194  new_entry->handler = handler;
1195  new_entry->userdata = userdata;
1196  new_entry->sender = sender;
1197 
1198 #ifdef VERBOSE
1199  printf("Adding user handler for type %ld, sender %ld\n", type, sender);
1200 #endif
1201 
1202  // TCH June 2000 - rewrote to insert at end of list instead of beginning,
1203  // to make sure multiple callbacks on the same type are triggered
1204  // in the order registered. Note that multiple entries with the same
1205  // info is okay.
1206 
1207  if (type == vrpn_ANY_TYPE) {
1208  ptr = &d_genericCallbacks;
1209  }
1210  else {
1211  ptr = &d_types[type].who_cares;
1212  }
1213 
1214  while (*ptr) {
1215  ptr = &((*ptr)->next);
1216  }
1217  *ptr = new_entry;
1218  new_entry->next = NULL;
1219 
1220  return 0;
1221 }
1222 
1223 int vrpn_TypeDispatcher::removeHandler(vrpn_int32 type,
1224  vrpn_MESSAGEHANDLER handler,
1225  void *userdata, vrpn_int32 sender)
1226 {
1227  // The pointer at *snitch points to victim
1228  vrpnMsgCallbackEntry *victim, **snitch;
1229 
1230  // Ensure that the type is a valid one (one that has been defined)
1231  // OR that it is "any"
1232  if (((type < 0) || (type >= d_numTypes)) && (type != vrpn_ANY_TYPE)) {
1233  fprintf(stderr, "vrpn_TypeDispatcher::removeHandler: No such type\n");
1234  return -1;
1235  }
1236 
1237  // Find a handler with this registry in the list (any one will do,
1238  // since all duplicates are the same).
1239  if (type == vrpn_ANY_TYPE) {
1240  snitch = &d_genericCallbacks;
1241  }
1242  else {
1243  snitch = &(d_types[type].who_cares);
1244  }
1245  victim = *snitch;
1246  while ((victim != NULL) &&
1247  ((victim->handler != handler) || (victim->userdata != userdata) ||
1248  (victim->sender != sender))) {
1249  snitch = &((*snitch)->next);
1250  victim = victim->next;
1251  }
1252 
1253  // Make sure we found one
1254  if (victim == NULL) {
1255  fprintf(stderr,
1256  "vrpn_TypeDispatcher::removeHandler: No such handler\n");
1257  return -1;
1258  }
1259 
1260  // Remove the entry from the list
1261  *snitch = victim->next;
1262  delete victim;
1263 
1264  return 0;
1265 }
1266 
1267 void vrpn_TypeDispatcher::setSystemHandler(vrpn_int32 type,
1268  vrpn_MESSAGEHANDLER handler)
1269 {
1270  d_systemMessages[-type] = handler;
1271 }
1272 
1273 int vrpn_TypeDispatcher::doCallbacksFor(vrpn_int32 type, vrpn_int32 sender,
1274  timeval time, vrpn_uint32 len,
1275  const char *buffer)
1276 {
1277  vrpnMsgCallbackEntry *who;
1279 
1280  // We don't dispatch system messages (kluge?).
1281  if (type < 0) {
1282  return 0;
1283  }
1284 
1285  if (type >= d_numTypes) {
1286  return -1;
1287  }
1288 
1289  // Fill in the parameter to be passed to the routines
1290  p.type = type;
1291  p.sender = sender;
1292  p.msg_time = time;
1293  p.payload_len = len;
1294  p.buffer = buffer;
1295 
1296  // Do generic callbacks (vrpn_ANY_TYPE)
1297  who = d_genericCallbacks;
1298 
1299  while (who) { // For each callback entry
1300  // Verify that the sender is ANY or matches
1301  if ((who->sender == vrpn_ANY_SENDER) || (who->sender == sender)) {
1302  if (who->handler(who->userdata, p)) {
1303  fprintf(stderr, "vrpn_TypeDispatcher::doCallbacksFor: "
1304  "Nonzero user generic handler return.\n");
1305  return -1;
1306  }
1307  }
1308 
1309  // Next callback in list
1310  who = who->next;
1311  }
1312 
1313  // Find the head for the list of callbacks to call
1314  who = d_types[type].who_cares;
1315  while (who) { // For each callback entry
1316  // Verify that the sender is ANY or matches
1317  if ((who->sender == vrpn_ANY_SENDER) || (who->sender == sender)) {
1318  if (who->handler(who->userdata, p)) {
1319  fprintf(stderr, "vrpn_TypeDispatcher::doCallbacksFor: "
1320  "Nonzero user handler return.\n");
1321  return -1;
1322  }
1323  }
1324 
1325  // Next callback in list
1326  who = who->next;
1327  }
1328 
1329  return 0;
1330 }
1331 
1332 int vrpn_TypeDispatcher::doSystemCallbacksFor(vrpn_int32 type,
1333  vrpn_int32 sender, timeval time,
1334  vrpn_uint32 len,
1335  const char *buffer,
1336  void *userdata)
1337 {
1339 
1340  if (type >= 0) {
1341  return 0;
1342  }
1343  if (-type >= vrpn_CONNECTION_MAX_TYPES) {
1344  fprintf(stderr, "vrpn_TypeDispatcher::doSystemCallbacksFor: "
1345  "Illegal type %d.\n",
1346  type);
1347  return -1;
1348  }
1349 
1350  if (!d_systemMessages[-type]) {
1351  return 0;
1352  }
1353 
1354  // Fill in the parameter to be passed to the routines
1355  p.type = type;
1356  p.sender = sender;
1357  p.msg_time = time;
1358  p.payload_len = len;
1359  p.buffer = buffer;
1360 
1361  return doSystemCallbacksFor(p, userdata);
1362 }
1363 
1364 int vrpn_TypeDispatcher::doSystemCallbacksFor(vrpn_HANDLERPARAM p,
1365  void *userdata)
1366 {
1367  int retval;
1368 
1369  if (p.type >= 0) {
1370  return 0;
1371  }
1372  if (-p.type >= vrpn_CONNECTION_MAX_TYPES) {
1373  fprintf(stderr, "vrpn_TypeDispatcher::doSystemCallbacksFor: "
1374  "Illegal type %d.\n",
1375  p.type);
1376  return -1;
1377  }
1378 
1379  if (!d_systemMessages[-p.type]) {
1380  return 0;
1381  }
1382 
1383  retval = d_systemMessages[-p.type](userdata, p);
1384  if (retval) {
1385  fprintf(stderr, "vrpn_TypeDispatcher::doSystemCallbacksFor: "
1386  "Nonzero system handler return.\n");
1387  return -1;
1388  }
1389  return 0;
1390 }
1391 
1392 void vrpn_TypeDispatcher::clear(void)
1393 {
1394  int i;
1395 
1396  for (i = 0; i < vrpn_CONNECTION_MAX_TYPES; i++) {
1397  d_types[i].who_cares = NULL;
1398  d_types[i].cCares = 0;
1399  d_types[i].name = NULL;
1400 
1401  d_systemMessages[i] = NULL;
1402  }
1403 
1404  for (i = 0; i < vrpn_CONNECTION_MAX_SENDERS; i++) {
1405  if (d_senders[i] != NULL) {
1406  delete[] d_senders[i];
1407  }
1408  d_senders[i] = NULL;
1409  }
1410 }
1411 
1413 {
1414  // fprintf(stderr, "In ~vrpn_ConnectionManager: tearing down the list.\n");
1415 
1416  // Call the destructor of every known connection.
1417  // That destructor will call vrpn_ConnectionManager::deleteConnection()
1418  // to remove itself from d_kcList.
1419  while (d_kcList) {
1420  delete d_kcList->connection;
1421  }
1422  while (d_anonList) {
1423  delete d_anonList->connection;
1424  }
1425 }
1426 
1427 // static
1429 {
1430  static vrpn_ConnectionManager manager;
1431  return manager;
1432 }
1433 
1435 {
1436  knownConnection *p;
1437 
1438  p = new knownConnection;
1439  p->connection = c;
1440 
1441  if (name) {
1442  strncpy(p->name, name, 1000);
1443  p->next = d_kcList;
1444  d_kcList = p;
1445  }
1446  else {
1447  p->name[0] = 0;
1448  p->next = d_anonList;
1449  d_anonList = p;
1450  }
1451 }
1452 
1454 {
1455  deleteConnection(c, &d_kcList);
1456  deleteConnection(c, &d_anonList);
1457 }
1458 
1460  knownConnection **snitch)
1461 {
1462  knownConnection *victim = *snitch;
1463 
1464  while (victim && (victim->connection != c)) {
1465  snitch = &((*snitch)->next);
1466  victim = *snitch;
1467  }
1468 
1469  if (!victim) {
1470  // No warning, because this connection might be on the *other* list.
1471  }
1472  else {
1473  *snitch = victim->next;
1474  delete victim;
1475  }
1476 }
1477 
1479 {
1480  knownConnection *p;
1481  for (p = d_kcList; p && strcmp(p->name, name); p = p->next) {
1482  // do nothing
1483  }
1484  if (!p) {
1485  return NULL;
1486  }
1487  return p->connection;
1488 }
1489 
1490 vrpn_ConnectionManager::vrpn_ConnectionManager(void)
1491  : d_kcList(NULL)
1492  , d_anonList(NULL)
1493 {
1494 }
1495 
1508 static int vrpn_getmyIP(char *myIPchar, unsigned maxlen,
1509  const char *NIC_IP = NULL,
1510  SOCKET incoming_socket = INVALID_SOCKET)
1511 {
1512  char myname[100]; // Host name of this host
1513  struct hostent *host; // Encoded host IP address, etc.
1514  char myIPstring[100]; // Hold "152.2.130.90" or whatever
1515 
1516  if (myIPchar == NULL) {
1517  fprintf(stderr, "vrpn_getmyIP: NULL pointer passed in\n");
1518  return -1;
1519  }
1520 
1521  // If we have a specified NIC_IP address, fill it in and return it.
1522  if (NIC_IP) {
1523  if (strlen(NIC_IP) > maxlen) {
1524  fprintf(stderr, "vrpn_getmyIP: Name too long to return\n");
1525  return -1;
1526  }
1527 #ifdef VERBOSE
1528  fprintf(stderr, "Was given IP address of %s so returning that.\n",
1529  NIC_IP);
1530 #endif
1531  strncpy(myIPchar, NIC_IP, maxlen);
1532  return 0;
1533  }
1534 
1535  // If we have a valid specified SOCKET, then look up its address and
1536  // return it.
1537  if (incoming_socket != INVALID_SOCKET) {
1538  struct sockaddr_in socket_name;
1539  int socket_namelen = sizeof(socket_name);
1540 
1541  if (getsockname(incoming_socket, (struct sockaddr *)&socket_name,
1542  GSN_CAST & socket_namelen)) {
1543  fprintf(stderr, "vrpn_getmyIP: cannot get socket name.\n");
1544  return -1;
1545  }
1546 
1547  sprintf(myIPstring, "%u.%u.%u.%u",
1548  ntohl(socket_name.sin_addr.s_addr) >> 24,
1549  (ntohl(socket_name.sin_addr.s_addr) >> 16) & 0xff,
1550  (ntohl(socket_name.sin_addr.s_addr) >> 8) & 0xff,
1551  ntohl(socket_name.sin_addr.s_addr) & 0xff);
1552 
1553  // Copy this to the output
1554  if ((unsigned)strlen(myIPstring) > maxlen) {
1555  fprintf(stderr, "vrpn_getmyIP: Name too long to return\n");
1556  return -1;
1557  }
1558 
1559  strcpy(myIPchar, myIPstring);
1560 
1561 #ifdef VERBOSE
1562  fprintf(stderr, "Decided on IP address of %s.\n", myIPchar);
1563 #endif
1564  return 0;
1565  }
1566 
1567  // Find out what my name is
1568  // gethostname() is guaranteed to produce something gethostbyname() can
1569  // parse.
1570  if (gethostname(myname, sizeof(myname))) {
1571  fprintf(stderr, "vrpn_getmyIP: Error finding local hostname\n");
1572  return -1;
1573  }
1574 
1575  // Find out what my IP address is
1576  host = gethostbyname(myname);
1577  if (host == NULL) {
1578  fprintf(stderr, "vrpn_getmyIP: error finding host by name (%s)\n",
1579  myname);
1580  return -1;
1581  }
1582 
1583 // Convert this back into a string
1584 #ifndef CRAY
1585  if (host->h_length != 4) {
1586  fprintf(stderr, "vrpn_getmyIP: Host length not 4\n");
1587  return -1;
1588  }
1589 #endif
1590  sprintf(myIPstring, "%u.%u.%u.%u",
1591  (unsigned int)(unsigned char)host->h_addr_list[0][0],
1592  (unsigned int)(unsigned char)host->h_addr_list[0][1],
1593  (unsigned int)(unsigned char)host->h_addr_list[0][2],
1594  (unsigned int)(unsigned char)host->h_addr_list[0][3]);
1595 
1596  // Copy this to the output
1597  if ((unsigned)strlen(myIPstring) > maxlen) {
1598  fprintf(stderr, "vrpn_getmyIP: Name too long to return\n");
1599  return -1;
1600  }
1601 
1602  strcpy(myIPchar, myIPstring);
1603 #ifdef VERBOSE
1604  fprintf(stderr, "Decided on IP address of %s.\n", myIPchar);
1605 #endif
1606  return 0;
1607 }
1608 
1615 int vrpn_noint_select(int width, fd_set *readfds, fd_set *writefds,
1616  fd_set *exceptfds, struct timeval *timeout)
1617 {
1618  fd_set tmpread, tmpwrite, tmpexcept;
1619  int ret;
1620  int done = 0;
1621  struct timeval timeout2;
1622  struct timeval *timeout2ptr;
1623  struct timeval start, stop, now;
1624 
1625  /* If the timeout parameter is non-NULL and non-zero, then we
1626  * may have to adjust it due to an interrupt. In these cases,
1627  * we will copy the timeout to timeout2, which will be used
1628  * to keep track. Also, the stop time is calculated so that
1629  * we can know when it is time to bail. */
1630  if ((timeout != NULL) &&
1631  ((timeout->tv_sec != 0) || (timeout->tv_usec != 0))) {
1632  timeout2 = *timeout;
1633  timeout2ptr = &timeout2;
1634  vrpn_gettimeofday(&start, NULL); /* Find start time */
1635  stop = vrpn_TimevalSum(start, *timeout); /* Find stop time */
1636  }
1637  else {
1638  timeout2ptr = timeout;
1639  stop.tv_sec = 0;
1640  stop.tv_usec = 0;
1641  }
1642 
1643  /* Repeat selects until it returns for a reason other than interrupt */
1644  do {
1645  /* Set the temp file descriptor sets to match parameters each time
1646  * through. */
1647  if (readfds != NULL) {
1648  tmpread = *readfds;
1649  }
1650  else {
1651  FD_ZERO(&tmpread);
1652  }
1653  if (writefds != NULL) {
1654  tmpwrite = *writefds;
1655  }
1656  else {
1657  FD_ZERO(&tmpwrite);
1658  }
1659  if (exceptfds != NULL) {
1660  tmpexcept = *exceptfds;
1661  }
1662  else {
1663  FD_ZERO(&tmpexcept);
1664  }
1665 
1666  /* Do the select on the temporary sets of descriptors */
1667  ret = select(width, &tmpread, &tmpwrite, &tmpexcept, timeout2ptr);
1668  if (ret >= 0) { /* We are done if timeout or found some */
1669  done = 1;
1670  }
1671  else if (errno != EINTR) { /* Done if non-intr error */
1672  done = 1;
1673  }
1674  else if ((timeout != NULL) &&
1675  ((timeout->tv_sec != 0) || (timeout->tv_usec != 0))) {
1676 
1677  /* Interrupt happened. Find new time timeout value */
1678  vrpn_gettimeofday(&now, NULL);
1679  if (vrpn_TimevalGreater(now, stop)) { /* Past stop time */
1680  done = 1;
1681  }
1682  else { /* Still time to go. */
1683  unsigned long usec_left;
1684  usec_left = (stop.tv_sec - now.tv_sec) * 1000000L;
1685  usec_left += stop.tv_usec - now.tv_usec;
1686  timeout2.tv_sec = usec_left / 1000000L;
1687  timeout2.tv_usec = usec_left % 1000000L;
1688  }
1689  }
1690  } while (!done);
1691 
1692  /* Copy the temporary sets back to the parameter sets */
1693  if (readfds != NULL) {
1694  *readfds = tmpread;
1695  }
1696  if (writefds != NULL) {
1697  *writefds = tmpwrite;
1698  }
1699  if (exceptfds != NULL) {
1700  *exceptfds = tmpexcept;
1701  }
1702 
1703  return (ret);
1704 }
1705 
1719 #ifndef VRPN_USE_WINSOCK_SOCKETS
1720 
1721 int vrpn_noint_block_write(int outfile, const char buffer[], size_t length)
1722 {
1723  register int sofar; /* How many characters sent so far */
1724  register int ret; /* Return value from write() */
1725 
1726  sofar = 0;
1727  do {
1728  /* Try to write the remaining data */
1729  ret = write(outfile, buffer + sofar, length - sofar);
1730  sofar += ret;
1731 
1732  /* Ignore interrupted system calls - retry */
1733  if ((ret == -1) && (errno == EINTR)) {
1734  ret = 1; /* So we go around the loop again */
1735  sofar += 1; /* Restoring it from above -1 */
1736  }
1737 
1738  } while ((ret > 0) && (sofar < length));
1739 
1740  if (ret == -1) return (-1); /* Error during write */
1741  if (ret == 0) return (0); /* EOF reached */
1742 
1743  return (sofar); /* All bytes written */
1744 }
1745 
1757 int vrpn_noint_block_read(int infile, char buffer[], size_t length)
1758 {
1759  register int sofar; /* How many we read so far */
1760  register int ret; /* Return value from the read() */
1761 
1762  // TCH 4 Jan 2000 - hackish - Cygwin will block forever on a 0-length
1763  // read(), and from the man pages this is close enough to in-spec that
1764  // other OS may do the same thing.
1765 
1766  if (!length) {
1767  return 0;
1768  }
1769  sofar = 0;
1770  do {
1771  /* Try to read all remaining data */
1772  ret = read(infile, buffer + sofar, length - sofar);
1773  sofar += ret;
1774 
1775  /* Ignore interrupted system calls - retry */
1776  if ((ret == -1) && (errno == EINTR)) {
1777  ret = 1; /* So we go around the loop again */
1778  sofar += 1; /* Restoring it from above -1 */
1779  }
1780  } while ((ret > 0) && (sofar < length));
1781 
1782  if (ret == -1) return (-1); /* Error during read */
1783  if (ret == 0) return (0); /* EOF reached */
1784 
1785  return (sofar); /* All bytes read */
1786 }
1787 
1788 #else /* winsock sockets */
1789 
1790 int vrpn_noint_block_write(SOCKET outsock, char *buffer, size_t length)
1791 {
1792  int nwritten;
1793  size_t sofar = 0;
1794  do {
1795  /* Try to write the remaining data */
1796  nwritten =
1797  send(outsock, buffer + sofar, static_cast<int>(length - sofar), 0);
1798 
1799  if (nwritten == SOCKET_ERROR) {
1800  return -1;
1801  }
1802 
1803  sofar += nwritten;
1804  } while (sofar < length);
1805 
1806  return static_cast<int>(sofar); /* All bytes written */
1807 }
1808 
1809 int vrpn_noint_block_read(SOCKET insock, char *buffer, size_t length)
1810 {
1811  int nread;
1812  size_t sofar = 0;
1813 
1814  // TCH 4 Jan 2000 - hackish - Cygwin will block forever on a 0-length
1815  // read(), and from the man pages this is close enough to in-spec that
1816  // other OS may do the same thing.
1817 
1818  if (!length) {
1819  return 0;
1820  }
1821 
1822  do {
1823  /* Try to read all remaining data */
1824  nread =
1825  recv(insock, buffer + sofar, static_cast<int>(length - sofar), 0);
1826 
1827  if (nread == SOCKET_ERROR) {
1828  return -1;
1829  }
1830  if (nread == 0) { /* socket closed */
1831  return 0;
1832  }
1833 
1834  sofar += nread;
1835  } while (sofar < length);
1836 
1837  return static_cast<int>(sofar); /* All bytes read */
1838 }
1839 
1840 #endif /* VRPN_USE_WINSOCK_SOCKETS */
1841 
1854 int vrpn_noint_block_read_timeout(SOCKET infile, char buffer[], size_t length,
1855  struct timeval *timeout)
1856 {
1857  size_t sofar; /* How many we read so far */
1858  register int ret; /* Return value from the read() */
1859  struct timeval timeout2;
1860  struct timeval *timeout2ptr;
1861  struct timeval start, stop, now;
1862 
1863  // TCH 4 Jan 2000 - hackish - Cygwin will block forever on a 0-length
1864  // read(), and from the man pages this is close enough to in-spec that
1865  // other OS may do the same thing.
1866 
1867  if (!length) {
1868  return 0;
1869  }
1870 
1871  /* If the timeout parameter is non-NULL and non-zero, then we
1872  * may have to adjust it due to an interrupt. In these cases,
1873  * we will copy the timeout to timeout2, which will be used
1874  * to keep track. Also, the current time is found so that we
1875  * can track elapsed time. */
1876  if ((timeout != NULL) &&
1877  ((timeout->tv_sec != 0) || (timeout->tv_usec != 0))) {
1878  timeout2 = *timeout;
1879  timeout2ptr = &timeout2;
1880  vrpn_gettimeofday(&start, NULL); /* Find start time */
1881  stop = vrpn_TimevalSum(start, *timeout); /* Find stop time */
1882  }
1883  else {
1884  timeout2ptr = timeout;
1885  }
1886 
1887  sofar = 0;
1888  do {
1889  int sel_ret;
1890  fd_set readfds, exceptfds;
1891 
1892  /* See if there is a character ready for read */
1893  FD_ZERO(&readfds);
1894  FD_SET(infile, &readfds);
1895  FD_ZERO(&exceptfds);
1896  FD_SET(infile, &exceptfds);
1897  sel_ret = vrpn_noint_select(static_cast<int>(infile) + 1, &readfds,
1898  NULL, &exceptfds, timeout2ptr);
1899  if (sel_ret == -1) { /* Some sort of error on select() */
1900  return -1;
1901  }
1902  if (FD_ISSET(infile, &exceptfds)) { /* Exception */
1903  return -1;
1904  }
1905  if (!FD_ISSET(infile, &readfds)) { /* No characters */
1906  if ((timeout != NULL) && (timeout->tv_sec == 0) &&
1907  (timeout->tv_usec == 0)) { /* Quick poll */
1908  return static_cast<int>(sofar); /* Timeout! */
1909  }
1910  }
1911 
1912  /* See what time it is now and how long we have to go */
1913  if (timeout2ptr) {
1914  vrpn_gettimeofday(&now, NULL);
1915  if (vrpn_TimevalGreater(now, stop)) { /* Timeout! */
1916  return static_cast<int>(sofar);
1917  }
1918  else {
1919  timeout2 = vrpn_TimevalDiff(stop, now);
1920  }
1921  }
1922 
1923  if (!FD_ISSET(infile, &readfds)) { /* No chars yet */
1924  ret = 0;
1925  continue;
1926  }
1927 
1928 #ifndef VRPN_USE_WINSOCK_SOCKETS
1929  ret = read(infile, buffer + sofar, length - sofar);
1930  sofar += ret;
1931 
1932  /* Ignore interrupted system calls - retry */
1933  if ((ret == -1) && (errno == EINTR)) {
1934  ret = 1; /* So we go around the loop again */
1935  sofar += 1; /* Restoring it from above -1 */
1936  }
1937 #else
1938  {
1939  int nread;
1940  nread = recv(infile, buffer + sofar,
1941  static_cast<int>(length - sofar), 0);
1942  sofar += nread;
1943  ret = nread;
1944  }
1945 #endif
1946 
1947  } while ((ret > 0) && (sofar < length));
1948 #ifndef VRPN_USE_WINSOCK_SOCKETS
1949  if (ret == -1) return (-1); /* Error during read */
1950 #endif
1951  if (ret == 0) return (0); /* EOF reached */
1952 
1953  return static_cast<int>(sofar); /* All bytes read */
1954 }
1955 
1966 static SOCKET open_socket(int type, unsigned short *portno,
1967  const char *IPaddress)
1968 {
1969  struct sockaddr_in name;
1970  struct hostent *phe; /* pointer to host information entry */
1971  int namelen;
1972 
1973  // create an Internet socket of the appropriate type
1974  SOCKET sock = socket(AF_INET, type, 0);
1975  if (sock == INVALID_SOCKET) {
1976  fprintf(stderr, "open_socket: can't open socket.\n");
1977 #ifndef _WIN32_WCE
1978  fprintf(stderr, " -- errno %d (%s).\n", errno, strerror(errno));
1979 #endif
1980  return INVALID_SOCKET;
1981  }
1982 
1983 // Added by Eric Boren to address socket reconnectivity on the Android
1984 #ifdef __ANDROID__
1985  vrpn_int32 optval = 1;
1986  vrpn_int32 sockoptsuccess =
1987  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
1988  fprintf(stderr, "setsockopt returned %i, optval: %i\n", sockoptsuccess,
1989  optval);
1990 #endif
1991 
1992  namelen = sizeof(name);
1993 
1994  // bind to local address
1995  memset((void *)&name, 0, namelen);
1996  name.sin_family = AF_INET;
1997  if (portno) {
1998  name.sin_port = htons(*portno);
1999  }
2000  else {
2001  name.sin_port = htons(0);
2002  }
2003 
2004  // Map our host name to our IP address, allowing for dotted decimal
2005  if (!IPaddress) {
2006  name.sin_addr.s_addr = INADDR_ANY;
2007  }
2008  else if ((name.sin_addr.s_addr = inet_addr(IPaddress)) == INADDR_NONE) {
2009  if ((phe = gethostbyname(IPaddress)) != NULL) {
2010  memcpy((void *)&name.sin_addr, (const void *)phe->h_addr,
2011  phe->h_length);
2012  }
2013  else {
2014  vrpn_closeSocket(sock);
2015  fprintf(stderr, "open_socket: can't get %s host entry\n",
2016  IPaddress);
2017  return INVALID_SOCKET;
2018  }
2019  }
2020 
2021 #ifdef VERBOSE3
2022  // NIC will be 0.0.0.0 if we use INADDR_ANY
2023  fprintf(stderr, "open_socket: request port %d, using NIC %d %d %d %d.\n",
2024  portno ? *portno : 0, ntohl(name.sin_addr.s_addr) >> 24,
2025  (ntohl(name.sin_addr.s_addr) >> 16) & 0xff,
2026  (ntohl(name.sin_addr.s_addr) >> 8) & 0xff,
2027  ntohl(name.sin_addr.s_addr) & 0xff);
2028 #endif
2029 
2030  if (bind(sock, (struct sockaddr *)&name, namelen) < 0) {
2031  fprintf(stderr, "open_socket: can't bind address");
2032  if (portno) {
2033  fprintf(stderr, " %d", *portno);
2034  }
2035 #ifndef _WIN32_WCE
2036  fprintf(stderr, " -- %d -- %s\n", errno, strerror(errno));
2037 #endif
2038  fprintf(stderr, " (This probably means that another application has "
2039  "the port open already)\n");
2040  vrpn_closeSocket(sock);
2041  return INVALID_SOCKET;
2042  }
2043 
2044  // Find out which port was actually bound
2045  if (getsockname(sock, (struct sockaddr *)&name, GSN_CAST & namelen)) {
2046  fprintf(stderr, "vrpn: open_socket: cannot get socket name.\n");
2047  vrpn_closeSocket(sock);
2048  return INVALID_SOCKET;
2049  }
2050  if (portno) {
2051  *portno = ntohs(name.sin_port);
2052  }
2053 
2054 #ifdef VERBOSE3
2055  // NIC will be 0.0.0.0 if we use INADDR_ANY
2056  fprintf(stderr, "open_socket: got port %d, using NIC %d %d %d %d.\n",
2057  portno ? *portno : ntohs(name.sin_port),
2058  ntohl(name.sin_addr.s_addr) >> 24,
2059  (ntohl(name.sin_addr.s_addr) >> 16) & 0xff,
2060  (ntohl(name.sin_addr.s_addr) >> 8) & 0xff,
2061  ntohl(name.sin_addr.s_addr) & 0xff);
2062 #endif
2063 
2064  return sock;
2065 }
2066 
2071 static SOCKET open_udp_socket(unsigned short *portno, const char *IPaddress)
2072 {
2073  return open_socket(SOCK_DGRAM, portno, IPaddress);
2074 }
2075 
2080 static SOCKET open_tcp_socket(unsigned short *portno = NULL,
2081  const char *NIC_IP = NULL)
2082 {
2083  return open_socket(SOCK_STREAM, portno, NIC_IP);
2084 }
2085 
2090 static SOCKET vrpn_connect_udp_port(const char *machineName, int remotePort,
2091  const char *NIC_IP = NULL)
2092 {
2093  SOCKET udp_socket;
2094  struct sockaddr_in udp_name;
2095  struct hostent *remoteHost;
2096  int udp_namelen;
2097 
2098  udp_socket = open_udp_socket(NULL, NIC_IP);
2099 
2100  udp_namelen = sizeof(udp_name);
2101 
2102  memset((void *)&udp_name, 0, udp_namelen);
2103  udp_name.sin_family = AF_INET;
2104 
2105  // gethostbyname() fails on SOME Windows NT boxes, but not all,
2106  // if given an IP octet string rather than a true name.
2107  // MS Documentation says it will always fail and inet_addr should
2108  // be called first. Avoids a 30+ second wait for
2109  // gethostbyname() to fail.
2110 
2111  if ((udp_name.sin_addr.s_addr = inet_addr(machineName)) == INADDR_NONE) {
2112  remoteHost = gethostbyname(machineName);
2113  if (remoteHost) {
2114 
2115 #ifdef CRAY
2116  int i;
2117  u_long foo_mark = 0L;
2118  for (i = 0; i < 4; i++) {
2119  u_long one_char = remoteHost->h_addr_list[0][i];
2120  foo_mark = (foo_mark << 8) | one_char;
2121  }
2122  udp_name.sin_addr.s_addr = foo_mark;
2123 #else
2124  memcpy(&(udp_name.sin_addr.s_addr), remoteHost->h_addr,
2125  remoteHost->h_length);
2126 #endif
2127  }
2128  else {
2129  vrpn_closeSocket(udp_socket);
2130  fprintf(stderr,
2131  "vrpn_connect_udp_port: error finding host by name (%s).\n",
2132  machineName);
2133  return INVALID_SOCKET;
2134  }
2135  }
2136 #ifndef VRPN_USE_WINSOCK_SOCKETS
2137  udp_name.sin_port = htons(remotePort);
2138 #else
2139  udp_name.sin_port = htons((u_short)remotePort);
2140 #endif
2141 
2142  if (connect(udp_socket, (struct sockaddr *)&udp_name, udp_namelen)) {
2143  fprintf(stderr, "vrpn_connect_udp_port: can't bind udp socket.\n");
2144  vrpn_closeSocket(udp_socket);
2145  return INVALID_SOCKET;
2146  }
2147 
2148  // Find out which port was actually bound
2149  udp_namelen = sizeof(udp_name);
2150  if (getsockname(udp_socket, (struct sockaddr *)&udp_name,
2151  GSN_CAST & udp_namelen)) {
2152  fprintf(stderr, "vrpn_connect_udp_port: cannot get socket name.\n");
2153  vrpn_closeSocket(udp_socket);
2154  return INVALID_SOCKET;
2155  }
2156 
2157 #ifdef VERBOSE3
2158  // NOTE NIC will be 0.0.0.0 if we listen on all NICs.
2159  fprintf(stderr,
2160  "vrpn_connect_udp_port: got port %d, using NIC %d %d %d %d.\n",
2161  ntohs(udp_name.sin_port), ntohl(udp_name.sin_addr.s_addr) >> 24,
2162  (ntohl(udp_name.sin_addr.s_addr) >> 16) & 0xff,
2163  (ntohl(udp_name.sin_addr.s_addr) >> 8) & 0xff,
2164  ntohl(udp_name.sin_addr.s_addr) & 0xff);
2165 #endif
2166 
2167  return udp_socket;
2168 }
2169 
2192 static int get_local_socket_name(char *local_host, size_t max_length, const char* remote_host)
2193 {
2194  const int remote_port = vrpn_DEFAULT_LISTEN_PORT_NO;
2195  struct sockaddr_in udp_name;
2196  int udp_namelen = sizeof(udp_name);
2197 
2198  SOCKET udp_socket = vrpn_connect_udp_port(remote_host, remote_port, NULL);
2199  if (udp_socket == INVALID_SOCKET) {
2200  fprintf(stderr, "get_local_socket_name: cannot connect_udp_port to %s.\n", remote_host);
2201  fprintf(stderr, " (returning 0.0.0.0 so we listen on all ports).\n");
2202  udp_name.sin_addr.s_addr = 0;
2203  } else {
2204  if (getsockname(udp_socket, (struct sockaddr *)&udp_name, GSN_CAST & udp_namelen)) {
2205  fprintf(stderr, "get_local_socket_name: cannot get socket name.\n");
2206  vrpn_closeSocket(udp_socket);
2207  return -1;
2208  }
2209  }
2210 
2211  // NOTE NIC will be 0.0.0.0 if we listen on all NICs.
2212  char myIPstring[100];
2213  int ret = sprintf(myIPstring, "%d.%d.%d.%d",
2214  ntohl(udp_name.sin_addr.s_addr) >> 24,
2215  (ntohl(udp_name.sin_addr.s_addr) >> 16) & 0xff,
2216  (ntohl(udp_name.sin_addr.s_addr) >> 8) & 0xff,
2217  ntohl(udp_name.sin_addr.s_addr) & 0xff);
2218 
2219  // Copy this to the output
2220  if ((unsigned)strlen(myIPstring) > max_length) {
2221  fprintf(stderr, "get_local_socket_name: Name too long to return\n");
2222  return -1;
2223  }
2224 
2225  strcpy(local_host, myIPstring);
2226  return ret;
2227 }
2228 
2247  SOCKET udp_sock, // Socket to use to send
2248  const char *machine, // Name of the machine to call
2249  const int remote_port, // UDP port on remote machine
2250  const int local_port, // TCP port on this machine
2251  const char *NIC_IP = NULL)
2252 {
2253  char msg[150]; /* Message to send */
2254  vrpn_int32 msglen; /* How long it is (including \0) */
2255  char myIPchar[100]; /* IP decription this host */
2256 
2257  /* Fill in the request message, telling the machine and port that
2258  * the remote server should connect to. These are ASCII, separated
2259  * by a space. vrpn_getmyIP returns the NIC_IP if it is not null,
2260  * or the host name of this machine using gethostname() if it is
2261  * NULL. If the NIC_IP is NULL but we have a socket (as we do here),
2262  * then it returns the address associated with the socket.
2263  */
2264  if (vrpn_getmyIP(myIPchar, sizeof(myIPchar), NIC_IP, udp_sock)) {
2265  fprintf(stderr,
2266  "vrpn_udp_request_lob_packet: Error finding local hostIP\n");
2267  vrpn_closeSocket(udp_sock);
2268  return (-1);
2269  }
2270  sprintf(msg, "%s %d", myIPchar, local_port);
2271  msglen = static_cast<vrpn_int32>(strlen(msg) +
2272  1); /* Include the terminating 0 char */
2273 
2274  // Lob the message
2275  if (send(udp_sock, msg, msglen, 0) == -1) {
2276  perror("vrpn_udp_request_lob_packet: send() failed");
2277  vrpn_closeSocket(udp_sock);
2278  return -1;
2279  }
2280 
2281  return 0;
2282 }
2283 
2294 static int vrpn_get_a_TCP_socket(SOCKET *listen_sock, int *listen_portnum,
2295  const char *NIC_IP = NULL)
2296 {
2297  struct sockaddr_in listen_name; /* The listen socket binding name */
2298  int listen_namelen;
2299 
2300  listen_namelen = sizeof(listen_name);
2301 
2302  /* Create a TCP socket to listen for incoming connections from the
2303  * remote server. */
2304 
2305  *listen_sock = open_tcp_socket(NULL, NIC_IP);
2306  if (*listen_sock < 0) {
2307  fprintf(stderr, "vrpn_get_a_TCP_socket: socket didn't open.\n");
2308  return -1;
2309  }
2310 
2311  if (listen(*listen_sock, 1)) {
2312  fprintf(stderr, "vrpn_get_a_TCP_socket: listen() failed.\n");
2313  vrpn_closeSocket(*listen_sock);
2314  return (-1);
2315  }
2316 
2317  if (getsockname(*listen_sock, (struct sockaddr *)&listen_name,
2318  GSN_CAST & listen_namelen)) {
2319  fprintf(stderr, "vrpn_get_a_TCP_socket: cannot get socket name.\n");
2320  vrpn_closeSocket(*listen_sock);
2321  return (-1);
2322  }
2323 
2324  *listen_portnum = ntohs(listen_name.sin_port);
2325 
2326  // fprintf(stderr, "Listening on port %d, address %d %d %d %d.\n",
2327  //*listen_portnum, listen_name.sin_addr.s_addr >> 24,
2328  //(listen_name.sin_addr.s_addr >> 16) & 0xff,
2329  //(listen_name.sin_addr.s_addr >> 8) & 0xff,
2330  // listen_name.sin_addr.s_addr & 0xff);
2331 
2332  return 0;
2333 }
2334 
2344 static int vrpn_poll_for_accept(SOCKET listen_sock, SOCKET *accept_sock,
2345  double timeout = 0.0)
2346 {
2347  fd_set rfds;
2348  struct timeval t;
2349 
2350  // See if we have a connection attempt within the timeout
2351  FD_ZERO(&rfds);
2352  FD_SET(listen_sock, &rfds); /* Check for read (connect) */
2353  t.tv_sec = (long)(timeout);
2354  t.tv_usec = (long)((timeout - t.tv_sec) * 1000000L);
2355  if (vrpn_noint_select(static_cast<int>(listen_sock) + 1, &rfds, NULL, NULL,
2356  &t) == -1) {
2357  perror("vrpn_poll_for_accept: select() failed");
2358  return -1;
2359  }
2360  if (FD_ISSET(listen_sock, &rfds)) { /* Got one! */
2361  /* Accept the connection from the remote machine and set TCP_NODELAY
2362  * on the socket. */
2363  if ((*accept_sock = accept(listen_sock, 0, 0)) == -1) {
2364  perror("vrpn_poll_for_accept: accept() failed");
2365  return -1;
2366  }
2367 #if !defined(_WIN32_WCE) && !defined(__ANDROID__)
2368  {
2369  struct protoent *p_entry;
2370  int nonzero = 1;
2371 
2372  if ((p_entry = getprotobyname("TCP")) == NULL) {
2373  fprintf(stderr,
2374  "vrpn_poll_for_accept: getprotobyname() failed.\n");
2375  vrpn_closeSocket(*accept_sock);
2376  return (-1);
2377  }
2378 
2379  if (setsockopt(*accept_sock, p_entry->p_proto, TCP_NODELAY,
2380  SOCK_CAST & nonzero, sizeof(nonzero)) == -1) {
2381  perror("vrpn_poll_for_accept: setsockopt() failed");
2382  vrpn_closeSocket(*accept_sock);
2383  return (-1);
2384  }
2385  }
2386 #endif
2387  return 1; // Got one!
2388  }
2389 
2390  return 0; // Nobody called
2391 }
2392 
2393 // This is like sdi_start_server except that the convention for
2394 // passing information on the client machine to the server program is
2395 // different; everything else has been left the same
2406 static int vrpn_start_server(const char *machine, char *server_name, char *args,
2407  const char *IPaddress = NULL)
2408 {
2409 #if defined(VRPN_USE_WINSOCK_SOCKETS) || defined(__CYGWIN__)
2410  fprintf(stderr, "VRPN: vrpn_start_server not ported"
2411  " for windows winsocks or cygwin!\n");
2412  IPaddress = IPaddress;
2413  args = args;
2414  server_name = server_name;
2415  machine = machine;
2416  return -1;
2417 #else
2418  int pid; /* Child's process ID */
2419  int server_sock; /* Where the accept returns */
2420  int child_socket; /* Where the final socket is */
2421  int PortNum; /* Port number we got */
2422 
2423  /* Open a socket and ensure we can bind it */
2424  if (vrpn_get_a_TCP_socket(&server_sock, &PortNum, IPaddress)) {
2425  fprintf(stderr, "vrpn_start_server: Cannot get listen socket\n");
2426  return -1;
2427  }
2428 
2429  if ((pid = fork()) == -1) {
2430  fprintf(stderr, "vrpn_start_server: cannot fork().\n");
2431  vrpn_closeSocket(server_sock);
2432  return (-1);
2433  }
2434  if (pid == 0) { /* CHILD */
2435  int loop;
2436  int ret;
2437  int num_descriptors; /* Number of available file descr */
2438  char myIPchar[100]; /* Host name of this host */
2439  char command[600]; /* Command passed to system() call */
2440  char *rsh_to_use; /* Full path to Rsh command. */
2441 
2442  if (vrpn_getmyIP(myIPchar, sizeof(myIPchar), IPaddress, server_sock)) {
2443  fprintf(stderr, "vrpn_start_server: Error finding my IP\n");
2444  vrpn_closeSocket(server_sock);
2445  return (-1);
2446  }
2447 
2448  /* Close all files except stdout and stderr. */
2449  /* This prevents a hung child from keeping devices open */
2450  num_descriptors = getdtablesize();
2451  for (loop = 0; loop < num_descriptors; loop++) {
2452  if ((loop != 1) && (loop != 2)) {
2453  close(loop);
2454  }
2455  }
2456 
2457  /* Find the RSH command, either from the environment
2458  * variable or the default, and use it to start up the
2459  * remote server. */
2460 
2461  if ((rsh_to_use = (char *)getenv("VRPN_RSH")) == NULL) {
2462  rsh_to_use = RSH;
2463  }
2464  sprintf(command, "%s %s %s %s -client %s %d", rsh_to_use, machine,
2465  server_name, args, myIPchar, PortNum);
2466  ret = system(command);
2467  if ((ret == 127) || (ret == -1)) {
2468  fprintf(stderr, "vrpn_start_server: system() failed !!!!!\n");
2469  perror("Error");
2470  fprintf(stderr, "Attempted command was: '%s'\n", command);
2471  vrpn_closeSocket(server_sock);
2472  exit(-1); /* This should never occur */
2473  }
2474  exit(0);
2475  }
2476  else { /* PARENT */
2477  int waitloop;
2478 
2479  /* Check to see if the child
2480  * is trying to call us back. Do SERVCOUNT waits, each of
2481  * which is SERVWAIT long.
2482  * If the child dies while we are waiting, then we can be
2483  * sure that they will not be calling us back. Check for
2484  * this while waiting for the callback. */
2485 
2486  for (waitloop = 0; waitloop < (SERVCOUNT); waitloop++) {
2487  int ret;
2488  pid_t deadkid;
2489 #if defined(sparc) || defined(FreeBSD) || defined(_AIX) || defined(__ANDROID__)
2490  int status; // doesn't exist on sparc_solaris or FreeBSD
2491 #else
2492  union wait status;
2493 #endif
2494 
2495  /* Check to see if they called back yet. */
2496  ret = vrpn_poll_for_accept(server_sock, &child_socket, SERVWAIT);
2497  if (ret == -1) {
2498  fprintf(stderr, "vrpn_start_server: Accept poll failed\n");
2499  vrpn_closeSocket(server_sock);
2500  return -1;
2501  }
2502  if (ret == 1) {
2503  break; // Got it!
2504  }
2505 
2506 /* Check to see if the child is dead yet */
2507 #if defined(hpux) || defined(sgi) || defined(__hpux) || defined(__CYGWIN__) || \
2508  defined(__APPLE__)
2509  /* hpux include files have the wrong declaration */
2510  deadkid = wait3((int *)&status, WNOHANG, NULL);
2511 #else
2512  deadkid = wait3(&status, WNOHANG, NULL);
2513 #endif
2514  if (deadkid == pid) {
2515  fprintf(stderr, "vrpn_start_server: server process exited\n");
2516  vrpn_closeSocket(server_sock);
2517  return (-1);
2518  }
2519  }
2520  if (waitloop == SERVCOUNT) {
2521  fprintf(stderr,
2522  "vrpn_start_server: server failed to connect in time\n");
2523  fprintf(stderr, " (took more than %d seconds)\n",
2524  SERVWAIT * SERVCOUNT);
2525  vrpn_closeSocket(server_sock);
2526  kill(pid, SIGKILL);
2527  wait(0);
2528  return (-1);
2529  }
2530 
2531  vrpn_closeSocket(server_sock);
2532  return (child_socket);
2533  }
2534  return 0;
2535 #endif
2536 }
2537 
2538 //** End of section pulled from SDI library
2539 //*********************************************************************
2540 
2541 // COOKIE MANIPULATION
2542 
2552 int write_vrpn_cookie(char *buffer, size_t length, long remote_log_mode)
2553 {
2554  if (length < vrpn_MAGICLEN + vrpn_ALIGN + 1) return -1;
2555 
2556  sprintf(buffer, "%s %c", vrpn_MAGIC,
2557  static_cast<char>(remote_log_mode + '0'));
2558  return 0;
2559 }
2560 
2567 int check_vrpn_cookie(const char *buffer)
2568 {
2569  const char *bp;
2570 
2571  // Comparison changed 9 Feb 98 by TCH
2572  // We don't care if the minor version numbers don't match,
2573  // so only check the characters through the last '.' in our
2574  // template. (If there is no last '.' in our template, somebody's
2575  // modified this code to break the constraints above, and we just
2576  // use a maximally restrictive check.)
2577  // XXX This pointer arithmetic isn't completely safe.
2578 
2579  bp = strrchr(buffer, '.');
2580  if (strncmp(buffer, vrpn_MAGIC,
2581  (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer))) {
2582  fprintf(stderr, "check_vrpn_cookie: "
2583  "bad cookie (wanted '%s', got '%s'\n",
2584  vrpn_MAGIC, buffer);
2585  return -1;
2586  }
2587 
2588  if (strncmp(buffer, vrpn_MAGIC, vrpn_MAGICLEN)) {
2589  fprintf(stderr,
2590  "check_vrpn_cookie(): "
2591  "VRPN Note: minor version number doesn't match: (prefer '%s', "
2592  "got '%s'). This is not normally a problem.\n",
2593  vrpn_MAGIC, buffer);
2594  return 1;
2595  }
2596 
2597  return 0;
2598 }
2599 
2600 int check_vrpn_file_cookie(const char *buffer)
2601 {
2602  const char *bp;
2603 
2604  // Comparison changed 9/1/00 by AAS and KTS
2605  // Here the difference is that we let the major version number be
2606  // less than or equal to our major version number as long as the major
2607  // version number is >= 4
2608 
2609  // We don't care if the minor version numbers don't match,
2610  // so only check the characters through the last '.' in our
2611  // template. (If there is no last '.' in our template, somebody's
2612  // modified this code to break the constraints above, and we just
2613  // use a maximally restrictive check.)
2614  // XXX This pointer arithmetic isn't completely safe.
2615 
2616  bp = strrchr(buffer, '.');
2617  int majorComparison = strncmp(
2618  buffer, vrpn_MAGIC, (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer));
2619  if (majorComparison > 0 ||
2620  strncmp(buffer, vrpn_FILE_MAGIC,
2621  (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer)) < 0) {
2622  fprintf(stderr, "check_vrpn_file_cookie: "
2623  "bad cookie (wanted >='%s' and <='%s', "
2624  "got '%s'\n",
2625  vrpn_FILE_MAGIC, vrpn_MAGIC, buffer);
2626  return -1;
2627  }
2628 
2629  if (majorComparison == 0 && strncmp(buffer, vrpn_MAGIC, vrpn_MAGICLEN)) {
2630  fprintf(stderr, "check_vrpn_file_cookie(): "
2631  "Note: Version number doesn't match: (prefer '%s', got "
2632  "'%s'). This is not normally a problem.\n",
2633  vrpn_MAGIC, buffer);
2634  return 1;
2635  }
2636 
2637  return 0;
2638 }
2639 
2640 size_t vrpn_cookie_size(void) { return vrpn_MAGICLEN + vrpn_ALIGN; }
2641 
2642 // END OF COOKIE CODE
2643 
2645  vrpn_int32 *connectedEndpointCounter)
2646  : status(BROKEN)
2647  , d_remoteLogMode(0)
2648  , d_remoteInLogName(NULL)
2649  , d_remoteOutLogName(NULL)
2650  , d_inLog(NULL)
2651  , d_outLog(NULL)
2652  , d_senders(NULL)
2653  , d_types(NULL)
2654  , d_dispatcher(dispatcher)
2655  , d_connectionCounter(connectedEndpointCounter)
2656 {
2658 }
2659 
2661  vrpn_int32 *connectedEndpointCounter)
2662  : vrpn_Endpoint(dispatcher, connectedEndpointCounter)
2663  , d_tcpSocket(INVALID_SOCKET)
2664  , d_tcpListenSocket(INVALID_SOCKET)
2665  , d_tcpListenPort(0)
2666  , d_udpLobSocket(INVALID_SOCKET)
2667  , d_remote_machine_name(NULL)
2668  , d_remote_port_number(0)
2669  , d_tcp_only(vrpn_FALSE)
2670  , d_udpOutboundSocket(INVALID_SOCKET)
2671  , d_udpInboundSocket(INVALID_SOCKET)
2672  , d_tcpOutbuf(new char[vrpn_CONNECTION_TCP_BUFLEN])
2673  , d_udpOutbuf(new char[vrpn_CONNECTION_UDP_BUFLEN])
2674  , d_tcpBuflen(d_tcpOutbuf ? vrpn_CONNECTION_TCP_BUFLEN : 0)
2675  , d_udpBuflen(d_udpOutbuf ? vrpn_CONNECTION_UDP_BUFLEN : 0)
2676  , d_tcpNumOut(0)
2677  , d_udpNumOut(0)
2678  , d_tcpSequenceNumber(0)
2679  , d_udpSequenceNumber(0)
2680  , d_tcpInbuf((char *)d_tcpAlignedInbuf)
2681  , d_udpInbuf((char *)d_udpAlignedInbuf)
2682  , d_NICaddress(NULL)
2683 {
2685 }
2686 
2688 {
2689 
2690  // Delete type and sender arrays
2691  if (d_senders) {
2692  delete d_senders;
2693  }
2694  if (d_types) {
2695  delete d_types;
2696  }
2697 
2698  // Delete the log, if any
2699  if (d_inLog) {
2700  // close() is called by destructor IFF necessary
2701  delete d_inLog;
2702  }
2703  if (d_outLog) {
2704  // close() is called by destructor IFF necessary
2705  delete d_outLog;
2706  }
2707 
2708  // Delete any file names created during the running
2709  if (d_remoteInLogName) {
2710  delete[] d_remoteInLogName;
2711  }
2712  if (d_remoteOutLogName) {
2713  delete[] d_remoteOutLogName;
2714  }
2715 }
2716 
2718 {
2719  // Close all of the sockets that are left open
2720  if (d_tcpSocket != INVALID_SOCKET) {
2723  d_tcpNumOut = 0; // Ignore characters waiting to go
2724  }
2728  d_udpNumOut = 0; // Ignore characters waiting to go
2729  }
2733  }
2737  }
2738  if (d_udpLobSocket != INVALID_SOCKET) {
2741  }
2742 
2743  // Delete the buffers created in the constructor
2744  if (d_tcpOutbuf) {
2745  delete[] d_tcpOutbuf;
2746  d_tcpOutbuf = NULL;
2747  }
2748  if (d_udpOutbuf) {
2749  delete[] d_udpOutbuf;
2750  d_udpOutbuf = NULL;
2751  }
2752 
2753  // Delete the remote machine name, if it has been set
2754  if (d_remote_machine_name) {
2755  delete[] d_remote_machine_name;
2756  d_remote_machine_name = NULL;
2757  }
2758 }
2759 
2761 {
2762  return (d_udpOutboundSocket != -1);
2763 }
2764 
2765 int vrpn_Endpoint::local_type_id(vrpn_int32 remote_type) const
2766 {
2767  return d_types->mapToLocalID(remote_type);
2768 }
2769 
2770 int vrpn_Endpoint::local_sender_id(vrpn_int32 remote_sender) const
2771 {
2772  return d_senders->mapToLocalID(remote_sender);
2773 }
2774 
2775 vrpn_int32 vrpn_Endpoint_IP::tcp_outbuf_size(void) const { return d_tcpBuflen; }
2776 
2777 vrpn_int32 vrpn_Endpoint_IP::udp_outbuf_size(void) const { return d_udpBuflen; }
2778 
2779 vrpn_bool vrpn_Endpoint_IP::doing_okay(void) const
2780 {
2781  return ((status >= TRYING_TO_CONNECT) || (status == LOGGING));
2782 }
2783 
2785 {
2786  // Set all of the local IDs to -1, in case the other side
2787  // sends a message of a type that it has not yet defined.
2788  // (for example, arriving on the UDP line ahead of its TCP
2789  // definition).
2792 
2793  if (!d_senders || !d_types) {
2794  fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2795  return;
2796  }
2797 
2799 
2800  if (!d_inLog) {
2801  fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2802  return;
2803  }
2804 
2806 
2807  if (!d_outLog) {
2808  fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2809  return;
2810  }
2811 }
2812 
2814 {
2817  d_tcpListenPort = 0;
2821 
2822  // Never tried a reconnect yet
2823  d_last_connect_attempt.tv_sec = 0;
2824  d_last_connect_attempt.tv_usec = 0;
2825 }
2826 
2827 int vrpn_Endpoint_IP::mainloop(timeval *timeout)
2828 {
2829  fd_set readfds, exceptfds;
2830  int tcp_messages_read;
2831  int udp_messages_read;
2832  int fd_max = static_cast<int>(d_tcpSocket);
2833  bool time_to_try_again = false;
2834 
2835  switch (status) {
2836 
2837  case CONNECTED:
2838 
2839  // Send all pending reports on the way out
2841 
2842  // check for pending incoming tcp or udp reports
2843  // we do this so that we can trigger out of the timeout
2844  // on either type of message without waiting on the other
2845 
2846  FD_ZERO(&readfds); /* Clear the descriptor sets */
2847  FD_ZERO(&exceptfds);
2848 
2849  // Read incoming messages from both the UDP and TCP channels
2850 
2851  FD_SET(d_tcpSocket, &readfds);
2852  FD_SET(d_tcpSocket, &exceptfds);
2853 
2854  if (d_udpInboundSocket != -1) {
2855  FD_SET(d_udpInboundSocket, &readfds);
2856  FD_SET(d_udpInboundSocket, &exceptfds);
2858  fd_max = static_cast<int>(d_udpInboundSocket);
2859  }
2860 
2861  // Select to see if ready to hear from other side, or exception
2862 
2863  if (vrpn_noint_select(fd_max + 1, &readfds, NULL, &exceptfds,
2864  timeout) == -1) {
2865  fprintf(stderr, "vrpn_Endpoint::mainloop: select failed.\n");
2866 #ifndef _WIN32_WCE
2867  fprintf(stderr, " Errno (%d): %s.\n", errno, strerror(errno));
2868 #endif
2869  status = BROKEN;
2870  return -1;
2871  }
2872 
2873  // See if exceptional condition on either socket
2874  if (FD_ISSET(d_tcpSocket, &exceptfds) ||
2875  ((d_udpInboundSocket != -1) &&
2876  FD_ISSET(d_udpInboundSocket, &exceptfds))) {
2877  fprintf(stderr, "vrpn_Endpoint::mainloop: Exception on socket\n");
2878  status = BROKEN;
2879  return -1;
2880  }
2881 
2882  // Read incoming messages from the UDP channel
2883  if ((d_udpInboundSocket != -1) &&
2884  FD_ISSET(d_udpInboundSocket, &readfds)) {
2885  udp_messages_read = handle_udp_messages(NULL);
2886  if (udp_messages_read == -1) {
2887  fprintf(stderr, "vrpn_Endpoint::mainloop: "
2888  "UDP handling failed, dropping connection\n");
2889  status = BROKEN;
2890  break;
2891  }
2892 #ifdef VERBOSE3
2893  if (udp_messages_read != 0)
2894  printf("udp message read = %d\n", udp_messages_read);
2895 #endif
2896  }
2897 
2898  // Read incoming messages from the TCP channel
2899  if (FD_ISSET(d_tcpSocket, &readfds)) {
2900  tcp_messages_read = handle_tcp_messages(NULL);
2901  if (tcp_messages_read == -1) {
2902  fprintf(stderr, "vrpn: TCP handling failed, dropping "
2903  "connection (this is normal when a connection "
2904  "is dropped)\n");
2905  status = BROKEN;
2906  break;
2907  }
2908 #ifdef VERBOSE3
2909  else {
2910  if (tcp_messages_read) {
2911  printf("tcp_message_read %d bytes\n", tcp_messages_read);
2912  }
2913  }
2914 #endif
2915  }
2916  break;
2917 
2918  case COOKIE_PENDING:
2919 
2920  poll_for_cookie(timeout);
2921 
2922  break;
2923 
2924  case TRYING_TO_CONNECT:
2925  struct timeval now;
2926  int ret;
2927 
2928 #ifdef VERBOSE
2929  printf("TRYING_TO_CONNECT\n");
2930 #endif
2931  // See if it has been long enough since our last attempt
2932  // to try again.
2933  vrpn_gettimeofday(&now, NULL);
2934  if (now.tv_sec - d_last_connect_attempt.tv_sec >= 2) {
2935  d_last_connect_attempt.tv_sec = now.tv_sec;
2936  time_to_try_again = true;
2937  }
2938 
2939  // If we are a TCP-only connection, then we retry to establish the
2940  // connection whenever it is time to try again. Otherwise, we're done.
2941  if (d_tcp_only) {
2942  if (time_to_try_again) {
2945  d_remote_port_number) == 0) {
2947  if (setup_new_connection()) {
2948  fprintf(stderr, "vrpn_Endpoint::mainloop: "
2949  "Can't set up new connection!\n");
2950  break;
2951  }
2952  }
2953  }
2954  break;
2955  }
2956 
2957  // We are not a TCP-only connect.
2958  // See if we have a connection yet (nonblocking select).
2959  ret = vrpn_poll_for_accept(d_tcpListenSocket, &d_tcpSocket);
2960  if (ret == -1) {
2961  fprintf(stderr, "vrpn_Endpoint: mainloop: Can't poll for accept\n");
2962  status = BROKEN;
2963  break;
2964  }
2965  if (ret == 1) { // Got one!
2967 #ifdef VERBOSE
2968  printf("vrpn: Connection established\n");
2969 #endif
2970  // Set up the things that need to happen when a new connection
2971  // is established.
2972  if (setup_new_connection()) {
2973  fprintf(stderr, "vrpn_Endpoint: mainloop: "
2974  "Can't set up new connection!\n");
2975  status = BROKEN;
2976  // fprintf(stderr, "BROKEN - vrpn_Endpoint::mainloop.\n");
2977  break;
2978  }
2979  break;
2980  }
2981 
2982  // Lob a request-to-connect packet every couple of seconds
2983  // If we don't wait a while between these we flood buffers and
2984  // do BAD THINGS (TM).
2985 
2986  if (time_to_try_again) {
2987  //XXX On Linux, if we are talking to a machine that does not
2988  // have a server running, then our connect eventually tells us
2989  // that is was refused, and we can't communicate on that
2990  // UDP socket anymore. We should switch to a connectionless
2991  // sendto() option instead, but this runs the way it used
2992  // to, which worked, but still leaves the socket open after
2993  // the send; closing it right away broke on some Windows
2994  // machines.
2996  d_udpLobSocket = vrpn_connect_udp_port(d_remote_machine_name,
2998 
3001  d_tcpListenPort, d_NICaddress) == -1) {
3002  fprintf(stderr,
3003  "vrpn_Endpoint: mainloop: Can't lob UDP request\n");
3004  status = BROKEN;
3005  // fprintf(stderr, "BROKEN - vrpn_Endpoint::mainloop.\n");
3006  break;
3007  }
3008  }
3009  break;
3010 
3011  case BROKEN:
3013  return -1;
3014 
3015  case LOGGING: // Just logging, so go about your business.
3016  break;
3017 
3018  default:
3019  fprintf(stderr, "vrpn_Endpoint::mainloop(): "
3020  "Unknown status (%d)\n",
3021  status);
3022  status = BROKEN;
3023  return -1;
3024  }
3025 
3026  return 0;
3027 } // MAINLOOP
3028 
3029 // Clear out the remote mapping list. This is done when a
3030 // connection is dropped and we want to try and re-establish
3031 // it.
3033 {
3034  d_senders->clear();
3035  d_types->clear();
3036 }
3037 
3038 // Make the local mapping for the otherside sender with the same
3039 // name, if there is one. Return 1 if there was a mapping; this
3040 // lets the higher-ups know that there is someone that cares
3041 // on the other side.
3042 int vrpn_Endpoint::newLocalSender(const char *name, vrpn_int32 which)
3043 {
3044  return d_senders->addLocalID(name, which);
3045 }
3046 
3047 // If the other side has declared this type, establish the
3048 // mapping for it. Return 1 if there was a mapping; this
3049 // lets the higher-ups know that there is someone that cares
3050 // on the other side.
3051 int vrpn_Endpoint::newLocalType(const char *name, vrpn_int32 which)
3052 {
3053  return d_types->addLocalID(name, which);
3054 }
3055 
3056 // Adds a new remote type and returns its index. Returns -1 on error.
3057 int vrpn_Endpoint::newRemoteType(cName type_name, vrpn_int32 remote_id,
3058  vrpn_int32 local_id)
3059 {
3060  return d_types->addRemoteEntry(type_name, remote_id, local_id);
3061 }
3062 
3063 // Adds a new remote sender and returns its index. Returns -1 on error.
3064 int vrpn_Endpoint::newRemoteSender(cName sender_name, vrpn_int32 remote_id,
3065  vrpn_int32 local_id)
3066 {
3067  return d_senders->addRemoteEntry(sender_name, remote_id, local_id);
3068 }
3069 
3085 int vrpn_Endpoint_IP::pack_message(vrpn_uint32 len, timeval time,
3086  vrpn_int32 type, vrpn_int32 sender,
3087  const char *buffer,
3088  vrpn_uint32 class_of_service)
3089 {
3090  int ret;
3091 
3092  // Any semantic checking needs to have been done by the Connection
3093  // class: the Endpoint doesn't know enough to do it. Similarly
3094  // for any local callbacks that need to be done. Similarly, filtering.
3095 
3096  // Logging must come before filtering and should probably come before
3097  // any other failure-prone action (such as do_callbacks_for()). Only
3098  // semantic checking should precede it.
3099 
3100  if (d_outLog->logOutgoingMessage(len, time, type, sender, buffer)) {
3101  fprintf(stderr, "vrpn_Endpoint::pack_message: "
3102  "Couldn't log outgoing message.!\n");
3103  return -1;
3104  }
3105 
3106  if (status == LOGGING) {
3107  // No error message; this endpoint is ONLY logging.
3108  return 0;
3109  }
3110 
3111  // TCH 26 April 2000
3112  if (status != CONNECTED) {
3113 #ifdef VERBOSE2
3114  fprintf(stderr, "vrpn_Endpoint::pack_message: "
3115  "Not connected, so throwing out message.\n");
3116 #endif
3117  return 0;
3118  }
3119 
3120  // Determine the class of service and pass it off to the
3121  // appropriate service (TCP for reliable, UDP for everything else).
3122  // If we don't have a UDP outbound channel, send everything TCP
3123  if ((d_udpOutboundSocket == -1) ||
3124  (class_of_service & vrpn_CONNECTION_RELIABLE)) {
3125 
3126  // Ensure that we have an outgoing TCP buffer. If not, then
3127  // we don't have anywhere to send it.
3128  if (d_tcpSocket == -1) {
3129  ret = 0;
3130  }
3131  else {
3132  ret =
3134  type, sender, buffer, d_tcpSequenceNumber);
3135  d_tcpNumOut += ret;
3136  if (ret > 0) {
3138  }
3139  }
3140  }
3141  else {
3142 
3143  ret = tryToMarshall(d_udpOutbuf, d_udpBuflen, d_udpNumOut, len, time,
3144  type, sender, buffer, d_udpSequenceNumber);
3145  d_udpNumOut += ret;
3146  if (ret > 0) {
3148  }
3149  }
3150  return (!ret) ? -1 : 0;
3151 }
3152 
3154 {
3155  vrpn_int32 ret, sent = 0;
3156  int connection;
3157  timeval timeout;
3158 
3159  // Make sure we've got a valid TCP connection; else we can't send them.
3160  if (d_tcpSocket == -1) {
3161  fprintf(stderr,
3162  "vrpn_Endpoint::send_pending_reports(): No TCP connection\n");
3163  status = BROKEN;
3164  clearBuffers();
3165  return -1;
3166  }
3167 
3168  // Check for an exception on the socket. If there is one, shut it
3169  // down and go back to listening.
3170  timeout.tv_sec = 0;
3171  timeout.tv_usec = 0;
3172 
3173  fd_set f;
3174  FD_ZERO(&f);
3175  FD_SET(d_tcpSocket, &f);
3176 
3177  connection = vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, NULL,
3178  NULL, &f, &timeout);
3179  if (connection) {
3180  fprintf(stderr, "vrpn_Endpoint::send_pending_reports(): "
3181  "select() failed.\n");
3182 #ifdef VRPN_USE_WINSOCK_SOCKETS
3183  char Message[1024];
3184  FormatMessage(
3185  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
3186  FORMAT_MESSAGE_MAX_WIDTH_MASK,
3187  NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3188  (LPSTR)Message, 1024, NULL);
3189  fprintf(stderr, "Windows Sockets Error (%d): %s.\n", WSAGetLastError(),
3190  Message);
3191 #else
3192  fprintf(stderr, "Errno (%d): %s.\n", errno, strerror(errno));
3193 #endif
3194  status = BROKEN;
3195  return -1;
3196  }
3197 
3198 // Send all of the messages that have built
3199 // up in the TCP buffer. If there is an error during the send, or
3200 // an exceptional condition, close the accept socket and go back
3201 // to listening for new connections.
3202 #ifdef VERBOSE
3203  if (d_tcpNumOut) printf("TCP Need to send %d bytes\n", d_tcpNumOut);
3204 #endif
3205  while (sent < d_tcpNumOut) {
3206  ret = send(d_tcpSocket, &d_tcpOutbuf[sent], d_tcpNumOut - sent, 0);
3207 #ifdef VERBOSE
3208  printf("TCP Sent %d bytes\n", ret);
3209 #endif
3210  if (ret == -1) {
3211  fprintf(stderr, "vrpn_Endpoint::send_pending_reports: "
3212  "TCP send failed.\n");
3213  status = BROKEN;
3214  return -1;
3215  }
3216  sent += ret;
3217  }
3218 
3219  // Send all of the messages that have built
3220  // up in the UDP buffer. If there is an error during the send, or
3221  // an exceptional condition, close the accept socket and go back
3222  // to listening for new connections.
3223 
3224  if ((d_udpOutboundSocket != -1) && (d_udpNumOut > 0)) {
3225 
3226  ret = send(d_udpOutboundSocket, d_udpOutbuf, d_udpNumOut, 0);
3227 #ifdef VERBOSE
3228  printf("UDP Sent %d bytes\n", ret);
3229 #endif
3230  if (ret == -1) {
3231  fprintf(stderr, "vrpn_Endpoint::send_pending_reports: "
3232  " UDP send failed.");
3233  status = BROKEN;
3234  return -1;
3235  }
3236  }
3237 
3238  clearBuffers();
3239  return 0;
3240 }
3241 
3242 // Pack a message telling to call back this host on the specified
3243 // port number. It is important that the IP address of the host
3244 // refers to the one that was used by the original TCP connection
3245 // rather than (for example) the default IP address for the host.
3246 // This is because the remote machine may not have a route to
3247 // that NIC, but only the one used to establish the TCP connection.
3248 
3250 {
3251  struct timeval now;
3252  vrpn_uint32 portparam = portno;
3253  char myIPchar[1000];
3254  int retval;
3255 
3256 #ifdef VERBOSE2
3257  fprintf(stderr, "Getting IP address of NIC %s.\n", d_NICaddress);
3258 #endif
3259 
3260  // Find the local host name that we should be using to connect.
3261  // If d_NICaddress is set, use it; otherwise, use the d_tcpSocket
3262  // if it is valid.
3263  retval =
3264  vrpn_getmyIP(myIPchar, sizeof(myIPchar), d_NICaddress, d_tcpSocket);
3265  if (retval) {
3266  perror("vrpn_Endpoint::pack_udp_description: can't get host name");
3267  return -1;
3268  }
3269 
3270 // Pack a message with type vrpn_CONNECTION_UDP_DESCRIPTION
3271 // whose sender ID is the ID of the port that is to be
3272 // used and whose body holds the zero-terminated string
3273 // name of the host to contact.
3274 
3275 #ifdef VERBOSE
3276  fprintf(stderr, "vrpn_Endpoint::pack_udp_description: "
3277  "Packing UDP %s:%d\n",
3278  myIPchar, portno);
3279 #endif
3280  vrpn_gettimeofday(&now, NULL);
3281 
3282  return pack_message(static_cast<vrpn_uint32>(strlen(myIPchar)) + 1, now,
3283  vrpn_CONNECTION_UDP_DESCRIPTION, portparam, myIPchar,
3285 }
3286 
3288 {
3289  struct timeval now;
3290 
3291  // Handle the case of NULL pointers in the log file names
3292  // by pointing local copies at the empty string if they occur.
3293  const char *inName = "";
3294  const char *outName = "";
3295  if (d_remoteInLogName) {
3296  inName = d_remoteInLogName;
3297  }
3298  if (d_remoteOutLogName) {
3299  outName = d_remoteOutLogName;
3300  }
3301 
3302  // Include the NULL termination for the strings in the length of the buffer.
3303  size_t bufsize =
3304  2 * sizeof(vrpn_int32) + strlen(inName) + 1 + strlen(outName) + 1;
3305  char *buf = new char[bufsize];
3306  if (buf == NULL) {
3307  fprintf(stderr,
3308  "vrpn_Endpoint::pack_log_description(): Out of memory\n");
3309  return -1;
3310  }
3311 
3312  // If we're not requesting remote logging, don't send any message.
3313 
3314  if (!d_remoteLogMode) {
3315  delete[] buf;
3316  return 0;
3317  }
3318 
3319  // Pack a message with type vrpn_CONNECTION_LOG_DESCRIPTION whose
3320  // sender ID is the logging mode to be used by the remote connection
3321  // and whose body holds the zero-terminated string name of the file
3322  // to write to.
3323 
3324  vrpn_gettimeofday(&now, NULL);
3325  char *bpp = buf;
3326  char **bp = &bpp;
3327  vrpn_int32 bufleft = static_cast<vrpn_int32>(bufsize);
3328  vrpn_buffer(bp, &bufleft, (vrpn_int32)strlen(inName));
3329  vrpn_buffer(bp, &bufleft, (vrpn_int32)strlen(outName));
3330  vrpn_buffer(bp, &bufleft, inName, static_cast<vrpn_int32>(strlen(inName)));
3331  vrpn_buffer(bp, &bufleft, (char)0);
3332  vrpn_buffer(bp, &bufleft, outName,
3333  static_cast<vrpn_int32>(strlen(outName)));
3334  vrpn_buffer(bp, &bufleft, (char)0);
3335  int ret = pack_message(static_cast<vrpn_uint32>(bufsize - bufleft), now,
3338  delete[] buf;
3339  return ret;
3340 }
3341 
3342 // Read all messages available on the given file descriptor (a TCP link).
3343 // Handle each message that is received.
3344 // Return the number of messages read, or -1 on failure.
3345 
3346 int vrpn_Endpoint_IP::handle_tcp_messages(const struct timeval *timeout)
3347 {
3348  timeval localTimeout;
3349  fd_set readfds, exceptfds;
3350  unsigned num_messages_read = 0;
3351  int retval;
3352  int sel_ret;
3353 
3354 #ifdef VERBOSE2
3355  printf("vrpn_Endpoint::handle_tcp_messages() called\n");
3356 #endif
3357 
3358  if (timeout) {
3359  localTimeout.tv_sec = timeout->tv_sec;
3360  localTimeout.tv_usec = timeout->tv_usec;
3361  }
3362  else {
3363  localTimeout.tv_sec = 0;
3364  localTimeout.tv_usec = 0;
3365  }
3366 
3367  // Read incoming messages until there are no more characters to
3368  // read from the other side. For each message, determine what
3369  // type it is and then pass it off to the appropriate handler
3370  // routine. If d_stop_processing_messages_after has been set
3371  // to a nonzero value, then stop processing if we have received
3372  // at least that many messages.
3373 
3374  do {
3375  // Select to see if ready to hear from other side, or exception
3376  FD_ZERO(&readfds); /* Clear the descriptor sets */
3377  FD_ZERO(&exceptfds);
3378  FD_SET(d_tcpSocket, &readfds); /* Check for read */
3379  FD_SET(d_tcpSocket, &exceptfds); /* Check for exceptions */
3380  sel_ret = vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, &readfds,
3381  NULL, &exceptfds, &localTimeout);
3382  if (sel_ret == -1) {
3383  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
3384  "select failed");
3385  return (-1);
3386  }
3387 
3388  // See if exceptional condition on socket
3389  if (FD_ISSET(d_tcpSocket, &exceptfds)) {
3390  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
3391  "Exception on socket\n");
3392  return (-1);
3393  }
3394 
3395  // If there is anything to read, get the next message
3396  if (FD_ISSET(d_tcpSocket, &readfds)) {
3397  retval = getOneTCPMessage(static_cast<int>(d_tcpSocket), d_tcpInbuf,
3398  sizeof(d_tcpAlignedInbuf));
3399  if (retval) {
3400  return -1;
3401  }
3402 
3403  // Got one more message
3404  num_messages_read++;
3405  }
3406 
3407  // If we've been asked to process only a certain number of
3408  // messages, then stop if we've gotten at least that many.
3409  if (d_parent->get_Jane_value() != 0) {
3410  if (num_messages_read >= d_parent->get_Jane_value()) {
3411  break;
3412  }
3413  }
3414  } while (sel_ret);
3415 
3416  return num_messages_read;
3417 }
3418 
3419 // Read all messages available on the given file descriptor (a UDP link).
3420 // Handle each message that is received.
3421 // Return the number of messages read, or -1 on failure.
3422 // This routine and the TCP read routine are annoyingly similar, so it
3423 // seems like they should be merged. They can't though: using read() on
3424 // the UDP socket fails, so we need the UDP version. If we use the UDP
3425 // version for the TCP code, it hangs when we the client drops its
3426 // connection, so we need the TCP code as well.
3427 // If d_stop_processing_messages_after has been set
3428 // to a nonzero value, then stop processing if we have received
3429 // at least that many messages.
3430 
3431 int vrpn_Endpoint_IP::handle_udp_messages(const struct timeval *timeout)
3432 {
3433  timeval localTimeout;
3434  fd_set readfds, exceptfds;
3435  unsigned num_messages_read = 0;
3436  int sel_ret;
3437  int retval;
3438 
3439 #ifdef VERBOSE2
3440  printf("vrpn_Endpoint::handle_udp_messages() called\n");
3441 #endif
3442 
3443  if (timeout) {
3444  localTimeout.tv_sec = timeout->tv_sec;
3445  localTimeout.tv_usec = timeout->tv_usec;
3446  }
3447  else {
3448  localTimeout.tv_sec = 0;
3449  localTimeout.tv_usec = 0;
3450  }
3451 
3452  // Read incoming messages until there are no more packets to
3453  // read from the other side. Each packet may have more than one
3454  // message in it. For each message, determine what
3455  // type it is and then pass it off to the appropriate handler
3456  // routine.
3457 
3458  do {
3459  // Select to see if ready to hear from server, or exception
3460  FD_ZERO(&readfds); /* Clear the descriptor sets */
3461  FD_ZERO(&exceptfds);
3462  FD_SET(d_udpInboundSocket, &readfds); /* Check for read */
3463  FD_SET(d_udpInboundSocket, &exceptfds); /* Check for exceptions */
3464  sel_ret = vrpn_noint_select(static_cast<int>(d_udpInboundSocket) + 1,
3465  &readfds, NULL, &exceptfds, &localTimeout);
3466  if (sel_ret == -1) {
3467  perror("vrpn_Endpoint::handle_udp_messages: select failed()");
3468  return (-1);
3469  }
3470 
3471  // See if exceptional condition on socket
3472  if (FD_ISSET(d_udpInboundSocket, &exceptfds)) {
3473  fprintf(stderr, "vrpn: vrpn_Endpoint::handle_udp_messages: "
3474  "Exception on socket\n");
3475  return (-1);
3476  }
3477 
3478  // If there is anything to read, get the next message
3479  if (FD_ISSET(d_udpInboundSocket, &readfds)) {
3480  char *inbuf_ptr;
3481  int inbuf_len;
3482 
3483  inbuf_ptr = d_udpInbuf;
3484  inbuf_len = recv(d_udpInboundSocket, d_udpInbuf,
3485  sizeof(d_udpAlignedInbuf), 0);
3486  if (inbuf_len == -1) {
3487  fprintf(stderr, "vrpn_Endpoint::handle_udp_message: "
3488  "recv() failed.\n");
3489  return -1;
3490  }
3491 
3492  while (inbuf_len) {
3493  retval = getOneUDPMessage(inbuf_ptr, inbuf_len);
3494  if (retval == -1) {
3495  return -1;
3496  }
3497  inbuf_len -= retval;
3498  inbuf_ptr += retval;
3499  // fprintf(stderr, " Advancing inbuf pointer %d bytes.\n",
3500  // retval);
3501  // Got one more message
3502  num_messages_read++;
3503  }
3504  }
3505 
3506  // If we've been asked to process only a certain number of
3507  // messages, then stop if we've gotten at least that many.
3508  if (d_parent->get_Jane_value() != 0) {
3509  if (num_messages_read >= d_parent->get_Jane_value()) {
3510  break;
3511  }
3512  }
3513 
3514  } while (sel_ret);
3515 
3516  return num_messages_read;
3517 }
3518 
3519 //---------------------------------------------------------------------------
3520 // This routine opens a TCP socket and connects it to the machine and port
3521 // that are passed in the msg parameter. This is a string that contains
3522 // the machine name, a space, then the port number.
3523 // The routine returns -1 on failure and the file descriptor on success.
3524 
3526 {
3527  char machine[1000];
3528  int port;
3529 
3530  // Find the machine name and port number
3531  if (sscanf(msg, "%s %d", machine, &port) != 2) {
3532  return -1;
3533  }
3534 
3535  return connect_tcp_to(machine, port);
3536 }
3537 
3538 int vrpn_Endpoint_IP::connect_tcp_to(const char *addr, int port)
3539 {
3540  struct sockaddr_in client; /* The name of the client */
3541  struct hostent *host; /* The host to connect to */
3542 
3543  /* set up the socket */
3544  d_tcpSocket = open_tcp_socket(NULL, d_NICaddress);
3545  if (d_tcpSocket < 0) {
3546  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: "
3547  "can't open socket\n");
3548  return -1;
3549  }
3550  client.sin_family = AF_INET;
3551 
3552  // gethostbyname() fails on SOME Windows NT boxes, but not all,
3553  // if given an IP octet string rather than a true name.
3554  // MS Documentation says it will always fail and inet_addr should
3555  // be called first. Avoids a 30+ second wait for
3556  // gethostbyname() to fail.
3557 
3558  if ((client.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE) {
3559  host = gethostbyname(addr);
3560  if (host) {
3561 
3562 #ifdef CRAY
3563  {
3564  int i;
3565  u_long foo_mark = 0;
3566  for (i = 0; i < 4; i++) {
3567  u_long one_char = host->h_addr_list[0][i];
3568  foo_mark = (foo_mark << 8) | one_char;
3569  }
3570  client.sin_addr.s_addr = foo_mark;
3571  }
3572 #else
3573  memcpy(&(client.sin_addr.s_addr), host->h_addr, host->h_length);
3574 #endif
3575  }
3576  else {
3577 
3578 #if !defined(hpux) && !defined(__hpux) && !defined(_WIN32) && !defined(sparc)
3579  herror("gethostbyname error:");
3580 #else
3581  perror("gethostbyname error:");
3582 #endif
3583  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: "
3584  "error finding host by name (%s)\n",
3585  addr);
3586  return -1;
3587  }
3588  }
3589 
3590 #ifndef VRPN_USE_WINSOCK_SOCKETS
3591  client.sin_port = htons(port);
3592 #else
3593  client.sin_port = htons((u_short)port);
3594 #endif
3595 
3596  if (connect(d_tcpSocket, (struct sockaddr *)&client, sizeof(client)) < 0) {
3597 #ifdef VRPN_USE_WINSOCK_SOCKETS
3598  if (!d_tcp_only) {
3599  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: Could not connect "
3600  "to machine %d.%d.%d.%d port %d\n",
3601  (int)(client.sin_addr.S_un.S_un_b.s_b1),
3602  (int)(client.sin_addr.S_un.S_un_b.s_b2),
3603  (int)(client.sin_addr.S_un.S_un_b.s_b3),
3604  (int)(client.sin_addr.S_un.S_un_b.s_b4),
3605  (int)(ntohs(client.sin_port)));
3606  int error = WSAGetLastError();
3607  fprintf(stderr, "Winsock error: %d\n", error);
3608  }
3609 #else
3610  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: Could not connect to "
3611  "machine %d.%d.%d.%d port %d\n",
3612  (int)((client.sin_addr.s_addr >> 24) & 0xff),
3613  (int)((client.sin_addr.s_addr >> 16) & 0xff),
3614  (int)((client.sin_addr.s_addr >> 8) & 0xff),
3615  (int)((client.sin_addr.s_addr >> 0) & 0xff),
3616  (int)(ntohs(client.sin_port)));
3617 #endif
3619  status = BROKEN;
3620  return (-1);
3621  }
3622 
3623 /* Set the socket for TCP_NODELAY */
3624 #if !defined(_WIN32_WCE) && !defined(__ANDROID__)
3625  {
3626  struct protoent *p_entry;
3627  int nonzero = 1;
3628 
3629  if ((p_entry = getprotobyname("TCP")) == NULL) {
3630  fprintf(
3631  stderr,
3632  "vrpn_Endpoint::connect_tcp_to: getprotobyname() failed.\n");
3634  status = BROKEN;
3635  return -1;
3636  }
3637 
3638  if (setsockopt(d_tcpSocket, p_entry->p_proto, TCP_NODELAY,
3639  SOCK_CAST & nonzero, sizeof(nonzero)) == -1) {
3640  perror("vrpn_Endpoint::connect_tcp_to: setsockopt() failed");
3642  status = BROKEN;
3643  return -1;
3644  }
3645  }
3646 #endif
3648 
3649  return 0;
3650 }
3651 
3652 int vrpn_Endpoint_IP::connect_udp_to(const char *addr, int port)
3653 {
3654  if (!d_tcp_only) {
3655  d_udpOutboundSocket = ::vrpn_connect_udp_port(addr, port, d_NICaddress);
3656  if (d_udpOutboundSocket == -1) {
3657  fprintf(stderr, "vrpn_Endpoint::connect_udp_to: "
3658  "Couldn't open outbound UDP link.\n");
3659  status = BROKEN;
3660  return -1;
3661  }
3662  }
3663  return 0;
3664 }
3665 
3666 vrpn_int32 vrpn_Endpoint_IP::set_tcp_outbuf_size(vrpn_int32 bytecount)
3667 {
3668  char *new_outbuf;
3669 
3670  if (bytecount < 0) {
3671  return d_tcpBuflen;
3672  }
3673 
3674  new_outbuf = new char[bytecount];
3675 
3676  if (!new_outbuf) {
3677  return -1;
3678  }
3679 
3680  if (d_tcpOutbuf) {
3681  delete[] d_tcpOutbuf;
3682  }
3683 
3684  d_tcpOutbuf = new_outbuf;
3685  d_tcpBuflen = bytecount;
3686 
3687  return d_tcpBuflen;
3688 }
3689 
3691 {
3692 
3693  if (d_tcpSocket != INVALID_SOCKET) {
3696  d_tcpNumOut = 0; // Ignore characters waiting to go
3697  }
3701  d_udpNumOut = 0; // Ignore characters waiting to go
3702  }
3706  }
3707 
3708  // Remove the remote mappings for senders and types. If we
3709  // reconnect, we will want to fill them in again. First,
3710  // free the space allocated for the list of names, then
3711  // set all of the local IDs to -1, in case the other side
3712  // sends a message of a type that it has not yet defined.
3713  // (for example, arriving on the UDP line ahead of its TCP
3714  // definition).
3715 
3717 
3718  // Clear out the buffers; nothing to read or send if no connection.
3719  clearBuffers();
3720 
3721  struct timeval now;
3722  vrpn_gettimeofday(&now, NULL);
3723 
3724  // If we are logging, put a message in the log telling that we
3725  // have had a disconnection. We don't close the logfile here unless
3726  // there is an error logging the message. This is because we'll want
3727  // to keep logging if there is a reconnection. We close the file when
3728  // the endpoint is destroyed.
3729  if (d_outLog->logMode()) {
3731  NULL, 0) == -1) {
3732  fprintf(stderr, "vrpn_Endpoint::drop_connection: Can't log\n");
3733  d_outLog->close(); // Hope for the best...
3734  }
3735  }
3736 
3737  // Recall that the connection counter is a pointer to our parent
3738  // connection's count of active endpoints. If it exists, we need
3739  // to send disconnect messages to those who care. If this is the
3740  // last endpoint, then we send the last endpoint message; we
3741  // always send a connection dropped message.
3742  // Message needs to be dispatched *locally only*, so we do_callbacks_for()
3743  // and never pack_message()
3744 
3745  if (d_connectionCounter != NULL) { // Do nothing on NULL pointer
3746 
3747  (*d_connectionCounter)--; // One less connection
3748 
3749  d_dispatcher->doCallbacksFor(
3750  d_dispatcher->registerType(vrpn_dropped_connection),
3751  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
3752 
3753  if (*d_connectionCounter == 0) { // None more left
3754  d_dispatcher->doCallbacksFor(
3756  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
3757  }
3758  }
3759 }
3760 
3762 {
3763  d_tcpNumOut = 0;
3764  d_udpNumOut = 0;
3765 }
3766 
3767 void vrpn_Endpoint_IP::setNICaddress(const char *address)
3768 {
3769  if (d_NICaddress) {
3770  delete[] d_NICaddress;
3771  }
3772 
3773 #ifdef VERBOSE
3774  fprintf(stderr, "Setting endpoint NIC address to %s.\n", address);
3775 #endif
3776 
3777  d_NICaddress = NULL;
3778  if (!address) {
3779  return;
3780  }
3781  d_NICaddress = new char[1 + strlen(address)];
3782  if (!d_NICaddress) {
3783  fprintf(stderr, "vrpn_Endpoint::setNICaddress: Out of memory.\n");
3784  return;
3785  }
3786  strcpy(d_NICaddress, address);
3787 }
3788 
3790 {
3791  char sendbuf[501];
3792  vrpn_int32 sendlen;
3793  int retval;
3794 
3795  retval =
3797  if (retval < 0) {
3798  perror("vrpn_Endpoint::setup_new_connection: "
3799  "Internal error - array too small. The code's broken.");
3800  return -1;
3801  }
3802  sendlen = static_cast<vrpn_int32>(vrpn_cookie_size());
3803 
3804  // Write the magic cookie header to the server
3805  // NOTE: Valgrind will complain about this because we didn't fill in all of the
3806  // characters we're writing. But we don't care about the characters that are
3807  // beyond the terminating NULL character in the string.
3808  if (vrpn_noint_block_write(d_tcpSocket, sendbuf, sendlen) != sendlen) {
3809  fprintf(stderr, "vrpn_Endpoint::setup_new_connection: "
3810  "Can't write cookie.\n");
3811  status = BROKEN;
3812  return -1;
3813  }
3814 
3816  poll_for_cookie();
3817 
3818  return 0;
3819 }
3820 
3821 void vrpn_Endpoint_IP::poll_for_cookie(const timeval *pTimeout)
3822 {
3823  timeval timeout;
3824 
3825  if (pTimeout) {
3826  timeout = *pTimeout;
3827  }
3828  else {
3829  timeout.tv_sec = 0;
3830  timeout.tv_usec = 0;
3831  }
3832 
3833  fd_set readfds, exceptfds;
3834 
3835  // most of this code copied from mainloop() case CONNECTED
3836 
3837  // check for pending incoming tcp or udp reports
3838  // we do this so that we can trigger out of the timeout
3839  // on either type of message without waiting on the other
3840 
3841  FD_ZERO(&readfds); /* Clear the descriptor sets */
3842  FD_ZERO(&exceptfds);
3843 
3844  // Read incoming COOKIE from TCP channel
3845 
3846  FD_SET(d_tcpSocket, &readfds);
3847  FD_SET(d_tcpSocket, &exceptfds);
3848 
3849  // Select to see if ready to hear from other side, or exception
3850 
3851  if (vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, &readfds, NULL,
3852  &exceptfds, &timeout) == -1) {
3853  fprintf(stderr, "vrpn_Endpoint::poll_for_cookie(): select failed.\n");
3854  status = BROKEN;
3855  return;
3856  }
3857 
3858  // See if exceptional condition on either socket
3859  if (FD_ISSET(d_tcpSocket, &exceptfds)) {
3860  fprintf(stderr,
3861  "vrpn_Endpoint::poll_for_cookie(): Exception on socket\n");
3862  return;
3863  }
3864 
3865  // Read incoming COOKIE from the TCP channel
3866  if (FD_ISSET(d_tcpSocket, &readfds)) {
3868  if (!doing_okay()) {
3869  fprintf(stderr,
3870  "vrpn_Endpoint::poll_for_cookie: cookie handling failed\n"
3871  " while connecting to \"%s\"\n",
3873  return;
3874  }
3875 #ifdef VERBOSE3
3876  else if (status == CONNECTED) {
3877  printf("vrpn_Endpoint::poll_for_cookie() got cookie\n");
3878  }
3879 #endif
3880  }
3881 }
3882 
3884 {
3885 
3886  vrpn_int32 sendlen = static_cast<vrpn_int32>(vrpn_cookie_size());
3887  char *recvbuf = new char[sendlen];
3888  if (recvbuf == NULL) {
3889  fprintf(stderr, "vrpn_Endpoint_IP::finish_new_connection_setup(): Out "
3890  "of memory when allocating receiver buffer\n");
3891  status = BROKEN;
3892  return -1;
3893  }
3894 
3895  // Try to read the magic cookie from the server.
3896  int ret = vrpn_noint_block_read(d_tcpSocket, recvbuf, sendlen);
3897  if (ret != sendlen) {
3898  perror("vrpn_Endpoint::finish_new_connection_setup: Can't read cookie");
3899  status = BROKEN;
3900  delete[] recvbuf;
3901  return -1;
3902  }
3903 
3904  if (check_vrpn_cookie(recvbuf) < 0) {
3905  status = BROKEN;
3906  delete[] recvbuf;
3907  return -1;
3908  }
3909 
3910  // Store the magic cookie from the other side into a buffer so
3911  // that it can be put into an incoming log file.
3912  d_inLog->setCookie(recvbuf);
3913 
3914  // Find out what log mode they want us to be in BEFORE we pack
3915  // type, sender, and udp descriptions! That is because we will
3916  // need the type and sender messages to go into the log file if
3917  // we're logging outgoing messages. If it's nonzero, the
3918  // filename to use should come in a log_description message later.
3919 
3920  long received_logmode = recvbuf[vrpn_MAGICLEN + 2] - '0';
3921  if ((received_logmode < 0) ||
3922  (received_logmode > (vrpn_LOG_INCOMING | vrpn_LOG_OUTGOING))) {
3923  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3924  "Got invalid log mode %d\n",
3925  static_cast<int>(received_logmode));
3926  status = BROKEN;
3927  delete[] recvbuf;
3928  return -1;
3929  }
3930  if (received_logmode & vrpn_LOG_INCOMING) {
3932  }
3933  if (received_logmode & vrpn_LOG_OUTGOING) {
3935  }
3936 
3937  // status must be sent to CONNECTED *before* any messages are
3938  // packed; otherwise they're silently discarded in pack_message.
3939  status = CONNECTED;
3940 
3941  if (pack_log_description() == -1) {
3942  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3943  "Can't pack remote logging instructions.\n");
3944  status = BROKEN;
3945  delete[] recvbuf;
3946  return -1;
3947  }
3948 
3949  // If we do not have a socket for inbound connections open, and if we
3950  // are allowed to do other-than-TCP sockets, then open one and tell the
3951  // other side that it can use it.
3952  if (!d_tcp_only) {
3953 
3955  // Open the UDP port to accept time-critical messages on.
3956 
3957  unsigned short udp_portnum = static_cast<unsigned short>(INADDR_ANY);
3958  d_udpInboundSocket = ::open_udp_socket(&udp_portnum, d_NICaddress);
3960  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3961  "can't open UDP socket\n");
3962  status = BROKEN;
3963  delete[] recvbuf;
3964  return -1;
3965  }
3966 
3967  // Tell the other side what port number to send its UDP messages to.
3968  if (pack_udp_description(udp_portnum) == -1) {
3969  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3970  "Can't pack UDP msg\n");
3971  status = BROKEN;
3972  delete[] recvbuf;
3973  return -1;
3974  }
3975  }
3976  }
3977 
3978 #ifdef VERBOSE
3979  fprintf(stderr,
3980  "CONNECTED - vrpn_Endpoint::finish_new_connection_setup.\n");
3981 #endif
3982 
3983  // Pack messages that describe the types of messages and sender
3984  // ID mappings that have been described to this connection. These
3985  // messages use special IDs (negative ones).
3986  for (int i = 0; i < d_dispatcher->numSenders(); i++) {
3988  }
3989  for (int i = 0; i < d_dispatcher->numTypes(); i++) {
3991  }
3992 
3993  // Send the messages
3994  if (send_pending_reports() == -1) {
3995  fprintf(
3996  stderr,
3997  "vrpn_Endpoint::finish_new_connection_setup: Can't send UDP msg\n");
3998  status = BROKEN;
3999  delete[] recvbuf;
4000  return -1;
4001  }
4002 
4003  // The connection-established messages need to be dispatched *locally only*,
4004  // so we do_callbacks_for and never pack_message()
4005  struct timeval now;
4006  vrpn_gettimeofday(&now, NULL);
4007 
4008  // Connection counter gives us a single point to count connections that
4009  // actually make it to CONNECTED, not just constructed, so we send
4010  // got-first-/dropped-last-connection messages properly.
4011 
4013  d_dispatcher->doCallbacksFor(
4014  d_dispatcher->registerType(vrpn_got_first_connection),
4015  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
4016  }
4017 
4018  d_dispatcher->doCallbacksFor(
4019  d_dispatcher->registerType(vrpn_got_connection),
4020  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
4021 
4022  if (d_connectionCounter) {
4023  (*d_connectionCounter)++;
4024  }
4025 
4026  delete[] recvbuf;
4027  return 0;
4028 }
4029 
4030 int vrpn_Endpoint_IP::getOneTCPMessage(int fd, char *buf, size_t buflen)
4031 {
4032  vrpn_int32 header[5];
4033  struct timeval time;
4034  vrpn_int32 sender, type;
4035  size_t len, payload_len, ceil_len;
4036  int retval;
4037 
4038 #ifdef VERBOSE2
4039  fprintf(stderr,
4040  "vrpn_Endpoint::handle_tcp_messages(): something to read\n");
4041 #endif
4042 
4043  // Read and parse the header
4044  if (vrpn_noint_block_read(fd, (char *)header, sizeof(header)) !=
4045  sizeof(header)) {
4046  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
4047  "Can't read header (this is normal when a connection "
4048  "is dropped)\n");
4049  return -1;
4050  }
4051  len = ntohl(header[0]);
4052  time.tv_sec = ntohl(header[1]);
4053  time.tv_usec = ntohl(header[2]);
4054  sender = ntohl(header[3]);
4055  type = ntohl(header[4]);
4056 #ifdef VERBOSE2
4057  fprintf(stderr, " header: Len %d, Sender %d, Type %d\n", (int)len,
4058  (int)sender, (int)type);
4059 #endif
4060 
4061  // skip up to alignment
4062  vrpn_int32 header_len = sizeof(header);
4063  if (header_len % vrpn_ALIGN) {
4064  header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4065  }
4066  if (header_len > static_cast<vrpn_int32>(sizeof(header))) {
4067  // the difference can be no larger than this
4068  char rgch[vrpn_ALIGN];
4069  if (vrpn_noint_block_read(fd, (char *)rgch,
4070  header_len - sizeof(header)) !=
4071  (int)(header_len - sizeof(header))) {
4072  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
4073  "Can't read header + alignment\n");
4074  return -1;
4075  }
4076  }
4077 
4078  // Figure out how long the message body is, and how long it
4079  // is including any padding to make sure that it is a
4080  // multiple of four bytes long.
4081  payload_len = len - header_len;
4082  ceil_len = payload_len;
4083  if (ceil_len % vrpn_ALIGN) {
4084  ceil_len += vrpn_ALIGN - ceil_len % vrpn_ALIGN;
4085  }
4086 
4087  // Make sure the buffer is long enough to hold the whole
4088  // message body.
4089  if (buflen < ceil_len) {
4090  fprintf(stderr,
4091  "vrpn: vrpn_Endpoint::handle_tcp_messages: Message too long\n");
4092  return -1;
4093  }
4094 
4095  // Read the body of the message
4096  if (vrpn_noint_block_read(fd, buf, ceil_len) != ceil_len) {
4097  perror("vrpn: vrpn_Endpoint::handle_tcp_messages: Can't read body");
4098  return -1;
4099  }
4100 
4101  if (d_inLog->logIncomingMessage(payload_len, time, type, sender, buf)) {
4102  fprintf(stderr, "Couldn't log incoming message.!\n");
4103  return -1;
4104  }
4105 
4106  retval = dispatch(type, sender, time, static_cast<vrpn_uint32>(payload_len),
4107  buf);
4108  if (retval) {
4109  return -1;
4110  }
4111 
4112  return 0;
4113 }
4114 
4115 int vrpn_Endpoint_IP::getOneUDPMessage(char *inbuf_ptr, size_t inbuf_len)
4116 {
4117  vrpn_int32 header[5];
4118  struct timeval time;
4119  vrpn_int32 sender, type;
4120  vrpn_uint32 len, payload_len, ceil_len;
4121  int retval;
4122 
4123  // Read and parse the header
4124  // skip up to alignment
4125  vrpn_uint32 header_len = sizeof(header);
4126  if (header_len % vrpn_ALIGN) {
4127  header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4128  }
4129 
4130  if (header_len > (vrpn_uint32)inbuf_len) {
4131  fprintf(stderr, "vrpn_Endpoint::getOneUDPMessage: Can't read header");
4132  return -1;
4133  }
4134  memcpy(header, inbuf_ptr, sizeof(header));
4135  inbuf_ptr += header_len;
4136  len = ntohl(header[0]);
4137  time.tv_sec = ntohl(header[1]);
4138  time.tv_usec = ntohl(header[2]);
4139  sender = ntohl(header[3]);
4140  type = ntohl(header[4]);
4141 
4142 #ifdef VERBOSE
4143  fprintf(stderr, "Message type %ld (local type %ld), sender %ld received\n",
4144  type, local_type_id(type), sender);
4145  fprintf(stderr, "Message length is %d (buffer length %d).\n", len,
4146  inbuf_len);
4147 #endif
4148 
4149  // Figure out how long the message body is, and how long it
4150  // is including any padding to make sure that it is a
4151  // multiple of vrpn_ALIGN bytes long.
4152  payload_len = len - header_len;
4153  ceil_len = payload_len;
4154  if (ceil_len % vrpn_ALIGN) {
4155  ceil_len += vrpn_ALIGN - ceil_len % vrpn_ALIGN;
4156  }
4157 
4158  // Make sure we received enough to cover the entire payload
4159  if (header_len + ceil_len > (vrpn_uint32)inbuf_len) {
4160  fprintf(stderr, "vrpn_Endpoint::getOneUDPMessage: Can't read payload");
4161  return -1;
4162  }
4163 
4164  if (d_inLog->logIncomingMessage(payload_len, time, type, sender,
4165  inbuf_ptr)) {
4166  fprintf(stderr, "Couldn't log incoming message.!\n");
4167  return -1;
4168  }
4169 
4170  retval = dispatch(type, sender, time, payload_len, inbuf_ptr);
4171  if (retval) {
4172  return -1;
4173  }
4174 
4175  return ceil_len + header_len;
4176 }
4177 
4178 int vrpn_Endpoint::dispatch(vrpn_int32 type, vrpn_int32 sender, timeval time,
4179  vrpn_uint32 payload_len, char *bufptr)
4180 {
4181 
4182  // Call the handler for this message type
4183  // If it returns nonzero, return an error.
4184  if (type >= 0) { // User handler, map to local id
4185 
4186  // Only process if local id has been set.
4187 
4188  if (local_type_id(type) >= 0) {
4189  if (d_dispatcher->doCallbacksFor(local_type_id(type),
4190  local_sender_id(sender), time,
4191  payload_len, bufptr)) {
4192  return -1;
4193  }
4194  }
4195  }
4196  else { // System handler
4197 
4198  if (d_dispatcher->doSystemCallbacksFor(type, sender, time, payload_len,
4199  bufptr, this)) {
4200  fprintf(stderr, "vrpn_Endpoint::dispatch: "
4201  "Nonzero system return\n");
4202  return -1;
4203  }
4204  }
4205 
4206  return 0;
4207 }
4208 
4209 int vrpn_Endpoint::tryToMarshall(char *outbuf, vrpn_int32 &buflen,
4210  vrpn_int32 &numOut, vrpn_uint32 len,
4211  timeval time, vrpn_int32 type,
4212  vrpn_int32 sender, const char *buffer,
4213  vrpn_uint32 sequenceNumber)
4214 {
4215  int retval;
4216 
4217  retval = marshall_message(outbuf, buflen, numOut, len, time, type, sender,
4218  buffer, sequenceNumber);
4219 
4220  // If the marshalling failed, try clearing the outgoing buffers
4221  // by sending the stuff in them to see if this makes enough
4222  // room. If not, we'll have to give up.
4223  if (!retval) {
4224  if (send_pending_reports() != 0) {
4225  return 0;
4226  }
4227  retval = marshall_message(outbuf, buflen, numOut, len, time, type,
4228  sender, buffer, sequenceNumber);
4229  }
4230 
4231  return retval;
4232 }
4233 
4240 // TCH 22 Feb 99
4241 // Marshall the sequence number, but never unmarshall it - it's currently
4242 // only provided for the benefit of sniffers.
4243 
4245  char *outbuf, // Base pointer to the output buffer
4246  vrpn_uint32 outbuf_size, // Total size of the output buffer
4247  vrpn_uint32 initial_out, // How many characters are already in outbuf
4248  vrpn_uint32 len, // Length of the message payload
4249  struct timeval time, // Time the message was generated
4250  vrpn_int32 type, // Type of the message
4251  vrpn_int32 sender, // Sender of the message
4252  const char *buffer, // Message payload
4253  vrpn_uint32 seqNo) // Sequence number
4254 {
4255  vrpn_uint32 ceil_len, header_len, total_len;
4256  vrpn_uint32 curr_out = initial_out; // How many out total so far
4257 
4258  // Compute the length of the message plus its padding to make it
4259  // an even multiple of vrpn_ALIGN bytes.
4260 
4261  // Compute the total message length and put the message
4262  // into the message buffer (if we have room for the whole message)
4263  ceil_len = len;
4264  if (len % vrpn_ALIGN) {
4265  ceil_len += vrpn_ALIGN - len % vrpn_ALIGN;
4266  }
4267  header_len = 5 * sizeof(vrpn_int32);
4268  if (header_len % vrpn_ALIGN) {
4269  header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4270  }
4271  total_len = header_len + ceil_len;
4272  if ((curr_out + total_len) > (vrpn_uint32)outbuf_size) {
4273  return 0;
4274  }
4275 
4276  // fprintf(stderr, " Marshalling message type %d, sender %d, length %d.\n",
4277  // type, sender, len);
4278 
4279  // The packet header len field does not include the padding bytes,
4280  // these are inferred on the other side.
4281  // Later, to make things clearer, we should probably infer the header
4282  // len on the other side (in the same way the padding is done)
4283  // The reason we don't include the padding in the len is that we
4284  // would not be able to figure out the size of the padding on the
4285  // far side)
4286  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(header_len + len);
4287  curr_out += sizeof(vrpn_uint32);
4288 
4289  // Pack the time (using gettimeofday() format) into the buffer
4290  // and do network byte ordering.
4291  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(time.tv_sec);
4292  curr_out += sizeof(vrpn_uint32);
4293  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(time.tv_usec);
4294  curr_out += sizeof(vrpn_uint32);
4295 
4296  // Pack the sender and type and do network byte-ordering
4297  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(sender);
4298  curr_out += sizeof(vrpn_uint32);
4299  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(type);
4300  curr_out += sizeof(vrpn_uint32);
4301 
4302  // Pack the sequence number. If something's really screwy with
4303  // our sizes/types and there isn't room for the sequence number,
4304  // skipping for alignment below will overwrite it!
4305  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(seqNo);
4306  curr_out += sizeof(vrpn_uint32);
4307 
4308  // skip chars if needed for alignment
4309  curr_out = initial_out + header_len;
4310 
4311  // Pack the message from the buffer. Then skip as many characters
4312  // as needed to make the end of the buffer fall on an even alignment
4313  // of vrpn_ALIGN bytes (the size of largest element sent via vrpn.
4314  if (buffer != NULL) {
4315  memcpy(&outbuf[curr_out], buffer, len);
4316  }
4317  curr_out += ceil_len;
4318 #ifdef VERBOSE
4319  printf("Marshalled: len %d, ceil_len %d: '", len, ceil_len);
4320  printf("'\n");
4321 #endif
4322  return curr_out - initial_out; // How many extra bytes we sent
4323 }
4324 
4325 // static
4327 {
4328  vrpn_Endpoint *endpoint = static_cast<vrpn_Endpoint *>(userdata);
4329  cName type_name;
4330  vrpn_int32 i;
4331  vrpn_int32 local_id;
4332 
4333  if (static_cast<unsigned>(p.payload_len) > sizeof(cName)) {
4334  fprintf(stderr, "vrpn: vrpn_Endpoint::handle_type_message: "
4335  "Type name too long\n");
4336  return -1;
4337  }
4338 
4339  // Find out the name of the type (skip the length)
4340  strncpy(type_name, p.buffer + sizeof(vrpn_int32),
4341  p.payload_len - sizeof(vrpn_int32));
4342 
4343  // Use the exact length packed into the start of the buffer
4344  // to figure out where to put the trailing '\0'
4345  i = ntohl(*((vrpn_int32 *)p.buffer));
4346  type_name[i] = '\0';
4347 
4348 #ifdef VERBOSE
4349  printf("Registering other-side type: '%s'\n", type_name);
4350 #endif
4351  // If there is a corresponding local type defined, find the mapping.
4352  local_id = endpoint->d_dispatcher->getTypeID(type_name);
4353  // If not, add this type locally
4354  if (local_id == -1) {
4355  if (endpoint->d_parent != NULL) {
4356  local_id = endpoint->d_parent->register_message_type(type_name);
4357  }
4358 #ifdef VERBOSE
4359  else {
4360  printf("vrpn_Endpoint::handle_type_message: NULL d_parent "
4361  "when trying to auto-register remote message type %s.\n",
4362  type_name);
4363  }
4364 #endif
4365  }
4366  if (endpoint->newRemoteType(type_name, p.sender, local_id) == -1) {
4367  fprintf(stderr, "vrpn: Failed to add remote type %s\n", type_name);
4368  return -1;
4369  }
4370 
4371  return 0;
4372 }
4373 
4374 void vrpn_Endpoint::setLogNames(const char *inName, const char *outName)
4375 {
4376  if (inName != NULL) {
4377  d_inLog->setName(inName);
4378  }
4379  if (outName != NULL) {
4380  d_outLog->setName(outName);
4381  }
4382 }
4383 
4385 {
4386 
4387  if (d_inLog->open()) {
4388  return -1;
4389  }
4390  if (d_outLog->open()) {
4391  return -1;
4392  }
4393 
4394  return 0;
4395 }
4396 
4397 // static
4399 {
4400  vrpn_Endpoint *endpoint = static_cast<vrpn_Endpoint *>(userdata);
4401  cName sender_name;
4402  vrpn_int32 i;
4403  vrpn_int32 local_id;
4404 
4405  if (static_cast<size_t>(p.payload_len) > sizeof(cName)) {
4406  fprintf(stderr, "vrpn: vrpn_Endpoint::handle_sender_message():Sender "
4407  "name too long\n");
4408  return -1;
4409  }
4410 
4411  // Find out the name of the sender (skip the length)
4412  strncpy(sender_name, p.buffer + sizeof(vrpn_int32),
4413  p.payload_len - sizeof(vrpn_int32));
4414 
4415  // Use the exact length packed into the start of the buffer
4416  // to figure out where to put the trailing '\0'
4417  i = ntohl(*((vrpn_int32 *)p.buffer));
4418  sender_name[i] = '\0';
4419 
4420 #ifdef VERBOSE
4421  printf("Registering other-side sender: '%s'\n", sender_name);
4422 #endif
4423  // If there is a corresponding local sender defined, find the mapping.
4424  local_id = endpoint->d_dispatcher->getSenderID(sender_name);
4425  // If not, add this sender locally
4426  if (local_id == -1) {
4427  if (endpoint->d_parent != NULL) {
4428  local_id = endpoint->d_parent->register_sender(sender_name);
4429  }
4430 #ifdef VERBOSE
4431  else {
4432  printf("vrpn_Endpoint::handle_sender_message: NULL d_parent "
4433  "when trying to auto-register remote message sender %s\n",
4434  sender_name);
4435  }
4436 #endif
4437  }
4438  if (endpoint->newRemoteSender(sender_name, p.sender, local_id) == -1) {
4439  fprintf(stderr, "vrpn: Failed to add remote sender %s\n", sender_name);
4440  return -1;
4441  }
4442 
4443  return 0;
4444 }
4445 
4447 {
4448  struct timeval now;
4449 
4450  // need to pack the null char as well
4451  vrpn_uint32 len =
4452  static_cast<vrpn_int32>(strlen(d_dispatcher->typeName(which)) + 1);
4453  vrpn_uint32 netlen;
4454  char buffer[sizeof(len) + sizeof(cName)];
4455 
4456  netlen = htonl(len);
4457 // Pack a message with type vrpn_CONNECTION_TYPE_DESCRIPTION
4458 // whose sender ID is the ID of the type that is being
4459 // described and whose body contains the length of the name
4460 // and then the name of the type.
4461 
4462 #ifdef VERBOSE
4463  printf(" vrpn_Connection: Packing type '%s', %d\n",
4464  d_dispatcher->typeName(which), which);
4465 #endif
4466  memcpy(buffer, &netlen, sizeof(netlen));
4467  memcpy(&buffer[sizeof(len)], d_dispatcher->typeName(which),
4468  (vrpn_int32)len);
4469  vrpn_gettimeofday(&now, NULL);
4470 
4471  return pack_message((vrpn_uint32)(len + sizeof(len)), now,
4472  vrpn_CONNECTION_TYPE_DESCRIPTION, which, buffer,
4474 }
4475 
4477 {
4478  struct timeval now;
4479 
4480  // need to pack the null char as well
4481  vrpn_uint32 len =
4482  static_cast<vrpn_int32>(strlen(d_dispatcher->senderName(which)) + 1);
4483  vrpn_uint32 netlen;
4484  char buffer[sizeof(len) + sizeof(cName)];
4485 
4486  netlen = htonl(len);
4487 // Pack a message with type vrpn_CONNECTION_SENDER_DESCRIPTION
4488 // whose sender ID is the ID of the sender that is being
4489 // described and whose body contains the length of the name
4490 // and then the name of the sender.
4491 
4492 #ifdef VERBOSE
4493  printf(" vrpn_Connection: Packing sender '%s'\n",
4494  d_dispatcher->senderName(which));
4495 #endif
4496  memcpy(buffer, &netlen, sizeof(netlen));
4497  memcpy(&buffer[sizeof(len)], d_dispatcher->senderName(which),
4498  (vrpn_int32)len);
4499  vrpn_gettimeofday(&now, NULL);
4500 
4501  return pack_message((vrpn_uint32)(len + sizeof(len)), now,
4502  vrpn_CONNECTION_SENDER_DESCRIPTION, which, buffer,
4504 }
4505 
4506 static int flush_udp_socket(SOCKET fd)
4507 {
4508  timeval localTimeout;
4509  fd_set readfds, exceptfds;
4510  char buf[10000];
4511  int sel_ret;
4512 
4513  // fprintf(stderr, "flush_udp_socket().\n");
4514 
4515  localTimeout.tv_sec = 0;
4516  localTimeout.tv_usec = 0;
4517 
4518  // Empty out any pending UDP messages by reading the socket and
4519  // then throwing it away.
4520 
4521  do {
4522  // Select to see if ready to hear from server, or exception
4523  FD_ZERO(&readfds); /* Clear the descriptor sets */
4524  FD_ZERO(&exceptfds);
4525  FD_SET(fd, &readfds); /* Check for read */
4526  FD_SET(fd, &exceptfds); /* Check for exceptions */
4527  sel_ret = vrpn_noint_select(static_cast<int>(fd) + 1, &readfds, NULL,
4528  &exceptfds, &localTimeout);
4529  if (sel_ret == -1) {
4530  fprintf(stderr, "flush_udp_socket: select failed().");
4531  return -1;
4532  }
4533 
4534  // See if exceptional condition on socket
4535  if (FD_ISSET(fd, &exceptfds)) {
4536  fprintf(stderr, "flush_udp_socket: Exception on socket.\n");
4537  return -1;
4538  }
4539 
4540  // If there is anything to read, get the next message
4541  if (FD_ISSET(fd, &readfds)) {
4542  int inbuf_len;
4543 
4544  inbuf_len = recv(fd, buf, 10000, 0);
4545  if (inbuf_len == -1) {
4546  fprintf(stderr, "flush_udp_socket: recv() failed.\n");
4547  return -1;
4548  }
4549  }
4550 
4551  } while (sel_ret);
4552 
4553  return 0;
4554 }
4555 
4557 {
4558  int retval;
4559  int i;
4560 
4561  for (i = 0; i < d_numEndpoints; i++) {
4562  if (d_endpoints[i]) {
4563  retval = d_endpoints[i]->pack_type_description(which);
4564  if (retval) {
4565  return -1;
4566  }
4567  }
4568  }
4569 
4570  return 0;
4571 }
4572 
4574 {
4575  int retval;
4576  int i;
4577 
4578  for (i = 0; i < d_numEndpoints; i++) {
4579  if (d_endpoints[i]) {
4580  retval = d_endpoints[i]->pack_sender_description(which);
4581  if (retval) {
4582  return -1;
4583  }
4584  }
4585  }
4586 
4587  return 0;
4588 }
4589 
4590 // static
4592 {
4593  vrpn_Endpoint *endpoint = (vrpn_Endpoint *)userdata;
4594  int retval = 0;
4595  vrpn_int32 inNameLen, outNameLen;
4596  const char **bp = &p.buffer;
4597 
4598  // TCH 16 Feb 01
4599  vrpn_unbuffer(bp, &inNameLen);
4600  vrpn_unbuffer(bp, &outNameLen);
4601 
4602  // must deal properly with only opening one log file
4603  // the log message contains "" (an empty string) if
4604  // there is no desire to log that file.
4605  endpoint->setLogNames(inNameLen == 0 ? NULL : *bp,
4606  outNameLen == 0 ? NULL : *bp + inNameLen + 1);
4607  if (inNameLen > 0) retval = endpoint->d_inLog->open();
4608  if (outNameLen > 0) retval = endpoint->d_outLog->open();
4609 
4610  // Safety check:
4611  // If we can't log when the client asks us to, close the connection.
4612  // Something more talkative would be useful.
4613  // The problem with implementing this is that it's over-strict: clients
4614  // that assume logging succeeded unless the connection was dropped
4615  // will be running on the wrong assumption if we later change this to
4616  // be a notification message.
4617 
4618  if (retval == -1) {
4619  // Will be dropped automatically on next pass through mainloop
4620  endpoint->status = BROKEN;
4621  }
4622  else {
4623  fprintf(stderr, "vrpn_Connection::handle_log_message: "
4624  "Remote connection requested logging.\n");
4625  }
4626 
4627  // OR the remotely-requested logging mode with whatever we've
4628  // been told to do locally
4629  if (p.sender & vrpn_LOG_INCOMING) {
4630  endpoint->d_inLog->logMode() |= vrpn_LOG_INCOMING;
4631  }
4632  if (p.sender & vrpn_LOG_OUTGOING) {
4633  endpoint->d_outLog->logMode() |= vrpn_LOG_OUTGOING;
4634  }
4635 
4636  return retval;
4637 }
4638 
4639 // Pack a message to all open endpoints. If the pack fails for any of
4640 // the endpoints, return failure.
4641 
4642 int vrpn_Connection::pack_message(vrpn_uint32 len, struct timeval time,
4643  vrpn_int32 type, vrpn_int32 sender,
4644  const char *buffer,
4645  vrpn_uint32 class_of_service)
4646 {
4647  int i, ret;
4648 
4649  // Make sure I'm not broken
4650  if (connectionStatus == BROKEN) {
4651  printf("vrpn_Connection::pack_message: Can't pack because the "
4652  "connection is broken\n");
4653  return -1;
4654  }
4655 
4656  // Make sure type is either a system type (-) or a legal user type
4657  if (type >= d_dispatcher->numTypes()) {
4658  printf("vrpn_Connection::pack_message: bad type (%d)\n", type);
4659  return -1;
4660  }
4661 
4662  // If this is not a system message, make sure the sender is legal.
4663  if (type >= 0) {
4664  if ((sender < 0) || (sender >= d_dispatcher->numSenders())) {
4665  printf("vrpn_Connection::pack_message: bad sender (%d)\n", sender);
4666  return -1;
4667  }
4668  }
4669 
4670  // Pack the message to all open endpoints This must be done before
4671  // yanking local callbacks in order to have message delivery be the
4672  // same on local and remote systems in the case where a local handler
4673  // packs one or more messages in response to this message.
4674  ret = 0;
4675  for (i = 0; i < d_numEndpoints; i++) {
4676  if (d_endpoints[i] &&
4677  (d_endpoints[i]->pack_message(len, time, type, sender, buffer,
4678  class_of_service) != 0)) {
4679  ret = -1;
4680  }
4681  }
4682 
4683  // See if there are any local handlers for this message type from
4684  // this sender. If so, yank the callbacks. This needs to be done
4685  // AFTER the message is packed to open endpoints so that messages
4686  // will be sent in the same order from local and remote senders
4687  // (since a local message handler may pack its own messages before
4688  // returning).
4689 
4690  if (do_callbacks_for(type, sender, time, len, buffer)) {
4691  return -1;
4692  }
4693 
4694  return ret;
4695 }
4696 
4697 // Returns the time since the connection opened.
4698 // Some subclasses may redefine time.
4699 
4700 // virtual
4701 int vrpn_Connection::time_since_connection_open(struct timeval *elapsed_time)
4702 {
4703  struct timeval now;
4704  vrpn_gettimeofday(&now, NULL);
4705  *elapsed_time = vrpn_TimevalDiff(now, start_time);
4706 
4707  return 0;
4708 }
4709 
4710 // returns the current time in the connection since the epoch (UTC time).
4711 // virtual
4713 {
4714  struct timeval now;
4715  vrpn_gettimeofday(&now, NULL);
4716  return now;
4717 }
4718 
4719 // Returns the name of the specified sender/type, or NULL
4720 // if the parameter is invalid.
4721 // virtual
4722 const char *vrpn_Connection::sender_name(vrpn_int32 sender)
4723 {
4724  return d_dispatcher->senderName(sender);
4725 }
4726 
4727 // virtual
4728 const char *vrpn_Connection::message_type_name(vrpn_int32 type)
4729 {
4730  return d_dispatcher->typeName(type);
4731 }
4732 
4733 // virtual
4735 {
4736  int i;
4737  for (i = 0; i < d_numEndpoints; i++) {
4738  d_endpoints[i]->d_inLog->addFilter(filter, userdata);
4739  d_endpoints[i]->d_outLog->addFilter(filter, userdata);
4740  }
4741  return 0;
4742 }
4743 
4744 // virtual
4746 {
4747  int i;
4748  int final_retval = 0;
4749  for (i = 0; i < d_numEndpoints; i++) {
4750  final_retval |= d_endpoints[i]->d_inLog->saveLogSoFar();
4751  final_retval |= d_endpoints[i]->d_outLog->saveLogSoFar();
4752  }
4753  return final_retval;
4754 }
4755 
4756 // virtual
4758 {
4759  return NULL;
4760 }
4761 
4763 {
4764  vrpn_int32 i;
4765 
4766  // Lots of constants used to be set up here. They were moved
4767  // into the constructors in 02.10; this will create a slight
4768  // increase in maintenance burden keeping the constructors consistient.
4769 
4770  for (i = 0; i < vrpn_MAX_ENDPOINTS; i++) {
4771  d_endpoints[i] = NULL;
4772  }
4773 
4774  vrpn_gettimeofday(&start_time, NULL);
4775 
4777 
4778  // These should be among the first senders & types sent over the wire
4779  d_dispatcher->registerSender(vrpn_CONTROL);
4780  d_dispatcher->registerType(vrpn_got_first_connection);
4781  d_dispatcher->registerType(vrpn_got_connection);
4782  d_dispatcher->registerType(vrpn_dropped_connection);
4784 
4790  handle_disconnect_message);
4791 
4792  d_stop_processing_messages_after = 0;
4793 }
4794 
4799 int vrpn_Connection::delete_endpoint(int endpointIndex)
4800 {
4801 
4802  vrpn_Endpoint *endpoint = d_endpoints[endpointIndex];
4803 
4804  if (endpoint) {
4805  delete endpoint;
4806  }
4807  d_endpoints[endpointIndex] = NULL;
4808 
4809  return 0;
4810 }
4811 
4817 {
4818  int i;
4819 
4820  for (i = 0; i < d_numEndpoints; i++) {
4821  if (!d_endpoints[i]) {
4822  d_endpoints[i] = d_endpoints[d_numEndpoints - 1];
4823  d_endpoints[d_numEndpoints - 1] = NULL;
4824 
4825  d_numEndpoints--;
4826  }
4827  }
4828 
4829  return 0;
4830 }
4831 
4832 // Set up to be a server connection, creating a logging connection if
4833 // asked for.
4834 vrpn_Connection::vrpn_Connection(const char *local_in_logfile_name,
4835  const char *local_out_logfile_name,
4837  vrpn_int32 *))
4838  : d_numEndpoints(0)
4839  , d_numConnectedEndpoints(0)
4840  , d_references(0)
4841  , d_autoDeleteStatus(false)
4842  , d_dispatcher(NULL)
4843  , d_serverLogCount(0)
4844  , d_serverLogMode(
4845  (local_in_logfile_name ? vrpn_LOG_INCOMING : vrpn_LOG_NONE) |
4846  (local_out_logfile_name ? vrpn_LOG_OUTGOING : vrpn_LOG_NONE))
4847  , d_serverLogName(NULL)
4848  , d_endpointAllocator(epa)
4849  , d_updateEndpoint(vrpn_FALSE)
4850 {
4851  int retval;
4852  vrpn_Endpoint *endpoint; // shorthand for d_endpoints[0]
4853 
4854  // Initialize the things that must be for any constructor
4856 
4857  // Server connections should handle log messages.
4859  handle_log_message);
4860 
4861  if (local_out_logfile_name) {
4862  d_endpoints[0] = (*d_endpointAllocator)(this, NULL);
4863  if (!d_endpoints[0]) {
4864  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4865  "Couldn't create endpoint for log file.\n",
4866  __LINE__);
4867  connectionStatus = BROKEN;
4868  return;
4869  }
4870  endpoint = d_endpoints[0];
4871  endpoint->setConnection(this);
4872  d_updateEndpoint = vrpn_TRUE;
4873  endpoint->d_outLog->setName(local_out_logfile_name);
4874  endpoint->d_outLog->logMode() = d_serverLogMode;
4875  retval = endpoint->d_outLog->open();
4876  if (retval == -1) {
4877  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4878  "Couldn't open outgoing log file.\n",
4879  __LINE__);
4880  delete d_endpoints[0];
4881  d_endpoints[0] = NULL;
4882  connectionStatus = BROKEN;
4883  return;
4884  }
4885  d_numEndpoints = 1;
4886  endpoint->d_remoteLogMode = vrpn_LOG_NONE;
4887  endpoint->d_remoteInLogName = new char[10];
4888  strcpy(endpoint->d_remoteInLogName, "");
4889  endpoint->d_remoteOutLogName = new char[10];
4890  strcpy(endpoint->d_remoteOutLogName, "");
4891  // Outgoing messages are logged regardless of connection status.
4892  endpoint->status = LOGGING;
4893  }
4894 
4895  if (local_in_logfile_name) {
4896  d_serverLogName = new char[1 + strlen(local_in_logfile_name)];
4897  if (!d_serverLogName) {
4898  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4899  "Out of memory.\n",
4900  __LINE__);
4901  connectionStatus = BROKEN;
4902  return;
4903  }
4904  strcpy(d_serverLogName, local_in_logfile_name);
4905  }
4906 }
4907 
4909  const char *local_in_logfile_name, const char *local_out_logfile_name,
4910  const char *remote_in_logfile_name, const char *remote_out_logfile_name,
4911  vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
4912  : connectionStatus(BROKEN)
4913  , // default value if not otherwise set in ctr
4914  d_numEndpoints(0)
4915  , d_numConnectedEndpoints(0)
4916  , d_references(0)
4917  , d_autoDeleteStatus(false)
4918  , d_dispatcher(NULL)
4919  , d_serverLogCount(0)
4920  , d_serverLogMode(vrpn_LOG_NONE)
4921  , d_serverLogName(NULL)
4922  , d_endpointAllocator(epa)
4923  , d_updateEndpoint(vrpn_FALSE)
4924 {
4925  vrpn_Endpoint *endpoint;
4926  int retval;
4927 
4928  // Initialize the things that must be for any constructor
4930 
4931  // We're a client; create our single endpoint and initialize it.
4932  d_endpoints[0] = (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
4933  d_endpoints[0]->setConnection(this);
4934  d_updateEndpoint = vrpn_TRUE;
4935  if (!d_endpoints[0]) {
4936  fprintf(stderr, "vrpn_Connection:%d Out of memory.\n", __LINE__);
4937  connectionStatus = BROKEN;
4938  return;
4939  }
4940 
4941  d_numEndpoints = 1;
4942  endpoint = d_endpoints[0]; // shorthand
4943 
4944  // Store the remote log file name and the remote log mode
4945  endpoint->d_remoteLogMode =
4946  (((remote_in_logfile_name && strlen(remote_in_logfile_name) > 0)
4948  : vrpn_LOG_NONE) |
4949  ((remote_out_logfile_name && strlen(remote_out_logfile_name) > 0)
4951  : vrpn_LOG_NONE));
4952  if (!remote_in_logfile_name) {
4953  endpoint->d_remoteInLogName = new char[10];
4954  strcpy(endpoint->d_remoteInLogName, "");
4955  }
4956  else {
4957  endpoint->d_remoteInLogName =
4958  new char[strlen(remote_in_logfile_name) + 1];
4959  strcpy(endpoint->d_remoteInLogName, remote_in_logfile_name);
4960  }
4961 
4962  if (!remote_out_logfile_name) {
4963  endpoint->d_remoteOutLogName = new char[10];
4964  strcpy(endpoint->d_remoteOutLogName, "");
4965  }
4966  else {
4967  endpoint->d_remoteOutLogName =
4968  new char[strlen(remote_out_logfile_name) + 1];
4969  strcpy(endpoint->d_remoteOutLogName, remote_out_logfile_name);
4970  }
4971 
4972  // If we are doing local logging, turn it on here. If we
4973  // can't open the file, then the connection is broken.
4974 
4975  if (local_in_logfile_name && (strlen(local_in_logfile_name) != 0)) {
4976  endpoint->d_inLog->setName(local_in_logfile_name);
4977  endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
4978  retval = endpoint->d_inLog->open();
4979  if (retval == -1) {
4980  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4981  "Couldn't open incoming log file.\n",
4982  __LINE__);
4983  connectionStatus = BROKEN;
4984  // fprintf(stderr, "BROKEN - vrpn_Connection::vrpn_Connection.\n");
4985  return;
4986  }
4987  // fprintf(stderr, "vrpn_Connection: opened logfile.\n");
4988  }
4989 
4990  if (local_out_logfile_name && (strlen(local_out_logfile_name) != 0)) {
4991  endpoint->d_outLog->setName(local_out_logfile_name);
4992  endpoint->d_outLog->logMode() = vrpn_LOG_OUTGOING;
4993  retval = endpoint->d_outLog->open();
4994  if (retval == -1) {
4995  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4996  "Couldn't open local outgoing log file.\n",
4997  __LINE__);
4998  connectionStatus = BROKEN;
4999  // fprintf(stderr, "BROKEN - vrpn_Connection::vrpn_Connection.\n");
5000  return;
5001  }
5002  // fprintf(stderr, "vrpn_Connection: opened logfile.\n");
5003  }
5004 }
5005 
5007 {
5008 
5009  // Clean up types, senders, and callbacks.
5010  if (d_dispatcher) {
5011  delete d_dispatcher;
5012  d_dispatcher = NULL;
5013  }
5014 
5015  if (d_references > 0) {
5016  fprintf(stderr,
5017  "Connection was deleted while %d references still remain.\n",
5018  d_references);
5019  }
5020 }
5021 
5022 // Some object is now using this connection.
5023 void vrpn_Connection::addReference() { d_references++; }
5024 
5025 // Some object has stopped using this connection. Decrement the ref counter.
5026 // If there aren't any references, this connection is no longer in use.
5027 // Once it's no longer in use destroy the connection iff d_autoDeleteStatus
5028 // has been set to TRUE. If d_autoDeleteStatus is FALSE, the user must
5029 // destroy the connection explicitly.
5031 {
5032  d_references--;
5033  if (d_references == 0 && d_autoDeleteStatus == true) {
5034  delete this;
5035  }
5036  else if (d_references < 0) { // this shouldn't happen.
5037  // sanity check
5038  fprintf(stderr, "Negative reference count. This shouldn't happen.");
5039  }
5040 }
5041 
5042 vrpn_int32 vrpn_Connection::register_sender(const char *name)
5043 {
5044  vrpn_int32 retval;
5045  vrpn_int32 i;
5046 
5047 #ifdef VERBOSE
5048  fprintf(stderr, "vrpn_Connection::register_sender: "
5049  "%d senders; new name \"%s\"\n",
5050  d_dispatcher->numSenders(), name);
5051 #endif
5052 
5053  // See if the name is already in the list. If so, return it.
5054  retval = d_dispatcher->getSenderID(name);
5055  if (retval != -1) {
5056 #ifdef VERBOSE
5057  fprintf(stderr, "Sender already defined as id %d.\n", retval);
5058 #endif
5059  return retval;
5060  }
5061 
5062  retval = d_dispatcher->addSender(name);
5063 
5064 #ifdef VERBOSE
5065  fprintf(stderr, "Packing sender description for %s, type %d.\n", name,
5066  retval);
5067 #endif
5068 
5069  // Pack the sender description.
5070  // TCH 24 Jan 00 - Need to do this even if not connected so
5071  // that it goes into the logs (if we're keeping any).
5072  pack_sender_description(retval);
5073 
5074  // If the other side has declared this sender, establish the
5075  // mapping for it.
5076  for (i = 0; i < d_numEndpoints; i++) {
5077  d_endpoints[i]->newLocalSender(name, retval);
5078  }
5079 
5080  // One more in place -- return its index
5081  return retval;
5082 }
5083 
5084 vrpn_int32 vrpn_Connection::register_message_type(const char *name)
5085 {
5086  vrpn_int32 retval;
5087  vrpn_int32 i;
5088 
5089 #ifdef VERBOSE
5090  fprintf(stderr, "vrpn_Connection::register_message_type: "
5091  "%d type; new name \"%s\"\n",
5092  d_dispatcher->numTypes(), name);
5093 #endif
5094 
5095  // See if the name is already in the list. If so, return it.
5096  retval = d_dispatcher->getTypeID(name);
5097  if (retval != -1) {
5098 #ifdef VERBOSE
5099  fprintf(stderr, "Type already defined as id %d.\n", retval);
5100 #endif
5101  return retval;
5102  }
5103 
5104  retval = d_dispatcher->addType(name);
5105 
5106 // Pack the type description.
5107 // TCH 24 Jan 00 - Need to do this even if not connected so
5108 // that it goes into the logs (if we're keeping any).
5109 
5110 #ifdef VERBOSE
5111  fprintf(stderr, "Packing type description for %s, type %d.\n", name,
5112  retval);
5113 #endif
5114 
5115  pack_type_description(retval);
5116 
5117  // If the other side has declared this type, establish the
5118  // mapping for it.
5119  for (i = 0; i < d_numEndpoints; i++) {
5120  d_endpoints[i]->newLocalType(name, retval);
5121  }
5122 
5123  // One more in place -- return its index
5124  return retval;
5125 }
5126 
5127 // Yank the callback chain for a message type. Call all handlers that
5128 // are interested in messages from this sender. Return 0 if they all
5129 // return 0, -1 otherwise.
5130 
5131 int vrpn_Connection::do_callbacks_for(vrpn_int32 type, vrpn_int32 sender,
5132  struct timeval time,
5133  vrpn_uint32 payload_len, const char *buf)
5134 {
5135  return d_dispatcher->doCallbacksFor(type, sender, time, payload_len, buf);
5136 }
5137 
5139 {
5140  return d_dispatcher->doSystemCallbacksFor(p, ud);
5141 }
5142 
5143 void vrpn_Connection::get_log_names(char **local_in_logname,
5144  char **local_out_logname,
5145  char **remote_in_logname,
5146  char **remote_out_logname)
5147 {
5148  if (!(d_endpoints[0])) return;
5149  vrpn_Endpoint *endpoint = d_endpoints[0];
5150  // XXX it is possible to have more than one endpoint, and other endpoints
5151  // may have other log names
5152 
5153  if (local_in_logname != NULL)
5154  *local_in_logname = endpoint->d_inLog->getName();
5155  if (local_out_logname != NULL)
5156  *local_out_logname = endpoint->d_outLog->getName();
5157 
5158  if (remote_in_logname != NULL) {
5159  if (endpoint->d_remoteInLogName != NULL) {
5160  *remote_in_logname =
5161  new char[strlen(endpoint->d_remoteInLogName) + 1];
5162  strcpy(*remote_in_logname, endpoint->d_remoteInLogName);
5163  }
5164  else {
5165  *remote_in_logname = NULL;
5166  }
5167  }
5168 
5169  if (remote_out_logname != NULL) {
5170  if (endpoint->d_remoteOutLogName != NULL) {
5171  *remote_out_logname =
5172  new char[strlen(endpoint->d_remoteOutLogName) + 1];
5173  strcpy(*remote_out_logname, endpoint->d_remoteOutLogName);
5174  }
5175  else {
5176  *remote_out_logname = NULL;
5177  }
5178  }
5179 }
5180 
5181 // virtual
5183 
5184 // static
5186  vrpn_int32 *connectedEC)
5187 {
5188  return new vrpn_Endpoint_IP(me->d_dispatcher, connectedEC);
5189 }
5190 
5191 // This is called when a disconnect message is found in the logfile.
5192 // It causes the other-side sender and type messages to be cleared,
5193 // in anticipation of a possible new set of messages caused by a
5194 // reconnected server.
5195 
5198 {
5199  vrpn_Endpoint *endpoint = (vrpn_Endpoint *)userdata;
5200 
5201 #ifdef VERBOSE
5202  printf("Just read disconnect message from logfile\n");
5203 #endif
5204  endpoint->clear_other_senders_and_types();
5205 
5206  return 0;
5207 }
5208 
5210  vrpn_MESSAGEHANDLER handler,
5211  void *userdata, vrpn_int32 sender)
5212 {
5213  return d_dispatcher->addHandler(type, handler, userdata, sender);
5214 }
5215 
5217  vrpn_MESSAGEHANDLER handler,
5218  void *userdata, vrpn_int32 sender)
5219 {
5220  return d_dispatcher->removeHandler(type, handler, userdata, sender);
5221 }
5222 
5224 {
5225  return d_dispatcher->getTypeID(name);
5226 }
5227 
5228 // Changed 8 November 1999 by TCH
5229 // With multiple connections allowed, TRYING_TO_CONNECT is an
5230 // "ok" status, so we need to admit it. (Used to check >= 0)
5231 // XXX What if one endpoint is BROKEN? Don't we need to loop?
5232 vrpn_bool vrpn_Connection::doing_okay(void) const
5233 {
5234 
5235  int endpointIndex;
5236 
5237  for (endpointIndex = 0; endpointIndex < d_numEndpoints; endpointIndex++) {
5238  if (d_endpoints[endpointIndex] &&
5239  (!d_endpoints[endpointIndex]->doing_okay())) {
5240  return VRPN_FALSE;
5241  }
5242  }
5243  return (connectionStatus > BROKEN);
5244 }
5245 
5246 // Loop over endpoints and return TRUE if any of them are connected.
5247 vrpn_bool vrpn_Connection::connected(void) const
5248 {
5249  int endpointIndex;
5250 
5251  for (endpointIndex = 0; endpointIndex < d_numEndpoints; endpointIndex++) {
5252  if (d_endpoints[endpointIndex] &&
5253  (d_endpoints[endpointIndex]->status == CONNECTED)) {
5254  return VRPN_TRUE;
5255  }
5256  }
5257  return VRPN_FALSE;
5258 }
5259 
5260 //------------------------------------------------------------------------
5261 // This section holds data structures and functions to open
5262 // connections by name.
5263 // The intention of this section is that it can open connections for
5264 // objects that are of different types (trackers, buttons and sound),
5265 // even if they all refer to the same connection.
5266 
5267 // This routine will return a pointer to the connection whose name
5268 // is passed in. If the routine is called multiple times with the same
5269 // name, it will return the same pointer, rather than trying to make
5270 // multiple of the same connection (unless force_connection = true).
5271 // If the connection is in a bad way, it returns NULL.
5272 // This routine will strip off any part of the string before and
5273 // including the '@' character, considering this to be the local part
5274 // of a device name, rather than part of the connection name. This allows
5275 // the opening of a connection to "Tracker0@ioglab" for example, which will
5276 // open a connection to ioglab.
5277 
5278 // This routine adds to the reference count of the connection in question.
5279 // This happens regardless of whether the connection already exists
5280 // or it is to be created.
5281 // Any user code that calls vrpn_get_connection_by_name() directly
5282 // should call vrpn_Connection::removeReference() when it is finished
5283 // with the pointer. It's ok if you have old code that doesn't do this;
5284 // it just means the connection will remain open until the program quits,
5285 // which isn't so bad.
5286 
5288  const char *cname, const char *local_in_logfile_name,
5289  const char *local_out_logfile_name, const char *remote_in_logfile_name,
5290  const char *remote_out_logfile_name, const char *NIC_IPaddress,
5291  bool force_connection)
5292 {
5293  if (cname == NULL) {
5294  fprintf(stderr, "vrpn_get_connection_by_name(): NULL name\n");
5295  return NULL;
5296  }
5297 
5298  // Find the relevant part of the name (skip past last '@'
5299  // if there is one)
5300  const char *where_at; // Part of name past last '@'
5301  if ((where_at = strrchr(cname, '@')) != NULL) {
5302  cname = where_at + 1; // Chop off the front of the name
5303  }
5304 
5305  vrpn_Connection *c = NULL;
5306  if (!force_connection) {
5308  }
5309 
5310  // If its not already open, open it.
5311  // Its constructor will add it to the list (?).
5312  if (!c) {
5313 
5314  // connections now self-register in the known list --
5315  // this is kind of odd, but oh well (can probably be done
5316  // more cleanly later).
5317 
5318  int is_file = !strncmp(cname, "file:", 5);
5319 
5320  if (is_file) {
5321  c = new vrpn_File_Connection(cname, local_in_logfile_name,
5322  local_out_logfile_name);
5323  } else {
5324  int port = vrpn_get_port_number(cname);
5325  c = new vrpn_Connection_IP(
5326  cname, port, local_in_logfile_name, local_out_logfile_name,
5327  remote_in_logfile_name, remote_out_logfile_name, NIC_IPaddress);
5328  }
5329 
5330  if (c) { // creation succeeded
5331  c->setAutoDeleteStatus(true); // destroy when refcount hits zero.
5332  }
5333  else { // creation failed
5334  fprintf(stderr, "Could not create new connection.");
5335  return NULL;
5336  }
5337  }
5338  // else the connection was already open.
5339 
5340  c->addReference(); // increment the reference count either way.
5341 
5342  // Return a pointer to the connection, even if it is not doing
5343  // okay. This will allow a connection to retry over and over
5344  // again before connecting to the server.
5345  return c;
5346 }
5347 
5348 // Create a server connection that will listen for client connections.
5349 // To create a VRPN TCP/UDP server, use a name like:
5350 // x-vrpn:machine_name_or_ip:port
5351 // x-vrpn::port
5352 // machine_name_or_ip:port
5353 // machine_name_or_ip
5354 // :port
5355 // To create a loopback (networkless) server, use the name:
5356 // loopback:
5357 // To create an MPI server, use a name like:
5358 // mpi:MPI_COMM_WORLD
5359 // mpi:comm_number
5360 //
5361 // This routine will strip off any part of the string before and
5362 // including the '@' character, considering this to be the local part
5363 // of a device name, rather than part of the connection name. This allows
5364 // the opening of a connection to "Tracker0@ioglab" for example, which will
5365 // open a connection to ioglab.
5366 
5369  const char *local_in_logfile_name,
5370  const char *local_out_logfile_name)
5371 {
5372  vrpn_Connection *c = NULL;
5373 
5374  // Parse the name to find out what kind of connection we are to make.
5375  if (cname == NULL) {
5376  fprintf(stderr, "vrpn_create_server_connection(): NULL name\n");
5377  return NULL;
5378  }
5379  char *location = vrpn_copy_service_location(cname);
5380  if (location == NULL) {
5381  return NULL;
5382  }
5383  int is_loopback = !strncmp(cname, "loopback:", 9);
5384  int is_mpi = !strncmp(cname, "mpi:", 4);
5385  if (is_mpi) {
5386 #ifdef VRPN_USE_MPI
5387  XXX_implement_MPI_server_connection;
5388 #else
5389  fprintf(stderr, "vrpn_create_server_connection(): MPI support not "
5390  "compiled in. Set VRPN_USE_MPI in vrpn_Configure.h "
5391  "and recompile.\n");
5392  delete[] location;
5393  return NULL;
5394 #endif
5395  } else if (is_loopback) {
5396  c = new vrpn_Connection_Loopback();
5397  } else {
5398  // Not Loopback or MPI port, so we presume that we are a standard VRPN UDP/TCP
5399  // port. Open that kind, based on the machine and port name. If we
5400  // don't
5401  // have a machine name, then we pass NULL to the NIC address. If we do
5402  // have
5403  // one, we pass it to the NIC address.
5404  if (strlen(location) == 0) {
5406  local_in_logfile_name,
5407  local_out_logfile_name);
5408  }
5409  else {
5410  // Find machine name and port number. Port number returns default
5411  // if there is not one specified. If the machine name is zero
5412  // length
5413  // (just got :port) then use NULL, which means the default NIC.
5414  char *machine = vrpn_copy_machine_name(location);
5415  if (strlen(machine) == 0) {
5416  delete[] machine;
5417  machine = NULL;
5418  }
5419  unsigned short port =
5420  static_cast<unsigned short>(vrpn_get_port_number(location));
5421  c = new vrpn_Connection_IP(port, local_in_logfile_name,
5422  local_out_logfile_name, machine);
5423  if (machine) {
5424  delete[] machine;
5425  }
5426  }
5427  }
5428  delete[] location;
5429 
5430  if (!c) { // creation failed
5431  fprintf(stderr, "vrpn_create_server_connection(): Could not create new "
5432  "connection.");
5433  return NULL;
5434  }
5435 
5436  c->setAutoDeleteStatus(true); // destroy when refcount hits zero.
5437  c->addReference(); // increment the reference count for the connection.
5438 
5439  // Return a pointer to the connection, even if it is not doing
5440  // okay. This will allow a connection to retry over and over
5441  // again before connecting to the server.
5442  return c;
5443 }
5444 
5454 int vrpn_Connection_IP::connect_to_client(const char *machine, int port)
5455 {
5456  if (connectionStatus != LISTEN) {
5457  return -1;
5458  };
5459 
5460  int which_end = d_numEndpoints;
5461 
5462  // Make sure that we have room for a new connection
5463  if (which_end >= vrpn_MAX_ENDPOINTS) {
5464  fprintf(stderr, "vrpn_Connection_IP::connect_to_client:"
5465  " Too many existing connections.\n");
5466  return -1;
5467  }
5468 
5469  d_endpoints[which_end] =
5470  (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
5471  d_endpoints[which_end]->setConnection(this);
5472  d_updateEndpoint = vrpn_TRUE;
5473  vrpn_Endpoint_IP *endpoint = d_endpoints[which_end];
5474 
5475  if (!endpoint) {
5476  fprintf(stderr, "vrpn_Connection_IP::connect_to_client:"
5477  " Out of memory on new endpoint\n");
5478  return -1;
5479  }
5480 
5481  char msg[100];
5482  sprintf(msg, "%s %d", machine, port);
5483  printf("vrpn_Connection_IP::connect_to_client: "
5484  "Connection request received: %s\n",
5485  msg);
5486  endpoint->connect_tcp_to(msg);
5487  if (endpoint->status != COOKIE_PENDING) { // Something broke
5488  endpoint->status = BROKEN;
5489  return -1;
5490  }
5491  else {
5492  d_numEndpoints++;
5493  handle_connection(which_end);
5494  }
5495 
5496  return 0;
5497 }
5498 
5500 {
5501 
5502  vrpn_Endpoint *endpoint = d_endpoints[endpointIndex];
5503 
5504  // Set up the things that need to happen when a new connection is
5505  // started.
5506  if (endpoint->setup_new_connection()) {
5507  fprintf(stderr, "vrpn_Connection_IP::handle_connection(): "
5508  "Can't set up new connection!\n");
5509  drop_connection(endpointIndex);
5510  return;
5511  }
5512 }
5513 
5514 // Get the UDP port description from the other side and connect the
5515 // outgoing UDP socket to that port so we can send lossy but time-
5516 // critical (tracker) messages that way.
5517 
5518 // static
5520 {
5521  vrpn_Endpoint_IP *endpoint = (vrpn_Endpoint_IP *)userdata;
5522  char rhostname[1000]; // name of remote host
5523 
5524 #ifdef VERBOSE
5525  printf(" Received request for UDP channel to %s\n", p.buffer);
5526 #endif
5527 
5528  // Get the name of the remote host from the buffer (ensure terminated)
5529  strncpy(rhostname, p.buffer, sizeof(rhostname));
5530  rhostname[sizeof(rhostname) - 1] = '\0';
5531 
5532  // Open the UDP outbound port and connect it to the port on the
5533  // remote machine.
5534  // (remember that the sender field holds the UDP port number)
5535  endpoint->connect_udp_to(rhostname, (int)p.sender);
5536  if (endpoint->status == BROKEN) {
5537  return -1;
5538  }
5539 
5540  // Put this here because currently every connection opens a UDP
5541  // port and every host will get this data. Previous implementation
5542  // did it in connect_tcp_to, which only gets called by servers.
5543 
5544  strncpy(endpoint->rhostname, rhostname, sizeof(endpoint->rhostname));
5545 
5546 #ifdef VERBOSE
5547  printf(" Opened UDP channel to %s:%d\n", rhostname, p.sender);
5548 #endif
5549  return 0;
5550 }
5551 
5553 {
5554  int i;
5555 
5556  for (i = 0; i < d_numEndpoints; i++) {
5557  if (d_endpoints[i] && (d_endpoints[i]->send_pending_reports() != 0)) {
5558  fprintf(stderr, "vrpn_Connection_IP::send_pending_reports: "
5559  "Closing failed endpoint.\n");
5560  drop_connection(i);
5561  }
5562  }
5563 
5564  compact_endpoints();
5565 
5566  return 0;
5567 }
5568 
5570 {
5571 
5572 #ifdef VRPN_USE_WINSOCK_SOCKETS
5573  // Make sure sockets are set up
5574  // TCH 2 Nov 98 after Phil Winston
5575 
5576  WSADATA wsaData;
5577  int winStatus;
5578 
5579  winStatus = WSAStartup(MAKEWORD(1, 1), &wsaData);
5580  if (winStatus) {
5581  fprintf(stderr, "vrpn_Connection_IP::init(): "
5582  "Failed to set up sockets.\n");
5583  fprintf(stderr, "WSAStartup failed with error code %d\n", winStatus);
5584  exit(0);
5585  }
5586 #endif // windows sockets
5587 
5588 // Ignore SIGPIPE, so that the program does not crash when a
5589 // remote client OR SERVER shuts down its TCP connection. We'll find out
5590 // about it as an exception on the socket when we select() for
5591 // read.
5592 // Mips/Ultrix header file signal.h appears to be broken and
5593 // require the following cast
5594 #ifndef _WIN32 // XXX what about cygwin?
5595 #ifdef ultrix
5596  signal(SIGPIPE, (void (*)(int))SIG_IGN);
5597 #else
5598  signal(SIGPIPE, SIG_IGN);
5599 #endif
5600 #endif
5601 
5602  // Set up to handle the UDP-request system message.
5604  handle_UDP_message);
5605 }
5606 
5607 //---------------------------------------------------------------------------
5608 // This routine checks for a request for attention from a remote machine.
5609 // The requests come as datagrams to the well-known port number on this
5610 // machine.
5611 // The datagram includes the machine name and port number on the remote
5612 // machine to which this one should establish a connection.
5613 // This routine establishes the TCP connection and then sends a magic
5614 // cookie describing this as a VRPN connection and telling which port to
5615 // use for incoming UDP packets of data associated with the current TCP
5616 // session. It reads the associated information from the other side and
5617 // sets up the local UDP sender.
5618 // It then sends descriptions for all of the known packet types.
5619 
5621  const struct timeval *pTimeout)
5622 {
5623  vrpn_Endpoint_IP *endpoint; // shorthand for d_endpoints[which_end]
5624  int request;
5625  timeval timeout;
5626  int which_end = d_numEndpoints;
5627  int retval;
5628  int port;
5629 
5630  if (pTimeout) {
5631  timeout = *pTimeout;
5632  }
5633  else {
5634  timeout.tv_sec = 0;
5635  timeout.tv_usec = 0;
5636  }
5637 
5638  // Do a select() with timeout (perhaps zero timeout) to see if
5639  // there is an incoming packet on the UDP socket.
5640 
5641  fd_set f;
5642  FD_ZERO(&f);
5643  FD_SET(listen_udp_sock, &f);
5644  request = vrpn_noint_select(static_cast<int>(listen_udp_sock) + 1, &f, NULL,
5645  NULL, &timeout);
5646  if (request == -1) { // Error in the select()
5647  fprintf(stderr,
5648  "vrpn_Connection_IP::server_check_for_incoming_connections(): "
5649  "select failed.\n");
5650  connectionStatus = BROKEN;
5651  // fprintf(stderr, "BROKEN -
5652  // vrpn_Connection::server_check_for_incoming_connections.\n");
5653  return;
5654  }
5655  else if (request != 0) { // Some data to read! Go get it.
5656  struct sockaddr_in from;
5657  int fromlen = sizeof(from);
5658 
5659  char msg[200]; // Message received on the request channel
5660  if (recvfrom(listen_udp_sock, msg, sizeof(msg) - 1, 0,
5661  (struct sockaddr *)&from, GSN_CAST & fromlen) == -1) {
5662  fprintf(stderr,
5663  "vrpn: Error on recvfrom: Bad connection attempt\n");
5664  return;
5665  }
5666  else {
5667  // Force null termination
5668  msg[sizeof(msg) - 1] = '\0';
5669  }
5670 
5671  // Because we sometimes use multiple NICs, we are ignoring the IP from
5672  // the
5673  // client, and filling in the NIC that the udp request arrived on.
5674  char fromname[1024];
5675  unsigned long addr_num = ntohl(from.sin_addr.s_addr);
5676  sprintf(fromname, "%lu.%lu.%lu.%lu", (addr_num) >> 24,
5677  (addr_num >> 16) & 0xff, (addr_num >> 8) & 0xff,
5678  addr_num & 0xff);
5679  printf("vrpn: Connection request received from %s: %s\n", fromname,
5680  msg);
5681 
5682  // Make sure that the request is well-formed. That is, it
5683  // has an ASCII string name of a host followed by an integer
5684  // that is larger than 1024 (ports < 1024 are reserved for
5685  // use by the root process). If it is not well-formed, then
5686  // don't go off trying to connect to it because this slows
5687  // things down. This was happening to one user who had a
5688  // network device that was lobbing mal-formed UDP packets at
5689  // the incoming port on his machine.
5690  char *checkHost = new char[strlen(msg) + 1];
5691  int checkPort;
5692  if (checkHost == NULL) {
5693  fprintf(stderr,
5694  "server_check_for_incoming_connections(): Out of memory\n");
5695  return;
5696  }
5697  if (sscanf(msg, "%s %d", checkHost, &checkPort) != 2) {
5698  fprintf(
5699  stderr,
5700  "server_check_for_incoming_connections(): Malformed request\n");
5701  delete[] checkHost;
5702  return;
5703  }
5704  if (checkPort < 1024) {
5705  fprintf(stderr,
5706  "server_check_for_incoming_connections(): Bad port\n");
5707  delete[] checkHost;
5708  return;
5709  }
5710  // Check all of the characters in the hostname to make sure they are
5711  // either a letter, a digit, or a dot (.).
5712  size_t checkLoop;
5713  for (checkLoop = 0; checkLoop < strlen(checkHost); checkLoop++) {
5714  char checkChar = checkHost[checkLoop];
5715  if (!isalnum(checkChar) && (checkChar != '.')) {
5716  fprintf(
5717  stderr,
5718  "server_check_for_incoming_connections(): Bad hostname\n");
5719  delete[] checkHost;
5720  return;
5721  }
5722  }
5723  delete[] checkHost;
5724 
5725  // Make sure that we have room for a new connection
5726  if (which_end >= vrpn_MAX_ENDPOINTS) {
5727  fprintf(stderr, "vrpn: Too many existing connections; "
5728  "ignoring request from %s\n",
5729  msg);
5730  return;
5731  }
5732 
5733  // Create a new endpoint and start trying to connect it to
5734  // the client.
5735  d_endpoints[which_end] =
5736  (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
5737  d_endpoints[which_end]->setConnection(this);
5738  d_updateEndpoint = vrpn_TRUE;
5739  endpoint = d_endpoints[which_end];
5740  if (!endpoint) {
5741  fprintf(
5742  stderr,
5743  "vrpn_Connection_IP::server_check_for_incoming_connections:\n"
5744  " Out of memory on new endpoint\n");
5745  return;
5746  }
5747 
5748  // Server-side logging under multiconnection - TCH July 2000
5749  // Check for NULL server log name, which happens when the log file
5750  // already exists and it can't save it.
5751  if ((d_serverLogMode & vrpn_LOG_INCOMING) &&
5752  (d_serverLogName != NULL)) {
5753  d_serverLogCount++;
5754  endpoint->d_inLog->setCompoundName(d_serverLogName,
5755  d_serverLogCount);
5756  endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
5757  retval = endpoint->d_inLog->open();
5758  if (retval == -1) {
5759  fprintf(stderr, "vrpn_Connection_IP::server_check_for_incoming_"
5760  "connections: "
5761  "Couldn't open log file.\n");
5762  connectionStatus = BROKEN;
5763  return;
5764  }
5765  }
5766 
5767  endpoint->setNICaddress(d_NIC_IP);
5768  endpoint->status = TRYING_TO_CONNECT;
5769 
5770  // d_numEndpoints must be incremented before handle_connection is called
5771  // otherwise the functions doing_okay and connected do not check all
5772  // the endpoints. Because of this topo was unable to send the header
5773  // information and nano crashed...
5774  d_numEndpoints++;
5775 
5776  // Because we sometimes use multiple NICs, we are ignoring the IP from
5777  // the
5778  // client, and filling in the NIC that the udp request arrived on.
5779  sscanf(msg, "%*s %d", &port); // get the port
5780  // Fill in NIC address. Copy the machine name so that we can delete it
5781  // in the destructor.
5782  endpoint->d_remote_machine_name = vrpn_copy_service_location(fromname);
5783  endpoint->connect_tcp_to(msg);
5784  handle_connection(which_end);
5785 
5786  // HACK
5787  // We don't want to do this, but connection requests are soft state
5788  // that will be restored in 1 second; meanwhile, if we accept multiple
5789  // connection requests from the same source we try to open multiple
5790  // connections to it, which invariably makes SOMEBODY crash sooner or
5791  // later.
5792  flush_udp_socket(listen_udp_sock);
5793  }
5794 
5795  // Do a zero-time select() to see if there are incoming TCP requests on
5796  // the listen socket. This is used when the client needs to punch through
5797  // a firewall.
5798 
5799  SOCKET newSocket;
5800  retval = vrpn_poll_for_accept(listen_tcp_sock, &newSocket);
5801 
5802  if (retval == -1) {
5803  fprintf(stderr, "Error accepting on TCP socket.\n");
5804  return;
5805  }
5806  else if (retval) { // Some data to read! Go get it.
5807 
5808  printf("vrpn: TCP connection request received.\n");
5809 
5810  if (which_end >= vrpn_MAX_ENDPOINTS) {
5811  fprintf(stderr, "vrpn: Too many existing connections; "
5812  "ignoring request.\n");
5813  return;
5814  }
5815 
5816  d_endpoints[which_end] =
5817  (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
5818  d_endpoints[which_end]->setConnection(this);
5819  d_updateEndpoint = vrpn_TRUE;
5820  endpoint = d_endpoints[which_end];
5821  if (!endpoint) {
5822  fprintf(
5823  stderr,
5824  "vrpn_Connection_IP::server_check_for_incoming_connections:\n"
5825  " Out of memory on new endpoint\n");
5826  return;
5827  }
5828 
5829  // Since we're being connected to using a TCP request, tell the endpoint
5830  // not to try and establish any other connections (since the client is
5831  // presumably coming through a firewall or NAT and UDP packets won't get
5832  // through).
5833  endpoint->d_tcp_only = vrpn_TRUE;
5834 
5835  // Find out the remote port number and store it.
5836  struct sockaddr_in peer;
5837 #ifdef VRPN_USE_WINSOCK_SOCKETS
5838  int peerlen = sizeof(peer);
5839 #else
5840 #if defined(sgi)
5841  int peerlen = sizeof(peer);
5842 #else
5843  socklen_t peerlen = sizeof(peer);
5844 #endif
5845 #endif
5846  unsigned short peer_port = 0;
5847  if (getpeername(newSocket, static_cast<struct sockaddr *>(
5848  static_cast<void *>(&peer)),
5849  &peerlen) == 0) {
5850  peer_port = ntohs(peer.sin_port);
5851  }
5852  endpoint->d_remote_port_number = peer_port;
5853 
5854  // Server-side logging under multiconnection - TCH July 2000
5855  if (d_serverLogMode & vrpn_LOG_INCOMING) {
5856  d_serverLogCount++;
5857  endpoint->d_inLog->setCompoundName(d_serverLogName,
5858  d_serverLogCount);
5859  endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
5860  retval = endpoint->d_inLog->open();
5861  if (retval == -1) {
5862  fprintf(stderr, "vrpn_Connection_IP::server_check_for_incoming_"
5863  "connections: "
5864  "Couldn't open incoming log file.\n");
5865  connectionStatus = BROKEN;
5866  return;
5867  }
5868  }
5869 
5870  endpoint->setNICaddress(d_NIC_IP);
5871  endpoint->d_tcpSocket = newSocket;
5872 
5873  d_numEndpoints++;
5874 
5875  handle_connection(which_end);
5876  }
5877 
5878  return;
5879 }
5880 
5882 {
5883  vrpn_Endpoint *endpoint = d_endpoints[whichEndpoint];
5884 
5885  endpoint->drop_connection();
5886 
5887  // If we're a client, try to reconnect to the server
5888  // that just dropped its connection.
5889  // If we're a server, delete the endpoint.
5890  if (listen_udp_sock == INVALID_SOCKET) {
5891  endpoint->status = TRYING_TO_CONNECT;
5892  }
5893  else {
5894  delete_endpoint(whichEndpoint);
5895  }
5896 }
5897 
5898 int vrpn_Connection_IP::mainloop(const struct timeval *pTimeout)
5899 {
5900  vrpn_Endpoint *endpoint;
5901  timeval timeout;
5902  int endpointIndex;
5903 
5904  if (d_updateEndpoint) {
5905  updateEndpoints();
5906  d_updateEndpoint = vrpn_FALSE;
5907  }
5908  // struct timeval perSocketTimeout;
5909  // const int numSockets = 2;
5910  // divide timeout over all selects()
5911  // if (timeout) {
5912  // perSocketTimeout.tv_sec = timeout->tv_sec / numSockets;
5913  // perSocketTimeout.tv_usec = timeout->tv_usec / numSockets
5914  // + (timeout->tv_sec % numSockets) *
5915  // (1000000L / numSockets);
5916  // } else {
5917  // perSocketTimeout.tv_sec = 0;
5918  // perSocketTimeout.tv_usec = 0;
5919  // }
5920 
5921  // BETTER IDEA: do one select rather than multiple -- otherwise you are
5922  // potentially holding up one or the other. This allows clients which
5923  // should not do anything until they get messages to request infinite
5924  // waits (servers can't usually do infinite waits this because they need
5925  // to service other devices to generate info which they then send to
5926  // clients) . weberh 3/20/99
5927 
5928  if (connectionStatus == LISTEN) {
5929  server_check_for_incoming_connections(pTimeout);
5930  }
5931 
5932  for (endpointIndex = 0; endpointIndex < d_numEndpoints; endpointIndex++) {
5933  endpoint = d_endpoints[endpointIndex];
5934 
5935  // The current array-sorting code is liable to break when unexpected
5936  // things happen, so we have to double-check it here.
5937  if (!endpoint) {
5938  continue;
5939  }
5940 
5941  if (pTimeout) {
5942  timeout = *pTimeout;
5943  }
5944  else {
5945  timeout.tv_sec = 0;
5946  timeout.tv_usec = 0;
5947  }
5948 
5949  endpoint->mainloop(&timeout);
5950 
5951  if (endpoint->status == BROKEN) {
5952  drop_connection(endpointIndex);
5953  }
5954  }
5955 
5956  // Do housekeeping on the endpoint array
5957  compact_endpoints();
5958 
5959  return 0;
5960 }
5961 
5963  unsigned short listen_port_no, const char *local_in_logfile_name,
5964  const char *local_out_logfile_name, const char *NIC_IPaddress,
5965  vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
5966  : vrpn_Connection(local_in_logfile_name, local_out_logfile_name, epa)
5967  , listen_udp_sock(INVALID_SOCKET)
5968  , listen_tcp_sock(INVALID_SOCKET)
5969  , d_NIC_IP(NULL)
5970 {
5971  // Copy the NIC_IPaddress so that we do not have to rely on the caller
5972  // to keep it from changing.
5973  if (NIC_IPaddress != NULL) {
5974  char *IP = new char[strlen(NIC_IPaddress) + 1];
5975  if (IP == NULL) {
5976  fprintf(
5977  stderr,
5978  "vrpn_Connection_IP::vrpn_Connection_IP(): Out of memory\n");
5979  }
5980  else {
5981  strcpy(IP, NIC_IPaddress);
5982  d_NIC_IP = IP;
5983  }
5984  }
5985 
5986  // Initialize the things that must be for any constructor
5988 
5989  listen_udp_sock = ::open_udp_socket(&listen_port_no, NIC_IPaddress);
5990  // TCH OHS HACK
5991  listen_tcp_sock = ::open_tcp_socket(&listen_port_no, NIC_IPaddress);
5992  if ((listen_udp_sock == INVALID_SOCKET) ||
5993  (listen_tcp_sock == INVALID_SOCKET)) {
5994  connectionStatus = BROKEN;
5995  return;
5996  // fprintf(stderr, "BROKEN -
5997  // vrpn_Connection_IP::vrpn_Connection_I{.\n");
5998  }
5999  else {
6000  connectionStatus = LISTEN;
6001 // fprintf(stderr, "LISTEN - vrpn_Connection_IP::vrpn_Connection_IP.\n");
6002 #ifdef VERBOSE
6003  printf("vrpn: Listening for requests on port %d\n", listen_port_no);
6004 #endif
6005  }
6006 
6007  // TCH OHS HACK
6008  if (listen(listen_tcp_sock, 1)) {
6009  fprintf(stderr, "Couldn't listen on TCP listening socket.\n");
6010  connectionStatus = BROKEN;
6011  return;
6012  }
6013 
6014  flush_udp_socket(listen_udp_sock);
6015 
6017 }
6018 
6020  const char *station_name, int port, const char *local_in_logfile_name,
6021  const char *local_out_logfile_name, const char *remote_in_logfile_name,
6022  const char *remote_out_logfile_name, const char *NIC_IPaddress,
6023  vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
6024  : vrpn_Connection(local_in_logfile_name, local_out_logfile_name,
6025  remote_in_logfile_name, remote_out_logfile_name, epa)
6026  , listen_udp_sock(INVALID_SOCKET)
6027  , listen_tcp_sock(INVALID_SOCKET)
6028  , d_NIC_IP(NULL)
6029 {
6030  vrpn_Endpoint_IP *endpoint;
6031  vrpn_bool isrsh;
6032  vrpn_bool istcp;
6033  int retval;
6034 
6035  // Copy the NIC_IPaddress so that we do not have to rely on the caller
6036  // to keep it from changing.
6037  if (NIC_IPaddress != NULL) {
6038  char *IP = new char[strlen(NIC_IPaddress) + 1];
6039  if (IP == NULL) {
6040  fprintf(
6041  stderr,
6042  "vrpn_Connection_IP::vrpn_Connection_IP(): Out of memory\n");
6043  }
6044  else {
6045  strcpy(IP, NIC_IPaddress);
6046  d_NIC_IP = IP;
6047  }
6048  }
6049 
6050  isrsh = (strstr(station_name, "x-vrsh:") ? VRPN_TRUE : VRPN_FALSE);
6051  istcp = (strstr(station_name, "tcp:") ? VRPN_TRUE : VRPN_FALSE);
6052 
6053  // Initialize the things that must be for any constructor
6055 
6056  endpoint = d_endpoints[0]; // shorthand
6057  endpoint->setNICaddress(d_NIC_IP);
6058 
6059  // If we are not a TCP-only or remote-server-starting
6060  // type of connection, then set up to lob UDP packets
6061  // to the other side and put us in the mode that will
6062  // wait for the responses. Go ahead and set up the TCP
6063  // socket that we will listen on and lob a packet.
6064 
6065  if (!isrsh && !istcp) {
6066  // Open a connection to the station using a UDP request
6067  // that asks to machine to call us back here.
6068  endpoint->d_remote_machine_name = vrpn_copy_machine_name(station_name);
6069  if (!endpoint->d_remote_machine_name) {
6070  fprintf(stderr,
6071  "vrpn_Connection_IP: Can't get remote machine name!\n");
6072  connectionStatus = BROKEN;
6073  // fprintf(stderr, "BROKEN -
6074  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6075  return;
6076  }
6077  if (port < 0) {
6079  }
6080  else {
6081  endpoint->d_remote_port_number = port;
6082  }
6083 
6084  endpoint->status = TRYING_TO_CONNECT;
6085 
6086  /* Create a UDP socket and connect it to the port on the remote
6087  * machine. */
6088 
6089  endpoint->d_udpLobSocket = vrpn_connect_udp_port(endpoint->d_remote_machine_name,
6090  endpoint->d_remote_port_number, d_NIC_IP);
6091  if (endpoint->d_udpLobSocket == INVALID_SOCKET) {
6092  fprintf(stderr,
6093  "vrpn_Connection_IP: Can't Set up socket to lob UDP packets!\n");
6094  connectionStatus = BROKEN;
6095  // fprintf(stderr, "BROKEN -
6096  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6097  return;
6098  }
6099 
6100 #ifdef VERBOSE
6101  printf("vrpn_Connection_IP: Getting the TCP port to listen on\n");
6102 #endif
6103  // Determine which IP address we should listen on.
6104  // By listening on only localhost (as opposed to all interfaces,
6105  // i.e., 0.0.0.0), we can avoid complaints from the Windows firewall.
6106  char local_host[64];
6107  get_local_socket_name(local_host, sizeof(local_host), endpoint->d_remote_machine_name);
6108 
6109  // Set up the connection that we will listen on.
6110  if (vrpn_get_a_TCP_socket(&endpoint->d_tcpListenSocket,
6111  &endpoint->d_tcpListenPort,
6112  local_host) == -1) {
6113  fprintf(stderr, "vrpn_Connection_IP: Can't create listen socket\n");
6114  endpoint->status = BROKEN;
6115  endpoint->d_tcpListenSocket = INVALID_SOCKET;
6116  // fprintf(stderr, "BROKEN -
6117  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6118  return;
6119  }
6120 
6121  // Lob a packet asking for a connection on that port.
6122  vrpn_gettimeofday(&endpoint->d_last_connect_attempt, NULL);
6124  endpoint->d_remote_machine_name, endpoint->d_remote_port_number,
6125  endpoint->d_tcpListenPort, NIC_IPaddress) == -1) {
6126  fprintf(stderr, "vrpn_Connection_IP: Can't lob UDP request\n");
6127  endpoint->status = BROKEN;
6128  // fprintf(stderr, "BROKEN -
6129  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6130  return;
6131  }
6132 
6133  // the next line is something jeff added to get vrpn to work on his
6134  // PC. Tom Hudson independently added a line that is similar, but
6135  // different. I'm (jeff) am not sure what the right thing is here.
6136  //
6137  // Let's do both, because otherwise connectionStatus is
6138  // never initialized, and doing_ok() returns FALSE sometimes.
6139  connectionStatus = TRYING_TO_CONNECT;
6140 
6141  // here is the line that Tom added
6142  endpoint->status = TRYING_TO_CONNECT;
6143 
6144  // See if we have a connection yet (wait for 1 sec at most).
6145  // This will allow the connection to come up fast if things are
6146  // all set. Otherwise, we'll drop into re-sends when we get
6147  // to mainloop().
6148  retval = vrpn_poll_for_accept(endpoint->d_tcpListenSocket,
6149  &endpoint->d_tcpSocket, 1.0);
6150  if (retval == -1) {
6151  fprintf(stderr, "vrpn_Connection_IP: Can't poll for accept\n");
6152  connectionStatus = BROKEN;
6153  // fprintf(stderr, "BROKEN -
6154  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6155  return;
6156  }
6157  if (retval == 1) { // Got one!
6158  endpoint->status = COOKIE_PENDING;
6159 // fprintf(stderr, "COOKIE_PENDING -
6160 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6161 #ifdef VERBOSE
6162  printf("vrpn: Connection established on initial try\n");
6163 #endif
6164  // Set up the things that need to happen when a new connection
6165  // is established.
6166  if (endpoint->setup_new_connection()) {
6167  fprintf(stderr, "vrpn_Connection_IP: "
6168  "Can't set up new connection!\n");
6169  drop_connection(0);
6170  // status = BROKEN;
6171  // fprintf(stderr, "BROKEN -
6172  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6173  return;
6174  }
6175  }
6176  }
6177 
6178  // TCH OHS HACK
6179  if (istcp) {
6180  endpoint->d_remote_machine_name = vrpn_copy_machine_name(station_name);
6181  if (!endpoint->d_remote_machine_name) {
6182  fprintf(stderr, "vrpn_Connection_IP: Can't get remote machine name "
6183  "for tcp: connection!\n");
6184  connectionStatus = BROKEN;
6185  return;
6186  }
6187  endpoint->d_remote_port_number = port;
6188 
6189  // Since we are doing a TCP connection, tell the endpoint not to try and
6190  // use any other communication mechanism to get to the server.
6191  endpoint->d_tcp_only = vrpn_TRUE;
6192 
6193  endpoint->status = TRYING_TO_CONNECT;
6194 
6195 #ifdef VERBOSE
6196  printf("vrpn_Connection_IP: Getting the TCP port to connect with.\n");
6197 #endif
6198 
6199  // Set up the connection that we will connect with.
6200  // Blocks, doesn't it?
6201  retval =
6202  endpoint->connect_tcp_to(endpoint->d_remote_machine_name, port);
6203 
6204  if (retval == -1) {
6205  fprintf(stderr,
6206  "vrpn_Connection_IP: Can't create TCP connection.\n");
6207  endpoint->status = BROKEN;
6208  return;
6209  }
6210 
6211  connectionStatus = TRYING_TO_CONNECT;
6212  endpoint->status = TRYING_TO_CONNECT;
6213 
6214  if (endpoint->setup_new_connection()) {
6215  fprintf(stderr, "vrpn_Connection_IP: "
6216  "Can't set up new connection!\n");
6217  drop_connection(0);
6218  return;
6219  }
6220  }
6221 
6222  // If we are a remote-server-starting type of connection,
6223  // Try to start the remote server and connect to it. If
6224  // we fail, then the connection is broken. Otherwise, we
6225  // are connected.
6226 
6227  if (isrsh) {
6228  // Start up the server and wait for it to connect back
6229  char *machinename;
6230  char *server_program;
6231  char *server_args; // server program plus its arguments
6232  char *token;
6233 
6234  machinename = vrpn_copy_machine_name(station_name);
6235  server_program = vrpn_copy_rsh_program(station_name);
6236  server_args = vrpn_copy_rsh_arguments(station_name);
6237  token = server_args;
6238  // replace all argument separators (',') with spaces (' ')
6239  while ((token = strchr(token, ',')) != NULL) {
6240  *token = ' ';
6241  }
6242 
6243  endpoint->d_tcpSocket = vrpn_start_server(machinename, server_program,
6244  server_args, NIC_IPaddress);
6245  if (machinename) delete[](char *)machinename;
6246  if (server_program) delete[](char *)server_program;
6247  if (server_args) delete[](char *)server_args;
6248 
6249  if (endpoint->d_tcpSocket < 0) {
6250  fprintf(stderr, "vrpn_Connection_IP: "
6251  "Can't open %s\n",
6252  station_name);
6253  endpoint->status = BROKEN;
6254  // fprintf(stderr, "BROKEN -
6255  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6256  return;
6257  }
6258  else {
6259  endpoint->status = COOKIE_PENDING;
6260  // fprintf(stderr, "COOKIE_PENDING -
6261  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6262 
6263  if (endpoint->setup_new_connection()) {
6264  fprintf(stderr, "vrpn_Connection_IP: "
6265  "Can't set up new connection!\n");
6266  drop_connection(0);
6267  connectionStatus = BROKEN;
6268  // fprintf(stderr, "BROKEN -
6269  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6270  return;
6271  }
6272  }
6273  }
6274 
6275  vrpn_ConnectionManager::instance().addConnection(this, station_name);
6276 }
6277 
6279 {
6280 
6281  vrpn_int32 i;
6282 
6283  // Remove myself from the "known connections" list
6284  // (or the "anonymous connections" list).
6286 
6287  // Send any pending messages
6289 
6290  // Close the UDP and TCP listen endpoints if we're a server
6291  if (listen_udp_sock != INVALID_SOCKET) {
6292  vrpn_closeSocket(listen_udp_sock);
6293  }
6294  if (listen_tcp_sock != INVALID_SOCKET) {
6295  vrpn_closeSocket(listen_tcp_sock);
6296  }
6297 
6298  if (d_NIC_IP) {
6299  delete[] d_NIC_IP;
6300  d_NIC_IP = NULL;
6301  }
6302 
6303  for (i = 0; i < d_numEndpoints; i++) {
6304  if (d_endpoints[i]) {
6305  d_endpoints[i]->drop_connection();
6306  delete d_endpoints[i];
6307  }
6308  }
6309 
6310 #ifdef VRPN_USE_WINSOCK_SOCKETS
6311 
6312  if (WSACleanup() == SOCKET_ERROR) {
6313  fprintf(stderr, "~vrpn_Connection_IP(): "
6314  "WSACleanup() failed with error code %d\n",
6315  WSAGetLastError());
6316  }
6317 
6318 #endif // VRPN_USE_WINSOCK_SOCKETS
6319 }
6320 
6321 // Set up to be a server connection, which is the only kind we can be.
6323  : vrpn_Connection(NULL, NULL, NULL, NULL)
6324 {
6325  // We're always "connected."
6327 
6328  // Add this to the list of known connections.
6329  vrpn_ConnectionManager::instance().addConnection(this, "Loopback");
6330 }
6331 
6333 {
6334  // Remove myself from the "known connections" list
6335  // (or the "anonymous connections" list).
6337 }
6338 
6339 int vrpn_Connection_Loopback::mainloop(const timeval * /*timeout*/)
6340 {
6341  return 0;
6342 }
6343 
6344 // utility routines to parse names (<service>@<URL>)
6345 char *vrpn_copy_service_name(const char *fullname)
6346 {
6347  if (fullname == NULL) {
6348  return NULL;
6349  }
6350  else {
6351  size_t len = 1 + strcspn(fullname, "@");
6352  char *tbuf = new char[len];
6353  if (!tbuf)
6354  fprintf(stderr, "vrpn_copy_service_name: Out of memory!\n");
6355  else {
6356  strncpy(tbuf, fullname, len - 1);
6357  tbuf[len - 1] = 0;
6358  }
6359  return tbuf;
6360  }
6361 }
6362 
6363 char *vrpn_copy_service_location(const char *fullname)
6364 {
6365  // If there is no "@" sign in the string, copy the whole string.
6366  int offset = static_cast<int>(strcspn(fullname, "@"));
6367  size_t len = strlen(fullname) - offset;
6368  if (len == 0) {
6369  offset = -1; // We add one to it below.
6370  len = strlen(fullname) + 1; // We subtract one from it below.
6371  }
6372  char *tbuf = new char[len];
6373  if (!tbuf)
6374  fprintf(stderr, "vrpn_copy_service_name: Out of memory!\n");
6375  else {
6376  strncpy(tbuf, fullname + offset + 1, len - 1);
6377  tbuf[len - 1] = 0;
6378  }
6379  return tbuf;
6380 }
6381 
6382 char *vrpn_copy_file_name(const char *filespecifier)
6383 {
6384  char *filename;
6385  const char *fp;
6386  size_t len;
6387 
6388  fp = filespecifier;
6389  if (!fp) return NULL;
6390 
6391  if (!strncmp(fp, "file://", 7)) {
6392  fp += 7;
6393  }
6394  else if (!strncmp(fp, "file:", 5)) {
6395  fp += 5;
6396  }
6397 
6398  len = 1 + strlen(fp);
6399  filename = new char[len];
6400  if (!filename)
6401  fprintf(stderr, "vrpn_copy_file_name: Out of memory!\n");
6402  else {
6403  strncpy(filename, fp, len - 1);
6404  filename[len - 1] = 0;
6405  }
6406  return filename;
6407 }
6408 
6409 // Returns the length in characters of the header on the name that is
6410 // passed to it. Helper routine for those that follow.
6411 
6412 static int header_len(const char *hostspecifier)
6413 {
6414  // If the name begins with "x-vrpn://" or "x-vrsh://" or "tcp://" skip that
6415  // (also handle the case where there is no // after the colon).
6416  if (!strncmp(hostspecifier, "x-vrpn://", 9) ||
6417  !strncmp(hostspecifier, "x-vrsh://", 9)) {
6418  return 9;
6419  }
6420  else if (!strncmp(hostspecifier, "x-vrpn:", 7) ||
6421  !strncmp(hostspecifier, "x-vrsh:", 7)) {
6422  return 7;
6423  }
6424  else if (!strncmp(hostspecifier, "tcp://", 6)) {
6425  return 6;
6426  }
6427  else if (!strncmp(hostspecifier, "tcp:", 4)) {
6428  return 4;
6429  }
6430  else if (!strncmp(hostspecifier, "mpi://", 6)) {
6431  return 6;
6432  }
6433  else if (!strncmp(hostspecifier, "mpi:", 4)) {
6434  return 4;
6435  }
6436 
6437  // No header found.
6438  return 0;
6439 }
6440 
6441 // The caller is responsible for calling delete [] on the
6442 // returned pointer if it is not null.
6443 
6444 char *vrpn_copy_machine_name(const char *hostspecifier)
6445 {
6446  size_t nearoffset = 0;
6447  size_t faroffset;
6448  // if it contains a ':', copy only the prefix before the last ':'
6449  // otherwise copy all of it
6450  size_t len;
6451  char *tbuf;
6452 
6453  // Skip past the header, if any; this includes any tcp:// or tcp:
6454  // at the beginning of the string.
6455  nearoffset = header_len(hostspecifier);
6456 
6457  // stop at first occurrence of :<port #> or /<rsh arguments>.
6458  // Note that this may be the beginning of the string, right at
6459  // nearoffset.
6460  faroffset = strcspn(hostspecifier + nearoffset, ":/");
6461  len = 1 + faroffset;
6462 
6463  tbuf = new char[len];
6464  if (!tbuf) {
6465  fprintf(stderr, "vrpn_copy_machine_name: Out of memory!\n");
6466  }
6467  else {
6468  strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6469  tbuf[len - 1] = 0;
6470  }
6471  return tbuf;
6472 }
6473 
6474 int vrpn_get_port_number(const char *hostspecifier)
6475 {
6476  const char *pn;
6477  int port = vrpn_DEFAULT_LISTEN_PORT_NO;
6478 
6479  pn = hostspecifier;
6480  if (!pn) return -1;
6481 
6482  // Skip over the header, if present
6483  pn += header_len(hostspecifier);
6484 
6485  pn = strrchr(pn, ':');
6486  if (pn) {
6487  pn++;
6488  port = atoi(pn);
6489  }
6490 
6491  return port;
6492 }
6493 
6494 char *vrpn_copy_rsh_program(const char *hostspecifier)
6495 {
6496  size_t nearoffset = 0; // location of first char after machine name
6497  size_t faroffset; // location of last character of program name
6498  size_t len;
6499  char *tbuf;
6500 
6501  nearoffset += header_len(hostspecifier);
6502 
6503  nearoffset += strcspn(hostspecifier + nearoffset, "/");
6504  nearoffset++; // step past the '/'
6505  faroffset = strcspn(hostspecifier + nearoffset, ",");
6506  len = 1 + (faroffset ? faroffset : strlen(hostspecifier) - nearoffset);
6507  tbuf = new char[len];
6508 
6509  if (!tbuf)
6510  fprintf(stderr, "vrpn_copy_rsh_program: Out of memory!\n");
6511  else {
6512  strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6513  tbuf[len - 1] = 0;
6514  // fprintf(stderr, "server program: '%s'.\n", tbuf);
6515  }
6516  return tbuf;
6517 }
6518 
6519 char *vrpn_copy_rsh_arguments(const char *hostspecifier)
6520 {
6521  size_t nearoffset = 0; // location of first char after server name
6522  size_t faroffset; // location of last character
6523  size_t len;
6524  char *tbuf;
6525 
6526  nearoffset += header_len(hostspecifier);
6527 
6528  nearoffset += strcspn(hostspecifier + nearoffset, "/");
6529  nearoffset += strcspn(hostspecifier + nearoffset, ",");
6530  faroffset = strlen(hostspecifier);
6531  len = 1 + faroffset - nearoffset;
6532  tbuf = new char[len];
6533 
6534  if (!tbuf)
6535  fprintf(stderr, "vrpn_copy_rsh_arguments: Out of memory!\n");
6536  else {
6537  strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6538  tbuf[len - 1] = 0;
6539  // fprintf(stderr, "server args: '%s'.\n", tbuf);
6540  }
6541  return tbuf;
6542 }
6543 
6544 // For a host specifier without a service name, this routine prepends
6545 // the given string newServiceName to it.
6546 // For a host specifier with a service name (e.g. "service@URL"),
6547 // this routine strips off the service name and adds the given
6548 // string newServiceName in its place (e.g. "newServiceName@URL").
6549 // This routine allocates memory for the return value. Caller is
6550 // responsible for freeing the memory.
6551 char *vrpn_set_service_name(const char *specifier, const char *newServiceName)
6552 {
6553  size_t inputLength = strlen(specifier);
6554  size_t atSymbolIndex = strcspn(specifier, "@");
6555 
6556  char *location = NULL;
6557 
6558  if (atSymbolIndex == inputLength) {
6559  // no @ symbol present; just a location.
6560  location = new char[inputLength + 1];
6561  strcpy(location, specifier); // take the whole thing to be the location
6562  }
6563  else {
6564  // take everything after the @ symbol to be the location
6565  location = vrpn_copy_service_location(specifier);
6566  }
6567 
6568  // prepend newServiceName to location.
6569  size_t len = strlen(location) + strlen(newServiceName);
6570  char *newSpecifier = new char[len + 2]; // extra space for '@'
6571  // and terminal '/0'
6572  strcpy(newSpecifier, newServiceName);
6573  strcat(newSpecifier, "@");
6574  strcat(newSpecifier, location);
6575  delete[] location;
6576  return newSpecifier;
6577 }
6578 
6579 
char * d_magicCookie
Definition: vrpn_Log.h:82
virtual int unregister_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
const int vrpn_ANY_TYPE
vrpn_ANY_TYPE can be used to register callbacks for any USER type of message from a given sender...
vrpn_Connection * getByName(const char *name)
Searches through d_kcList but NOT d_anonList (Connections constructed with no name) ...
int finish_new_connection_setup(void)
virtual vrpn_File_Connection * get_File_Connection(void)
vrpn_File_Connection implements this as "return this" so it can be used to detect a File_Connection a...
virtual int dispatch(vrpn_int32 type, vrpn_int32 sender, timeval time, vrpn_uint32 payload_len, char *bufptr)
int vrpn_udp_request_lob_packet(SOCKET udp_sock, const char *machine, const int remote_port, const int local_port, const char *NIC_IP=NULL)
This section deals with implementing a method of connection termed a UDP request. ...
vrpn_LOGLIST * d_firstEntry
Definition: vrpn_Log.h:78
const char * vrpn_got_first_connection
These are the strings that define the system-generated message types that tell when connections are r...
class VRPN_API vrpn_File_Connection
void * userdata
passed along
struct timeval msg_time
int pack_type_description(vrpn_int32 which)
Packs a type description.
int close(void)
Closes and saves the log file.
vrpn_uint32 get_Jane_value(void)
int pack_sender_description(vrpn_int32 which)
Packs a sender description over our socket.
vrpn_Connection(const char *local_in_logfile_name, const char *local_out_logfile_name, vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *)=allocateEndpoint)
Constructor for server connection. This cannot be called directly any more because vrpn_Connection is...
char * d_remoteOutLogName
Name of the remote log file.
virtual int mainloop(timeval *timeout)=0
int d_tcpListenPort
Socket and port that the client listens on < when lobbing datagrams at the server and < waiting for i...
#define SERVWAIT
#define vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE
virtual void updateEndpoints(void)
This function will be called on the mainloop() iteration < after *d_endpointAllocator is called...
virtual vrpn_bool connected(void) const
Returns vrpn_true if the connection has been established, vrpn_false if not (For a networkless connec...
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
Definition: vrpn_Shared.C:312
vrpn_int32 set_tcp_outbuf_size(vrpn_int32 bytecount)
int getOneTCPMessage(int fd, char *buf, size_t buflen)
int logMessage(vrpn_int32 payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_bool isRemote=VRPN_FALSE)
We&#39;d like to make this protected, but there&#39;s one place it needs < to be exposed, at least until we g...
vrpn_bool d_wroteMagicCookie
Definition: vrpn_Log.h:84
class VRPN_API vrpn_Log
int checkFilters(vrpn_int32 payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer)
virtual int send_pending_reports(void)
send pending report, clear the buffer.
const char * vrpn_dropped_connection
vrpn_Log(vrpn_TranslationTable *senders, vrpn_TranslationTable *types)
const vrpn_uint32 vrpn_CONNECTION_RELIABLE
Classes of service for messages, specify multiple by ORing them together Priority of satisfying these...
vrpn_int32 udp_outbuf_size(void) const
int getOneUDPMessage(char *buf, size_t buflen)
vrpn_LOGLIST * prev
Encapsulation of the data and methods for a single IP-based connection to take care of one part of ma...
vrpn_int32 payload_len
virtual vrpn_int32 register_sender(const char *name)
Get a token to use for the string name of the sender or type. Remember to check for -1 meaning failur...
vrpn_TranslationTable * d_senders
Definition: vrpn_Log.h:88
char * vrpn_copy_rsh_arguments(const char *hostspecifier)
static int VRPN_CALLBACK handle_type_message(void *userdata, vrpn_HANDLERPARAM p)
size_t vrpn_cookie_size(void)
Returns the size of the magic cookie buffer, plus any alignment overhead.
virtual const char * message_type_name(vrpn_int32 type)
int connect_tcp_to(const char *msg)
Description of a callback entry for a user type.
const int vrpn_MAGICLEN
void poll_for_cookie(const timeval *timeout=NULL)
timeval lastLogTime()
Returns the time of the last message that was logged.
FILE * d_file
Definition: vrpn_Log.h:80
int pack_udp_description(int portno)
vrpn_Log * d_outLog
int d_remote_port_number
Port to connect to on remote machine.
virtual timeval get_time()
returns the current time in the connection (since the epoch – UTC time).
int setName(const char *name)
int logIncomingMessage(size_t payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer)
Should be called with the timeval adjusted by the clock offset < on the receiving Endpoint...
const vrpn_int32 vrpn_CONNECTION_UDP_DESCRIPTION
virtual void handle_connection(int whichEndpoint)
This routine is called by a server-side connection when a new connection has just been established...
char * vrpn_set_service_name(const char *specifier, const char *newServiceName)
Utility routine to rename the service name of a given host specifier.
#define GSN_CAST
int saveLogSoFar(void)
Saves any messages logged so far.
const char * buffer
virtual int mainloop(const struct timeval *timeout=NULL)
Call each time through program main loop to handle receiving any incoming messages and sending any pa...
vrpn_Endpoint(vrpn_TypeDispatcher *dispatcher, vrpn_int32 *connectedEndpointCounter)
virtual int send_pending_reports(void)
send pending report, clear the buffer.
int check_vrpn_cookie(const char *buffer)
Checks to see if the given buffer has the magic cookie.
vrpn_Connection * d_parent
const vrpn_int32 vrpn_CONNECTION_SENDER_DESCRIPTION
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:92
const char * vrpn_MAGIC
void drop_connection(void)
Should only be called by vrpn_Connection::drop_connection(), < since there&#39;s more housecleaning to do...
char * vrpn_copy_file_name(const char *filespecifier)
Utility routines to parse file specifiers FROM service locations.
virtual int mainloop(const struct timeval *timeout=NULL)
Call each time through program main loop to handle receiving any incoming messages and sending any pa...
#define SERVCOUNT
int newRemoteSender(cName sender_name, vrpn_int32 remote_id, vrpn_int32 local_id)
char * d_logFileName
Definition: vrpn_Log.h:74
const vrpn_int32 vrpn_CONNECTION_DISCONNECT_MESSAGE
int newLocalType(const char *name, vrpn_int32 which)
int pack_log_description(void)
Packs the log description set by setup_new_connection().
int vrpn_noint_select(int width, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
This routine will perform like a normal select() call, but it will restart if it quit because of an i...
vrpn_Connection_IP(const char *server_name, int port=vrpn_DEFAULT_LISTEN_PORT_NO, const char *local_in_logfile_name=NULL, const char *local_out_logfile_name=NULL, const char *remote_in_logfile_name=NULL, const char *remote_out_logfile_name=NULL, const char *NIC_IPaddress=NULL, vrpn_Endpoint_IP *(*epa)( vrpn_Connection *, vrpn_int32 *)=allocateEndpoint)
Make a client connection. To access this from user code, call vrpn_get_connection_by_name(). Create a connection - if server_name is not a file: name, makes an SDI-like connection to the named remote server (otherwise functions as a non-networked messaging hub). Port less than zero forces default. Currently, server_name is an extended URL that defaults to VRPN connections at the port, but can be file:: to read from a file. Other extensions should maintain this, so that VRPN uses URLs to name things that are to be connected to.
Generic connection class not specific to the transport mechanism.
int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 class_of_service)
Pack a message that will be sent the next time mainloop() is called.
int setup_new_connection(void)
Sends the magic cookie and other information to its < peer. It is called by both the client and serve...
char * d_remote_machine_name
Machine to call.
const unsigned vrpn_ALIGN
VRPN buffers are aligned on 8 byte boundaries so that we can pack and unpack doubles into them on arc...
int newRemoteType(cName type_name, vrpn_int32 remote_id, vrpn_int32 local_id)
Adds a new remote type/sender and returns its index. Returns -1 on error.
vrpn_MESSAGEHANDLER handler
Routine to call.
vrpn_int32 d_udpBuflen
int handle_tcp_messages(const timeval *timeout)
virtual int time_since_connection_open(struct timeval *elapsed_time)
Returns the time since the connection opened. Some subclasses may redefine time.
virtual int register_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Set up (or remove) a handler for a message of a given type. Optionally, specify which sender to handl...
vrpn_bool outbound_udp_open(void) const
True if the UDP outbound is open, False if not.
int(VRPN_CALLBACK * vrpn_MESSAGEHANDLER)(void *userdata, vrpn_HANDLERPARAM p)
Type of a message handler for vrpn_Connection messages.
#define INVALID_SOCKET
const char * vrpn_dropped_last_connection
int mainloop(timeval *timeout)
vrpn_LOGFILTER filter
routine to call
const vrpn_int32 vrpn_CONNECTION_LOG_DESCRIPTION
vrpn_float64 d_udpAlignedInbuf[vrpn_CONNECTION_UDP_BUFLEN/sizeof(vrpn_float64)+ 1]
Constructor for a Loopback connection that will basically just pass messages between objects that are...
vrpn_int32 d_udpSequenceNumber
int check_vrpn_file_cookie(const char *buffer)
void clear_other_senders_and_types(void)
Clear out the remote mapping list. This is done when a connection is dropped and we want to try and r...
int marshall_message(char *outbuf, vrpn_uint32 outbuf_size, vrpn_uint32 initial_out, vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 sequenceNumber)
Marshal the message into the buffer if it will fit.
#define SOCK_CAST
const long vrpn_LOG_OUTGOING
void addConnection(vrpn_Connection *, const char *name)
NB implementation is not particularly efficient; we expect to have O(10) connections, not O(1000).
const vrpn_int32 vrpn_CONNECTION_TYPE_DESCRIPTION
virtual ~vrpn_Connection_IP(void)
int setCookie(const char *cookieBuffer)
The magic cookie is set to the default value of the version of < VRPN compiled, but a more correct va...
void deleteConnection(vrpn_Connection *)
char * vrpn_copy_service_location(const char *fullname)
int setCompoundName(const char *name, int index)
Takes a name of the form foo.bar and an index <n> and sets the < name of the log file to be foo-<n>...
vrpn_int32 d_tcpSequenceNumber
static int VRPN_CALLBACK handle_UDP_message(void *userdata, vrpn_HANDLERPARAM p)
char cName[100]
Length of names within VRPN.
void setConnection(vrpn_Connection *conn)
vrpnLogFilterEntry * next
This structure is what is passed to a vrpn_Connection message callback.
int connect_udp_to(const char *addr, int port)
Connects d_udpSocket to the specified address and port; < returns 0 on success, sets status to BROKEN...
timeval d_lastLogTime
Definition: vrpn_Log.h:91
virtual int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 class_of_service)
Pack a message that will be sent the next time mainloop() is called. Turn off the RELIABLE flag if yo...
void setAutoDeleteStatus(bool setvalue)
Specify whether this connection should be deleted automatically when it is no longer need (reference ...
virtual void init(void)
Base initialization for all constructors.
Singleton class that keeps track of all known VRPN connections and makes sure they&#39;re deleted on shut...
class VRPN_API vrpn_TranslationTable
int connectionStatus
Status of the connection.
virtual ~vrpn_Endpoint_IP(void)
virtual int register_log_filter(vrpn_LOGFILTER filter, void *userdata)
Sets up a filter function for logging. Any user message to be logged is first passed to this function...
vrpn_float64 d_tcpAlignedInbuf[vrpn_CONNECTION_TCP_BUFLEN/sizeof(vrpn_float64)+ 1]
virtual int setup_new_connection(void)=0
Sends the magic cookie and other information to its < peer. It is called by both the client and serve...
static vrpn_ConnectionManager & instance(void)
The only way to get access to an instance of this class. Guarantees that there is only one...
void * userdata
Passed along.
int local_sender_id(vrpn_int32 remote_sender) const
Returns the local mapping for the remote sender (-1 if none).
vrpn_int32 sender
Only if from sender.
class VRPN_API vrpn_Connection
Definition: vrpn_3Space.h:7
int vrpn_noint_block_write(int outfile, const char buffer[], size_t length)
This routine will write a block to a file descriptor.
const long vrpn_LOG_NONE
virtual vrpn_bool doing_okay(void) const
char * d_remoteInLogName
Name of the remote log file.
vrpn_MESSAGEHANDLER vrpn_LOGFILTER
Type of handler for filters on logfiles is the same as connection handler.
bool vrpn_TimevalGreater(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:113
vrpn_int32 d_tcpNumOut
const char * vrpn_got_connection
long d_remoteLogMode
Mode to put the remote logging in.
virtual ~vrpn_Connection_Loopback(void)
vrpnLogFilterEntry * d_filters
Definition: vrpn_Log.h:86
Encapsulation of the data and methods for a single generic connection to take care of one part of man...
vrpn_int32 * d_connectionCounter
int compact_endpoints(void)
Makes sure the endpoint array is set up cleanly for the next pass through.
int vrpn_get_port_number(const char *hostspecifier)
void setNICaddress(const char *)
int openLogs(void)
#define SOCKET
Definition: vrpn_Shared.h:46
static int VRPN_CALLBACK handle_log_message(void *userdata, vrpn_HANDLERPARAM p)
Routines that handle system messages.
int vrpn_noint_block_read_timeout(SOCKET infile, char buffer[], size_t length, struct timeval *timeout)
This routine will read in a block from the file descriptor.
void setLogNames(const char *inName, const char *outName)
char * vrpn_copy_machine_name(const char *hostspecifier)
virtual void drop_connection(void)=0
Should only be called by vrpn_Connection::drop_connection(), < since there&#39;s more housecleaning to do...
int local_type_id(vrpn_int32 remote_type) const
Returns the local mapping for the remote type (-1 if none).
long d_logmode
Definition: vrpn_Log.h:75
const long vrpn_LOG_INCOMING
int doSystemCallbacksFor(vrpn_HANDLERPARAM, void *)
virtual void server_check_for_incoming_connections(const struct timeval *timeout=NULL)
char * vrpn_copy_service_name(const char *fullname)
const int vrpn_CONNECTION_MAX_TYPES
vrpn_Log * d_inLog
vrpn_Endpoint_IP(vrpn_TypeDispatcher *dispatcher, vrpn_int32 *connectedEndpointCounter)
vrpn_TranslationTable * d_senders
virtual const char * sender_name(vrpn_int32 sender)
Returns the name of the specified sender/type, or NULL if the parameter is invalid. Only works for user messages (type >= 0).
long & logMode(void)
Returns a reference so we can |= it.
int vrpn_noint_block_read(int infile, char buffer[], size_t length)
This routine will read in a block from the file descriptor.
char * vrpn_copy_rsh_program(const char *hostspecifier)
int handle_udp_messages(const timeval *timeout)
vrpn_int32 tcp_outbuf_size(void) const
const int vrpn_CONNECTION_MAX_SENDERS
Types now have their storage dynamically allocated, so we can afford to have large tables...
vrpn_HANDLERPARAM data
virtual void drop_connection(int whichEndpoint)
int addFilter(vrpn_LOGFILTER filter, void *userdata)
vrpn_TranslationTable * d_types
Definition: vrpn_Log.h:89
virtual void init(void)
Called by all constructors.
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
const char * vrpn_CONTROL
vrpn_CONTROL is the sender used for notification messages sent to the user from the local VRPN implem...
vrpn_Connection * vrpn_get_connection_by_name(const char *cname, const char *local_in_logfile_name, const char *local_out_logfile_name, const char *remote_in_logfile_name, const char *remote_out_logfile_name, const char *NIC_IPaddress, bool force_connection)
Create a client connection of arbitrary type (VRPN UDP/TCP, TCP, File, Loopback, MPI).
char * getName()
Allocates a new string and copies the log file name to it. < IMPORTANT: code calling this function is...
VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen, const timeval t)
Utility routine for placing a timeval struct into a buffer that is to be sent as a message...
Definition: vrpn_Shared.C:241
static int VRPN_CALLBACK handle_sender_message(void *userdata, vrpn_HANDLERPARAM p)
int tryToMarshall(char *outbuf, vrpn_int32 &buflen, vrpn_int32 &numOut, vrpn_uint32 len, timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 classOfService)
Calls marshall_message(); if that fails, calls < send_pending_reports() and then marshalls again...
virtual int connect_to_client(const char *machine, int port)
This is similar to check connection except that it can be used to receive requests from before a serv...
const char * vrpn_FILE_MAGIC
class VRPN_API vrpn_TypeDispatcher
virtual int save_log_so_far()
Save any messages on any endpoints which have been logged so far.
vrpn_LOGLIST * d_logTail
Definition: vrpn_Log.h:77
int open(void)
Opens the log file.
int delete_endpoint(int whichEndpoint)
Deletes the endpoint and NULLs the entry in the list of open endpoints.
vrpn_int32 d_udpNumOut
virtual ~vrpn_Endpoint(void)
const int vrpn_CONNECTION_TCP_BUFLEN
vrpnMsgCallbackEntry * next
Next handler.
char rhostname[150]
virtual ~vrpn_Connection(void)
int logOutgoingMessage(vrpn_int32 payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer)
#define vrpn_DEFAULT_LISTEN_PORT_NO
virtual int pack_type_description(vrpn_int32 which)
Send the type description to ALL endpoints.
timeval d_last_connect_attempt
When the last UDP lob occurred.
~vrpn_Log(void)
int message_type_is_registered(const char *) const
Returns message type ID, or -1 if unregistered.
vrpn_Connection * vrpn_create_server_connection(const char *cname, const char *local_in_logfile_name, const char *local_out_logfile_name)
Create a server connection of arbitrary type (VRPN UDP/TCP, TCP, File, Loopback, MPI).
const int vrpn_CONNECTION_UDP_BUFLEN
SOCKET d_udpInboundSocket
Inbound unreliable messages come here. < Need one for each due to different < clock synchronization f...
void clearBuffers(void)
Empties out the TCP and UDP send buffers. < Needed by vrpn_FileConnection to get at {udp...
vrpn_bool d_tcp_only
For connections made through firewalls or NAT with the < tcp: URL, we do not want to allow the endpoi...
const int vrpn_MAX_ENDPOINTS
Number of endpoints that a server connection can have. Arbitrary limit.
static int VRPN_CALLBACK handle_disconnect_message(void *userdata, vrpn_HANDLERPARAM p)
vrpn_Connection_Loopback()
Make a client connection. To access this from user code, call vrpn_create_server_connection() with a ...
void get_log_names(char **local_in_logname, char **local_out_logname, char **remote_in_logname, char **remote_out_logname)
This function returns the logfile names of this connection in the parameters. It will allocate memory...
vrpn_TypeDispatcher * d_dispatcher
Derived classes need access to d_dispatcher in their allocateEndpoint() routine. Several compilers wo...
void addReference()
Counting references to this connection.
static vrpn_Endpoint_IP * allocateEndpoint(vrpn_Connection *, vrpn_int32 *connectedEC)
Redefining this and passing it to constructors < allows a subclass to use a different subclass of End...
timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:45
vrpn_TypeDispatcher * d_dispatcher
virtual vrpn_int32 register_message_type(const char *name)
SOCKET d_tcpListenSocket
This section deals with when a client connection is trying to establish (or re-establish) a connectio...
virtual vrpn_bool doing_okay(void) const
Returns vrpn_true if the connection is okay, vrpn_false if not.
int write_vrpn_cookie(char *buffer, size_t length, long remote_log_mode)
Writes the magic cookie into buffer with given length.
vrpn_LOGLIST * next
#define vrpn_closeSocket
#define RSH
Placed here so vrpn_FileConnection can use it too.
vrpn_TranslationTable * d_types
virtual int do_callbacks_for(vrpn_int32 type, vrpn_int32 sender, struct timeval time, vrpn_uint32 len, const char *buffer)
virtual int pack_sender_description(vrpn_int32 which)
Send the sender description to ALL endpoints.
vrpn_int32 d_tcpBuflen
SOCKET d_udpLobSocket
Socket to use to lob UDP requests asking for the server to call us back.
const int vrpn_ANY_SENDER
vrpn_ANY_SENDER can be used to register callbacks on a given message type from any sender...
int newLocalSender(const char *name, vrpn_int32 which)
A new local sender or type has been established; set the local type for it if the other side has decl...