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;
978  char *d_senders[vrpn_CONNECTION_MAX_SENDERS];
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  int status;
2490 
2491  /* Check to see if they called back yet. */
2492  ret = vrpn_poll_for_accept(server_sock, &child_socket, SERVWAIT);
2493  if (ret == -1) {
2494  fprintf(stderr, "vrpn_start_server: Accept poll failed\n");
2495  vrpn_closeSocket(server_sock);
2496  return -1;
2497  }
2498  if (ret == 1) {
2499  break; // Got it!
2500  }
2501 
2502 /* Check to see if the child is dead yet */
2503  deadkid = wait3(&status, WNOHANG, NULL);
2504  if (deadkid == pid) {
2505  fprintf(stderr, "vrpn_start_server: server process exited\n");
2506  vrpn_closeSocket(server_sock);
2507  return (-1);
2508  }
2509  }
2510  if (waitloop == SERVCOUNT) {
2511  fprintf(stderr,
2512  "vrpn_start_server: server failed to connect in time\n");
2513  fprintf(stderr, " (took more than %d seconds)\n",
2514  SERVWAIT * SERVCOUNT);
2515  vrpn_closeSocket(server_sock);
2516  kill(pid, SIGKILL);
2517  wait(0);
2518  return (-1);
2519  }
2520 
2521  vrpn_closeSocket(server_sock);
2522  return (child_socket);
2523  }
2524  return 0;
2525 #endif
2526 }
2527 
2528 //** End of section pulled from SDI library
2529 //*********************************************************************
2530 
2531 // COOKIE MANIPULATION
2532 
2542 int write_vrpn_cookie(char *buffer, size_t length, long remote_log_mode)
2543 {
2544  if (length < vrpn_MAGICLEN + vrpn_ALIGN + 1) return -1;
2545 
2546  sprintf(buffer, "%s %c", vrpn_MAGIC,
2547  static_cast<char>(remote_log_mode + '0'));
2548  return 0;
2549 }
2550 
2557 int check_vrpn_cookie(const char *buffer)
2558 {
2559  const char *bp;
2560 
2561  // Comparison changed 9 Feb 98 by TCH
2562  // We don't care if the minor version numbers don't match,
2563  // so only check the characters through the last '.' in our
2564  // template. (If there is no last '.' in our template, somebody's
2565  // modified this code to break the constraints above, and we just
2566  // use a maximally restrictive check.)
2567  // XXX This pointer arithmetic isn't completely safe.
2568 
2569  bp = strrchr(buffer, '.');
2570  if (strncmp(buffer, vrpn_MAGIC,
2571  (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer))) {
2572  fprintf(stderr, "check_vrpn_cookie: "
2573  "bad cookie (wanted '%s', got '%s'\n",
2574  vrpn_MAGIC, buffer);
2575  return -1;
2576  }
2577 
2578  if (strncmp(buffer, vrpn_MAGIC, vrpn_MAGICLEN)) {
2579  fprintf(stderr,
2580  "check_vrpn_cookie(): "
2581  "VRPN Note: minor version number doesn't match: (prefer '%s', "
2582  "got '%s'). This is not normally a problem.\n",
2583  vrpn_MAGIC, buffer);
2584  return 1;
2585  }
2586 
2587  return 0;
2588 }
2589 
2590 int check_vrpn_file_cookie(const char *buffer)
2591 {
2592  const char *bp;
2593 
2594  // Comparison changed 9/1/00 by AAS and KTS
2595  // Here the difference is that we let the major version number be
2596  // less than or equal to our major version number as long as the major
2597  // version number is >= 4
2598 
2599  // We don't care if the minor version numbers don't match,
2600  // so only check the characters through the last '.' in our
2601  // template. (If there is no last '.' in our template, somebody's
2602  // modified this code to break the constraints above, and we just
2603  // use a maximally restrictive check.)
2604  // XXX This pointer arithmetic isn't completely safe.
2605 
2606  bp = strrchr(buffer, '.');
2607  int majorComparison = strncmp(
2608  buffer, vrpn_MAGIC, (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer));
2609  if (majorComparison > 0 ||
2610  strncmp(buffer, vrpn_FILE_MAGIC,
2611  (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer)) < 0) {
2612  fprintf(stderr, "check_vrpn_file_cookie: "
2613  "bad cookie (wanted >='%s' and <='%s', "
2614  "got '%s'\n",
2615  vrpn_FILE_MAGIC, vrpn_MAGIC, buffer);
2616  return -1;
2617  }
2618 
2619  if (majorComparison == 0 && strncmp(buffer, vrpn_MAGIC, vrpn_MAGICLEN)) {
2620  fprintf(stderr, "check_vrpn_file_cookie(): "
2621  "Note: Version number doesn't match: (prefer '%s', got "
2622  "'%s'). This is not normally a problem.\n",
2623  vrpn_MAGIC, buffer);
2624  return 1;
2625  }
2626 
2627  return 0;
2628 }
2629 
2630 size_t vrpn_cookie_size(void) { return vrpn_MAGICLEN + vrpn_ALIGN; }
2631 
2632 // END OF COOKIE CODE
2633 
2635  vrpn_int32 *connectedEndpointCounter)
2636  : status(BROKEN)
2637  , d_remoteLogMode(0)
2638  , d_remoteInLogName(NULL)
2639  , d_remoteOutLogName(NULL)
2640  , d_inLog(NULL)
2641  , d_outLog(NULL)
2642  , d_senders(NULL)
2643  , d_types(NULL)
2644  , d_dispatcher(dispatcher)
2645  , d_connectionCounter(connectedEndpointCounter)
2646 {
2648 }
2649 
2651  vrpn_int32 *connectedEndpointCounter)
2652  : vrpn_Endpoint(dispatcher, connectedEndpointCounter)
2653  , d_tcpSocket(INVALID_SOCKET)
2654  , d_tcpListenSocket(INVALID_SOCKET)
2655  , d_tcpListenPort(0)
2656  , d_udpLobSocket(INVALID_SOCKET)
2657  , d_remote_machine_name(NULL)
2658  , d_remote_port_number(0)
2659  , d_tcp_only(vrpn_FALSE)
2660  , d_udpOutboundSocket(INVALID_SOCKET)
2661  , d_udpInboundSocket(INVALID_SOCKET)
2662  , d_tcpOutbuf(new char[vrpn_CONNECTION_TCP_BUFLEN])
2663  , d_udpOutbuf(new char[vrpn_CONNECTION_UDP_BUFLEN])
2664  , d_tcpBuflen(d_tcpOutbuf ? vrpn_CONNECTION_TCP_BUFLEN : 0)
2665  , d_udpBuflen(d_udpOutbuf ? vrpn_CONNECTION_UDP_BUFLEN : 0)
2666  , d_tcpNumOut(0)
2667  , d_udpNumOut(0)
2668  , d_tcpSequenceNumber(0)
2669  , d_udpSequenceNumber(0)
2670  , d_tcpInbuf((char *)d_tcpAlignedInbuf)
2671  , d_udpInbuf((char *)d_udpAlignedInbuf)
2672  , d_NICaddress(NULL)
2673 {
2675 }
2676 
2678 {
2679 
2680  // Delete type and sender arrays
2681  if (d_senders) {
2682  delete d_senders;
2683  }
2684  if (d_types) {
2685  delete d_types;
2686  }
2687 
2688  // Delete the log, if any
2689  if (d_inLog) {
2690  // close() is called by destructor IFF necessary
2691  delete d_inLog;
2692  }
2693  if (d_outLog) {
2694  // close() is called by destructor IFF necessary
2695  delete d_outLog;
2696  }
2697 
2698  // Delete any file names created during the running
2699  if (d_remoteInLogName) {
2700  delete[] d_remoteInLogName;
2701  }
2702  if (d_remoteOutLogName) {
2703  delete[] d_remoteOutLogName;
2704  }
2705 }
2706 
2708 {
2709  // Close all of the sockets that are left open
2710  if (d_tcpSocket != INVALID_SOCKET) {
2713  d_tcpNumOut = 0; // Ignore characters waiting to go
2714  }
2718  d_udpNumOut = 0; // Ignore characters waiting to go
2719  }
2723  }
2727  }
2728  if (d_udpLobSocket != INVALID_SOCKET) {
2731  }
2732 
2733  // Delete the buffers created in the constructor
2734  if (d_tcpOutbuf) {
2735  delete[] d_tcpOutbuf;
2736  d_tcpOutbuf = NULL;
2737  }
2738  if (d_udpOutbuf) {
2739  delete[] d_udpOutbuf;
2740  d_udpOutbuf = NULL;
2741  }
2742 
2743  // Delete the remote machine name, if it has been set
2744  if (d_remote_machine_name) {
2745  delete[] d_remote_machine_name;
2746  d_remote_machine_name = NULL;
2747  }
2748 }
2749 
2751 {
2752  return (d_udpOutboundSocket != -1);
2753 }
2754 
2755 int vrpn_Endpoint::local_type_id(vrpn_int32 remote_type) const
2756 {
2757  return d_types->mapToLocalID(remote_type);
2758 }
2759 
2760 int vrpn_Endpoint::local_sender_id(vrpn_int32 remote_sender) const
2761 {
2762  return d_senders->mapToLocalID(remote_sender);
2763 }
2764 
2765 vrpn_int32 vrpn_Endpoint_IP::tcp_outbuf_size(void) const { return d_tcpBuflen; }
2766 
2767 vrpn_int32 vrpn_Endpoint_IP::udp_outbuf_size(void) const { return d_udpBuflen; }
2768 
2769 vrpn_bool vrpn_Endpoint_IP::doing_okay(void) const
2770 {
2771  return ((status >= TRYING_TO_CONNECT) || (status == LOGGING));
2772 }
2773 
2775 {
2776  // Set all of the local IDs to -1, in case the other side
2777  // sends a message of a type that it has not yet defined.
2778  // (for example, arriving on the UDP line ahead of its TCP
2779  // definition).
2782 
2783  if (!d_senders || !d_types) {
2784  fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2785  return;
2786  }
2787 
2789 
2790  if (!d_inLog) {
2791  fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2792  return;
2793  }
2794 
2796 
2797  if (!d_outLog) {
2798  fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2799  return;
2800  }
2801 }
2802 
2804 {
2807  d_tcpListenPort = 0;
2811 
2812  // Never tried a reconnect yet
2813  d_last_connect_attempt.tv_sec = 0;
2814  d_last_connect_attempt.tv_usec = 0;
2815 }
2816 
2817 int vrpn_Endpoint_IP::mainloop(timeval *timeout)
2818 {
2819  fd_set readfds, exceptfds;
2820  int tcp_messages_read;
2821  int udp_messages_read;
2822  int fd_max = static_cast<int>(d_tcpSocket);
2823  bool time_to_try_again = false;
2824 
2825  switch (status) {
2826 
2827  case CONNECTED:
2828 
2829  // Send all pending reports on the way out
2831 
2832  // check for pending incoming tcp or udp reports
2833  // we do this so that we can trigger out of the timeout
2834  // on either type of message without waiting on the other
2835 
2836  FD_ZERO(&readfds); /* Clear the descriptor sets */
2837  FD_ZERO(&exceptfds);
2838 
2839  // Read incoming messages from both the UDP and TCP channels
2840 
2841  FD_SET(d_tcpSocket, &readfds);
2842  FD_SET(d_tcpSocket, &exceptfds);
2843 
2844  if (d_udpInboundSocket != -1) {
2845  FD_SET(d_udpInboundSocket, &readfds);
2846  FD_SET(d_udpInboundSocket, &exceptfds);
2848  fd_max = static_cast<int>(d_udpInboundSocket);
2849  }
2850 
2851  // Select to see if ready to hear from other side, or exception
2852 
2853  if (vrpn_noint_select(fd_max + 1, &readfds, NULL, &exceptfds,
2854  timeout) == -1) {
2855  fprintf(stderr, "vrpn_Endpoint::mainloop: select failed.\n");
2856 #ifndef _WIN32_WCE
2857  fprintf(stderr, " Errno (%d): %s.\n", errno, strerror(errno));
2858 #endif
2859  status = BROKEN;
2860  return -1;
2861  }
2862 
2863  // See if exceptional condition on either socket
2864  if (FD_ISSET(d_tcpSocket, &exceptfds) ||
2865  ((d_udpInboundSocket != -1) &&
2866  FD_ISSET(d_udpInboundSocket, &exceptfds))) {
2867  fprintf(stderr, "vrpn_Endpoint::mainloop: Exception on socket\n");
2868  status = BROKEN;
2869  return -1;
2870  }
2871 
2872  // Read incoming messages from the UDP channel
2873  if ((d_udpInboundSocket != -1) &&
2874  FD_ISSET(d_udpInboundSocket, &readfds)) {
2875  udp_messages_read = handle_udp_messages(NULL);
2876  if (udp_messages_read == -1) {
2877  fprintf(stderr, "vrpn_Endpoint::mainloop: "
2878  "UDP handling failed, dropping connection\n");
2879  status = BROKEN;
2880  break;
2881  }
2882 #ifdef VERBOSE3
2883  if (udp_messages_read != 0)
2884  printf("udp message read = %d\n", udp_messages_read);
2885 #endif
2886  }
2887 
2888  // Read incoming messages from the TCP channel
2889  if (FD_ISSET(d_tcpSocket, &readfds)) {
2890  tcp_messages_read = handle_tcp_messages(NULL);
2891  if (tcp_messages_read == -1) {
2892  fprintf(stderr, "vrpn: TCP handling failed, dropping "
2893  "connection (this is normal when a connection "
2894  "is dropped)\n");
2895  status = BROKEN;
2896  break;
2897  }
2898 #ifdef VERBOSE3
2899  else {
2900  if (tcp_messages_read) {
2901  printf("tcp_message_read %d bytes\n", tcp_messages_read);
2902  }
2903  }
2904 #endif
2905  }
2906  break;
2907 
2908  case COOKIE_PENDING:
2909 
2910  poll_for_cookie(timeout);
2911 
2912  break;
2913 
2914  case TRYING_TO_CONNECT:
2915  struct timeval now;
2916  int ret;
2917 
2918 #ifdef VERBOSE
2919  printf("TRYING_TO_CONNECT\n");
2920 #endif
2921  // See if it has been long enough since our last attempt
2922  // to try again.
2923  vrpn_gettimeofday(&now, NULL);
2924  if (now.tv_sec - d_last_connect_attempt.tv_sec >= 2) {
2925  d_last_connect_attempt.tv_sec = now.tv_sec;
2926  time_to_try_again = true;
2927  }
2928 
2929  // If we are a TCP-only connection, then we retry to establish the
2930  // connection whenever it is time to try again. Otherwise, we're done.
2931  if (d_tcp_only) {
2932  if (time_to_try_again) {
2935  d_remote_port_number) == 0) {
2937  if (setup_new_connection()) {
2938  fprintf(stderr, "vrpn_Endpoint::mainloop: "
2939  "Can't set up new connection!\n");
2940  break;
2941  }
2942  }
2943  }
2944  break;
2945  }
2946 
2947  // We are not a TCP-only connect.
2948  // See if we have a connection yet (nonblocking select).
2949  ret = vrpn_poll_for_accept(d_tcpListenSocket, &d_tcpSocket);
2950  if (ret == -1) {
2951  fprintf(stderr, "vrpn_Endpoint: mainloop: Can't poll for accept\n");
2952  status = BROKEN;
2953  break;
2954  }
2955  if (ret == 1) { // Got one!
2957 #ifdef VERBOSE
2958  printf("vrpn: Connection established\n");
2959 #endif
2960  // Set up the things that need to happen when a new connection
2961  // is established.
2962  if (setup_new_connection()) {
2963  fprintf(stderr, "vrpn_Endpoint: mainloop: "
2964  "Can't set up new connection!\n");
2965  status = BROKEN;
2966  // fprintf(stderr, "BROKEN - vrpn_Endpoint::mainloop.\n");
2967  break;
2968  }
2969  break;
2970  }
2971 
2972  // Lob a request-to-connect packet every couple of seconds
2973  // If we don't wait a while between these we flood buffers and
2974  // do BAD THINGS (TM).
2975 
2976  if (time_to_try_again) {
2977  //XXX On Linux, if we are talking to a machine that does not
2978  // have a server running, then our connect eventually tells us
2979  // that is was refused, and we can't communicate on that
2980  // UDP socket anymore. We should switch to a connectionless
2981  // sendto() option instead, but this runs the way it used
2982  // to, which worked, but still leaves the socket open after
2983  // the send; closing it right away broke on some Windows
2984  // machines.
2986  d_udpLobSocket = vrpn_connect_udp_port(d_remote_machine_name,
2988 
2991  d_tcpListenPort, d_NICaddress) == -1) {
2992  fprintf(stderr,
2993  "vrpn_Endpoint: mainloop: Can't lob UDP request\n");
2994  status = BROKEN;
2995  // fprintf(stderr, "BROKEN - vrpn_Endpoint::mainloop.\n");
2996  break;
2997  }
2998  }
2999  break;
3000 
3001  case BROKEN:
3003  return -1;
3004 
3005  case LOGGING: // Just logging, so go about your business.
3006  break;
3007 
3008  default:
3009  fprintf(stderr, "vrpn_Endpoint::mainloop(): "
3010  "Unknown status (%d)\n",
3011  status);
3012  status = BROKEN;
3013  return -1;
3014  }
3015 
3016  return 0;
3017 } // MAINLOOP
3018 
3019 // Clear out the remote mapping list. This is done when a
3020 // connection is dropped and we want to try and re-establish
3021 // it.
3023 {
3024  d_senders->clear();
3025  d_types->clear();
3026 }
3027 
3028 // Make the local mapping for the otherside sender with the same
3029 // name, if there is one. Return 1 if there was a mapping; this
3030 // lets the higher-ups know that there is someone that cares
3031 // on the other side.
3032 int vrpn_Endpoint::newLocalSender(const char *name, vrpn_int32 which)
3033 {
3034  return d_senders->addLocalID(name, which);
3035 }
3036 
3037 // If the other side has declared this type, establish the
3038 // mapping for it. Return 1 if there was a mapping; this
3039 // lets the higher-ups know that there is someone that cares
3040 // on the other side.
3041 int vrpn_Endpoint::newLocalType(const char *name, vrpn_int32 which)
3042 {
3043  return d_types->addLocalID(name, which);
3044 }
3045 
3046 // Adds a new remote type and returns its index. Returns -1 on error.
3047 int vrpn_Endpoint::newRemoteType(cName type_name, vrpn_int32 remote_id,
3048  vrpn_int32 local_id)
3049 {
3050  return d_types->addRemoteEntry(type_name, remote_id, local_id);
3051 }
3052 
3053 // Adds a new remote sender and returns its index. Returns -1 on error.
3054 int vrpn_Endpoint::newRemoteSender(cName sender_name, vrpn_int32 remote_id,
3055  vrpn_int32 local_id)
3056 {
3057  return d_senders->addRemoteEntry(sender_name, remote_id, local_id);
3058 }
3059 
3075 int vrpn_Endpoint_IP::pack_message(vrpn_uint32 len, timeval time,
3076  vrpn_int32 type, vrpn_int32 sender,
3077  const char *buffer,
3078  vrpn_uint32 class_of_service)
3079 {
3080  int ret;
3081 
3082  // Any semantic checking needs to have been done by the Connection
3083  // class: the Endpoint doesn't know enough to do it. Similarly
3084  // for any local callbacks that need to be done. Similarly, filtering.
3085 
3086  // Logging must come before filtering and should probably come before
3087  // any other failure-prone action (such as do_callbacks_for()). Only
3088  // semantic checking should precede it.
3089 
3090  if (d_outLog->logOutgoingMessage(len, time, type, sender, buffer)) {
3091  fprintf(stderr, "vrpn_Endpoint::pack_message: "
3092  "Couldn't log outgoing message.!\n");
3093  return -1;
3094  }
3095 
3096  if (status == LOGGING) {
3097  // No error message; this endpoint is ONLY logging.
3098  return 0;
3099  }
3100 
3101  // TCH 26 April 2000
3102  if (status != CONNECTED) {
3103 #ifdef VERBOSE2
3104  fprintf(stderr, "vrpn_Endpoint::pack_message: "
3105  "Not connected, so throwing out message.\n");
3106 #endif
3107  return 0;
3108  }
3109 
3110  // Determine the class of service and pass it off to the
3111  // appropriate service (TCP for reliable, UDP for everything else).
3112  // If we don't have a UDP outbound channel, send everything TCP
3113  if ((d_udpOutboundSocket == -1) ||
3114  (class_of_service & vrpn_CONNECTION_RELIABLE)) {
3115 
3116  // Ensure that we have an outgoing TCP buffer. If not, then
3117  // we don't have anywhere to send it.
3118  if (d_tcpSocket == -1) {
3119  ret = 0;
3120  }
3121  else {
3122  ret =
3124  type, sender, buffer, d_tcpSequenceNumber);
3125  d_tcpNumOut += ret;
3126  if (ret > 0) {
3128  }
3129  }
3130  }
3131  else {
3132 
3133  ret = tryToMarshall(d_udpOutbuf, d_udpBuflen, d_udpNumOut, len, time,
3134  type, sender, buffer, d_udpSequenceNumber);
3135  d_udpNumOut += ret;
3136  if (ret > 0) {
3138  }
3139  }
3140  return (!ret) ? -1 : 0;
3141 }
3142 
3144 {
3145  vrpn_int32 ret, sent = 0;
3146  int connection;
3147  timeval timeout;
3148 
3149  // Make sure we've got a valid TCP connection; else we can't send them.
3150  if (d_tcpSocket == -1) {
3151  fprintf(stderr,
3152  "vrpn_Endpoint::send_pending_reports(): No TCP connection\n");
3153  status = BROKEN;
3154  clearBuffers();
3155  return -1;
3156  }
3157 
3158  // Check for an exception on the socket. If there is one, shut it
3159  // down and go back to listening.
3160  timeout.tv_sec = 0;
3161  timeout.tv_usec = 0;
3162 
3163  fd_set f;
3164  FD_ZERO(&f);
3165  FD_SET(d_tcpSocket, &f);
3166 
3167  connection = vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, NULL,
3168  NULL, &f, &timeout);
3169  if (connection) {
3170  fprintf(stderr, "vrpn_Endpoint::send_pending_reports(): "
3171  "select() failed.\n");
3172 #ifdef VRPN_USE_WINSOCK_SOCKETS
3173  char Message[1024];
3174  FormatMessage(
3175  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
3176  FORMAT_MESSAGE_MAX_WIDTH_MASK,
3177  NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3178  (LPSTR)Message, 1024, NULL);
3179  fprintf(stderr, "Windows Sockets Error (%d): %s.\n", WSAGetLastError(),
3180  Message);
3181 #else
3182  fprintf(stderr, "Errno (%d): %s.\n", errno, strerror(errno));
3183 #endif
3184  status = BROKEN;
3185  return -1;
3186  }
3187 
3188 // Send all of the messages that have built
3189 // up in the TCP buffer. If there is an error during the send, or
3190 // an exceptional condition, close the accept socket and go back
3191 // to listening for new connections.
3192 #ifdef VERBOSE
3193  if (d_tcpNumOut) printf("TCP Need to send %d bytes\n", d_tcpNumOut);
3194 #endif
3195  while (sent < d_tcpNumOut) {
3196  ret = send(d_tcpSocket, &d_tcpOutbuf[sent], d_tcpNumOut - sent, 0);
3197 #ifdef VERBOSE
3198  printf("TCP Sent %d bytes\n", ret);
3199 #endif
3200  if (ret == -1) {
3201  fprintf(stderr, "vrpn_Endpoint::send_pending_reports: "
3202  "TCP send failed.\n");
3203  status = BROKEN;
3204  return -1;
3205  }
3206  sent += ret;
3207  }
3208 
3209  // Send all of the messages that have built
3210  // up in the UDP buffer. If there is an error during the send, or
3211  // an exceptional condition, close the accept socket and go back
3212  // to listening for new connections.
3213 
3214  if ((d_udpOutboundSocket != -1) && (d_udpNumOut > 0)) {
3215 
3216  ret = send(d_udpOutboundSocket, d_udpOutbuf, d_udpNumOut, 0);
3217 #ifdef VERBOSE
3218  printf("UDP Sent %d bytes\n", ret);
3219 #endif
3220  if (ret == -1) {
3221  fprintf(stderr, "vrpn_Endpoint::send_pending_reports: "
3222  " UDP send failed.");
3223  status = BROKEN;
3224  return -1;
3225  }
3226  }
3227 
3228  clearBuffers();
3229  return 0;
3230 }
3231 
3232 // Pack a message telling to call back this host on the specified
3233 // port number. It is important that the IP address of the host
3234 // refers to the one that was used by the original TCP connection
3235 // rather than (for example) the default IP address for the host.
3236 // This is because the remote machine may not have a route to
3237 // that NIC, but only the one used to establish the TCP connection.
3238 
3240 {
3241  struct timeval now;
3242  vrpn_uint32 portparam = portno;
3243  char myIPchar[1000];
3244  int retval;
3245 
3246 #ifdef VERBOSE2
3247  fprintf(stderr, "Getting IP address of NIC %s.\n", d_NICaddress);
3248 #endif
3249 
3250  // Find the local host name that we should be using to connect.
3251  // If d_NICaddress is set, use it; otherwise, use the d_tcpSocket
3252  // if it is valid.
3253  retval =
3254  vrpn_getmyIP(myIPchar, sizeof(myIPchar), d_NICaddress, d_tcpSocket);
3255  if (retval) {
3256  perror("vrpn_Endpoint::pack_udp_description: can't get host name");
3257  return -1;
3258  }
3259 
3260 // Pack a message with type vrpn_CONNECTION_UDP_DESCRIPTION
3261 // whose sender ID is the ID of the port that is to be
3262 // used and whose body holds the zero-terminated string
3263 // name of the host to contact.
3264 
3265 #ifdef VERBOSE
3266  fprintf(stderr, "vrpn_Endpoint::pack_udp_description: "
3267  "Packing UDP %s:%d\n",
3268  myIPchar, portno);
3269 #endif
3270  vrpn_gettimeofday(&now, NULL);
3271 
3272  return pack_message(static_cast<vrpn_uint32>(strlen(myIPchar)) + 1, now,
3273  vrpn_CONNECTION_UDP_DESCRIPTION, portparam, myIPchar,
3275 }
3276 
3278 {
3279  struct timeval now;
3280 
3281  // Handle the case of NULL pointers in the log file names
3282  // by pointing local copies at the empty string if they occur.
3283  const char *inName = "";
3284  const char *outName = "";
3285  if (d_remoteInLogName) {
3286  inName = d_remoteInLogName;
3287  }
3288  if (d_remoteOutLogName) {
3289  outName = d_remoteOutLogName;
3290  }
3291 
3292  // Include the NULL termination for the strings in the length of the buffer.
3293  size_t bufsize =
3294  2 * sizeof(vrpn_int32) + strlen(inName) + 1 + strlen(outName) + 1;
3295  char *buf = new char[bufsize];
3296  if (buf == NULL) {
3297  fprintf(stderr,
3298  "vrpn_Endpoint::pack_log_description(): Out of memory\n");
3299  return -1;
3300  }
3301 
3302  // If we're not requesting remote logging, don't send any message.
3303 
3304  if (!d_remoteLogMode) {
3305  delete[] buf;
3306  return 0;
3307  }
3308 
3309  // Pack a message with type vrpn_CONNECTION_LOG_DESCRIPTION whose
3310  // sender ID is the logging mode to be used by the remote connection
3311  // and whose body holds the zero-terminated string name of the file
3312  // to write to.
3313 
3314  vrpn_gettimeofday(&now, NULL);
3315  char *bpp = buf;
3316  char **bp = &bpp;
3317  vrpn_int32 bufleft = static_cast<vrpn_int32>(bufsize);
3318  vrpn_buffer(bp, &bufleft, (vrpn_int32)strlen(inName));
3319  vrpn_buffer(bp, &bufleft, (vrpn_int32)strlen(outName));
3320  vrpn_buffer(bp, &bufleft, inName, static_cast<vrpn_int32>(strlen(inName)));
3321  vrpn_buffer(bp, &bufleft, (char)0);
3322  vrpn_buffer(bp, &bufleft, outName,
3323  static_cast<vrpn_int32>(strlen(outName)));
3324  vrpn_buffer(bp, &bufleft, (char)0);
3325  int ret = pack_message(static_cast<vrpn_uint32>(bufsize - bufleft), now,
3328  delete[] buf;
3329  return ret;
3330 }
3331 
3332 // Read all messages available on the given file descriptor (a TCP link).
3333 // Handle each message that is received.
3334 // Return the number of messages read, or -1 on failure.
3335 
3336 int vrpn_Endpoint_IP::handle_tcp_messages(const struct timeval *timeout)
3337 {
3338  timeval localTimeout;
3339  fd_set readfds, exceptfds;
3340  unsigned num_messages_read = 0;
3341  int retval;
3342  int sel_ret;
3343 
3344 #ifdef VERBOSE2
3345  printf("vrpn_Endpoint::handle_tcp_messages() called\n");
3346 #endif
3347 
3348  if (timeout) {
3349  localTimeout.tv_sec = timeout->tv_sec;
3350  localTimeout.tv_usec = timeout->tv_usec;
3351  }
3352  else {
3353  localTimeout.tv_sec = 0;
3354  localTimeout.tv_usec = 0;
3355  }
3356 
3357  // Read incoming messages until there are no more characters to
3358  // read from the other side. For each message, determine what
3359  // type it is and then pass it off to the appropriate handler
3360  // routine. If d_stop_processing_messages_after has been set
3361  // to a nonzero value, then stop processing if we have received
3362  // at least that many messages.
3363 
3364  do {
3365  // Select to see if ready to hear from other side, or exception
3366  FD_ZERO(&readfds); /* Clear the descriptor sets */
3367  FD_ZERO(&exceptfds);
3368  FD_SET(d_tcpSocket, &readfds); /* Check for read */
3369  FD_SET(d_tcpSocket, &exceptfds); /* Check for exceptions */
3370  sel_ret = vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, &readfds,
3371  NULL, &exceptfds, &localTimeout);
3372  if (sel_ret == -1) {
3373  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
3374  "select failed");
3375  return (-1);
3376  }
3377 
3378  // See if exceptional condition on socket
3379  if (FD_ISSET(d_tcpSocket, &exceptfds)) {
3380  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
3381  "Exception on socket\n");
3382  return (-1);
3383  }
3384 
3385  // If there is anything to read, get the next message
3386  if (FD_ISSET(d_tcpSocket, &readfds)) {
3387  retval = getOneTCPMessage(static_cast<int>(d_tcpSocket), d_tcpInbuf,
3388  sizeof(d_tcpAlignedInbuf));
3389  if (retval) {
3390  return -1;
3391  }
3392 
3393  // Got one more message
3394  num_messages_read++;
3395  }
3396 
3397  // If we've been asked to process only a certain number of
3398  // messages, then stop if we've gotten at least that many.
3399  if (d_parent->get_Jane_value() != 0) {
3400  if (num_messages_read >= d_parent->get_Jane_value()) {
3401  break;
3402  }
3403  }
3404  } while (sel_ret);
3405 
3406  return num_messages_read;
3407 }
3408 
3409 // Read all messages available on the given file descriptor (a UDP link).
3410 // Handle each message that is received.
3411 // Return the number of messages read, or -1 on failure.
3412 // This routine and the TCP read routine are annoyingly similar, so it
3413 // seems like they should be merged. They can't though: using read() on
3414 // the UDP socket fails, so we need the UDP version. If we use the UDP
3415 // version for the TCP code, it hangs when we the client drops its
3416 // connection, so we need the TCP code as well.
3417 // If d_stop_processing_messages_after has been set
3418 // to a nonzero value, then stop processing if we have received
3419 // at least that many messages.
3420 
3421 int vrpn_Endpoint_IP::handle_udp_messages(const struct timeval *timeout)
3422 {
3423  timeval localTimeout;
3424  fd_set readfds, exceptfds;
3425  unsigned num_messages_read = 0;
3426  int sel_ret;
3427  int retval;
3428 
3429 #ifdef VERBOSE2
3430  printf("vrpn_Endpoint::handle_udp_messages() called\n");
3431 #endif
3432 
3433  if (timeout) {
3434  localTimeout.tv_sec = timeout->tv_sec;
3435  localTimeout.tv_usec = timeout->tv_usec;
3436  }
3437  else {
3438  localTimeout.tv_sec = 0;
3439  localTimeout.tv_usec = 0;
3440  }
3441 
3442  // Read incoming messages until there are no more packets to
3443  // read from the other side. Each packet may have more than one
3444  // message in it. For each message, determine what
3445  // type it is and then pass it off to the appropriate handler
3446  // routine.
3447 
3448  do {
3449  // Select to see if ready to hear from server, or exception
3450  FD_ZERO(&readfds); /* Clear the descriptor sets */
3451  FD_ZERO(&exceptfds);
3452  FD_SET(d_udpInboundSocket, &readfds); /* Check for read */
3453  FD_SET(d_udpInboundSocket, &exceptfds); /* Check for exceptions */
3454  sel_ret = vrpn_noint_select(static_cast<int>(d_udpInboundSocket) + 1,
3455  &readfds, NULL, &exceptfds, &localTimeout);
3456  if (sel_ret == -1) {
3457  perror("vrpn_Endpoint::handle_udp_messages: select failed()");
3458  return (-1);
3459  }
3460 
3461  // See if exceptional condition on socket
3462  if (FD_ISSET(d_udpInboundSocket, &exceptfds)) {
3463  fprintf(stderr, "vrpn: vrpn_Endpoint::handle_udp_messages: "
3464  "Exception on socket\n");
3465  return (-1);
3466  }
3467 
3468  // If there is anything to read, get the next message
3469  if (FD_ISSET(d_udpInboundSocket, &readfds)) {
3470  char *inbuf_ptr;
3471  int inbuf_len;
3472 
3473  inbuf_ptr = d_udpInbuf;
3474  inbuf_len = recv(d_udpInboundSocket, d_udpInbuf,
3475  sizeof(d_udpAlignedInbuf), 0);
3476  if (inbuf_len == -1) {
3477  fprintf(stderr, "vrpn_Endpoint::handle_udp_message: "
3478  "recv() failed.\n");
3479  return -1;
3480  }
3481 
3482  while (inbuf_len) {
3483  retval = getOneUDPMessage(inbuf_ptr, inbuf_len);
3484  if (retval == -1) {
3485  return -1;
3486  }
3487  inbuf_len -= retval;
3488  inbuf_ptr += retval;
3489  // fprintf(stderr, " Advancing inbuf pointer %d bytes.\n",
3490  // retval);
3491  // Got one more message
3492  num_messages_read++;
3493  }
3494  }
3495 
3496  // If we've been asked to process only a certain number of
3497  // messages, then stop if we've gotten at least that many.
3498  if (d_parent->get_Jane_value() != 0) {
3499  if (num_messages_read >= d_parent->get_Jane_value()) {
3500  break;
3501  }
3502  }
3503 
3504  } while (sel_ret);
3505 
3506  return num_messages_read;
3507 }
3508 
3509 //---------------------------------------------------------------------------
3510 // This routine opens a TCP socket and connects it to the machine and port
3511 // that are passed in the msg parameter. This is a string that contains
3512 // the machine name, a space, then the port number.
3513 // The routine returns -1 on failure and the file descriptor on success.
3514 
3516 {
3517  char machine[1000];
3518  int port;
3519 
3520  // Find the machine name and port number
3521  if (sscanf(msg, "%s %d", machine, &port) != 2) {
3522  return -1;
3523  }
3524 
3525  return connect_tcp_to(machine, port);
3526 }
3527 
3528 int vrpn_Endpoint_IP::connect_tcp_to(const char *addr, int port)
3529 {
3530  struct sockaddr_in client; /* The name of the client */
3531  struct hostent *host; /* The host to connect to */
3532 
3533  /* set up the socket */
3534  d_tcpSocket = open_tcp_socket(NULL, d_NICaddress);
3535  if (d_tcpSocket < 0) {
3536  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: "
3537  "can't open socket\n");
3538  return -1;
3539  }
3540  client.sin_family = AF_INET;
3541 
3542  // gethostbyname() fails on SOME Windows NT boxes, but not all,
3543  // if given an IP octet string rather than a true name.
3544  // MS Documentation says it will always fail and inet_addr should
3545  // be called first. Avoids a 30+ second wait for
3546  // gethostbyname() to fail.
3547 
3548  if ((client.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE) {
3549  host = gethostbyname(addr);
3550  if (host) {
3551 
3552 #ifdef CRAY
3553  {
3554  int i;
3555  u_long foo_mark = 0;
3556  for (i = 0; i < 4; i++) {
3557  u_long one_char = host->h_addr_list[0][i];
3558  foo_mark = (foo_mark << 8) | one_char;
3559  }
3560  client.sin_addr.s_addr = foo_mark;
3561  }
3562 #else
3563  memcpy(&(client.sin_addr.s_addr), host->h_addr, host->h_length);
3564 #endif
3565  }
3566  else {
3567 
3568 #if !defined(hpux) && !defined(__hpux) && !defined(_WIN32) && !defined(sparc)
3569  herror("gethostbyname error:");
3570 #else
3571  perror("gethostbyname error:");
3572 #endif
3573  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: "
3574  "error finding host by name (%s)\n",
3575  addr);
3576  return -1;
3577  }
3578  }
3579 
3580 #ifndef VRPN_USE_WINSOCK_SOCKETS
3581  client.sin_port = htons(port);
3582 #else
3583  client.sin_port = htons((u_short)port);
3584 #endif
3585 
3586  if (connect(d_tcpSocket, (struct sockaddr *)&client, sizeof(client)) < 0) {
3587 #ifdef VRPN_USE_WINSOCK_SOCKETS
3588  if (!d_tcp_only) {
3589  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: Could not connect "
3590  "to machine %d.%d.%d.%d port %d\n",
3591  (int)(client.sin_addr.S_un.S_un_b.s_b1),
3592  (int)(client.sin_addr.S_un.S_un_b.s_b2),
3593  (int)(client.sin_addr.S_un.S_un_b.s_b3),
3594  (int)(client.sin_addr.S_un.S_un_b.s_b4),
3595  (int)(ntohs(client.sin_port)));
3596  int error = WSAGetLastError();
3597  fprintf(stderr, "Winsock error: %d\n", error);
3598  }
3599 #else
3600  fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: Could not connect to "
3601  "machine %d.%d.%d.%d port %d\n",
3602  (int)((client.sin_addr.s_addr >> 24) & 0xff),
3603  (int)((client.sin_addr.s_addr >> 16) & 0xff),
3604  (int)((client.sin_addr.s_addr >> 8) & 0xff),
3605  (int)((client.sin_addr.s_addr >> 0) & 0xff),
3606  (int)(ntohs(client.sin_port)));
3607 #endif
3609  status = BROKEN;
3610  return (-1);
3611  }
3612 
3613 /* Set the socket for TCP_NODELAY */
3614 #if !defined(_WIN32_WCE) && !defined(__ANDROID__)
3615  {
3616  struct protoent *p_entry;
3617  int nonzero = 1;
3618 
3619  if ((p_entry = getprotobyname("TCP")) == NULL) {
3620  fprintf(
3621  stderr,
3622  "vrpn_Endpoint::connect_tcp_to: getprotobyname() failed.\n");
3624  status = BROKEN;
3625  return -1;
3626  }
3627 
3628  if (setsockopt(d_tcpSocket, p_entry->p_proto, TCP_NODELAY,
3629  SOCK_CAST & nonzero, sizeof(nonzero)) == -1) {
3630  perror("vrpn_Endpoint::connect_tcp_to: setsockopt() failed");
3632  status = BROKEN;
3633  return -1;
3634  }
3635  }
3636 #endif
3638 
3639  return 0;
3640 }
3641 
3642 int vrpn_Endpoint_IP::connect_udp_to(const char *addr, int port)
3643 {
3644  if (!d_tcp_only) {
3645  d_udpOutboundSocket = ::vrpn_connect_udp_port(addr, port, d_NICaddress);
3646  if (d_udpOutboundSocket == -1) {
3647  fprintf(stderr, "vrpn_Endpoint::connect_udp_to: "
3648  "Couldn't open outbound UDP link.\n");
3649  status = BROKEN;
3650  return -1;
3651  }
3652  }
3653  return 0;
3654 }
3655 
3656 vrpn_int32 vrpn_Endpoint_IP::set_tcp_outbuf_size(vrpn_int32 bytecount)
3657 {
3658  char *new_outbuf;
3659 
3660  if (bytecount < 0) {
3661  return d_tcpBuflen;
3662  }
3663 
3664  new_outbuf = new char[bytecount];
3665 
3666  if (!new_outbuf) {
3667  return -1;
3668  }
3669 
3670  if (d_tcpOutbuf) {
3671  delete[] d_tcpOutbuf;
3672  }
3673 
3674  d_tcpOutbuf = new_outbuf;
3675  d_tcpBuflen = bytecount;
3676 
3677  return d_tcpBuflen;
3678 }
3679 
3681 {
3682 
3683  if (d_tcpSocket != INVALID_SOCKET) {
3686  d_tcpNumOut = 0; // Ignore characters waiting to go
3687  }
3691  d_udpNumOut = 0; // Ignore characters waiting to go
3692  }
3696  }
3697 
3698  // Remove the remote mappings for senders and types. If we
3699  // reconnect, we will want to fill them in again. First,
3700  // free the space allocated for the list of names, then
3701  // set all of the local IDs to -1, in case the other side
3702  // sends a message of a type that it has not yet defined.
3703  // (for example, arriving on the UDP line ahead of its TCP
3704  // definition).
3705 
3707 
3708  // Clear out the buffers; nothing to read or send if no connection.
3709  clearBuffers();
3710 
3711  struct timeval now;
3712  vrpn_gettimeofday(&now, NULL);
3713 
3714  // If we are logging, put a message in the log telling that we
3715  // have had a disconnection. We don't close the logfile here unless
3716  // there is an error logging the message. This is because we'll want
3717  // to keep logging if there is a reconnection. We close the file when
3718  // the endpoint is destroyed.
3719  if (d_outLog->logMode()) {
3721  NULL, 0) == -1) {
3722  fprintf(stderr, "vrpn_Endpoint::drop_connection: Can't log\n");
3723  d_outLog->close(); // Hope for the best...
3724  }
3725  }
3726 
3727  // Recall that the connection counter is a pointer to our parent
3728  // connection's count of active endpoints. If it exists, we need
3729  // to send disconnect messages to those who care. If this is the
3730  // last endpoint, then we send the last endpoint message; we
3731  // always send a connection dropped message.
3732  // Message needs to be dispatched *locally only*, so we do_callbacks_for()
3733  // and never pack_message()
3734 
3735  if (d_connectionCounter != NULL) { // Do nothing on NULL pointer
3736 
3737  (*d_connectionCounter)--; // One less connection
3738 
3739  d_dispatcher->doCallbacksFor(
3740  d_dispatcher->registerType(vrpn_dropped_connection),
3741  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
3742 
3743  if (*d_connectionCounter == 0) { // None more left
3744  d_dispatcher->doCallbacksFor(
3746  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
3747  }
3748  }
3749 }
3750 
3752 {
3753  d_tcpNumOut = 0;
3754  d_udpNumOut = 0;
3755 }
3756 
3757 void vrpn_Endpoint_IP::setNICaddress(const char *address)
3758 {
3759  if (d_NICaddress) {
3760  delete[] d_NICaddress;
3761  }
3762 
3763 #ifdef VERBOSE
3764  fprintf(stderr, "Setting endpoint NIC address to %s.\n", address);
3765 #endif
3766 
3767  d_NICaddress = NULL;
3768  if (!address) {
3769  return;
3770  }
3771  d_NICaddress = new char[1 + strlen(address)];
3772  if (!d_NICaddress) {
3773  fprintf(stderr, "vrpn_Endpoint::setNICaddress: Out of memory.\n");
3774  return;
3775  }
3776  strcpy(d_NICaddress, address);
3777 }
3778 
3780 {
3781  char sendbuf[501];
3782  vrpn_int32 sendlen;
3783  int retval;
3784 
3785  retval =
3787  if (retval < 0) {
3788  perror("vrpn_Endpoint::setup_new_connection: "
3789  "Internal error - array too small. The code's broken.");
3790  return -1;
3791  }
3792  sendlen = static_cast<vrpn_int32>(vrpn_cookie_size());
3793 
3794  // Write the magic cookie header to the server
3795  // NOTE: Valgrind will complain about this because we didn't fill in all of the
3796  // characters we're writing. But we don't care about the characters that are
3797  // beyond the terminating NULL character in the string.
3798  if (vrpn_noint_block_write(d_tcpSocket, sendbuf, sendlen) != sendlen) {
3799  fprintf(stderr, "vrpn_Endpoint::setup_new_connection: "
3800  "Can't write cookie.\n");
3801  status = BROKEN;
3802  return -1;
3803  }
3804 
3806  poll_for_cookie();
3807 
3808  return 0;
3809 }
3810 
3811 void vrpn_Endpoint_IP::poll_for_cookie(const timeval *pTimeout)
3812 {
3813  timeval timeout;
3814 
3815  if (pTimeout) {
3816  timeout = *pTimeout;
3817  }
3818  else {
3819  timeout.tv_sec = 0;
3820  timeout.tv_usec = 0;
3821  }
3822 
3823  fd_set readfds, exceptfds;
3824 
3825  // most of this code copied from mainloop() case CONNECTED
3826 
3827  // check for pending incoming tcp or udp reports
3828  // we do this so that we can trigger out of the timeout
3829  // on either type of message without waiting on the other
3830 
3831  FD_ZERO(&readfds); /* Clear the descriptor sets */
3832  FD_ZERO(&exceptfds);
3833 
3834  // Read incoming COOKIE from TCP channel
3835 
3836  FD_SET(d_tcpSocket, &readfds);
3837  FD_SET(d_tcpSocket, &exceptfds);
3838 
3839  // Select to see if ready to hear from other side, or exception
3840 
3841  if (vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, &readfds, NULL,
3842  &exceptfds, &timeout) == -1) {
3843  fprintf(stderr, "vrpn_Endpoint::poll_for_cookie(): select failed.\n");
3844  status = BROKEN;
3845  return;
3846  }
3847 
3848  // See if exceptional condition on either socket
3849  if (FD_ISSET(d_tcpSocket, &exceptfds)) {
3850  fprintf(stderr,
3851  "vrpn_Endpoint::poll_for_cookie(): Exception on socket\n");
3852  return;
3853  }
3854 
3855  // Read incoming COOKIE from the TCP channel
3856  if (FD_ISSET(d_tcpSocket, &readfds)) {
3858  if (!doing_okay()) {
3859  fprintf(stderr,
3860  "vrpn_Endpoint::poll_for_cookie: cookie handling failed\n"
3861  " while connecting to \"%s\"\n",
3863  return;
3864  }
3865 #ifdef VERBOSE3
3866  else if (status == CONNECTED) {
3867  printf("vrpn_Endpoint::poll_for_cookie() got cookie\n");
3868  }
3869 #endif
3870  }
3871 }
3872 
3874 {
3875 
3876  vrpn_int32 sendlen = static_cast<vrpn_int32>(vrpn_cookie_size());
3877  char *recvbuf = new char[sendlen];
3878  if (recvbuf == NULL) {
3879  fprintf(stderr, "vrpn_Endpoint_IP::finish_new_connection_setup(): Out "
3880  "of memory when allocating receiver buffer\n");
3881  status = BROKEN;
3882  return -1;
3883  }
3884 
3885  // Try to read the magic cookie from the server.
3886  int ret = vrpn_noint_block_read(d_tcpSocket, recvbuf, sendlen);
3887  if (ret != sendlen) {
3888  perror("vrpn_Endpoint::finish_new_connection_setup: Can't read cookie");
3889  status = BROKEN;
3890  delete[] recvbuf;
3891  return -1;
3892  }
3893 
3894  if (check_vrpn_cookie(recvbuf) < 0) {
3895  status = BROKEN;
3896  delete[] recvbuf;
3897  return -1;
3898  }
3899 
3900  // Store the magic cookie from the other side into a buffer so
3901  // that it can be put into an incoming log file.
3902  d_inLog->setCookie(recvbuf);
3903 
3904  // Find out what log mode they want us to be in BEFORE we pack
3905  // type, sender, and udp descriptions! That is because we will
3906  // need the type and sender messages to go into the log file if
3907  // we're logging outgoing messages. If it's nonzero, the
3908  // filename to use should come in a log_description message later.
3909 
3910  long received_logmode = recvbuf[vrpn_MAGICLEN + 2] - '0';
3911  if ((received_logmode < 0) ||
3912  (received_logmode > (vrpn_LOG_INCOMING | vrpn_LOG_OUTGOING))) {
3913  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3914  "Got invalid log mode %d\n",
3915  static_cast<int>(received_logmode));
3916  status = BROKEN;
3917  delete[] recvbuf;
3918  return -1;
3919  }
3920  if (received_logmode & vrpn_LOG_INCOMING) {
3922  }
3923  if (received_logmode & vrpn_LOG_OUTGOING) {
3925  }
3926 
3927  // status must be sent to CONNECTED *before* any messages are
3928  // packed; otherwise they're silently discarded in pack_message.
3929  status = CONNECTED;
3930 
3931  if (pack_log_description() == -1) {
3932  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3933  "Can't pack remote logging instructions.\n");
3934  status = BROKEN;
3935  delete[] recvbuf;
3936  return -1;
3937  }
3938 
3939  // If we do not have a socket for inbound connections open, and if we
3940  // are allowed to do other-than-TCP sockets, then open one and tell the
3941  // other side that it can use it.
3942  if (!d_tcp_only) {
3943 
3945  // Open the UDP port to accept time-critical messages on.
3946 
3947  unsigned short udp_portnum = static_cast<unsigned short>(INADDR_ANY);
3948  d_udpInboundSocket = ::open_udp_socket(&udp_portnum, d_NICaddress);
3950  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3951  "can't open UDP socket\n");
3952  status = BROKEN;
3953  delete[] recvbuf;
3954  return -1;
3955  }
3956 
3957  // Tell the other side what port number to send its UDP messages to.
3958  if (pack_udp_description(udp_portnum) == -1) {
3959  fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
3960  "Can't pack UDP msg\n");
3961  status = BROKEN;
3962  delete[] recvbuf;
3963  return -1;
3964  }
3965  }
3966  }
3967 
3968 #ifdef VERBOSE
3969  fprintf(stderr,
3970  "CONNECTED - vrpn_Endpoint::finish_new_connection_setup.\n");
3971 #endif
3972 
3973  // Pack messages that describe the types of messages and sender
3974  // ID mappings that have been described to this connection. These
3975  // messages use special IDs (negative ones).
3976  for (int i = 0; i < d_dispatcher->numSenders(); i++) {
3978  }
3979  for (int i = 0; i < d_dispatcher->numTypes(); i++) {
3981  }
3982 
3983  // Send the messages
3984  if (send_pending_reports() == -1) {
3985  fprintf(
3986  stderr,
3987  "vrpn_Endpoint::finish_new_connection_setup: Can't send UDP msg\n");
3988  status = BROKEN;
3989  delete[] recvbuf;
3990  return -1;
3991  }
3992 
3993  // The connection-established messages need to be dispatched *locally only*,
3994  // so we do_callbacks_for and never pack_message()
3995  struct timeval now;
3996  vrpn_gettimeofday(&now, NULL);
3997 
3998  // Connection counter gives us a single point to count connections that
3999  // actually make it to CONNECTED, not just constructed, so we send
4000  // got-first-/dropped-last-connection messages properly.
4001 
4003  d_dispatcher->doCallbacksFor(
4004  d_dispatcher->registerType(vrpn_got_first_connection),
4005  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
4006  }
4007 
4008  d_dispatcher->doCallbacksFor(
4009  d_dispatcher->registerType(vrpn_got_connection),
4010  d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
4011 
4012  if (d_connectionCounter) {
4013  (*d_connectionCounter)++;
4014  }
4015 
4016  delete[] recvbuf;
4017  return 0;
4018 }
4019 
4020 int vrpn_Endpoint_IP::getOneTCPMessage(int fd, char *buf, size_t buflen)
4021 {
4022  vrpn_int32 header[5];
4023  struct timeval time;
4024  vrpn_int32 sender, type;
4025  size_t len, payload_len, ceil_len;
4026  int retval;
4027 
4028 #ifdef VERBOSE2
4029  fprintf(stderr,
4030  "vrpn_Endpoint::handle_tcp_messages(): something to read\n");
4031 #endif
4032 
4033  // Read and parse the header
4034  if (vrpn_noint_block_read(fd, (char *)header, sizeof(header)) !=
4035  sizeof(header)) {
4036  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
4037  "Can't read header (this is normal when a connection "
4038  "is dropped)\n");
4039  return -1;
4040  }
4041  len = ntohl(header[0]);
4042  time.tv_sec = ntohl(header[1]);
4043  time.tv_usec = ntohl(header[2]);
4044  sender = ntohl(header[3]);
4045  type = ntohl(header[4]);
4046 #ifdef VERBOSE2
4047  fprintf(stderr, " header: Len %d, Sender %d, Type %d\n", (int)len,
4048  (int)sender, (int)type);
4049 #endif
4050 
4051  // skip up to alignment
4052  vrpn_int32 header_len = sizeof(header);
4053  if (header_len % vrpn_ALIGN) {
4054  header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4055  }
4056  if (header_len > static_cast<vrpn_int32>(sizeof(header))) {
4057  // the difference can be no larger than this
4058  char rgch[vrpn_ALIGN];
4059  if (vrpn_noint_block_read(fd, (char *)rgch,
4060  header_len - sizeof(header)) !=
4061  (int)(header_len - sizeof(header))) {
4062  fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
4063  "Can't read header + alignment\n");
4064  return -1;
4065  }
4066  }
4067 
4068  // Figure out how long the message body is, and how long it
4069  // is including any padding to make sure that it is a
4070  // multiple of four bytes long.
4071  payload_len = len - header_len;
4072  ceil_len = payload_len;
4073  if (ceil_len % vrpn_ALIGN) {
4074  ceil_len += vrpn_ALIGN - ceil_len % vrpn_ALIGN;
4075  }
4076 
4077  // Make sure the buffer is long enough to hold the whole
4078  // message body.
4079  if (buflen < ceil_len) {
4080  fprintf(stderr,
4081  "vrpn: vrpn_Endpoint::handle_tcp_messages: Message too long\n");
4082  return -1;
4083  }
4084 
4085  // Read the body of the message
4086  if (vrpn_noint_block_read(fd, buf, ceil_len) != ceil_len) {
4087  perror("vrpn: vrpn_Endpoint::handle_tcp_messages: Can't read body");
4088  return -1;
4089  }
4090 
4091  if (d_inLog->logIncomingMessage(payload_len, time, type, sender, buf)) {
4092  fprintf(stderr, "Couldn't log incoming message.!\n");
4093  return -1;
4094  }
4095 
4096  retval = dispatch(type, sender, time, static_cast<vrpn_uint32>(payload_len),
4097  buf);
4098  if (retval) {
4099  return -1;
4100  }
4101 
4102  return 0;
4103 }
4104 
4105 int vrpn_Endpoint_IP::getOneUDPMessage(char *inbuf_ptr, size_t inbuf_len)
4106 {
4107  vrpn_int32 header[5];
4108  struct timeval time;
4109  vrpn_int32 sender, type;
4110  vrpn_uint32 len, payload_len, ceil_len;
4111  int retval;
4112 
4113  // Read and parse the header
4114  // skip up to alignment
4115  vrpn_uint32 header_len = sizeof(header);
4116  if (header_len % vrpn_ALIGN) {
4117  header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4118  }
4119 
4120  if (header_len > (vrpn_uint32)inbuf_len) {
4121  fprintf(stderr, "vrpn_Endpoint::getOneUDPMessage: Can't read header");
4122  return -1;
4123  }
4124  memcpy(header, inbuf_ptr, sizeof(header));
4125  inbuf_ptr += header_len;
4126  len = ntohl(header[0]);
4127  time.tv_sec = ntohl(header[1]);
4128  time.tv_usec = ntohl(header[2]);
4129  sender = ntohl(header[3]);
4130  type = ntohl(header[4]);
4131 
4132 #ifdef VERBOSE
4133  fprintf(stderr, "Message type %ld (local type %ld), sender %ld received\n",
4134  type, local_type_id(type), sender);
4135  fprintf(stderr, "Message length is %d (buffer length %d).\n", len,
4136  inbuf_len);
4137 #endif
4138 
4139  // Figure out how long the message body is, and how long it
4140  // is including any padding to make sure that it is a
4141  // multiple of vrpn_ALIGN bytes long.
4142  payload_len = len - header_len;
4143  ceil_len = payload_len;
4144  if (ceil_len % vrpn_ALIGN) {
4145  ceil_len += vrpn_ALIGN - ceil_len % vrpn_ALIGN;
4146  }
4147 
4148  // Make sure we received enough to cover the entire payload
4149  if (header_len + ceil_len > (vrpn_uint32)inbuf_len) {
4150  fprintf(stderr, "vrpn_Endpoint::getOneUDPMessage: Can't read payload");
4151  return -1;
4152  }
4153 
4154  if (d_inLog->logIncomingMessage(payload_len, time, type, sender,
4155  inbuf_ptr)) {
4156  fprintf(stderr, "Couldn't log incoming message.!\n");
4157  return -1;
4158  }
4159 
4160  retval = dispatch(type, sender, time, payload_len, inbuf_ptr);
4161  if (retval) {
4162  return -1;
4163  }
4164 
4165  return ceil_len + header_len;
4166 }
4167 
4168 int vrpn_Endpoint::dispatch(vrpn_int32 type, vrpn_int32 sender, timeval time,
4169  vrpn_uint32 payload_len, char *bufptr)
4170 {
4171 
4172  // Call the handler for this message type
4173  // If it returns nonzero, return an error.
4174  if (type >= 0) { // User handler, map to local id
4175 
4176  // Only process if local id has been set.
4177 
4178  if (local_type_id(type) >= 0) {
4179  if (d_dispatcher->doCallbacksFor(local_type_id(type),
4180  local_sender_id(sender), time,
4181  payload_len, bufptr)) {
4182  return -1;
4183  }
4184  }
4185  }
4186  else { // System handler
4187 
4188  if (d_dispatcher->doSystemCallbacksFor(type, sender, time, payload_len,
4189  bufptr, this)) {
4190  fprintf(stderr, "vrpn_Endpoint::dispatch: "
4191  "Nonzero system return\n");
4192  return -1;
4193  }
4194  }
4195 
4196  return 0;
4197 }
4198 
4199 int vrpn_Endpoint::tryToMarshall(char *outbuf, vrpn_int32 &buflen,
4200  vrpn_int32 &numOut, vrpn_uint32 len,
4201  timeval time, vrpn_int32 type,
4202  vrpn_int32 sender, const char *buffer,
4203  vrpn_uint32 sequenceNumber)
4204 {
4205  int retval;
4206 
4207  retval = marshall_message(outbuf, buflen, numOut, len, time, type, sender,
4208  buffer, sequenceNumber);
4209 
4210  // If the marshalling failed, try clearing the outgoing buffers
4211  // by sending the stuff in them to see if this makes enough
4212  // room. If not, we'll have to give up.
4213  if (!retval) {
4214  if (send_pending_reports() != 0) {
4215  return 0;
4216  }
4217  retval = marshall_message(outbuf, buflen, numOut, len, time, type,
4218  sender, buffer, sequenceNumber);
4219  }
4220 
4221  return retval;
4222 }
4223 
4230 // TCH 22 Feb 99
4231 // Marshall the sequence number, but never unmarshall it - it's currently
4232 // only provided for the benefit of sniffers.
4233 
4235  char *outbuf, // Base pointer to the output buffer
4236  vrpn_uint32 outbuf_size, // Total size of the output buffer
4237  vrpn_uint32 initial_out, // How many characters are already in outbuf
4238  vrpn_uint32 len, // Length of the message payload
4239  struct timeval time, // Time the message was generated
4240  vrpn_int32 type, // Type of the message
4241  vrpn_int32 sender, // Sender of the message
4242  const char *buffer, // Message payload
4243  vrpn_uint32 seqNo) // Sequence number
4244 {
4245  vrpn_uint32 ceil_len, header_len, total_len;
4246  vrpn_uint32 curr_out = initial_out; // How many out total so far
4247 
4248  // Compute the length of the message plus its padding to make it
4249  // an even multiple of vrpn_ALIGN bytes.
4250 
4251  // Compute the total message length and put the message
4252  // into the message buffer (if we have room for the whole message)
4253  ceil_len = len;
4254  if (len % vrpn_ALIGN) {
4255  ceil_len += vrpn_ALIGN - len % vrpn_ALIGN;
4256  }
4257  header_len = 5 * sizeof(vrpn_int32);
4258  if (header_len % vrpn_ALIGN) {
4259  header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4260  }
4261  total_len = header_len + ceil_len;
4262  if ((curr_out + total_len) > (vrpn_uint32)outbuf_size) {
4263  return 0;
4264  }
4265 
4266  // fprintf(stderr, " Marshalling message type %d, sender %d, length %d.\n",
4267  // type, sender, len);
4268 
4269  // The packet header len field does not include the padding bytes,
4270  // these are inferred on the other side.
4271  // Later, to make things clearer, we should probably infer the header
4272  // len on the other side (in the same way the padding is done)
4273  // The reason we don't include the padding in the len is that we
4274  // would not be able to figure out the size of the padding on the
4275  // far side)
4276  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(header_len + len);
4277  curr_out += sizeof(vrpn_uint32);
4278 
4279  // Pack the time (using gettimeofday() format) into the buffer
4280  // and do network byte ordering.
4281  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(time.tv_sec);
4282  curr_out += sizeof(vrpn_uint32);
4283  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(time.tv_usec);
4284  curr_out += sizeof(vrpn_uint32);
4285 
4286  // Pack the sender and type and do network byte-ordering
4287  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(sender);
4288  curr_out += sizeof(vrpn_uint32);
4289  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(type);
4290  curr_out += sizeof(vrpn_uint32);
4291 
4292  // Pack the sequence number. If something's really screwy with
4293  // our sizes/types and there isn't room for the sequence number,
4294  // skipping for alignment below will overwrite it!
4295  *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(seqNo);
4296  curr_out += sizeof(vrpn_uint32);
4297 
4298  // skip chars if needed for alignment
4299  curr_out = initial_out + header_len;
4300 
4301  // Pack the message from the buffer. Then skip as many characters
4302  // as needed to make the end of the buffer fall on an even alignment
4303  // of vrpn_ALIGN bytes (the size of largest element sent via vrpn.
4304  if (buffer != NULL) {
4305  memcpy(&outbuf[curr_out], buffer, len);
4306  }
4307  curr_out += ceil_len;
4308 #ifdef VERBOSE
4309  printf("Marshalled: len %d, ceil_len %d: '", len, ceil_len);
4310  printf("'\n");
4311 #endif
4312  return curr_out - initial_out; // How many extra bytes we sent
4313 }
4314 
4315 // static
4317 {
4318  vrpn_Endpoint *endpoint = static_cast<vrpn_Endpoint *>(userdata);
4319  cName type_name;
4320  vrpn_int32 i;
4321  vrpn_int32 local_id;
4322 
4323  if (static_cast<unsigned>(p.payload_len) > sizeof(cName)) {
4324  fprintf(stderr, "vrpn: vrpn_Endpoint::handle_type_message: "
4325  "Type name too long\n");
4326  return -1;
4327  }
4328 
4329  // Find out the name of the type (skip the length)
4330  strncpy(type_name, p.buffer + sizeof(vrpn_int32),
4331  p.payload_len - sizeof(vrpn_int32));
4332 
4333  // Use the exact length packed into the start of the buffer
4334  // to figure out where to put the trailing '\0'
4335  i = ntohl(*((vrpn_int32 *)p.buffer));
4336  type_name[i] = '\0';
4337 
4338 #ifdef VERBOSE
4339  printf("Registering other-side type: '%s'\n", type_name);
4340 #endif
4341  // If there is a corresponding local type defined, find the mapping.
4342  local_id = endpoint->d_dispatcher->getTypeID(type_name);
4343  // If not, add this type locally
4344  if (local_id == -1) {
4345  if (endpoint->d_parent != NULL) {
4346  local_id = endpoint->d_parent->register_message_type(type_name);
4347  }
4348 #ifdef VERBOSE
4349  else {
4350  printf("vrpn_Endpoint::handle_type_message: NULL d_parent "
4351  "when trying to auto-register remote message type %s.\n",
4352  type_name);
4353  }
4354 #endif
4355  }
4356  if (endpoint->newRemoteType(type_name, p.sender, local_id) == -1) {
4357  fprintf(stderr, "vrpn: Failed to add remote type %s\n", type_name);
4358  return -1;
4359  }
4360 
4361  return 0;
4362 }
4363 
4364 void vrpn_Endpoint::setLogNames(const char *inName, const char *outName)
4365 {
4366  if (inName != NULL) {
4367  d_inLog->setName(inName);
4368  }
4369  if (outName != NULL) {
4370  d_outLog->setName(outName);
4371  }
4372 }
4373 
4375 {
4376 
4377  if (d_inLog->open()) {
4378  return -1;
4379  }
4380  if (d_outLog->open()) {
4381  return -1;
4382  }
4383 
4384  return 0;
4385 }
4386 
4387 // static
4389 {
4390  vrpn_Endpoint *endpoint = static_cast<vrpn_Endpoint *>(userdata);
4391  cName sender_name;
4392  vrpn_int32 i;
4393  vrpn_int32 local_id;
4394 
4395  if (static_cast<size_t>(p.payload_len) > sizeof(cName)) {
4396  fprintf(stderr, "vrpn: vrpn_Endpoint::handle_sender_message():Sender "
4397  "name too long\n");
4398  return -1;
4399  }
4400 
4401  // Find out the name of the sender (skip the length)
4402  strncpy(sender_name, p.buffer + sizeof(vrpn_int32),
4403  p.payload_len - sizeof(vrpn_int32));
4404 
4405  // Use the exact length packed into the start of the buffer
4406  // to figure out where to put the trailing '\0'
4407  i = ntohl(*((vrpn_int32 *)p.buffer));
4408  sender_name[i] = '\0';
4409 
4410 #ifdef VERBOSE
4411  printf("Registering other-side sender: '%s'\n", sender_name);
4412 #endif
4413  // If there is a corresponding local sender defined, find the mapping.
4414  local_id = endpoint->d_dispatcher->getSenderID(sender_name);
4415  // If not, add this sender locally
4416  if (local_id == -1) {
4417  if (endpoint->d_parent != NULL) {
4418  local_id = endpoint->d_parent->register_sender(sender_name);
4419  }
4420 #ifdef VERBOSE
4421  else {
4422  printf("vrpn_Endpoint::handle_sender_message: NULL d_parent "
4423  "when trying to auto-register remote message sender %s\n",
4424  sender_name);
4425  }
4426 #endif
4427  }
4428  if (endpoint->newRemoteSender(sender_name, p.sender, local_id) == -1) {
4429  fprintf(stderr, "vrpn: Failed to add remote sender %s\n", sender_name);
4430  return -1;
4431  }
4432 
4433  return 0;
4434 }
4435 
4437 {
4438  struct timeval now;
4439 
4440  // need to pack the null char as well
4441  vrpn_uint32 len =
4442  static_cast<vrpn_int32>(strlen(d_dispatcher->typeName(which)) + 1);
4443  vrpn_uint32 netlen;
4444  char buffer[sizeof(len) + sizeof(cName)];
4445 
4446  netlen = htonl(len);
4447 // Pack a message with type vrpn_CONNECTION_TYPE_DESCRIPTION
4448 // whose sender ID is the ID of the type that is being
4449 // described and whose body contains the length of the name
4450 // and then the name of the type.
4451 
4452 #ifdef VERBOSE
4453  printf(" vrpn_Connection: Packing type '%s', %d\n",
4454  d_dispatcher->typeName(which), which);
4455 #endif
4456  memcpy(buffer, &netlen, sizeof(netlen));
4457  memcpy(&buffer[sizeof(len)], d_dispatcher->typeName(which),
4458  (vrpn_int32)len);
4459  vrpn_gettimeofday(&now, NULL);
4460 
4461  return pack_message((vrpn_uint32)(len + sizeof(len)), now,
4462  vrpn_CONNECTION_TYPE_DESCRIPTION, which, buffer,
4464 }
4465 
4467 {
4468  struct timeval now;
4469 
4470  // need to pack the null char as well
4471  vrpn_uint32 len =
4472  static_cast<vrpn_int32>(strlen(d_dispatcher->senderName(which)) + 1);
4473  vrpn_uint32 netlen;
4474  char buffer[sizeof(len) + sizeof(cName)];
4475 
4476  netlen = htonl(len);
4477 // Pack a message with type vrpn_CONNECTION_SENDER_DESCRIPTION
4478 // whose sender ID is the ID of the sender that is being
4479 // described and whose body contains the length of the name
4480 // and then the name of the sender.
4481 
4482 #ifdef VERBOSE
4483  printf(" vrpn_Connection: Packing sender '%s'\n",
4484  d_dispatcher->senderName(which));
4485 #endif
4486  memcpy(buffer, &netlen, sizeof(netlen));
4487  memcpy(&buffer[sizeof(len)], d_dispatcher->senderName(which),
4488  (vrpn_int32)len);
4489  vrpn_gettimeofday(&now, NULL);
4490 
4491  return pack_message((vrpn_uint32)(len + sizeof(len)), now,
4492  vrpn_CONNECTION_SENDER_DESCRIPTION, which, buffer,
4494 }
4495 
4496 static int flush_udp_socket(SOCKET fd)
4497 {
4498  timeval localTimeout;
4499  fd_set readfds, exceptfds;
4500  char buf[10000];
4501  int sel_ret;
4502 
4503  // fprintf(stderr, "flush_udp_socket().\n");
4504 
4505  localTimeout.tv_sec = 0;
4506  localTimeout.tv_usec = 0;
4507 
4508  // Empty out any pending UDP messages by reading the socket and
4509  // then throwing it away.
4510 
4511  do {
4512  // Select to see if ready to hear from server, or exception
4513  FD_ZERO(&readfds); /* Clear the descriptor sets */
4514  FD_ZERO(&exceptfds);
4515  FD_SET(fd, &readfds); /* Check for read */
4516  FD_SET(fd, &exceptfds); /* Check for exceptions */
4517  sel_ret = vrpn_noint_select(static_cast<int>(fd) + 1, &readfds, NULL,
4518  &exceptfds, &localTimeout);
4519  if (sel_ret == -1) {
4520  fprintf(stderr, "flush_udp_socket: select failed().");
4521  return -1;
4522  }
4523 
4524  // See if exceptional condition on socket
4525  if (FD_ISSET(fd, &exceptfds)) {
4526  fprintf(stderr, "flush_udp_socket: Exception on socket.\n");
4527  return -1;
4528  }
4529 
4530  // If there is anything to read, get the next message
4531  if (FD_ISSET(fd, &readfds)) {
4532  int inbuf_len;
4533 
4534  inbuf_len = recv(fd, buf, 10000, 0);
4535  if (inbuf_len == -1) {
4536  fprintf(stderr, "flush_udp_socket: recv() failed.\n");
4537  return -1;
4538  }
4539  }
4540 
4541  } while (sel_ret);
4542 
4543  return 0;
4544 }
4545 
4547 {
4548  int retval;
4549  int i;
4550 
4551  for (i = 0; i < d_numEndpoints; i++) {
4552  if (d_endpoints[i]) {
4553  retval = d_endpoints[i]->pack_type_description(which);
4554  if (retval) {
4555  return -1;
4556  }
4557  }
4558  }
4559 
4560  return 0;
4561 }
4562 
4564 {
4565  int retval;
4566  int i;
4567 
4568  for (i = 0; i < d_numEndpoints; i++) {
4569  if (d_endpoints[i]) {
4570  retval = d_endpoints[i]->pack_sender_description(which);
4571  if (retval) {
4572  return -1;
4573  }
4574  }
4575  }
4576 
4577  return 0;
4578 }
4579 
4580 // static
4582 {
4583  vrpn_Endpoint *endpoint = (vrpn_Endpoint *)userdata;
4584  int retval = 0;
4585  vrpn_int32 inNameLen, outNameLen;
4586  const char **bp = &p.buffer;
4587 
4588  // TCH 16 Feb 01
4589  vrpn_unbuffer(bp, &inNameLen);
4590  vrpn_unbuffer(bp, &outNameLen);
4591 
4592  // must deal properly with only opening one log file
4593  // the log message contains "" (an empty string) if
4594  // there is no desire to log that file.
4595  endpoint->setLogNames(inNameLen == 0 ? NULL : *bp,
4596  outNameLen == 0 ? NULL : *bp + inNameLen + 1);
4597  if (inNameLen > 0) retval = endpoint->d_inLog->open();
4598  if (outNameLen > 0) retval = endpoint->d_outLog->open();
4599 
4600  // Safety check:
4601  // If we can't log when the client asks us to, close the connection.
4602  // Something more talkative would be useful.
4603  // The problem with implementing this is that it's over-strict: clients
4604  // that assume logging succeeded unless the connection was dropped
4605  // will be running on the wrong assumption if we later change this to
4606  // be a notification message.
4607 
4608  if (retval == -1) {
4609  // Will be dropped automatically on next pass through mainloop
4610  endpoint->status = BROKEN;
4611  }
4612  else {
4613  fprintf(stderr, "vrpn_Connection::handle_log_message: "
4614  "Remote connection requested logging.\n");
4615  }
4616 
4617  // OR the remotely-requested logging mode with whatever we've
4618  // been told to do locally
4619  if (p.sender & vrpn_LOG_INCOMING) {
4620  endpoint->d_inLog->logMode() |= vrpn_LOG_INCOMING;
4621  }
4622  if (p.sender & vrpn_LOG_OUTGOING) {
4623  endpoint->d_outLog->logMode() |= vrpn_LOG_OUTGOING;
4624  }
4625 
4626  return retval;
4627 }
4628 
4629 // Pack a message to all open endpoints. If the pack fails for any of
4630 // the endpoints, return failure.
4631 
4632 int vrpn_Connection::pack_message(vrpn_uint32 len, struct timeval time,
4633  vrpn_int32 type, vrpn_int32 sender,
4634  const char *buffer,
4635  vrpn_uint32 class_of_service)
4636 {
4637  int i, ret;
4638 
4639  // Make sure I'm not broken
4640  if (connectionStatus == BROKEN) {
4641  printf("vrpn_Connection::pack_message: Can't pack because the "
4642  "connection is broken\n");
4643  return -1;
4644  }
4645 
4646  // Make sure type is either a system type (-) or a legal user type
4647  if (type >= d_dispatcher->numTypes()) {
4648  printf("vrpn_Connection::pack_message: bad type (%d)\n", type);
4649  return -1;
4650  }
4651 
4652  // If this is not a system message, make sure the sender is legal.
4653  if (type >= 0) {
4654  if ((sender < 0) || (sender >= d_dispatcher->numSenders())) {
4655  printf("vrpn_Connection::pack_message: bad sender (%d)\n", sender);
4656  return -1;
4657  }
4658  }
4659 
4660  // Pack the message to all open endpoints This must be done before
4661  // yanking local callbacks in order to have message delivery be the
4662  // same on local and remote systems in the case where a local handler
4663  // packs one or more messages in response to this message.
4664  ret = 0;
4665  for (i = 0; i < d_numEndpoints; i++) {
4666  if (d_endpoints[i] &&
4667  (d_endpoints[i]->pack_message(len, time, type, sender, buffer,
4668  class_of_service) != 0)) {
4669  ret = -1;
4670  }
4671  }
4672 
4673  // See if there are any local handlers for this message type from
4674  // this sender. If so, yank the callbacks. This needs to be done
4675  // AFTER the message is packed to open endpoints so that messages
4676  // will be sent in the same order from local and remote senders
4677  // (since a local message handler may pack its own messages before
4678  // returning).
4679 
4680  if (do_callbacks_for(type, sender, time, len, buffer)) {
4681  return -1;
4682  }
4683 
4684  return ret;
4685 }
4686 
4687 // Returns the time since the connection opened.
4688 // Some subclasses may redefine time.
4689 
4690 // virtual
4691 int vrpn_Connection::time_since_connection_open(struct timeval *elapsed_time)
4692 {
4693  struct timeval now;
4694  vrpn_gettimeofday(&now, NULL);
4695  *elapsed_time = vrpn_TimevalDiff(now, start_time);
4696 
4697  return 0;
4698 }
4699 
4700 // returns the current time in the connection since the epoch (UTC time).
4701 // virtual
4703 {
4704  struct timeval now;
4705  vrpn_gettimeofday(&now, NULL);
4706  return now;
4707 }
4708 
4709 // Returns the name of the specified sender/type, or NULL
4710 // if the parameter is invalid.
4711 // virtual
4712 const char *vrpn_Connection::sender_name(vrpn_int32 sender)
4713 {
4714  return d_dispatcher->senderName(sender);
4715 }
4716 
4717 // virtual
4718 const char *vrpn_Connection::message_type_name(vrpn_int32 type)
4719 {
4720  return d_dispatcher->typeName(type);
4721 }
4722 
4723 // virtual
4725 {
4726  int i;
4727  for (i = 0; i < d_numEndpoints; i++) {
4728  d_endpoints[i]->d_inLog->addFilter(filter, userdata);
4729  d_endpoints[i]->d_outLog->addFilter(filter, userdata);
4730  }
4731  return 0;
4732 }
4733 
4734 // virtual
4736 {
4737  int i;
4738  int final_retval = 0;
4739  for (i = 0; i < d_numEndpoints; i++) {
4740  final_retval |= d_endpoints[i]->d_inLog->saveLogSoFar();
4741  final_retval |= d_endpoints[i]->d_outLog->saveLogSoFar();
4742  }
4743  return final_retval;
4744 }
4745 
4746 // virtual
4748 {
4749  return NULL;
4750 }
4751 
4753 {
4754  vrpn_int32 i;
4755 
4756  // Lots of constants used to be set up here. They were moved
4757  // into the constructors in 02.10; this will create a slight
4758  // increase in maintenance burden keeping the constructors consistient.
4759 
4760  for (i = 0; i < vrpn_MAX_ENDPOINTS; i++) {
4761  d_endpoints[i] = NULL;
4762  }
4763 
4764  vrpn_gettimeofday(&start_time, NULL);
4765 
4767 
4768  // These should be among the first senders & types sent over the wire
4769  d_dispatcher->registerSender(vrpn_CONTROL);
4770  d_dispatcher->registerType(vrpn_got_first_connection);
4771  d_dispatcher->registerType(vrpn_got_connection);
4772  d_dispatcher->registerType(vrpn_dropped_connection);
4774 
4781 
4783 }
4784 
4789 int vrpn_Connection::delete_endpoint(int endpointIndex)
4790 {
4791 
4792  vrpn_Endpoint *endpoint = d_endpoints[endpointIndex];
4793 
4794  if (endpoint) {
4795  delete endpoint;
4796  }
4797  d_endpoints[endpointIndex] = NULL;
4798 
4799  return 0;
4800 }
4801 
4807 {
4808  int i;
4809 
4810  for (i = 0; i < d_numEndpoints; i++) {
4811  if (!d_endpoints[i]) {
4813  d_endpoints[d_numEndpoints - 1] = NULL;
4814 
4815  d_numEndpoints--;
4816  }
4817  }
4818 
4819  return 0;
4820 }
4821 
4822 // Set up to be a server connection, creating a logging connection if
4823 // asked for.
4824 vrpn_Connection::vrpn_Connection(const char *local_in_logfile_name,
4825  const char *local_out_logfile_name,
4827  vrpn_int32 *))
4828  : d_numEndpoints(0)
4829  , d_numConnectedEndpoints(0)
4830  , d_references(0)
4831  , d_autoDeleteStatus(false)
4832  , d_dispatcher(NULL)
4833  , d_serverLogCount(0)
4834  , d_serverLogMode(
4835  (local_in_logfile_name ? vrpn_LOG_INCOMING : vrpn_LOG_NONE) |
4836  (local_out_logfile_name ? vrpn_LOG_OUTGOING : vrpn_LOG_NONE))
4837  , d_serverLogName(NULL)
4838  , d_endpointAllocator(epa)
4839  , d_updateEndpoint(vrpn_FALSE)
4840 {
4841  int retval;
4842  vrpn_Endpoint *endpoint; // shorthand for d_endpoints[0]
4843 
4844  // Initialize the things that must be for any constructor
4846 
4847  // Server connections should handle log messages.
4850 
4851  if (local_out_logfile_name) {
4852  d_endpoints[0] = (*d_endpointAllocator)(this, NULL);
4853  if (!d_endpoints[0]) {
4854  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4855  "Couldn't create endpoint for log file.\n",
4856  __LINE__);
4858  return;
4859  }
4860  endpoint = d_endpoints[0];
4861  endpoint->setConnection(this);
4862  d_updateEndpoint = vrpn_TRUE;
4863  endpoint->d_outLog->setName(local_out_logfile_name);
4864  endpoint->d_outLog->logMode() = d_serverLogMode;
4865  retval = endpoint->d_outLog->open();
4866  if (retval == -1) {
4867  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4868  "Couldn't open outgoing log file.\n",
4869  __LINE__);
4870  delete d_endpoints[0];
4871  d_endpoints[0] = NULL;
4873  return;
4874  }
4875  d_numEndpoints = 1;
4876  endpoint->d_remoteLogMode = vrpn_LOG_NONE;
4877  endpoint->d_remoteInLogName = new char[10];
4878  strcpy(endpoint->d_remoteInLogName, "");
4879  endpoint->d_remoteOutLogName = new char[10];
4880  strcpy(endpoint->d_remoteOutLogName, "");
4881  // Outgoing messages are logged regardless of connection status.
4882  endpoint->status = LOGGING;
4883  }
4884 
4885  if (local_in_logfile_name) {
4886  d_serverLogName = new char[1 + strlen(local_in_logfile_name)];
4887  if (!d_serverLogName) {
4888  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4889  "Out of memory.\n",
4890  __LINE__);
4892  return;
4893  }
4894  strcpy(d_serverLogName, local_in_logfile_name);
4895  }
4896 }
4897 
4899  const char *local_in_logfile_name, const char *local_out_logfile_name,
4900  const char *remote_in_logfile_name, const char *remote_out_logfile_name,
4901  vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
4902  : connectionStatus(BROKEN)
4903  , // default value if not otherwise set in ctr
4904  d_numEndpoints(0)
4905  , d_numConnectedEndpoints(0)
4906  , d_references(0)
4907  , d_autoDeleteStatus(false)
4908  , d_dispatcher(NULL)
4909  , d_serverLogCount(0)
4910  , d_serverLogMode(vrpn_LOG_NONE)
4911  , d_serverLogName(NULL)
4912  , d_endpointAllocator(epa)
4913  , d_updateEndpoint(vrpn_FALSE)
4914 {
4915  vrpn_Endpoint *endpoint;
4916  int retval;
4917 
4918  // Initialize the things that must be for any constructor
4920 
4921  // We're a client; create our single endpoint and initialize it.
4922  d_endpoints[0] = (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
4923  d_endpoints[0]->setConnection(this);
4924  d_updateEndpoint = vrpn_TRUE;
4925  if (!d_endpoints[0]) {
4926  fprintf(stderr, "vrpn_Connection:%d Out of memory.\n", __LINE__);
4928  return;
4929  }
4930 
4931  d_numEndpoints = 1;
4932  endpoint = d_endpoints[0]; // shorthand
4933 
4934  // Store the remote log file name and the remote log mode
4935  endpoint->d_remoteLogMode =
4936  (((remote_in_logfile_name && strlen(remote_in_logfile_name) > 0)
4938  : vrpn_LOG_NONE) |
4939  ((remote_out_logfile_name && strlen(remote_out_logfile_name) > 0)
4941  : vrpn_LOG_NONE));
4942  if (!remote_in_logfile_name) {
4943  endpoint->d_remoteInLogName = new char[10];
4944  strcpy(endpoint->d_remoteInLogName, "");
4945  }
4946  else {
4947  endpoint->d_remoteInLogName =
4948  new char[strlen(remote_in_logfile_name) + 1];
4949  strcpy(endpoint->d_remoteInLogName, remote_in_logfile_name);
4950  }
4951 
4952  if (!remote_out_logfile_name) {
4953  endpoint->d_remoteOutLogName = new char[10];
4954  strcpy(endpoint->d_remoteOutLogName, "");
4955  }
4956  else {
4957  endpoint->d_remoteOutLogName =
4958  new char[strlen(remote_out_logfile_name) + 1];
4959  strcpy(endpoint->d_remoteOutLogName, remote_out_logfile_name);
4960  }
4961 
4962  // If we are doing local logging, turn it on here. If we
4963  // can't open the file, then the connection is broken.
4964 
4965  if (local_in_logfile_name && (strlen(local_in_logfile_name) != 0)) {
4966  endpoint->d_inLog->setName(local_in_logfile_name);
4967  endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
4968  retval = endpoint->d_inLog->open();
4969  if (retval == -1) {
4970  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4971  "Couldn't open incoming log file.\n",
4972  __LINE__);
4974  // fprintf(stderr, "BROKEN - vrpn_Connection::vrpn_Connection.\n");
4975  return;
4976  }
4977  // fprintf(stderr, "vrpn_Connection: opened logfile.\n");
4978  }
4979 
4980  if (local_out_logfile_name && (strlen(local_out_logfile_name) != 0)) {
4981  endpoint->d_outLog->setName(local_out_logfile_name);
4982  endpoint->d_outLog->logMode() = vrpn_LOG_OUTGOING;
4983  retval = endpoint->d_outLog->open();
4984  if (retval == -1) {
4985  fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4986  "Couldn't open local outgoing log file.\n",
4987  __LINE__);
4989  // fprintf(stderr, "BROKEN - vrpn_Connection::vrpn_Connection.\n");
4990  return;
4991  }
4992  // fprintf(stderr, "vrpn_Connection: opened logfile.\n");
4993  }
4994 }
4995 
4997 {
4998 
4999  // Clean up types, senders, and callbacks.
5000  if (d_dispatcher) {
5001  delete d_dispatcher;
5002  d_dispatcher = NULL;
5003  }
5004 
5005  if (d_references > 0) {
5006  fprintf(stderr,
5007  "Connection was deleted while %d references still remain.\n",
5008  d_references);
5009  }
5010 }
5011 
5012 // Some object is now using this connection.
5013 void vrpn_Connection::addReference() { d_references++; }
5014 
5015 // Some object has stopped using this connection. Decrement the ref counter.
5016 // If there aren't any references, this connection is no longer in use.
5017 // Once it's no longer in use destroy the connection iff d_autoDeleteStatus
5018 // has been set to TRUE. If d_autoDeleteStatus is FALSE, the user must
5019 // destroy the connection explicitly.
5021 {
5022  d_references--;
5023  if (d_references == 0 && d_autoDeleteStatus == true) {
5024  delete this;
5025  }
5026  else if (d_references < 0) { // this shouldn't happen.
5027  // sanity check
5028  fprintf(stderr, "Negative reference count. This shouldn't happen.");
5029  }
5030 }
5031 
5032 vrpn_int32 vrpn_Connection::register_sender(const char *name)
5033 {
5034  vrpn_int32 retval;
5035  vrpn_int32 i;
5036 
5037 #ifdef VERBOSE
5038  fprintf(stderr, "vrpn_Connection::register_sender: "
5039  "%d senders; new name \"%s\"\n",
5040  d_dispatcher->numSenders(), name);
5041 #endif
5042 
5043  // See if the name is already in the list. If so, return it.
5044  retval = d_dispatcher->getSenderID(name);
5045  if (retval != -1) {
5046 #ifdef VERBOSE
5047  fprintf(stderr, "Sender already defined as id %d.\n", retval);
5048 #endif
5049  return retval;
5050  }
5051 
5052  retval = d_dispatcher->addSender(name);
5053 
5054 #ifdef VERBOSE
5055  fprintf(stderr, "Packing sender description for %s, type %d.\n", name,
5056  retval);
5057 #endif
5058 
5059  // Pack the sender description.
5060  // TCH 24 Jan 00 - Need to do this even if not connected so
5061  // that it goes into the logs (if we're keeping any).
5062  pack_sender_description(retval);
5063 
5064  // If the other side has declared this sender, establish the
5065  // mapping for it.
5066  for (i = 0; i < d_numEndpoints; i++) {
5067  d_endpoints[i]->newLocalSender(name, retval);
5068  }
5069 
5070  // One more in place -- return its index
5071  return retval;
5072 }
5073 
5074 vrpn_int32 vrpn_Connection::register_message_type(const char *name)
5075 {
5076  vrpn_int32 retval;
5077  vrpn_int32 i;
5078 
5079 #ifdef VERBOSE
5080  fprintf(stderr, "vrpn_Connection::register_message_type: "
5081  "%d type; new name \"%s\"\n",
5082  d_dispatcher->numTypes(), name);
5083 #endif
5084 
5085  // See if the name is already in the list. If so, return it.
5086  retval = d_dispatcher->getTypeID(name);
5087  if (retval != -1) {
5088 #ifdef VERBOSE
5089  fprintf(stderr, "Type already defined as id %d.\n", retval);
5090 #endif
5091  return retval;
5092  }
5093 
5094  retval = d_dispatcher->addType(name);
5095 
5096 // Pack the type description.
5097 // TCH 24 Jan 00 - Need to do this even if not connected so
5098 // that it goes into the logs (if we're keeping any).
5099 
5100 #ifdef VERBOSE
5101  fprintf(stderr, "Packing type description for %s, type %d.\n", name,
5102  retval);
5103 #endif
5104 
5105  pack_type_description(retval);
5106 
5107  // If the other side has declared this type, establish the
5108  // mapping for it.
5109  for (i = 0; i < d_numEndpoints; i++) {
5110  d_endpoints[i]->newLocalType(name, retval);
5111  }
5112 
5113  // One more in place -- return its index
5114  return retval;
5115 }
5116 
5117 // Yank the callback chain for a message type. Call all handlers that
5118 // are interested in messages from this sender. Return 0 if they all
5119 // return 0, -1 otherwise.
5120 
5121 int vrpn_Connection::do_callbacks_for(vrpn_int32 type, vrpn_int32 sender,
5122  struct timeval time,
5123  vrpn_uint32 payload_len, const char *buf)
5124 {
5125  return d_dispatcher->doCallbacksFor(type, sender, time, payload_len, buf);
5126 }
5127 
5129 {
5130  return d_dispatcher->doSystemCallbacksFor(p, ud);
5131 }
5132 
5133 void vrpn_Connection::get_log_names(char **local_in_logname,
5134  char **local_out_logname,
5135  char **remote_in_logname,
5136  char **remote_out_logname)
5137 {
5138  if (!(d_endpoints[0])) return;
5139  vrpn_Endpoint *endpoint = d_endpoints[0];
5140  // XXX it is possible to have more than one endpoint, and other endpoints
5141  // may have other log names
5142 
5143  if (local_in_logname != NULL)
5144  *local_in_logname = endpoint->d_inLog->getName();
5145  if (local_out_logname != NULL)
5146  *local_out_logname = endpoint->d_outLog->getName();
5147 
5148  if (remote_in_logname != NULL) {
5149  if (endpoint->d_remoteInLogName != NULL) {
5150  *remote_in_logname =
5151  new char[strlen(endpoint->d_remoteInLogName) + 1];
5152  strcpy(*remote_in_logname, endpoint->d_remoteInLogName);
5153  }
5154  else {
5155  *remote_in_logname = NULL;
5156  }
5157  }
5158 
5159  if (remote_out_logname != NULL) {
5160  if (endpoint->d_remoteOutLogName != NULL) {
5161  *remote_out_logname =
5162  new char[strlen(endpoint->d_remoteOutLogName) + 1];
5163  strcpy(*remote_out_logname, endpoint->d_remoteOutLogName);
5164  }
5165  else {
5166  *remote_out_logname = NULL;
5167  }
5168  }
5169 }
5170 
5171 // virtual
5173 
5174 // static
5176  vrpn_int32 *connectedEC)
5177 {
5178  return new vrpn_Endpoint_IP(me->d_dispatcher, connectedEC);
5179 }
5180 
5181 // This is called when a disconnect message is found in the logfile.
5182 // It causes the other-side sender and type messages to be cleared,
5183 // in anticipation of a possible new set of messages caused by a
5184 // reconnected server.
5185 
5188 {
5189  vrpn_Endpoint *endpoint = (vrpn_Endpoint *)userdata;
5190 
5191 #ifdef VERBOSE
5192  printf("Just read disconnect message from logfile\n");
5193 #endif
5194  endpoint->clear_other_senders_and_types();
5195 
5196  return 0;
5197 }
5198 
5200  vrpn_MESSAGEHANDLER handler,
5201  void *userdata, vrpn_int32 sender)
5202 {
5203  return d_dispatcher->addHandler(type, handler, userdata, sender);
5204 }
5205 
5207  vrpn_MESSAGEHANDLER handler,
5208  void *userdata, vrpn_int32 sender)
5209 {
5210  return d_dispatcher->removeHandler(type, handler, userdata, sender);
5211 }
5212 
5214 {
5215  return d_dispatcher->getTypeID(name);
5216 }
5217 
5218 // Changed 8 November 1999 by TCH
5219 // With multiple connections allowed, TRYING_TO_CONNECT is an
5220 // "ok" status, so we need to admit it. (Used to check >= 0)
5221 // XXX What if one endpoint is BROKEN? Don't we need to loop?
5222 vrpn_bool vrpn_Connection::doing_okay(void) const
5223 {
5224 
5225  int endpointIndex;
5226 
5227  for (endpointIndex = 0; endpointIndex < d_numEndpoints; endpointIndex++) {
5228  if (d_endpoints[endpointIndex] &&
5229  (!d_endpoints[endpointIndex]->doing_okay())) {
5230  return VRPN_FALSE;
5231  }
5232  }
5233  return (connectionStatus > BROKEN);
5234 }
5235 
5236 // Loop over endpoints and return TRUE if any of them are connected.
5237 vrpn_bool vrpn_Connection::connected(void) const
5238 {
5239  int endpointIndex;
5240 
5241  for (endpointIndex = 0; endpointIndex < d_numEndpoints; endpointIndex++) {
5242  if (d_endpoints[endpointIndex] &&
5243  (d_endpoints[endpointIndex]->status == CONNECTED)) {
5244  return VRPN_TRUE;
5245  }
5246  }
5247  return VRPN_FALSE;
5248 }
5249 
5250 //------------------------------------------------------------------------
5251 // This section holds data structures and functions to open
5252 // connections by name.
5253 // The intention of this section is that it can open connections for
5254 // objects that are of different types (trackers, buttons and sound),
5255 // even if they all refer to the same connection.
5256 
5257 // This routine will return a pointer to the connection whose name
5258 // is passed in. If the routine is called multiple times with the same
5259 // name, it will return the same pointer, rather than trying to make
5260 // multiple of the same connection (unless force_connection = true).
5261 // If the connection is in a bad way, it returns NULL.
5262 // This routine will strip off any part of the string before and
5263 // including the '@' character, considering this to be the local part
5264 // of a device name, rather than part of the connection name. This allows
5265 // the opening of a connection to "Tracker0@ioglab" for example, which will
5266 // open a connection to ioglab.
5267 
5268 // This routine adds to the reference count of the connection in question.
5269 // This happens regardless of whether the connection already exists
5270 // or it is to be created.
5271 // Any user code that calls vrpn_get_connection_by_name() directly
5272 // should call vrpn_Connection::removeReference() when it is finished
5273 // with the pointer. It's ok if you have old code that doesn't do this;
5274 // it just means the connection will remain open until the program quits,
5275 // which isn't so bad.
5276 
5278  const char *cname, const char *local_in_logfile_name,
5279  const char *local_out_logfile_name, const char *remote_in_logfile_name,
5280  const char *remote_out_logfile_name, const char *NIC_IPaddress,
5281  bool force_connection)
5282 {
5283  if (cname == NULL) {
5284  fprintf(stderr, "vrpn_get_connection_by_name(): NULL name\n");
5285  return NULL;
5286  }
5287 
5288  // Find the relevant part of the name (skip past last '@'
5289  // if there is one)
5290  const char *where_at; // Part of name past last '@'
5291  if ((where_at = strrchr(cname, '@')) != NULL) {
5292  cname = where_at + 1; // Chop off the front of the name
5293  }
5294 
5295  vrpn_Connection *c = NULL;
5296  if (!force_connection) {
5298  }
5299 
5300  // If its not already open, open it.
5301  // Its constructor will add it to the list (?).
5302  if (!c) {
5303 
5304  // connections now self-register in the known list --
5305  // this is kind of odd, but oh well (can probably be done
5306  // more cleanly later).
5307 
5308  int is_file = !strncmp(cname, "file:", 5);
5309 
5310  if (is_file) {
5311  c = new vrpn_File_Connection(cname, local_in_logfile_name,
5312  local_out_logfile_name);
5313  } else {
5314  int port = vrpn_get_port_number(cname);
5315  c = new vrpn_Connection_IP(
5316  cname, port, local_in_logfile_name, local_out_logfile_name,
5317  remote_in_logfile_name, remote_out_logfile_name, NIC_IPaddress);
5318  }
5319 
5320  if (c) { // creation succeeded
5321  c->setAutoDeleteStatus(true); // destroy when refcount hits zero.
5322  }
5323  else { // creation failed
5324  fprintf(stderr, "Could not create new connection.");
5325  return NULL;
5326  }
5327  }
5328  // else the connection was already open.
5329 
5330  c->addReference(); // increment the reference count either way.
5331 
5332  // Return a pointer to the connection, even if it is not doing
5333  // okay. This will allow a connection to retry over and over
5334  // again before connecting to the server.
5335  return c;
5336 }
5337 
5338 // Create a server connection that will listen for client connections.
5339 // To create a VRPN TCP/UDP server, use a name like:
5340 // x-vrpn:machine_name_or_ip:port
5341 // x-vrpn::port
5342 // machine_name_or_ip:port
5343 // machine_name_or_ip
5344 // :port
5345 // To create a loopback (networkless) server, use the name:
5346 // loopback:
5347 // To create an MPI server, use a name like:
5348 // mpi:MPI_COMM_WORLD
5349 // mpi:comm_number
5350 //
5351 // This routine will strip off any part of the string before and
5352 // including the '@' character, considering this to be the local part
5353 // of a device name, rather than part of the connection name. This allows
5354 // the opening of a connection to "Tracker0@ioglab" for example, which will
5355 // open a connection to ioglab.
5356 
5359  const char *local_in_logfile_name,
5360  const char *local_out_logfile_name)
5361 {
5362  vrpn_Connection *c = NULL;
5363 
5364  // Parse the name to find out what kind of connection we are to make.
5365  if (cname == NULL) {
5366  fprintf(stderr, "vrpn_create_server_connection(): NULL name\n");
5367  return NULL;
5368  }
5369  char *location = vrpn_copy_service_location(cname);
5370  if (location == NULL) {
5371  return NULL;
5372  }
5373  int is_loopback = !strncmp(cname, "loopback:", 9);
5374  int is_mpi = !strncmp(cname, "mpi:", 4);
5375  if (is_mpi) {
5376 #ifdef VRPN_USE_MPI
5377  XXX_implement_MPI_server_connection;
5378 #else
5379  fprintf(stderr, "vrpn_create_server_connection(): MPI support not "
5380  "compiled in. Set VRPN_USE_MPI in vrpn_Configure.h "
5381  "and recompile.\n");
5382  delete[] location;
5383  return NULL;
5384 #endif
5385  } else if (is_loopback) {
5386  c = new vrpn_Connection_Loopback();
5387  } else {
5388  // Not Loopback or MPI port, so we presume that we are a standard VRPN UDP/TCP
5389  // port. Open that kind, based on the machine and port name. If we
5390  // don't
5391  // have a machine name, then we pass NULL to the NIC address. If we do
5392  // have
5393  // one, we pass it to the NIC address.
5394  if (strlen(location) == 0) {
5396  local_in_logfile_name,
5397  local_out_logfile_name);
5398  }
5399  else {
5400  // Find machine name and port number. Port number returns default
5401  // if there is not one specified. If the machine name is zero
5402  // length
5403  // (just got :port) then use NULL, which means the default NIC.
5404  char *machine = vrpn_copy_machine_name(location);
5405  if (strlen(machine) == 0) {
5406  delete[] machine;
5407  machine = NULL;
5408  }
5409  unsigned short port =
5410  static_cast<unsigned short>(vrpn_get_port_number(location));
5411  c = new vrpn_Connection_IP(port, local_in_logfile_name,
5412  local_out_logfile_name, machine);
5413  if (machine) {
5414  delete[] machine;
5415  }
5416  }
5417  }
5418  delete[] location;
5419 
5420  if (!c) { // creation failed
5421  fprintf(stderr, "vrpn_create_server_connection(): Could not create new "
5422  "connection.");
5423  return NULL;
5424  }
5425 
5426  c->setAutoDeleteStatus(true); // destroy when refcount hits zero.
5427  c->addReference(); // increment the reference count for the connection.
5428 
5429  // Return a pointer to the connection, even if it is not doing
5430  // okay. This will allow a connection to retry over and over
5431  // again before connecting to the server.
5432  return c;
5433 }
5434 
5444 int vrpn_Connection_IP::connect_to_client(const char *machine, int port)
5445 {
5446  if (connectionStatus != LISTEN) {
5447  return -1;
5448  };
5449 
5450  int which_end = d_numEndpoints;
5451 
5452  // Make sure that we have room for a new connection
5453  if (which_end >= vrpn_MAX_ENDPOINTS) {
5454  fprintf(stderr, "vrpn_Connection_IP::connect_to_client:"
5455  " Too many existing connections.\n");
5456  return -1;
5457  }
5458 
5459  d_endpoints[which_end] =
5460  (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
5461  d_endpoints[which_end]->setConnection(this);
5462  d_updateEndpoint = vrpn_TRUE;
5463  vrpn_Endpoint_IP *endpoint = d_endpoints[which_end];
5464 
5465  if (!endpoint) {
5466  fprintf(stderr, "vrpn_Connection_IP::connect_to_client:"
5467  " Out of memory on new endpoint\n");
5468  return -1;
5469  }
5470 
5471  char msg[100];
5472  sprintf(msg, "%s %d", machine, port);
5473  printf("vrpn_Connection_IP::connect_to_client: "
5474  "Connection request received: %s\n",
5475  msg);
5476  endpoint->connect_tcp_to(msg);
5477  if (endpoint->status != COOKIE_PENDING) { // Something broke
5478  endpoint->status = BROKEN;
5479  return -1;
5480  }
5481  else {
5482  d_numEndpoints++;
5483  handle_connection(which_end);
5484  }
5485 
5486  return 0;
5487 }
5488 
5490 {
5491 
5492  vrpn_Endpoint *endpoint = d_endpoints[endpointIndex];
5493 
5494  // Set up the things that need to happen when a new connection is
5495  // started.
5496  if (endpoint->setup_new_connection()) {
5497  fprintf(stderr, "vrpn_Connection_IP::handle_connection(): "
5498  "Can't set up new connection!\n");
5499  drop_connection(endpointIndex);
5500  return;
5501  }
5502 }
5503 
5504 // Get the UDP port description from the other side and connect the
5505 // outgoing UDP socket to that port so we can send lossy but time-
5506 // critical (tracker) messages that way.
5507 
5508 // static
5510 {
5511  vrpn_Endpoint_IP *endpoint = (vrpn_Endpoint_IP *)userdata;
5512  char rhostname[1000]; // name of remote host
5513 
5514 #ifdef VERBOSE
5515  printf(" Received request for UDP channel to %s\n", p.buffer);
5516 #endif
5517 
5518  // Get the name of the remote host from the buffer (ensure terminated)
5519  strncpy(rhostname, p.buffer, sizeof(rhostname));
5520  rhostname[sizeof(rhostname) - 1] = '\0';
5521 
5522  // Open the UDP outbound port and connect it to the port on the
5523  // remote machine.
5524  // (remember that the sender field holds the UDP port number)
5525  endpoint->connect_udp_to(rhostname, (int)p.sender);
5526  if (endpoint->status == BROKEN) {
5527  return -1;
5528  }
5529 
5530  // Put this here because currently every connection opens a UDP
5531  // port and every host will get this data. Previous implementation
5532  // did it in connect_tcp_to, which only gets called by servers.
5533 
5534  strncpy(endpoint->rhostname, rhostname, sizeof(endpoint->rhostname));
5535 
5536 #ifdef VERBOSE
5537  printf(" Opened UDP channel to %s:%d\n", rhostname, p.sender);
5538 #endif
5539  return 0;
5540 }
5541 
5543 {
5544  int i;
5545 
5546  for (i = 0; i < d_numEndpoints; i++) {
5547  if (d_endpoints[i] && (d_endpoints[i]->send_pending_reports() != 0)) {
5548  fprintf(stderr, "vrpn_Connection_IP::send_pending_reports: "
5549  "Closing failed endpoint.\n");
5550  drop_connection(i);
5551  }
5552  }
5553 
5555 
5556  return 0;
5557 }
5558 
5560 {
5561 
5562 #ifdef VRPN_USE_WINSOCK_SOCKETS
5563  // Make sure sockets are set up
5564  // TCH 2 Nov 98 after Phil Winston
5565 
5566  WSADATA wsaData;
5567  int winStatus;
5568 
5569  winStatus = WSAStartup(MAKEWORD(1, 1), &wsaData);
5570  if (winStatus) {
5571  fprintf(stderr, "vrpn_Connection_IP::init(): "
5572  "Failed to set up sockets.\n");
5573  fprintf(stderr, "WSAStartup failed with error code %d\n", winStatus);
5574  exit(0);
5575  }
5576 #endif // windows sockets
5577 
5578 // Ignore SIGPIPE, so that the program does not crash when a
5579 // remote client OR SERVER shuts down its TCP connection. We'll find out
5580 // about it as an exception on the socket when we select() for
5581 // read.
5582 // Mips/Ultrix header file signal.h appears to be broken and
5583 // require the following cast
5584 #ifndef _WIN32 // XXX what about cygwin?
5585 #ifdef ultrix
5586  signal(SIGPIPE, (void (*)(int))SIG_IGN);
5587 #else
5588  signal(SIGPIPE, SIG_IGN);
5589 #endif
5590 #endif
5591 
5592  // Set up to handle the UDP-request system message.
5595 }
5596 
5597 //---------------------------------------------------------------------------
5598 // This routine checks for a request for attention from a remote machine.
5599 // The requests come as datagrams to the well-known port number on this
5600 // machine.
5601 // The datagram includes the machine name and port number on the remote
5602 // machine to which this one should establish a connection.
5603 // This routine establishes the TCP connection and then sends a magic
5604 // cookie describing this as a VRPN connection and telling which port to
5605 // use for incoming UDP packets of data associated with the current TCP
5606 // session. It reads the associated information from the other side and
5607 // sets up the local UDP sender.
5608 // It then sends descriptions for all of the known packet types.
5609 
5611  const struct timeval *pTimeout)
5612 {
5613  vrpn_Endpoint_IP *endpoint; // shorthand for d_endpoints[which_end]
5614  int request;
5615  timeval timeout;
5616  int which_end = d_numEndpoints;
5617  int retval;
5618  int port;
5619 
5620  if (pTimeout) {
5621  timeout = *pTimeout;
5622  }
5623  else {
5624  timeout.tv_sec = 0;
5625  timeout.tv_usec = 0;
5626  }
5627 
5628  // Do a select() with timeout (perhaps zero timeout) to see if
5629  // there is an incoming packet on the UDP socket.
5630 
5631  fd_set f;
5632  FD_ZERO(&f);
5633  FD_SET(listen_udp_sock, &f);
5634  request = vrpn_noint_select(static_cast<int>(listen_udp_sock) + 1, &f, NULL,
5635  NULL, &timeout);
5636  if (request == -1) { // Error in the select()
5637  fprintf(stderr,
5638  "vrpn_Connection_IP::server_check_for_incoming_connections(): "
5639  "select failed.\n");
5641  // fprintf(stderr, "BROKEN -
5642  // vrpn_Connection::server_check_for_incoming_connections.\n");
5643  return;
5644  }
5645  else if (request != 0) { // Some data to read! Go get it.
5646  struct sockaddr_in from;
5647  int fromlen = sizeof(from);
5648 
5649  char msg[200]; // Message received on the request channel
5650  if (recvfrom(listen_udp_sock, msg, sizeof(msg) - 1, 0,
5651  (struct sockaddr *)&from, GSN_CAST & fromlen) == -1) {
5652  fprintf(stderr,
5653  "vrpn: Error on recvfrom: Bad connection attempt\n");
5654  return;
5655  }
5656  else {
5657  // Force null termination
5658  msg[sizeof(msg) - 1] = '\0';
5659  }
5660 
5661  // Because we sometimes use multiple NICs, we are ignoring the IP from
5662  // the
5663  // client, and filling in the NIC that the udp request arrived on.
5664  char fromname[1024];
5665  unsigned long addr_num = ntohl(from.sin_addr.s_addr);
5666  sprintf(fromname, "%lu.%lu.%lu.%lu", (addr_num) >> 24,
5667  (addr_num >> 16) & 0xff, (addr_num >> 8) & 0xff,
5668  addr_num & 0xff);
5669  printf("vrpn: Connection request received from %s: %s\n", fromname,
5670  msg);
5671 
5672  // Make sure that the request is well-formed. That is, it
5673  // has an ASCII string name of a host followed by an integer
5674  // that is larger than 1024 (ports < 1024 are reserved for
5675  // use by the root process). If it is not well-formed, then
5676  // don't go off trying to connect to it because this slows
5677  // things down. This was happening to one user who had a
5678  // network device that was lobbing mal-formed UDP packets at
5679  // the incoming port on his machine.
5680  char *checkHost = new char[strlen(msg) + 1];
5681  int checkPort;
5682  if (checkHost == NULL) {
5683  fprintf(stderr,
5684  "server_check_for_incoming_connections(): Out of memory\n");
5685  return;
5686  }
5687  if (sscanf(msg, "%s %d", checkHost, &checkPort) != 2) {
5688  fprintf(
5689  stderr,
5690  "server_check_for_incoming_connections(): Malformed request\n");
5691  delete[] checkHost;
5692  return;
5693  }
5694  if (checkPort < 1024) {
5695  fprintf(stderr,
5696  "server_check_for_incoming_connections(): Bad port\n");
5697  delete[] checkHost;
5698  return;
5699  }
5700  // Check all of the characters in the hostname to make sure they are
5701  // either a letter, a digit, or a dot (.).
5702  size_t checkLoop;
5703  for (checkLoop = 0; checkLoop < strlen(checkHost); checkLoop++) {
5704  char checkChar = checkHost[checkLoop];
5705  if (!isalnum(checkChar) && (checkChar != '.')) {
5706  fprintf(
5707  stderr,
5708  "server_check_for_incoming_connections(): Bad hostname\n");
5709  delete[] checkHost;
5710  return;
5711  }
5712  }
5713  delete[] checkHost;
5714 
5715  // Make sure that we have room for a new connection
5716  if (which_end >= vrpn_MAX_ENDPOINTS) {
5717  fprintf(stderr, "vrpn: Too many existing connections; "
5718  "ignoring request from %s\n",
5719  msg);
5720  return;
5721  }
5722 
5723  // Create a new endpoint and start trying to connect it to
5724  // the client.
5725  d_endpoints[which_end] =
5726  (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
5727  d_endpoints[which_end]->setConnection(this);
5728  d_updateEndpoint = vrpn_TRUE;
5729  endpoint = d_endpoints[which_end];
5730  if (!endpoint) {
5731  fprintf(
5732  stderr,
5733  "vrpn_Connection_IP::server_check_for_incoming_connections:\n"
5734  " Out of memory on new endpoint\n");
5735  return;
5736  }
5737 
5738  // Server-side logging under multiconnection - TCH July 2000
5739  // Check for NULL server log name, which happens when the log file
5740  // already exists and it can't save it.
5742  (d_serverLogName != NULL)) {
5743  d_serverLogCount++;
5746  endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
5747  retval = endpoint->d_inLog->open();
5748  if (retval == -1) {
5749  fprintf(stderr, "vrpn_Connection_IP::server_check_for_incoming_"
5750  "connections: "
5751  "Couldn't open log file.\n");
5753  return;
5754  }
5755  }
5756 
5757  endpoint->setNICaddress(d_NIC_IP);
5758  endpoint->status = TRYING_TO_CONNECT;
5759 
5760  // d_numEndpoints must be incremented before handle_connection is called
5761  // otherwise the functions doing_okay and connected do not check all
5762  // the endpoints. Because of this topo was unable to send the header
5763  // information and nano crashed...
5764  d_numEndpoints++;
5765 
5766  // Because we sometimes use multiple NICs, we are ignoring the IP from
5767  // the
5768  // client, and filling in the NIC that the udp request arrived on.
5769  sscanf(msg, "%*s %d", &port); // get the port
5770  // Fill in NIC address. Copy the machine name so that we can delete it
5771  // in the destructor.
5772  endpoint->d_remote_machine_name = vrpn_copy_service_location(fromname);
5773  endpoint->connect_tcp_to(msg);
5774  handle_connection(which_end);
5775 
5776  // HACK
5777  // We don't want to do this, but connection requests are soft state
5778  // that will be restored in 1 second; meanwhile, if we accept multiple
5779  // connection requests from the same source we try to open multiple
5780  // connections to it, which invariably makes SOMEBODY crash sooner or
5781  // later.
5782  flush_udp_socket(listen_udp_sock);
5783  }
5784 
5785  // Do a zero-time select() to see if there are incoming TCP requests on
5786  // the listen socket. This is used when the client needs to punch through
5787  // a firewall.
5788 
5789  SOCKET newSocket;
5790  retval = vrpn_poll_for_accept(listen_tcp_sock, &newSocket);
5791 
5792  if (retval == -1) {
5793  fprintf(stderr, "Error accepting on TCP socket.\n");
5794  return;
5795  }
5796  else if (retval) { // Some data to read! Go get it.
5797 
5798  printf("vrpn: TCP connection request received.\n");
5799 
5800  if (which_end >= vrpn_MAX_ENDPOINTS) {
5801  fprintf(stderr, "vrpn: Too many existing connections; "
5802  "ignoring request.\n");
5803  return;
5804  }
5805 
5806  d_endpoints[which_end] =
5807  (*d_endpointAllocator)(this, &d_numConnectedEndpoints);
5808  d_endpoints[which_end]->setConnection(this);
5809  d_updateEndpoint = vrpn_TRUE;
5810  endpoint = d_endpoints[which_end];
5811  if (!endpoint) {
5812  fprintf(
5813  stderr,
5814  "vrpn_Connection_IP::server_check_for_incoming_connections:\n"
5815  " Out of memory on new endpoint\n");
5816  return;
5817  }
5818 
5819  // Since we're being connected to using a TCP request, tell the endpoint
5820  // not to try and establish any other connections (since the client is
5821  // presumably coming through a firewall or NAT and UDP packets won't get
5822  // through).
5823  endpoint->d_tcp_only = vrpn_TRUE;
5824 
5825  // Find out the remote port number and store it.
5826  struct sockaddr_in peer;
5827 #ifdef VRPN_USE_WINSOCK_SOCKETS
5828  int peerlen = sizeof(peer);
5829 #else
5830 #if defined(sgi)
5831  int peerlen = sizeof(peer);
5832 #else
5833  socklen_t peerlen = sizeof(peer);
5834 #endif
5835 #endif
5836  unsigned short peer_port = 0;
5837  if (getpeername(newSocket, static_cast<struct sockaddr *>(
5838  static_cast<void *>(&peer)),
5839  &peerlen) == 0) {
5840  peer_port = ntohs(peer.sin_port);
5841  }
5842  endpoint->d_remote_port_number = peer_port;
5843 
5844  // Server-side logging under multiconnection - TCH July 2000
5846  d_serverLogCount++;
5849  endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
5850  retval = endpoint->d_inLog->open();
5851  if (retval == -1) {
5852  fprintf(stderr, "vrpn_Connection_IP::server_check_for_incoming_"
5853  "connections: "
5854  "Couldn't open incoming log file.\n");
5856  return;
5857  }
5858  }
5859 
5860  endpoint->setNICaddress(d_NIC_IP);
5861  endpoint->d_tcpSocket = newSocket;
5862 
5863  d_numEndpoints++;
5864 
5865  handle_connection(which_end);
5866  }
5867 
5868  return;
5869 }
5870 
5872 {
5873  vrpn_Endpoint *endpoint = d_endpoints[whichEndpoint];
5874 
5875  endpoint->drop_connection();
5876 
5877  // If we're a client, try to reconnect to the server
5878  // that just dropped its connection.
5879  // If we're a server, delete the endpoint.
5881  endpoint->status = TRYING_TO_CONNECT;
5882  }
5883  else {
5884  delete_endpoint(whichEndpoint);
5885  }
5886 }
5887 
5888 int vrpn_Connection_IP::mainloop(const struct timeval *pTimeout)
5889 {
5890  vrpn_Endpoint *endpoint;
5891  timeval timeout;
5892  int endpointIndex;
5893 
5894  if (d_updateEndpoint) {
5895  updateEndpoints();
5896  d_updateEndpoint = vrpn_FALSE;
5897  }
5898  // struct timeval perSocketTimeout;
5899  // const int numSockets = 2;
5900  // divide timeout over all selects()
5901  // if (timeout) {
5902  // perSocketTimeout.tv_sec = timeout->tv_sec / numSockets;
5903  // perSocketTimeout.tv_usec = timeout->tv_usec / numSockets
5904  // + (timeout->tv_sec % numSockets) *
5905  // (1000000L / numSockets);
5906  // } else {
5907  // perSocketTimeout.tv_sec = 0;
5908  // perSocketTimeout.tv_usec = 0;
5909  // }
5910 
5911  // BETTER IDEA: do one select rather than multiple -- otherwise you are
5912  // potentially holding up one or the other. This allows clients which
5913  // should not do anything until they get messages to request infinite
5914  // waits (servers can't usually do infinite waits this because they need
5915  // to service other devices to generate info which they then send to
5916  // clients) . weberh 3/20/99
5917 
5918  if (connectionStatus == LISTEN) {
5920  }
5921 
5922  for (endpointIndex = 0; endpointIndex < d_numEndpoints; endpointIndex++) {
5923  endpoint = d_endpoints[endpointIndex];
5924 
5925  // The current array-sorting code is liable to break when unexpected
5926  // things happen, so we have to double-check it here.
5927  if (!endpoint) {
5928  continue;
5929  }
5930 
5931  if (pTimeout) {
5932  timeout = *pTimeout;
5933  }
5934  else {
5935  timeout.tv_sec = 0;
5936  timeout.tv_usec = 0;
5937  }
5938 
5939  endpoint->mainloop(&timeout);
5940 
5941  if (endpoint->status == BROKEN) {
5942  drop_connection(endpointIndex);
5943  }
5944  }
5945 
5946  // Do housekeeping on the endpoint array
5948 
5949  return 0;
5950 }
5951 
5953  unsigned short listen_port_no, const char *local_in_logfile_name,
5954  const char *local_out_logfile_name, const char *NIC_IPaddress,
5955  vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
5956  : vrpn_Connection(local_in_logfile_name, local_out_logfile_name, epa)
5957  , listen_udp_sock(INVALID_SOCKET)
5958  , listen_tcp_sock(INVALID_SOCKET)
5959  , d_NIC_IP(NULL)
5960 {
5961  // Copy the NIC_IPaddress so that we do not have to rely on the caller
5962  // to keep it from changing.
5963  if (NIC_IPaddress != NULL) {
5964  char *IP = new char[strlen(NIC_IPaddress) + 1];
5965  if (IP == NULL) {
5966  fprintf(
5967  stderr,
5968  "vrpn_Connection_IP::vrpn_Connection_IP(): Out of memory\n");
5969  }
5970  else {
5971  strcpy(IP, NIC_IPaddress);
5972  d_NIC_IP = IP;
5973  }
5974  }
5975 
5976  // Initialize the things that must be for any constructor
5978 
5979  listen_udp_sock = ::open_udp_socket(&listen_port_no, NIC_IPaddress);
5980  // TCH OHS HACK
5981  listen_tcp_sock = ::open_tcp_socket(&listen_port_no, NIC_IPaddress);
5982  if ((listen_udp_sock == INVALID_SOCKET) ||
5985  return;
5986  // fprintf(stderr, "BROKEN -
5987  // vrpn_Connection_IP::vrpn_Connection_I{.\n");
5988  }
5989  else {
5991 // fprintf(stderr, "LISTEN - vrpn_Connection_IP::vrpn_Connection_IP.\n");
5992 #ifdef VERBOSE
5993  printf("vrpn: Listening for requests on port %d\n", listen_port_no);
5994 #endif
5995  }
5996 
5997  // TCH OHS HACK
5998  if (listen(listen_tcp_sock, 1)) {
5999  fprintf(stderr, "Couldn't listen on TCP listening socket.\n");
6001  return;
6002  }
6003 
6004  flush_udp_socket(listen_udp_sock);
6005 
6007 }
6008 
6010  const char *station_name, int port, const char *local_in_logfile_name,
6011  const char *local_out_logfile_name, const char *remote_in_logfile_name,
6012  const char *remote_out_logfile_name, const char *NIC_IPaddress,
6013  vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
6014  : vrpn_Connection(local_in_logfile_name, local_out_logfile_name,
6015  remote_in_logfile_name, remote_out_logfile_name, epa)
6016  , listen_udp_sock(INVALID_SOCKET)
6017  , listen_tcp_sock(INVALID_SOCKET)
6018  , d_NIC_IP(NULL)
6019 {
6020  vrpn_Endpoint_IP *endpoint;
6021  vrpn_bool isrsh;
6022  vrpn_bool istcp;
6023  int retval;
6024 
6025  // Copy the NIC_IPaddress so that we do not have to rely on the caller
6026  // to keep it from changing.
6027  if (NIC_IPaddress != NULL) {
6028  char *IP = new char[strlen(NIC_IPaddress) + 1];
6029  if (IP == NULL) {
6030  fprintf(
6031  stderr,
6032  "vrpn_Connection_IP::vrpn_Connection_IP(): Out of memory\n");
6033  }
6034  else {
6035  strcpy(IP, NIC_IPaddress);
6036  d_NIC_IP = IP;
6037  }
6038  }
6039 
6040  isrsh = (strstr(station_name, "x-vrsh:") ? VRPN_TRUE : VRPN_FALSE);
6041  istcp = (strstr(station_name, "tcp:") ? VRPN_TRUE : VRPN_FALSE);
6042 
6043  // Initialize the things that must be for any constructor
6045 
6046  endpoint = d_endpoints[0]; // shorthand
6047  endpoint->setNICaddress(d_NIC_IP);
6048 
6049  // If we are not a TCP-only or remote-server-starting
6050  // type of connection, then set up to lob UDP packets
6051  // to the other side and put us in the mode that will
6052  // wait for the responses. Go ahead and set up the TCP
6053  // socket that we will listen on and lob a packet.
6054 
6055  if (!isrsh && !istcp) {
6056  // Open a connection to the station using a UDP request
6057  // that asks to machine to call us back here.
6058  endpoint->d_remote_machine_name = vrpn_copy_machine_name(station_name);
6059  if (!endpoint->d_remote_machine_name) {
6060  fprintf(stderr,
6061  "vrpn_Connection_IP: Can't get remote machine name!\n");
6063  // fprintf(stderr, "BROKEN -
6064  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6065  return;
6066  }
6067  if (port < 0) {
6069  }
6070  else {
6071  endpoint->d_remote_port_number = port;
6072  }
6073 
6074  endpoint->status = TRYING_TO_CONNECT;
6075 
6076  /* Create a UDP socket and connect it to the port on the remote
6077  * machine. */
6078 
6079  endpoint->d_udpLobSocket = vrpn_connect_udp_port(endpoint->d_remote_machine_name,
6080  endpoint->d_remote_port_number, d_NIC_IP);
6081  if (endpoint->d_udpLobSocket == INVALID_SOCKET) {
6082  fprintf(stderr,
6083  "vrpn_Connection_IP: Can't Set up socket to lob UDP packets!\n");
6085  // fprintf(stderr, "BROKEN -
6086  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6087  return;
6088  }
6089 
6090 #ifdef VERBOSE
6091  printf("vrpn_Connection_IP: Getting the TCP port to listen on\n");
6092 #endif
6093  // Determine which IP address we should listen on.
6094  // By listening on only localhost (as opposed to all interfaces,
6095  // i.e., 0.0.0.0), we can avoid complaints from the Windows firewall.
6096  char local_host[64];
6097  get_local_socket_name(local_host, sizeof(local_host), endpoint->d_remote_machine_name);
6098 
6099  // Set up the connection that we will listen on.
6100  if (vrpn_get_a_TCP_socket(&endpoint->d_tcpListenSocket,
6101  &endpoint->d_tcpListenPort,
6102  local_host) == -1) {
6103  fprintf(stderr, "vrpn_Connection_IP: Can't create listen socket\n");
6104  endpoint->status = BROKEN;
6105  endpoint->d_tcpListenSocket = INVALID_SOCKET;
6106  // fprintf(stderr, "BROKEN -
6107  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6108  return;
6109  }
6110 
6111  // Lob a packet asking for a connection on that port.
6112  vrpn_gettimeofday(&endpoint->d_last_connect_attempt, NULL);
6114  endpoint->d_remote_machine_name, endpoint->d_remote_port_number,
6115  endpoint->d_tcpListenPort, NIC_IPaddress) == -1) {
6116  fprintf(stderr, "vrpn_Connection_IP: Can't lob UDP request\n");
6117  endpoint->status = BROKEN;
6118  // fprintf(stderr, "BROKEN -
6119  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6120  return;
6121  }
6122 
6123  // the next line is something jeff added to get vrpn to work on his
6124  // PC. Tom Hudson independently added a line that is similar, but
6125  // different. I'm (jeff) am not sure what the right thing is here.
6126  //
6127  // Let's do both, because otherwise connectionStatus is
6128  // never initialized, and doing_ok() returns FALSE sometimes.
6130 
6131  // here is the line that Tom added
6132  endpoint->status = TRYING_TO_CONNECT;
6133 
6134  // See if we have a connection yet (wait for 1 sec at most).
6135  // This will allow the connection to come up fast if things are
6136  // all set. Otherwise, we'll drop into re-sends when we get
6137  // to mainloop().
6138  retval = vrpn_poll_for_accept(endpoint->d_tcpListenSocket,
6139  &endpoint->d_tcpSocket, 1.0);
6140  if (retval == -1) {
6141  fprintf(stderr, "vrpn_Connection_IP: Can't poll for accept\n");
6143  // fprintf(stderr, "BROKEN -
6144  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6145  return;
6146  }
6147  if (retval == 1) { // Got one!
6148  endpoint->status = COOKIE_PENDING;
6149 // fprintf(stderr, "COOKIE_PENDING -
6150 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6151 #ifdef VERBOSE
6152  printf("vrpn: Connection established on initial try\n");
6153 #endif
6154  // Set up the things that need to happen when a new connection
6155  // is established.
6156  if (endpoint->setup_new_connection()) {
6157  fprintf(stderr, "vrpn_Connection_IP: "
6158  "Can't set up new connection!\n");
6159  drop_connection(0);
6160  // status = BROKEN;
6161  // fprintf(stderr, "BROKEN -
6162  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6163  return;
6164  }
6165  }
6166  }
6167 
6168  // TCH OHS HACK
6169  if (istcp) {
6170  endpoint->d_remote_machine_name = vrpn_copy_machine_name(station_name);
6171  if (!endpoint->d_remote_machine_name) {
6172  fprintf(stderr, "vrpn_Connection_IP: Can't get remote machine name "
6173  "for tcp: connection!\n");
6175  return;
6176  }
6177  endpoint->d_remote_port_number = port;
6178 
6179  // Since we are doing a TCP connection, tell the endpoint not to try and
6180  // use any other communication mechanism to get to the server.
6181  endpoint->d_tcp_only = vrpn_TRUE;
6182 
6183  endpoint->status = TRYING_TO_CONNECT;
6184 
6185 #ifdef VERBOSE
6186  printf("vrpn_Connection_IP: Getting the TCP port to connect with.\n");
6187 #endif
6188 
6189  // Set up the connection that we will connect with.
6190  // Blocks, doesn't it?
6191  retval =
6192  endpoint->connect_tcp_to(endpoint->d_remote_machine_name, port);
6193 
6194  if (retval == -1) {
6195  fprintf(stderr,
6196  "vrpn_Connection_IP: Can't create TCP connection.\n");
6197  endpoint->status = BROKEN;
6198  return;
6199  }
6200 
6202  endpoint->status = TRYING_TO_CONNECT;
6203 
6204  if (endpoint->setup_new_connection()) {
6205  fprintf(stderr, "vrpn_Connection_IP: "
6206  "Can't set up new connection!\n");
6207  drop_connection(0);
6208  return;
6209  }
6210  }
6211 
6212  // If we are a remote-server-starting type of connection,
6213  // Try to start the remote server and connect to it. If
6214  // we fail, then the connection is broken. Otherwise, we
6215  // are connected.
6216 
6217  if (isrsh) {
6218  // Start up the server and wait for it to connect back
6219  char *machinename;
6220  char *server_program;
6221  char *server_args; // server program plus its arguments
6222  char *token;
6223 
6224  machinename = vrpn_copy_machine_name(station_name);
6225  server_program = vrpn_copy_rsh_program(station_name);
6226  server_args = vrpn_copy_rsh_arguments(station_name);
6227  token = server_args;
6228  // replace all argument separators (',') with spaces (' ')
6229  while ((token = strchr(token, ',')) != NULL) {
6230  *token = ' ';
6231  }
6232 
6233  endpoint->d_tcpSocket = vrpn_start_server(machinename, server_program,
6234  server_args, NIC_IPaddress);
6235  if (machinename) delete[](char *)machinename;
6236  if (server_program) delete[](char *)server_program;
6237  if (server_args) delete[](char *)server_args;
6238 
6239  if (endpoint->d_tcpSocket < 0) {
6240  fprintf(stderr, "vrpn_Connection_IP: "
6241  "Can't open %s\n",
6242  station_name);
6243  endpoint->status = BROKEN;
6244  // fprintf(stderr, "BROKEN -
6245  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6246  return;
6247  }
6248  else {
6249  endpoint->status = COOKIE_PENDING;
6250  // fprintf(stderr, "COOKIE_PENDING -
6251  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6252 
6253  if (endpoint->setup_new_connection()) {
6254  fprintf(stderr, "vrpn_Connection_IP: "
6255  "Can't set up new connection!\n");
6256  drop_connection(0);
6258  // fprintf(stderr, "BROKEN -
6259  // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6260  return;
6261  }
6262  }
6263  }
6264 
6265  vrpn_ConnectionManager::instance().addConnection(this, station_name);
6266 }
6267 
6269 {
6270 
6271  vrpn_int32 i;
6272 
6273  // Remove myself from the "known connections" list
6274  // (or the "anonymous connections" list).
6276 
6277  // Send any pending messages
6279 
6280  // Close the UDP and TCP listen endpoints if we're a server
6283  }
6286  }
6287 
6288  if (d_NIC_IP) {
6289  delete[] d_NIC_IP;
6290  d_NIC_IP = NULL;
6291  }
6292 
6293  for (i = 0; i < d_numEndpoints; i++) {
6294  if (d_endpoints[i]) {
6296  delete d_endpoints[i];
6297  }
6298  }
6299 
6300 #ifdef VRPN_USE_WINSOCK_SOCKETS
6301 
6302  if (WSACleanup() == SOCKET_ERROR) {
6303  fprintf(stderr, "~vrpn_Connection_IP(): "
6304  "WSACleanup() failed with error code %d\n",
6305  WSAGetLastError());
6306  }
6307 
6308 #endif // VRPN_USE_WINSOCK_SOCKETS
6309 }
6310 
6311 // Set up to be a server connection, which is the only kind we can be.
6313  : vrpn_Connection(NULL, NULL, NULL, NULL)
6314 {
6315  // We're always "connected."
6317 
6318  // Add this to the list of known connections.
6319  vrpn_ConnectionManager::instance().addConnection(this, "Loopback");
6320 }
6321 
6323 {
6324  // Remove myself from the "known connections" list
6325  // (or the "anonymous connections" list).
6327 }
6328 
6329 int vrpn_Connection_Loopback::mainloop(const timeval * /*timeout*/)
6330 {
6331  return 0;
6332 }
6333 
6334 // utility routines to parse names (<service>@<URL>)
6335 char *vrpn_copy_service_name(const char *fullname)
6336 {
6337  if (fullname == NULL) {
6338  return NULL;
6339  }
6340  else {
6341  size_t len = 1 + strcspn(fullname, "@");
6342  char *tbuf = new char[len];
6343  if (!tbuf)
6344  fprintf(stderr, "vrpn_copy_service_name: Out of memory!\n");
6345  else {
6346  strncpy(tbuf, fullname, len - 1);
6347  tbuf[len - 1] = 0;
6348  }
6349  return tbuf;
6350  }
6351 }
6352 
6353 char *vrpn_copy_service_location(const char *fullname)
6354 {
6355  // If there is no "@" sign in the string, copy the whole string.
6356  int offset = static_cast<int>(strcspn(fullname, "@"));
6357  size_t len = strlen(fullname) - offset;
6358  if (len == 0) {
6359  offset = -1; // We add one to it below.
6360  len = strlen(fullname) + 1; // We subtract one from it below.
6361  }
6362  char *tbuf = new char[len];
6363  if (!tbuf)
6364  fprintf(stderr, "vrpn_copy_service_name: Out of memory!\n");
6365  else {
6366  strncpy(tbuf, fullname + offset + 1, len - 1);
6367  tbuf[len - 1] = 0;
6368  }
6369  return tbuf;
6370 }
6371 
6372 char *vrpn_copy_file_name(const char *filespecifier)
6373 {
6374  char *filename;
6375  const char *fp;
6376  size_t len;
6377 
6378  fp = filespecifier;
6379  if (!fp) return NULL;
6380 
6381  if (!strncmp(fp, "file://", 7)) {
6382  fp += 7;
6383  }
6384  else if (!strncmp(fp, "file:", 5)) {
6385  fp += 5;
6386  }
6387 
6388  len = 1 + strlen(fp);
6389  filename = new char[len];
6390  if (!filename)
6391  fprintf(stderr, "vrpn_copy_file_name: Out of memory!\n");
6392  else {
6393  strncpy(filename, fp, len - 1);
6394  filename[len - 1] = 0;
6395  }
6396  return filename;
6397 }
6398 
6399 // Returns the length in characters of the header on the name that is
6400 // passed to it. Helper routine for those that follow.
6401 
6402 static int header_len(const char *hostspecifier)
6403 {
6404  // If the name begins with "x-vrpn://" or "x-vrsh://" or "tcp://" skip that
6405  // (also handle the case where there is no // after the colon).
6406  if (!strncmp(hostspecifier, "x-vrpn://", 9) ||
6407  !strncmp(hostspecifier, "x-vrsh://", 9)) {
6408  return 9;
6409  }
6410  else if (!strncmp(hostspecifier, "x-vrpn:", 7) ||
6411  !strncmp(hostspecifier, "x-vrsh:", 7)) {
6412  return 7;
6413  }
6414  else if (!strncmp(hostspecifier, "tcp://", 6)) {
6415  return 6;
6416  }
6417  else if (!strncmp(hostspecifier, "tcp:", 4)) {
6418  return 4;
6419  }
6420  else if (!strncmp(hostspecifier, "mpi://", 6)) {
6421  return 6;
6422  }
6423  else if (!strncmp(hostspecifier, "mpi:", 4)) {
6424  return 4;
6425  }
6426 
6427  // No header found.
6428  return 0;
6429 }
6430 
6431 // The caller is responsible for calling delete [] on the
6432 // returned pointer if it is not null.
6433 
6434 char *vrpn_copy_machine_name(const char *hostspecifier)
6435 {
6436  size_t nearoffset = 0;
6437  size_t faroffset;
6438  // if it contains a ':', copy only the prefix before the last ':'
6439  // otherwise copy all of it
6440  size_t len;
6441  char *tbuf;
6442 
6443  // Skip past the header, if any; this includes any tcp:// or tcp:
6444  // at the beginning of the string.
6445  nearoffset = header_len(hostspecifier);
6446 
6447  // stop at first occurrence of :<port #> or /<rsh arguments>.
6448  // Note that this may be the beginning of the string, right at
6449  // nearoffset.
6450  faroffset = strcspn(hostspecifier + nearoffset, ":/");
6451  len = 1 + faroffset;
6452 
6453  tbuf = new char[len];
6454  if (!tbuf) {
6455  fprintf(stderr, "vrpn_copy_machine_name: Out of memory!\n");
6456  }
6457  else {
6458  strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6459  tbuf[len - 1] = 0;
6460  }
6461  return tbuf;
6462 }
6463 
6464 int vrpn_get_port_number(const char *hostspecifier)
6465 {
6466  const char *pn;
6467  int port = vrpn_DEFAULT_LISTEN_PORT_NO;
6468 
6469  pn = hostspecifier;
6470  if (!pn) return -1;
6471 
6472  // Skip over the header, if present
6473  pn += header_len(hostspecifier);
6474 
6475  pn = strrchr(pn, ':');
6476  if (pn) {
6477  pn++;
6478  port = atoi(pn);
6479  }
6480 
6481  return port;
6482 }
6483 
6484 char *vrpn_copy_rsh_program(const char *hostspecifier)
6485 {
6486  size_t nearoffset = 0; // location of first char after machine name
6487  size_t faroffset; // location of last character of program name
6488  size_t len;
6489  char *tbuf;
6490 
6491  nearoffset += header_len(hostspecifier);
6492 
6493  nearoffset += strcspn(hostspecifier + nearoffset, "/");
6494  nearoffset++; // step past the '/'
6495  faroffset = strcspn(hostspecifier + nearoffset, ",");
6496  len = 1 + (faroffset ? faroffset : strlen(hostspecifier) - nearoffset);
6497  tbuf = new char[len];
6498 
6499  if (!tbuf)
6500  fprintf(stderr, "vrpn_copy_rsh_program: Out of memory!\n");
6501  else {
6502  strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6503  tbuf[len - 1] = 0;
6504  // fprintf(stderr, "server program: '%s'.\n", tbuf);
6505  }
6506  return tbuf;
6507 }
6508 
6509 char *vrpn_copy_rsh_arguments(const char *hostspecifier)
6510 {
6511  size_t nearoffset = 0; // location of first char after server name
6512  size_t faroffset; // location of last character
6513  size_t len;
6514  char *tbuf;
6515 
6516  nearoffset += header_len(hostspecifier);
6517 
6518  nearoffset += strcspn(hostspecifier + nearoffset, "/");
6519  nearoffset += strcspn(hostspecifier + nearoffset, ",");
6520  faroffset = strlen(hostspecifier);
6521  len = 1 + faroffset - nearoffset;
6522  tbuf = new char[len];
6523 
6524  if (!tbuf)
6525  fprintf(stderr, "vrpn_copy_rsh_arguments: Out of memory!\n");
6526  else {
6527  strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6528  tbuf[len - 1] = 0;
6529  // fprintf(stderr, "server args: '%s'.\n", tbuf);
6530  }
6531  return tbuf;
6532 }
6533 
6534 // For a host specifier without a service name, this routine prepends
6535 // the given string newServiceName to it.
6536 // For a host specifier with a service name (e.g. "service@URL"),
6537 // this routine strips off the service name and adds the given
6538 // string newServiceName in its place (e.g. "newServiceName@URL").
6539 // This routine allocates memory for the return value. Caller is
6540 // responsible for freeing the memory.
6541 char *vrpn_set_service_name(const char *specifier, const char *newServiceName)
6542 {
6543  size_t inputLength = strlen(specifier);
6544  size_t atSymbolIndex = strcspn(specifier, "@");
6545 
6546  char *location = NULL;
6547 
6548  if (atSymbolIndex == inputLength) {
6549  // no @ symbol present; just a location.
6550  location = new char[inputLength + 1];
6551  strcpy(location, specifier); // take the whole thing to be the location
6552  }
6553  else {
6554  // take everything after the @ symbol to be the location
6555  location = vrpn_copy_service_location(specifier);
6556  }
6557 
6558  // prepend newServiceName to location.
6559  size_t len = strlen(location) + strlen(newServiceName);
6560  char *newSpecifier = new char[len + 2]; // extra space for '@'
6561  // and terminal '/0'
6562  strcpy(newSpecifier, newServiceName);
6563  strcat(newSpecifier, "@");
6564  strcat(newSpecifier, location);
6565  delete[] location;
6566  return newSpecifier;
6567 }
6568 
6569 
LOGGING
@ LOGGING
Definition: vrpn_Connection.h:34
vrpn_Connection::setAutoDeleteStatus
void setAutoDeleteStatus(bool setvalue)
Specify whether this connection should be deleted automatically when it is no longer need (reference ...
Definition: vrpn_Connection.h:724
SERVCOUNT
#define SERVCOUNT
Definition: vrpn_Connection.C:239
vrpn_TypeDispatcher
class VRPN_API vrpn_TypeDispatcher
Definition: vrpn_Connection.h:191
vrpn_Endpoint::handle_type_message
static int VRPN_CALLBACK handle_type_message(void *userdata, vrpn_HANDLERPARAM p)
Definition: vrpn_Connection.C:4316
vrpn_Connection::pack_message
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...
Definition: vrpn_Connection.C:4632
vrpn_Log::addFilter
int addFilter(vrpn_LOGFILTER filter, void *userdata)
Definition: vrpn_Connection.C:862
vrpn_Log::logMessage
int logMessage(vrpn_int32 payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_bool isRemote=VRPN_FALSE)
We'd like to make this protected, but there's one place it needs to be exposed, at least until we get...
Definition: vrpn_Connection.C:726
vrpn_Connection::connectionStatus
int connectionStatus
Status of the connection.
Definition: vrpn_Connection.h:653
INVALID_SOCKET
#define INVALID_SOCKET
Definition: vrpn_Connection.C:112
vrpn_CONNECTION_DISCONNECT_MESSAGE
const vrpn_int32 vrpn_CONNECTION_DISCONNECT_MESSAGE
Definition: vrpn_Connection.h:110
vrpn_Connection_IP::handle_connection
virtual void handle_connection(int whichEndpoint)
This routine is called by a server-side connection when a new connection has just been established,...
Definition: vrpn_Connection.C:5489
vrpn_Endpoint::handle_sender_message
static int VRPN_CALLBACK handle_sender_message(void *userdata, vrpn_HANDLERPARAM p)
Definition: vrpn_Connection.C:4388
vrpn_Connection::register_log_filter
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...
Definition: vrpn_Connection.C:4724
vrpn_Log::checkFilters
int checkFilters(vrpn_int32 payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer)
Definition: vrpn_Connection.C:882
vrpn_Endpoint_IP::drop_connection
void drop_connection(void)
Should only be called by vrpn_Connection::drop_connection(), since there's more housecleaning to do a...
Definition: vrpn_Connection.C:3680
vrpn_Connection_IP::send_pending_reports
virtual int send_pending_reports(void)
send pending report, clear the buffer.
Definition: vrpn_Connection.C:5542
vrpn_got_connection
const char * vrpn_got_connection
Definition: vrpn_Connection.C:185
vrpn_Log.h
vrpn_Endpoint::local_sender_id
int local_sender_id(vrpn_int32 remote_sender) const
Returns the local mapping for the remote sender (-1 if none).
Definition: vrpn_Connection.C:2760
vrpn_cookie_size
size_t vrpn_cookie_size(void)
Returns the size of the magic cookie buffer, plus any alignment overhead.
Definition: vrpn_Connection.C:2630
vrpn_Endpoint_IP::d_tcpNumOut
vrpn_int32 d_tcpNumOut
Definition: vrpn_Connection.h:488
vrpn_Endpoint::rhostname
char rhostname[150]
Definition: vrpn_Connection.h:297
vrpn_Endpoint::d_types
vrpn_TranslationTable * d_types
Definition: vrpn_Connection.h:353
vrpn_Log::d_senders
vrpn_TranslationTable * d_senders
Definition: vrpn_Log.h:88
vrpn_Endpoint::d_remoteOutLogName
char * d_remoteOutLogName
Name of the remote log file.
Definition: vrpn_Connection.h:292
vrpn_ConnectionManager
Singleton class that keeps track of all known VRPN connections and makes sure they're deleted on shut...
Definition: vrpn_Connection.h:1062
vrpn_Endpoint::pack_message
virtual int pack_message(vrpn_uint32 len, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer, vrpn_uint32 class_of_service)=0
Pack a message that will be sent the next time mainloop() is called. Turn off the RELIABLE flag if yo...
vrpn_noint_select
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...
Definition: vrpn_Connection.C:1615
vrpn_get_connection_by_name
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).
Definition: vrpn_Connection.C:5277
vrpn_Endpoint_IP::pack_message
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.
Definition: vrpn_Connection.C:3075
vrpn_Log::getName
char * getName()
Allocates a new string and copies the log file name to it. IMPORTANT: code calling this function is r...
Definition: vrpn_Connection.C:493
vrpn_Log::logIncomingMessage
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.
Definition: vrpn_Connection.C:695
vrpn_LOGLIST::next
vrpn_LOGLIST * next
Definition: vrpn_Connection.h:163
vrpn_Connection::init
virtual void init(void)
Base initialization for all constructors.
Definition: vrpn_Connection.C:4752
vrpn_Connection::handle_log_message
static int VRPN_CALLBACK handle_log_message(void *userdata, vrpn_HANDLERPARAM p)
Routines that handle system messages.
Definition: vrpn_Connection.C:4581
vrpn_Connection::d_serverLogCount
int d_serverLogCount
Server logging w. multiconnection - TCH July 00 Use one "hidden" endpoint for outgoing logs (?...
Definition: vrpn_Connection.h:750
vrpn_ALIGN
const unsigned vrpn_ALIGN
VRPN buffers are aligned on 8 byte boundaries so that we can pack and unpack doubles into them on arc...
Definition: vrpn_Connection.h:63
vrpnLogFilterEntry::next
vrpnLogFilterEntry * next
Definition: vrpn_Connection.h:184
vrpn_Connection::connected
virtual vrpn_bool connected(void) const
Returns vrpn_true if the connection has been established, vrpn_false if not (For a networkless connec...
Definition: vrpn_Connection.C:5237
vrpn_dropped_last_connection
const char * vrpn_dropped_last_connection
Definition: vrpn_Connection.C:187
vrpn_closeSocket
#define vrpn_closeSocket
Definition: vrpn_Connection.C:35
vrpn_FileConnection.h
vrpn_DEFAULT_LISTEN_PORT_NO
#define vrpn_DEFAULT_LISTEN_PORT_NO
Definition: vrpn_Configure.h:39
vrpn_Endpoint_IP::outbound_udp_open
vrpn_bool outbound_udp_open(void) const
True if the UDP outbound is open, False if not.
Definition: vrpn_Connection.C:2750
vrpn_Connection::start_time
timeval start_time
Timekeeping - TCH 30 June 98.
Definition: vrpn_Connection.h:701
vrpn_Log::setName
int setName(const char *name)
Definition: vrpn_Connection.C:825
vrpn_Connection::sender_name
virtual const char * sender_name(vrpn_int32 sender)
Returns the name of the specified sender/type, or NULL if the parameter is invalid....
Definition: vrpn_Connection.C:4712
vrpn_Endpoint::pack_type_description
int pack_type_description(vrpn_int32 which)
Packs a type description.
Definition: vrpn_Connection.C:4436
vrpn_CONNECTION_MAX_SENDERS
const int vrpn_CONNECTION_MAX_SENDERS
Types now have their storage dynamically allocated, so we can afford to have large tables....
Definition: vrpn_Connection.h:70
vrpn_Connection::d_updateEndpoint
vrpn_bool d_updateEndpoint
Definition: vrpn_Connection.h:755
vrpn_Endpoint::mainloop
virtual int mainloop(timeval *timeout)=0
vrpn_Endpoint::newLocalType
int newLocalType(const char *name, vrpn_int32 which)
Definition: vrpn_Connection.C:3041
vrpn_Connection::compact_endpoints
int compact_endpoints(void)
Makes sure the endpoint array is set up cleanly for the next pass through.
Definition: vrpn_Connection.C:4806
vrpn_Endpoint::d_outLog
vrpn_Log * d_outLog
Definition: vrpn_Connection.h:305
vrpn_Log::d_magicCookie
char * d_magicCookie
Definition: vrpn_Log.h:82
vrpn_Endpoint_IP::setup_new_connection
int setup_new_connection(void)
Sends the magic cookie and other information to its peer. It is called by both the client and server ...
Definition: vrpn_Connection.C:3779
vrpnLogFilterEntry::filter
vrpn_LOGFILTER filter
routine to call
Definition: vrpn_Connection.h:182
vrpn_Log::logMode
long & logMode(void)
Returns a reference so we can |= it.
Definition: vrpn_Connection.C:860
vrpn_copy_machine_name
char * vrpn_copy_machine_name(const char *hostspecifier)
Definition: vrpn_Connection.C:6434
vrpn_MAGICLEN
const int vrpn_MAGICLEN
Definition: vrpn_Connection.C:182
vrpn_Log::d_types
vrpn_TranslationTable * d_types
Definition: vrpn_Log.h:89
vrpn_MAGIC
const char * vrpn_MAGIC
Definition: vrpn_Connection.C:180
vrpn_Connection::d_numConnectedEndpoints
vrpn_int32 d_numConnectedEndpoints
We need to track the number of connected endpoints separately to properly send out got-first-connecti...
Definition: vrpn_Connection.h:668
vrpn_got_first_connection
const char * vrpn_got_first_connection
These are the strings that define the system-generated message types that tell when connections are r...
Definition: vrpn_Connection.C:184
vrpn_Endpoint_IP::vrpn_Endpoint_IP
vrpn_Endpoint_IP(vrpn_TypeDispatcher *dispatcher, vrpn_int32 *connectedEndpointCounter)
Definition: vrpn_Connection.C:2650
vrpn_Connection::doSystemCallbacksFor
int doSystemCallbacksFor(vrpn_HANDLERPARAM, void *)
Definition: vrpn_Connection.C:5128
vrpn_Endpoint::vrpn_Endpoint
vrpn_Endpoint(vrpn_TypeDispatcher *dispatcher, vrpn_int32 *connectedEndpointCounter)
Definition: vrpn_Connection.C:2634
vrpnMsgCallbackEntry
Description of a callback entry for a user type.
Definition: vrpn_Connection.h:174
vrpn_Connection::save_log_so_far
virtual int save_log_so_far()
Save any messages on any endpoints which have been logged so far.
Definition: vrpn_Connection.C:4735
vrpn_Endpoint_IP::clearBuffers
void clearBuffers(void)
Empties out the TCP and UDP send buffers. Needed by vrpn_FileConnection to get at {udp,...
Definition: vrpn_Connection.C:3751
vrpn_Endpoint::newRemoteType
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.
Definition: vrpn_Connection.C:3047
vrpn_Log::lastLogTime
timeval lastLogTime()
Returns the time of the last message that was logged.
Definition: vrpn_Connection.C:880
vrpn_TranslationTable
class VRPN_API vrpn_TranslationTable
Definition: vrpn_Connection.h:190
vrpn_Log::d_logTail
vrpn_LOGLIST * d_logTail
Definition: vrpn_Log.h:77
vrpn_HANDLERPARAM::payload_len
vrpn_int32 payload_len
Definition: vrpn_Connection.h:48
vrpn_CONNECTION_UDP_DESCRIPTION
const vrpn_int32 vrpn_CONNECTION_UDP_DESCRIPTION
Definition: vrpn_Connection.h:108
vrpn_Endpoint_IP
Encapsulation of the data and methods for a single IP-based connection to take care of one part of ma...
Definition: vrpn_Connection.h:369
vrpn_Connection::~vrpn_Connection
virtual ~vrpn_Connection(void)
Definition: vrpn_Connection.C:4996
vrpn_File_Connection
Definition: vrpn_FileConnection.h:73
vrpn_set_service_name
char * vrpn_set_service_name(const char *specifier, const char *newServiceName)
Utility routine to rename the service name of a given host specifier.
Definition: vrpn_Connection.C:6541
check_vrpn_cookie
int check_vrpn_cookie(const char *buffer)
Checks to see if the given buffer has the magic cookie.
Definition: vrpn_Connection.C:2557
vrpn_Log::setCompoundName
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>....
Definition: vrpn_Connection.C:798
LISTEN
@ LISTEN
Definition: vrpn_Connection.h:29
vrpn_Endpoint_IP::connect_udp_to
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 a...
Definition: vrpn_Connection.C:3642
vrpn_noint_block_write
int vrpn_noint_block_write(int outfile, const char buffer[], size_t length)
Definition: vrpn_Connection.C:1721
vrpnMsgCallbackEntry::handler
vrpn_MESSAGEHANDLER handler
Routine to call.
Definition: vrpn_Connection.h:175
vrpn_Endpoint
Encapsulation of the data and methods for a single generic connection to take care of one part of man...
Definition: vrpn_Connection.h:200
vrpn_Log::open
int open(void)
Opens the log file.
Definition: vrpn_Connection.C:504
vrpn_Log::close
int close(void)
Closes and saves the log file.
Definition: vrpn_Connection.C:566
vrpn_CONNECTION_TCP_BUFLEN
const int vrpn_CONNECTION_TCP_BUFLEN
Definition: vrpn_Connection.h:95
vrpn_Endpoint_IP::d_udpInboundSocket
SOCKET d_udpInboundSocket
Inbound unreliable messages come here. Need one for each due to different clock synchronization for e...
Definition: vrpn_Connection.h:477
vrpn_FILE_MAGIC
const char * vrpn_FILE_MAGIC
Definition: vrpn_Connection.C:181
vrpn_Endpoint_IP::d_tcpSocket
SOCKET d_tcpSocket
Definition: vrpn_Connection.h:446
vrpn_Connection::pack_type_description
virtual int pack_type_description(vrpn_int32 which)
Send the type description to ALL endpoints.
Definition: vrpn_Connection.C:4546
vrpn_Connection::vrpn_Connection
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...
Definition: vrpn_Connection.C:4824
COOKIE_PENDING
@ COOKIE_PENDING
Definition: vrpn_Connection.h:31
vrpn_MAX_ENDPOINTS
const int vrpn_MAX_ENDPOINTS
Number of endpoints that a server connection can have. Arbitrary limit.
Definition: vrpn_Connection.h:102
vrpn_Connection::d_endpoints
vrpn_Endpoint_IP * d_endpoints[vrpn_MAX_ENDPOINTS]
Sockets used to talk to remote Connection(s) and other information needed on a per-connection basis.
Definition: vrpn_Connection.h:665
vrpn_Connection::addReference
void addReference()
Counting references to this connection.
Definition: vrpn_Connection.C:5013
vrpn_Endpoint_IP::d_tcp_only
vrpn_bool d_tcp_only
For connections made through firewalls or NAT with the tcp: URL, we do not want to allow the endpoint...
Definition: vrpn_Connection.h:466
vrpn_unbuffer
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_CONNECTION_UDP_BUFLEN
const int vrpn_CONNECTION_UDP_BUFLEN
Definition: vrpn_Connection.h:96
vrpn_Endpoint::clear_other_senders_and_types
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...
Definition: vrpn_Connection.C:3022
vrpn_Connection::delete_endpoint
int delete_endpoint(int whichEndpoint)
Deletes the endpoint and NULLs the entry in the list of open endpoints.
Definition: vrpn_Connection.C:4789
vrpn_LOG_OUTGOING
const long vrpn_LOG_OUTGOING
Definition: vrpn_Connection.h:132
vrpn_noint_block_read_timeout
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.
Definition: vrpn_Connection.C:1854
vrpn_Endpoint_IP::d_tcpSequenceNumber
vrpn_int32 d_tcpSequenceNumber
Definition: vrpn_Connection.h:491
vrpn_Endpoint::marshall_message
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.
Definition: vrpn_Connection.C:4234
vrpn_Log::d_filters
vrpnLogFilterEntry * d_filters
Definition: vrpn_Log.h:86
vrpn_Endpoint_IP::d_last_connect_attempt
timeval d_last_connect_attempt
When the last UDP lob occurred.
Definition: vrpn_Connection.h:464
vrpn_Endpoint::setConnection
void setConnection(vrpn_Connection *conn)
Definition: vrpn_Connection.h:324
vrpn_HANDLERPARAM::buffer
const char * buffer
Definition: vrpn_Connection.h:49
vrpn_Connection::register_message_type
virtual vrpn_int32 register_message_type(const char *name)
Definition: vrpn_Connection.C:5074
vrpn_Endpoint::d_parent
vrpn_Connection * d_parent
Definition: vrpn_Connection.h:358
vrpn_Endpoint_IP::d_tcpAlignedInbuf
vrpn_float64 d_tcpAlignedInbuf[vrpn_CONNECTION_TCP_BUFLEN/sizeof(vrpn_float64)+1]
Definition: vrpn_Connection.h:496
vrpn_TimevalDiff
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:92
vrpn_Endpoint::d_connectionCounter
vrpn_int32 * d_connectionCounter
Definition: vrpn_Connection.h:356
vrpn_dropped_connection
const char * vrpn_dropped_connection
Definition: vrpn_Connection.C:186
vrpn_CONNECTION_RELIABLE
const vrpn_uint32 vrpn_CONNECTION_RELIABLE
Classes of service for messages, specify multiple by ORing them together Priority of satisfying these...
Definition: vrpn_Connection.h:120
vrpn_Connection::do_callbacks_for
virtual int do_callbacks_for(vrpn_int32 type, vrpn_int32 sender, struct timeval time, vrpn_uint32 len, const char *buffer)
Definition: vrpn_Connection.C:5121
vrpn_HANDLERPARAM
This structure is what is passed to a vrpn_Connection message callback.
Definition: vrpn_Connection.h:44
vrpn_Connection::handle_disconnect_message
static int VRPN_CALLBACK handle_disconnect_message(void *userdata, vrpn_HANDLERPARAM p)
Definition: vrpn_Connection.C:5186
vrpn_Endpoint::setLogNames
void setLogNames(const char *inName, const char *outName)
Definition: vrpn_Connection.C:4364
vrpn_copy_file_name
char * vrpn_copy_file_name(const char *filespecifier)
Utility routines to parse file specifiers FROM service locations.
Definition: vrpn_Connection.C:6372
vrpn_Endpoint::send_pending_reports
virtual int send_pending_reports(void)=0
send pending report, clear the buffer. This function was protected, now is public,...
vrpn_ConnectionManager::addConnection
void addConnection(vrpn_Connection *, const char *name)
NB implementation is not particularly efficient; we expect to have O(10) connections,...
Definition: vrpn_Connection.C:1434
vrpn_Connection::allocateEndpoint
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 Endpo...
Definition: vrpn_Connection.C:5175
vrpn_Connection::get_log_names
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...
Definition: vrpn_Connection.C:5133
vrpn_Endpoint_IP::d_udpLobSocket
SOCKET d_udpLobSocket
Socket to use to lob UDP requests asking for the server to call us back.
Definition: vrpn_Connection.h:460
vrpn_Connection_IP::drop_connection
virtual void drop_connection(int whichEndpoint)
Definition: vrpn_Connection.C:5871
vrpn_Connection::d_dispatcher
vrpn_TypeDispatcher * d_dispatcher
Derived classes need access to d_dispatcher in their allocateEndpoint() routine. Several compilers wo...
Definition: vrpn_Connection.h:735
vrpn_ConnectionManager::instance
static vrpn_ConnectionManager & instance(void)
The only way to get access to an instance of this class. Guarantees that there is only one,...
Definition: vrpn_Connection.C:1428
vrpn_CONNECTION_LOG_DESCRIPTION
const vrpn_int32 vrpn_CONNECTION_LOG_DESCRIPTION
Definition: vrpn_Connection.h:109
vrpn_CONNECTION_MAX_TYPES
const int vrpn_CONNECTION_MAX_TYPES
Definition: vrpn_Connection.h:71
vrpn_Endpoint_IP::tcp_outbuf_size
vrpn_int32 tcp_outbuf_size(void) const
Definition: vrpn_Connection.C:2765
write_vrpn_cookie
int write_vrpn_cookie(char *buffer, size_t length, long remote_log_mode)
Writes the magic cookie into buffer with given length.
Definition: vrpn_Connection.C:2542
vrpn_Connection::unregister_handler
virtual int unregister_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Definition: vrpn_Connection.C:5206
vrpn_Connection_IP::vrpn_Connection_IP
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()....
Definition: vrpn_Connection.C:6009
vrpn_Endpoint_IP::d_tcpOutbuf
char * d_tcpOutbuf
Definition: vrpn_Connection.h:484
vrpn_Endpoint_IP::d_remote_machine_name
char * d_remote_machine_name
Machine to call.
Definition: vrpn_Connection.h:462
vrpn_Connection_IP::mainloop
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...
Definition: vrpn_Connection.C:5888
vrpn_Connection::get_File_Connection
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...
Definition: vrpn_Connection.C:4747
vrpn_Endpoint_IP::doing_okay
virtual vrpn_bool doing_okay(void) const
Definition: vrpn_Connection.C:2769
vrpn_Endpoint::newRemoteSender
int newRemoteSender(cName sender_name, vrpn_int32 remote_id, vrpn_int32 local_id)
Definition: vrpn_Connection.C:3054
vrpn_Log::d_lastLogTime
timeval d_lastLogTime
Definition: vrpn_Log.h:91
vrpn_Connection::get_Jane_value
vrpn_uint32 get_Jane_value(void)
Definition: vrpn_Connection.h:642
vrpn_copy_rsh_arguments
char * vrpn_copy_rsh_arguments(const char *hostspecifier)
Definition: vrpn_Connection.C:6509
vrpn_Endpoint::init
void init(void)
Definition: vrpn_Connection.C:2774
vrpn_Log
class VRPN_API vrpn_Log
Definition: vrpn_Connection.h:189
vrpn_Connection::pack_sender_description
virtual int pack_sender_description(vrpn_int32 which)
Send the sender description to ALL endpoints.
Definition: vrpn_Connection.C:4563
SERVWAIT
#define SERVWAIT
Definition: vrpn_Connection.C:240
vrpn_Connection::updateEndpoints
virtual void updateEndpoints(void)
This function will be called on the mainloop() iteration after *d_endpointAllocator is called,...
Definition: vrpn_Connection.C:5172
vrpn_Endpoint_IP::handle_udp_messages
int handle_udp_messages(const timeval *timeout)
Definition: vrpn_Connection.C:3421
vrpn_Log::d_file
FILE * d_file
Definition: vrpn_Log.h:80
vrpn_Endpoint_IP::d_tcpBuflen
vrpn_int32 d_tcpBuflen
Definition: vrpn_Connection.h:486
vrpn_Log::d_firstEntry
vrpn_LOGLIST * d_firstEntry
Definition: vrpn_Log.h:78
vrpn_LOGLIST::prev
vrpn_LOGLIST * prev
Definition: vrpn_Connection.h:164
vrpn_Endpoint_IP::getOneTCPMessage
int getOneTCPMessage(int fd, char *buf, size_t buflen)
Definition: vrpn_Connection.C:4020
vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE
#define vrpn_CONNECTION_MAX_XLATION_TABLE_SIZE
Definition: vrpn_Connection.C:245
vrpn_LOGFILTER
vrpn_MESSAGEHANDLER vrpn_LOGFILTER
Type of handler for filters on logfiles is the same as connection handler.
Definition: vrpn_Connection.h:58
vrpn_Log::~vrpn_Log
~vrpn_Log(void)
Definition: vrpn_Connection.C:473
vrpn_HANDLERPARAM::msg_time
struct timeval msg_time
Definition: vrpn_Connection.h:47
SOCK_CAST
#define SOCK_CAST
Definition: vrpn_Connection.C:79
vrpn_Endpoint_IP::udp_outbuf_size
vrpn_int32 udp_outbuf_size(void) const
Definition: vrpn_Connection.C:2767
vrpn_Connection_IP::listen_tcp_sock
SOCKET listen_tcp_sock
TCP Connection requests come here.
Definition: vrpn_Connection.h:836
vrpn_Endpoint::drop_connection
virtual void drop_connection(void)=0
Should only be called by vrpn_Connection::drop_connection(), since there's more housecleaning to do a...
vrpn_Connection_IP::connect_to_client
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...
Definition: vrpn_Connection.C:5444
vrpn_Endpoint_IP::poll_for_cookie
void poll_for_cookie(const timeval *timeout=NULL)
Definition: vrpn_Connection.C:3811
vrpn_Connection
Generic connection class not specific to the transport mechanism.
Definition: vrpn_Connection.h:510
vrpn_LOGLIST
Placed here so vrpn_FileConnection can use it too.
Definition: vrpn_Connection.h:161
vrpn_Connection::d_numEndpoints
vrpn_int32 d_numEndpoints
Definition: vrpn_Connection.h:666
vrpn_Connection.h
vrpn_Endpoint_IP::d_tcpInbuf
char * d_tcpInbuf
Definition: vrpn_Connection.h:500
vrpn_Endpoint_IP::d_udpOutbuf
char * d_udpOutbuf
Definition: vrpn_Connection.h:485
vrpn_Endpoint_IP::getOneUDPMessage
int getOneUDPMessage(char *buf, size_t buflen)
Definition: vrpn_Connection.C:4105
vrpn_ANY_TYPE
const int vrpn_ANY_TYPE
vrpn_ANY_TYPE can be used to register callbacks for any USER type of message from a given sender....
Definition: vrpn_Connection.h:82
vrpn_Connection::d_serverLogMode
vrpn_int32 d_serverLogMode
Definition: vrpn_Connection.h:751
vrpn_Endpoint_IP::pack_udp_description
int pack_udp_description(int portno)
Definition: vrpn_Connection.C:3239
vrpn_udp_request_lob_packet
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.
Definition: vrpn_Connection.C:2246
vrpn_LOG_NONE
const long vrpn_LOG_NONE
Definition: vrpn_Connection.h:130
vrpn_Connection_IP::init
virtual void init(void)
Called by all constructors.
Definition: vrpn_Connection.C:5559
vrpn_Endpoint_IP::finish_new_connection_setup
int finish_new_connection_setup(void)
Definition: vrpn_Connection.C:3873
vrpn_Connection::d_serverLogName
char * d_serverLogName
Definition: vrpn_Connection.h:752
vrpn_Endpoint::d_inLog
vrpn_Log * d_inLog
Definition: vrpn_Connection.h:304
vrpn_Connection_IP::handle_UDP_message
static int VRPN_CALLBACK handle_UDP_message(void *userdata, vrpn_HANDLERPARAM p)
Routines that handle system messages.
Definition: vrpn_Connection.C:5509
vrpn_Log::vrpn_Log
vrpn_Log(vrpn_TranslationTable *senders, vrpn_TranslationTable *types)
Definition: vrpn_Connection.C:446
vrpn_Endpoint::pack_log_description
int pack_log_description(void)
Packs the log description set by setup_new_connection().
Definition: vrpn_Connection.C:3277
vrpn_gettimeofday
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
vrpn_Log::logOutgoingMessage
int logOutgoingMessage(vrpn_int32 payloadLen, struct timeval time, vrpn_int32 type, vrpn_int32 sender, const char *buffer)
Definition: vrpn_Connection.C:714
vrpn_ConnectionManager::~vrpn_ConnectionManager
~vrpn_ConnectionManager(void)
Definition: vrpn_Connection.C:1412
vrpn_Connection_IP::server_check_for_incoming_connections
virtual void server_check_for_incoming_connections(const struct timeval *timeout=NULL)
Definition: vrpn_Connection.C:5610
vrpn_Connection_Loopback::mainloop
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...
Definition: vrpn_Connection.C:6329
RSH
#define RSH
Definition: vrpn_Connection.C:227
vrpn_Endpoint_IP::send_pending_reports
virtual int send_pending_reports(void)
send pending report, clear the buffer.
Definition: vrpn_Connection.C:3143
vrpn_ConnectionManager::deleteConnection
void deleteConnection(vrpn_Connection *)
Definition: vrpn_Connection.C:1453
vrpn_Connection_IP::d_NIC_IP
char * d_NIC_IP
Definition: vrpn_Connection.h:865
vrpn_Endpoint_IP::d_NICaddress
char * d_NICaddress
Definition: vrpn_Connection.h:503
vrpn_copy_service_location
char * vrpn_copy_service_location(const char *fullname)
Definition: vrpn_Connection.C:6353
vrpn_ANY_SENDER
const int vrpn_ANY_SENDER
vrpn_ANY_SENDER can be used to register callbacks on a given message type from any sender.
Definition: vrpn_Connection.h:77
vrpn_Endpoint_IP::d_udpAlignedInbuf
vrpn_float64 d_udpAlignedInbuf[vrpn_CONNECTION_UDP_BUFLEN/sizeof(vrpn_float64)+1]
Definition: vrpn_Connection.h:499
BROKEN
@ BROKEN
Definition: vrpn_Connection.h:33
vrpn_TimevalGreater
bool vrpn_TimevalGreater(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:113
vrpn_Endpoint_IP::~vrpn_Endpoint_IP
virtual ~vrpn_Endpoint_IP(void)
Definition: vrpn_Connection.C:2707
vrpn_Connection::get_time
virtual timeval get_time()
returns the current time in the connection (since the epoch – UTC time).
Definition: vrpn_Connection.C:4702
vrpn_Endpoint::openLogs
int openLogs(void)
Definition: vrpn_Connection.C:4374
vrpn_Log::d_logFileName
char * d_logFileName
Definition: vrpn_Log.h:74
vrpn_MESSAGEHANDLER
int(VRPN_CALLBACK * vrpn_MESSAGEHANDLER)(void *userdata, vrpn_HANDLERPARAM p)
Type of a message handler for vrpn_Connection messages.
Definition: vrpn_Connection.h:53
vrpn_Connection_IP::~vrpn_Connection_IP
virtual ~vrpn_Connection_IP(void)
Definition: vrpn_Connection.C:6268
vrpn_Connection::register_sender
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...
Definition: vrpn_Connection.C:5032
vrpn_copy_rsh_program
char * vrpn_copy_rsh_program(const char *hostspecifier)
Definition: vrpn_Connection.C:6484
check_vrpn_file_cookie
int check_vrpn_file_cookie(const char *buffer)
Definition: vrpn_Connection.C:2590
vrpn_Connection::d_stop_processing_messages_after
vrpn_uint32 d_stop_processing_messages_after
If this value is greater than zero, the connection should stop looking for new messages on a given en...
Definition: vrpn_Connection.h:645
vrpn_Connection::message_type_name
virtual const char * message_type_name(vrpn_int32 type)
Definition: vrpn_Connection.C:4718
vrpn_Endpoint_IP::d_udpSequenceNumber
vrpn_int32 d_udpSequenceNumber
Definition: vrpn_Connection.h:492
vrpn_Endpoint_IP::d_udpInbuf
char * d_udpInbuf
Definition: vrpn_Connection.h:501
vrpn_Log::saveLogSoFar
int saveLogSoFar(void)
Saves any messages logged so far.
Definition: vrpn_Connection.C:586
vrpn_Endpoint_IP::d_udpOutboundSocket
SOCKET d_udpOutboundSocket
Definition: vrpn_Connection.h:476
vrpn_CONNECTION_TYPE_DESCRIPTION
const vrpn_int32 vrpn_CONNECTION_TYPE_DESCRIPTION
Definition: vrpn_Connection.h:107
vrpn_Endpoint::newLocalSender
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...
Definition: vrpn_Connection.C:3032
vrpn_LOGLIST::data
vrpn_HANDLERPARAM data
Definition: vrpn_Connection.h:162
vrpn_Endpoint::d_remoteInLogName
char * d_remoteInLogName
Name of the remote log file.
Definition: vrpn_Connection.h:291
vrpn_Log::d_logmode
long d_logmode
Definition: vrpn_Log.h:75
vrpn_Endpoint::setup_new_connection
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 server ...
TRYING_TO_CONNECT
@ TRYING_TO_CONNECT
Definition: vrpn_Connection.h:32
vrpn_noint_block_read
int vrpn_noint_block_read(int infile, char buffer[], size_t length)
Definition: vrpn_Connection.C:1757
vrpn_Log::setCookie
int setCookie(const char *cookieBuffer)
The magic cookie is set to the default value of the version of VRPN compiled, but a more correct valu...
Definition: vrpn_Connection.C:844
vrpn_LOG_INCOMING
const long vrpn_LOG_INCOMING
Definition: vrpn_Connection.h:131
vrpn_HANDLERPARAM::type
vrpn_int32 type
Definition: vrpn_Connection.h:45
vrpn_Endpoint::dispatch
virtual int dispatch(vrpn_int32 type, vrpn_int32 sender, timeval time, vrpn_uint32 payload_len, char *bufptr)
Definition: vrpn_Connection.C:4168
vrpn_Connection::removeReference
void removeReference()
Definition: vrpn_Connection.C:5020
vrpn_Log::d_wroteMagicCookie
vrpn_bool d_wroteMagicCookie
Definition: vrpn_Log.h:84
vrpn_Endpoint::d_remoteLogMode
long d_remoteLogMode
Mode to put the remote logging in.
Definition: vrpn_Connection.h:290
vrpn_buffer
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
vrpn_Endpoint::local_type_id
int local_type_id(vrpn_int32 remote_type) const
Returns the local mapping for the remote type (-1 if none).
Definition: vrpn_Connection.C:2755
vrpn_Endpoint::pack_sender_description
int pack_sender_description(vrpn_int32 which)
Packs a sender description over our socket.
Definition: vrpn_Connection.C:4466
vrpn_Connection::doing_okay
virtual vrpn_bool doing_okay(void) const
Returns vrpn_true if the connection is okay, vrpn_false if not.
Definition: vrpn_Connection.C:5222
cName
char cName[100]
Length of names within VRPN.
Definition: vrpn_Connection.h:158
vrpnLogFilterEntry
Definition: vrpn_Connection.h:181
vrpn_Connection_Loopback::~vrpn_Connection_Loopback
virtual ~vrpn_Connection_Loopback(void)
Definition: vrpn_Connection.C:6322
vrpn_Endpoint_IP::d_tcpListenSocket
SOCKET d_tcpListenSocket
This section deals with when a client connection is trying to establish (or re-establish) a connectio...
Definition: vrpn_Connection.h:452
vrpn_Endpoint_IP::set_tcp_outbuf_size
vrpn_int32 set_tcp_outbuf_size(vrpn_int32 bytecount)
Definition: vrpn_Connection.C:3656
vrpn_get_port_number
int vrpn_get_port_number(const char *hostspecifier)
Definition: vrpn_Connection.C:6464
vrpn_Endpoint_IP::setNICaddress
void setNICaddress(const char *)
Definition: vrpn_Connection.C:3757
vrpn_TimevalSum
timeval vrpn_TimevalSum(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:45
SOCKET
#define SOCKET
Definition: vrpn_Shared.h:46
vrpnLogFilterEntry::userdata
void * userdata
passed along
Definition: vrpn_Connection.h:183
vrpn_Endpoint_IP::d_udpBuflen
vrpn_int32 d_udpBuflen
Definition: vrpn_Connection.h:487
vrpn_Endpoint::~vrpn_Endpoint
virtual ~vrpn_Endpoint(void)
Definition: vrpn_Connection.C:2677
vrpnMsgCallbackEntry::next
vrpnMsgCallbackEntry * next
Next handler.
Definition: vrpn_Connection.h:178
GSN_CAST
#define GSN_CAST
Definition: vrpn_Connection.C:89
vrpn_Endpoint_IP::d_remote_port_number
int d_remote_port_number
Port to connect to on remote machine.
Definition: vrpn_Connection.h:463
vrpn_copy_service_name
char * vrpn_copy_service_name(const char *fullname)
Definition: vrpn_Connection.C:6335
vrpnMsgCallbackEntry::sender
vrpn_int32 sender
Only if from sender.
Definition: vrpn_Connection.h:177
vrpn_Connection_IP
Definition: vrpn_Connection.h:765
vrpn_File_Connection
class VRPN_API vrpn_File_Connection
Definition: vrpn_Connection.h:37
vrpn_HANDLERPARAM::sender
vrpn_int32 sender
Definition: vrpn_Connection.h:46
vrpnMsgCallbackEntry::userdata
void * userdata
Passed along.
Definition: vrpn_Connection.h:176
vrpn_ConnectionManager::getByName
vrpn_Connection * getByName(const char *name)
Searches through d_kcList but NOT d_anonList (Connections constructed with no name)
Definition: vrpn_Connection.C:1478
vrpn_Endpoint::d_senders
vrpn_TranslationTable * d_senders
Definition: vrpn_Connection.h:352
vrpn_Endpoint::status
int status
Definition: vrpn_Connection.h:284
vrpn_Connection::register_handler
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...
Definition: vrpn_Connection.C:5199
vrpn_Endpoint_IP::init
void init(void)
Definition: vrpn_Connection.C:2803
vrpn_Connection_Loopback
Constructor for a Loopback connection that will basically just pass messages between objects that are...
Definition: vrpn_Connection.h:874
vrpn_Endpoint_IP::d_tcpListenPort
int d_tcpListenPort
Socket and port that the client listens on when lobbing datagrams at the server and waiting for it to...
Definition: vrpn_Connection.h:453
vrpn_CONNECTION_SENDER_DESCRIPTION
const vrpn_int32 vrpn_CONNECTION_SENDER_DESCRIPTION
Definition: vrpn_Connection.h:106
vrpn_Endpoint::d_dispatcher
vrpn_TypeDispatcher * d_dispatcher
Definition: vrpn_Connection.h:355
CONNECTED
@ CONNECTED
Definition: vrpn_Connection.h:30
vrpn_Connection_IP::listen_udp_sock
SOCKET listen_udp_sock
UDP Connect requests come here.
Definition: vrpn_Connection.h:835
vrpn_Endpoint::tryToMarshall
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....
Definition: vrpn_Connection.C:4199
vrpn_Connection::message_type_is_registered
int message_type_is_registered(const char *) const
Returns message type ID, or -1 if unregistered.
Definition: vrpn_Connection.C:5213
vrpn_Connection::time_since_connection_open
virtual int time_since_connection_open(struct timeval *elapsed_time)
Returns the time since the connection opened. Some subclasses may redefine time.
Definition: vrpn_Connection.C:4691
vrpn_Endpoint_IP::mainloop
int mainloop(timeval *timeout)
Definition: vrpn_Connection.C:2817
vrpn_Connection_Loopback::vrpn_Connection_Loopback
vrpn_Connection_Loopback()
Make a client connection. To access this from user code, call vrpn_create_server_connection() with a ...
Definition: vrpn_Connection.C:6312
vrpn_CONTROL
const char * vrpn_CONTROL
vrpn_CONTROL is the sender used for notification messages sent to the user from the local VRPN implem...
Definition: vrpn_Connection.C:190
vrpn_Endpoint_IP::d_udpNumOut
vrpn_int32 d_udpNumOut
Definition: vrpn_Connection.h:489
vrpn_Endpoint_IP::handle_tcp_messages
int handle_tcp_messages(const timeval *timeout)
Definition: vrpn_Connection.C:3336
vrpn_Endpoint_IP::connect_tcp_to
int connect_tcp_to(const char *msg)
Definition: vrpn_Connection.C:3515
vrpn_create_server_connection
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).
Definition: vrpn_Connection.C:5358