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