vrpn 07.36
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.36";
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
305
306struct cRemoteMapping {
307 char *name;
308 vrpn_int32 remote_id;
309 vrpn_int32 local_id;
310};
311
312class vrpn_TranslationTable {
313
314public:
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(vrpn_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(vrpn_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(vrpn_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(vrpn_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)
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 vrpn_strncpynull(s, this->d_logFileName, strlen(this->d_logFileName) + 1);
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 return -1;
824 }
825
826 // need to explicitly override the const
827 memcpy(const_cast<char *>(lp->data.buffer), buffer, payloadLen);
828 }
829
830 // Insert the new message into the log
831 lp->next = d_logTail;
832 lp->prev = NULL;
833 if (d_logTail) {
834 d_logTail->prev = lp;
835 }
836 d_logTail = lp;
837 if (!d_firstEntry) {
838 d_firstEntry = lp;
839 }
840
841 return 0;
842}
843
844int vrpn_Log::setCompoundName(const char *name, int index)
845{
846 // Make sure we have room to store the output.
847 // The result of printing an integer will always be less than 100 characters.
848 // Fill it with zeroes so that whatever string is there will always be NULL-
849 // terminated.
850 vrpn_vector<char> newName;
851 newName.assign(strlen(name) + 100 + 1, 0);
852 const char *dot;
853 size_t len;
854
855 // Change foo.bar, 5 to foo-5.bar
856 // and foo, 5 to foo-5
857
858 dot = strrchr(name, '.');
859 if (dot) {
860 strncpy(newName.data(), name, dot - name);
861 // Automatically NULL-terminated above.
862 } else {
863 strncpy(newName.data(), name, newName.size());
864 }
865 len = strlen(newName.data());
866 snprintf(newName.data() + len, newName.size() - len, "-%d", index);
867 if (dot) {
868 strncat(newName.data(), dot, newName.size() - (strlen(newName.data())+1) );
869 }
870
871 return setName(newName.data());
872}
873
874int vrpn_Log::setName(const char *name) { return setName(name, strlen(name)); }
875
876int vrpn_Log::setName(const char *name, size_t len)
877{
878 if (d_logFileName) {
879 try {
880 delete[] d_logFileName;
881 } catch (...) {
882 fprintf(stderr, "vrpn_Log::setName: delete failed\n");
883 return -1;
885 d_logFileName = NULL;
886 }
887 try {
888 d_logFileName = new char[1 + len];
889 strncpy(d_logFileName, name, len);
890 d_logFileName[len] = '\0';
891 } catch (...) {
892 return -1;
893 }
894 return 0;
895}
896
897int vrpn_Log::setCookie(const char *cookieBuffer)
898{
899 if (d_magicCookie) {
900 try {
901 delete[] d_magicCookie;
902 } catch (...) {
903 fprintf(stderr, "vrpn_Log::setCookie: delete failed\n");
904 return -1;
905 }
906 }
907 try { d_magicCookie = new char[1 + vrpn_cookie_size()]; }
908 catch (...) {
909 fprintf(stderr, "vrpn_Log::setCookie: Out of memory.\n");
910 return -1;
911 }
912 memset(d_magicCookie, 0, 1 + vrpn_cookie_size());
913 strncpy(d_magicCookie, cookieBuffer, vrpn_cookie_size());
914
915 return 0;
916}
917
918long &vrpn_Log::logMode(void) { return d_logmode; }
919
920int vrpn_Log::addFilter(vrpn_LOGFILTER filter, void *userdata)
921{
922 vrpnLogFilterEntry *newEntry;
923
924 try { newEntry = new vrpnLogFilterEntry; }
925 catch (...) {
926 fprintf(stderr, "vrpn_Log::addFilter: Out of memory.\n");
927 return -1;
928 }
929
930 newEntry->filter = filter;
931 newEntry->userdata = userdata;
932 newEntry->next = d_filters;
933 d_filters = newEntry;
934
935 return 0;
936}
937
939
940int vrpn_Log::checkFilters(vrpn_int32 payloadLen, struct timeval time,
941 vrpn_int32 type, vrpn_int32 sender,
942 const char *buffer)
943{
944 vrpnLogFilterEntry *next;
945
947 p.type = type;
948 p.sender = sender;
949 p.msg_time.tv_sec = time.tv_sec;
950 p.msg_time.tv_usec = time.tv_usec;
951 p.payload_len = payloadLen;
952 p.buffer = buffer;
953
954 for (next = d_filters; next; next = next->next) {
955 if ((*next->filter)(next->userdata, p)) {
956 // Don't log
957 return 1;
958 }
959 }
960
961 return 0;
962}
963
970
971class vrpn_TypeDispatcher {
972
973public:
975 ~vrpn_TypeDispatcher(void);
976
977 // ACCESSORS
978
979 int numTypes(void) const;
980 const char *typeName(int which) const;
981
982 vrpn_int32 getTypeID(const char *name);
984
985 int numSenders(void) const;
986 const char *senderName(int which) const;
987
988 vrpn_int32 getSenderID(const char *name);
990
991 // MANIPULATORS
992
993 vrpn_int32 addType(const char *name);
994 vrpn_int32 addSender(const char *name);
995
996 vrpn_int32 registerType(const char *name);
1000
1001 vrpn_int32 registerSender(const char *name);
1005
1006 int addHandler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata,
1007 vrpn_int32 sender);
1008 int removeHandler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler,
1009 void *userdata, vrpn_int32 sender);
1010 void setSystemHandler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler);
1011
1012 // It'd make a certain amount of sense to unify these next few, but
1013 // there are some places in the code that depend on the side effect of
1014 // do_callbacks_for() NOT dispatching system messages.
1015
1016 int doCallbacksFor(vrpn_int32 type, vrpn_int32 sender, timeval time,
1017 vrpn_uint32 len, const char *buffer);
1018 int doSystemCallbacksFor(vrpn_int32 type, vrpn_int32 sender, timeval time,
1019 vrpn_uint32 len, const char *buffer,
1020 void *userdata);
1021 int doSystemCallbacksFor(vrpn_HANDLERPARAM p, void *userdata);
1022
1023 void clear(void);
1024
1025protected:
1026 struct vrpnLocalMapping {
1027 vrpn_CNAME name; // Name of type
1028 vrpnMsgCallbackEntry *who_cares; // Callbacks
1029 vrpn_int32 cCares; // TCH 28 Oct 97
1030 };
1031
1032 int d_numTypes;
1033 vrpnLocalMapping d_types[vrpn_CONNECTION_MAX_TYPES];
1034
1035 int d_numSenders;
1036 char *d_senders[vrpn_CONNECTION_MAX_SENDERS];
1037
1039
1040 vrpnMsgCallbackEntry *d_genericCallbacks;
1041};
1042
1043vrpn_TypeDispatcher::vrpn_TypeDispatcher(void)
1044 : d_numTypes(0)
1045 , d_numSenders(0)
1046 , d_genericCallbacks(NULL)
1047{
1048 int i;
1049 // Make all of the names NULL pointers so they get allocated later
1050 for (i = 0; i < vrpn_CONNECTION_MAX_SENDERS; i++) {
1051 d_senders[i] = NULL;
1052 }
1053
1054 // Clear out any entries in the table.
1055 clear();
1056}
1057
1058vrpn_TypeDispatcher::~vrpn_TypeDispatcher(void)
1059{
1060 vrpnMsgCallbackEntry *pVMCB, *pVMCB_Del;
1061 int i;
1062
1063 for (i = 0; i < d_numTypes; i++) {
1064 pVMCB = d_types[i].who_cares;
1065 while (pVMCB) {
1066 pVMCB_Del = pVMCB;
1067 pVMCB = pVMCB_Del->next;
1068 try {
1069 delete pVMCB_Del;
1070 } catch (...) {
1071 fprintf(stderr, "vrpn_TypeDispatcher::~vrpn_TypeDispatcher: delete failed\n");
1072 return;
1073 }
1074 }
1075 }
1076
1077 pVMCB = d_genericCallbacks;
1078
1079 while (pVMCB) {
1080 pVMCB_Del = pVMCB;
1081 pVMCB = pVMCB_Del->next;
1082 try {
1083 delete pVMCB_Del;
1084 } catch (...) {
1085 fprintf(stderr, "vrpn_TypeDispatcher::~vrpn_TypeDispatcher: delete failed\n");
1086 return;
1087 }
1088 }
1089
1090 // Clear out any entries in the table.
1091 clear();
1092}
1093
1094int vrpn_TypeDispatcher::numTypes(void) const { return d_numTypes; }
1095
1096const char *vrpn_TypeDispatcher::typeName(int i) const
1097{
1098 if ((i < 0) || (i >= d_numTypes)) {
1099 return NULL;
1100 }
1101 return d_types[i].name;
1102}
1103
1104vrpn_int32 vrpn_TypeDispatcher::getTypeID(const char *name)
1105{
1106 vrpn_int32 i;
1107
1108 for (i = 0; i < d_numTypes; i++) {
1109 if (!strcmp(name, d_types[i].name)) {
1110 return i;
1111 }
1112 }
1113
1114 return -1;
1115}
1116
1117int vrpn_TypeDispatcher::numSenders(void) const { return d_numSenders; }
1118
1119const char *vrpn_TypeDispatcher::senderName(int i) const
1120{
1121 if ((i < 0) || (i >= d_numSenders)) {
1122 return NULL;
1123 }
1124 return d_senders[i];
1125}
1126
1127vrpn_int32 vrpn_TypeDispatcher::getSenderID(const char *name)
1128{
1129 vrpn_int32 i;
1130
1131 for (i = 0; i < d_numSenders; i++) {
1132 if (!strcmp(name, d_senders[i])) {
1133 return i;
1134 }
1135 }
1136
1137 return -1;
1138}
1139
1140vrpn_int32 vrpn_TypeDispatcher::addType(const char *name)
1141{
1142
1143 // See if there are too many on the list. If so, return -1.
1144 if (d_numTypes >= vrpn_CONNECTION_MAX_TYPES) {
1145 fprintf(stderr, "vrpn_TypeDispatcher::addType: "
1146 "Too many! (%d)\n",
1147 d_numTypes);
1148 return -1;
1149 }
1150
1151 // Add this one into the list and return its index
1152 vrpn_strcpy(d_types[d_numTypes].name, name);
1153 d_types[d_numTypes].who_cares = NULL;
1154 d_types[d_numTypes].cCares = 0;
1155 d_numTypes++;
1156
1157 return d_numTypes - 1;
1158}
1159
1160vrpn_int32 vrpn_TypeDispatcher::addSender(const char *name)
1161{
1162
1163 // See if there are too many on the list. If so, return -1.
1164 if (d_numSenders >= vrpn_CONNECTION_MAX_SENDERS) {
1165 fprintf(stderr, "vrpn_TypeDispatcher::addSender: "
1166 "Too many! (%d).\n",
1167 d_numSenders);
1168 return -1;
1169 }
1170
1171 if (!d_senders[d_numSenders]) {
1172
1173 // fprintf(stderr, "Allocating a new name entry\n");
1174
1175 try { d_senders[d_numSenders] = new char[sizeof(vrpn_CNAME)]; }
1176 catch (...) {
1177 fprintf(stderr, "vrpn_TypeDispatcher::addSender: "
1178 "Can't allocate memory for new record\n");
1179 return -1;
1180 }
1181 }
1182
1183 // Add this one into the list
1184 strncpy(d_senders[d_numSenders], name, sizeof(vrpn_CNAME) - 1);
1185 d_senders[d_numSenders][sizeof(vrpn_CNAME) - 1] = '\0';
1186 d_numSenders++;
1187
1188 // One more in place -- return its index
1189 return d_numSenders - 1;
1190}
1191
1192vrpn_int32 vrpn_TypeDispatcher::registerType(const char *name)
1193{
1194 vrpn_int32 retval;
1195
1196 // See if the name is already in the list. If so, return it.
1197 retval = getTypeID(name);
1198 if (retval != -1) {
1199 return retval;
1200 }
1201
1202 return addType(name);
1203}
1204
1205vrpn_int32 vrpn_TypeDispatcher::registerSender(const char *name)
1206{
1207 vrpn_int32 retval;
1208
1209 // See if the name is already in the list. If so, return it.
1210 retval = getSenderID(name);
1211 if (retval != -1) {
1212 return retval;
1213 }
1214
1215 return addSender(name);
1216}
1217
1218int vrpn_TypeDispatcher::addHandler(vrpn_int32 type,
1219 vrpn_MESSAGEHANDLER handler, void *userdata,
1220 vrpn_int32 sender)
1221{
1222 vrpnMsgCallbackEntry *new_entry;
1223 vrpnMsgCallbackEntry **ptr;
1224
1225 // Ensure that the type is a valid one (one that has been defined)
1226 // OR that it is "any"
1227 if (((type < 0) || (type >= d_numTypes)) && (type != vrpn_ANY_TYPE)) {
1228 fprintf(stderr, "vrpn_TypeDispatcher::addHandler: No such type\n");
1229 return -1;
1230 }
1231
1232 // Ensure that the sender is a valid one (or "any")
1233 if ((sender != vrpn_ANY_SENDER) &&
1234 ((sender < 0) || (sender >= d_numSenders))) {
1235 fprintf(stderr, "vrpn_TypeDispatcher::addHandler: No such sender\n");
1236 return -1;
1237 }
1238
1239 // Ensure that the handler is non-NULL
1240 if (handler == NULL) {
1241 fprintf(stderr, "vrpn_TypeDispatcher::addHandler: NULL handler\n");
1242 return -1;
1243 }
1244
1245 // Allocate and initialize the new entry
1246 try {
1247 new_entry = new vrpnMsgCallbackEntry;
1248 new_entry->handler = handler;
1249 new_entry->userdata = userdata;
1250 new_entry->sender = sender;
1251 } catch (...) {
1252 fprintf(stderr, "vrpn_TypeDispatcher::addHandler: Out of memory\n");
1253 return -1;
1254 }
1255
1256#ifdef VERBOSE
1257 printf("Adding user handler for type %ld, sender %ld\n", type, sender);
1258#endif
1259
1260 // TCH June 2000 - rewrote to insert at end of list instead of beginning,
1261 // to make sure multiple callbacks on the same type are triggered
1262 // in the order registered. Note that multiple entries with the same
1263 // info is okay.
1264
1265 if (type == vrpn_ANY_TYPE) {
1266 ptr = &d_genericCallbacks;
1267 }
1268 else {
1269 ptr = &d_types[type].who_cares;
1270 }
1271
1272 while (*ptr) {
1273 ptr = &((*ptr)->next);
1274 }
1275 *ptr = new_entry;
1276 new_entry->next = NULL;
1277
1278 return 0;
1279}
1280
1281int vrpn_TypeDispatcher::removeHandler(vrpn_int32 type,
1282 vrpn_MESSAGEHANDLER handler,
1283 void *userdata, vrpn_int32 sender)
1284{
1285 // The pointer at *snitch points to victim
1286 vrpnMsgCallbackEntry *victim, **snitch;
1287
1288 // Ensure that the type is a valid one (one that has been defined)
1289 // OR that it is "any"
1290 if (((type < 0) || (type >= d_numTypes)) && (type != vrpn_ANY_TYPE)) {
1291 fprintf(stderr, "vrpn_TypeDispatcher::removeHandler: No such type\n");
1292 return -1;
1293 }
1294
1295 // Find a handler with this registry in the list (any one will do,
1296 // since all duplicates are the same).
1297 if (type == vrpn_ANY_TYPE) {
1298 snitch = &d_genericCallbacks;
1299 }
1300 else {
1301 snitch = &(d_types[type].who_cares);
1302 }
1303 victim = *snitch;
1304 while ((victim != NULL) &&
1305 ((victim->handler != handler) || (victim->userdata != userdata) ||
1306 (victim->sender != sender))) {
1307 snitch = &((*snitch)->next);
1308 victim = victim->next;
1309 }
1310
1311 // Make sure we found one
1312 if (victim == NULL) {
1313 fprintf(stderr,
1314 "vrpn_TypeDispatcher::removeHandler: No such handler\n");
1315 return -1;
1316 }
1317
1318 // Remove the entry from the list
1319 *snitch = victim->next;
1320 try {
1321 delete victim;
1322 } catch (...) {
1323 fprintf(stderr, "vrpn_TypeDispatcher::removeHandler: delete failed\n");
1324 return -1;
1325 }
1326
1327 return 0;
1328}
1329
1330void vrpn_TypeDispatcher::setSystemHandler(vrpn_int32 type,
1331 vrpn_MESSAGEHANDLER handler)
1332{
1333 d_systemMessages[-type] = handler;
1334}
1335
1336int vrpn_TypeDispatcher::doCallbacksFor(vrpn_int32 type, vrpn_int32 sender,
1337 timeval time, vrpn_uint32 len,
1338 const char *buffer)
1339{
1340 vrpnMsgCallbackEntry *who;
1341 vrpn_HANDLERPARAM p;
1342
1343 // We don't dispatch system messages (kluge?).
1344 if (type < 0) {
1345 return 0;
1346 }
1347
1348 if (type >= d_numTypes) {
1349 return -1;
1350 }
1351
1352 // Fill in the parameter to be passed to the routines
1353 p.type = type;
1354 p.sender = sender;
1355 p.msg_time = time;
1356 p.payload_len = len;
1357 p.buffer = buffer;
1358
1359 // Do generic callbacks (vrpn_ANY_TYPE)
1360 who = d_genericCallbacks;
1361
1362 while (who) { // For each callback entry
1363 // Verify that the sender is ANY or matches
1364 if ((who->sender == vrpn_ANY_SENDER) || (who->sender == sender)) {
1365 if (who->handler(who->userdata, p)) {
1366 fprintf(stderr, "vrpn_TypeDispatcher::doCallbacksFor: "
1367 "Nonzero user generic handler return.\n");
1368 return -1;
1369 }
1370 }
1371
1372 // Next callback in list
1373 who = who->next;
1374 }
1375
1376 // Find the head for the list of callbacks to call
1377 who = d_types[type].who_cares;
1378 while (who) { // For each callback entry
1379 // Verify that the sender is ANY or matches
1380 if ((who->sender == vrpn_ANY_SENDER) || (who->sender == sender)) {
1381 if (who->handler(who->userdata, p)) {
1382 fprintf(stderr, "vrpn_TypeDispatcher::doCallbacksFor: "
1383 "Nonzero user handler return.\n");
1384 return -1;
1385 }
1386 }
1387
1388 // Next callback in list
1389 who = who->next;
1390 }
1391
1392 return 0;
1393}
1394
1395int vrpn_TypeDispatcher::doSystemCallbacksFor(vrpn_int32 type,
1396 vrpn_int32 sender, timeval time,
1397 vrpn_uint32 len,
1398 const char *buffer,
1399 void *userdata)
1400{
1401 vrpn_HANDLERPARAM p;
1402
1403 if (type >= 0) {
1404 return 0;
1405 }
1406 if (-type >= vrpn_CONNECTION_MAX_TYPES) {
1407 fprintf(stderr, "vrpn_TypeDispatcher::doSystemCallbacksFor: "
1408 "Illegal type %d.\n",
1409 type);
1410 return -1;
1411 }
1412
1413 if (!d_systemMessages[-type]) {
1414 return 0;
1415 }
1416
1417 // Fill in the parameter to be passed to the routines
1418 p.type = type;
1419 p.sender = sender;
1420 p.msg_time = time;
1421 p.payload_len = len;
1422 p.buffer = buffer;
1423
1424 return doSystemCallbacksFor(p, userdata);
1425}
1426
1427int vrpn_TypeDispatcher::doSystemCallbacksFor(vrpn_HANDLERPARAM p,
1428 void *userdata)
1429{
1430 int retval;
1431
1432 if (p.type >= 0) {
1433 return 0;
1434 }
1435 if (-p.type >= vrpn_CONNECTION_MAX_TYPES) {
1436 fprintf(stderr, "vrpn_TypeDispatcher::doSystemCallbacksFor: "
1437 "Illegal type %d.\n",
1438 p.type);
1439 return -1;
1440 }
1441
1442 if (!d_systemMessages[-p.type]) {
1443 return 0;
1444 }
1445
1446 retval = d_systemMessages[-p.type](userdata, p);
1447 if (retval) {
1448 fprintf(stderr, "vrpn_TypeDispatcher::doSystemCallbacksFor: "
1449 "Nonzero system handler return.\n");
1450 return -1;
1451 }
1452 return 0;
1453}
1454
1455void vrpn_TypeDispatcher::clear(void)
1456{
1457 int i;
1458
1459 for (i = 0; i < vrpn_CONNECTION_MAX_TYPES; i++) {
1460 d_types[i].who_cares = NULL;
1461 d_types[i].cCares = 0;
1462
1463 d_systemMessages[i] = NULL;
1464 }
1465
1466 for (i = 0; i < vrpn_CONNECTION_MAX_SENDERS; i++) {
1467 if (d_senders[i] != NULL) {
1468 try {
1469 delete[] d_senders[i];
1470 } catch (...) {
1471 fprintf(stderr, "vrpn_TypeDispatcher::clear: delete failed\n");
1472 return;
1473 }
1474 }
1475 d_senders[i] = NULL;
1476 }
1477}
1478
1480{
1481 vrpn::SemaphoreGuard guard(d_semaphore);
1482 // fprintf(stderr, "In ~vrpn_ConnectionManager: tearing down the list.\n");
1483
1484 // Call the destructor of every known connection.
1485 // That destructor will call vrpn_ConnectionManager::deleteConnection()
1486 // to remove itself from d_kcList, so we need to free up the semaphore
1487 // during the call to delete it).
1488 while (d_kcList) {
1489 vrpn_Connection *ptr = d_kcList->connection;
1490 d_semaphore.v();
1491 try {
1492 delete ptr;
1493 } catch (...) {
1494 fprintf(stderr, "vrpn_ConnectionManager::~vrpn_ConnectionManager: delete failed\n");
1495 return;
1496 }
1497 d_semaphore.p();
1498 }
1499 while (d_anonList) {
1500 vrpn_Connection *ptr = d_anonList->connection;
1501 d_semaphore.v();
1502 try {
1503 delete ptr;
1504 } catch (...) {
1505 fprintf(stderr, "vrpn_ConnectionManager::~vrpn_ConnectionManager: delete failed\n");
1506 return;
1507 }
1508 d_semaphore.p();
1509 }
1510}
1511
1512// static
1513vrpn_ConnectionManager &vrpn_ConnectionManager::instance(void)
1514{
1515 // We have a separate semaphore for this static function to
1516 // make sure it is only entered by one thread at a time.
1517 // This avoids a race on the constructor of the static
1518 // instance.
1519 static vrpn_Semaphore sem;
1520 vrpn::SemaphoreGuard guard(sem);
1521 static vrpn_ConnectionManager manager;
1522 return manager;
1523}
1524
1526{
1527 vrpn::SemaphoreGuard guard(d_semaphore);
1528 {
1529 knownConnection *p;
1530
1531 p = new knownConnection;
1532 p->connection = c;
1533
1534 if (name) {
1535 vrpn_strcpy(p->name, name);
1536 p->next = d_kcList;
1537 d_kcList = p;
1538 }
1539 else {
1540 p->name[0] = 0;
1541 p->next = d_anonList;
1542 d_anonList = p;
1543 }
1544 }
1545}
1546
1548{
1549 vrpn::SemaphoreGuard guard(d_semaphore);
1550 {
1551 deleteConnection(c, &d_kcList);
1552 deleteConnection(c, &d_anonList);
1553 }
1554}
1555
1557 knownConnection **snitch)
1558{
1559 // NOTE: The private methods do not grab the semaphore; it will have
1560 // been grabbed by the public method that called it.
1561 knownConnection *victim = *snitch;
1562
1563 while (victim && (victim->connection != c)) {
1564 snitch = &((*snitch)->next);
1565 victim = *snitch;
1566 }
1567
1568 if (!victim) {
1569 // No warning, because this connection might be on the *other* list.
1570 }
1571 else {
1572 *snitch = victim->next;
1573 try {
1574 delete victim;
1575 } catch (...) {
1576 fprintf(stderr, "vrpn_ConnectionManager::deleteConnection: delete failed\n");
1577 return;
1578 }
1579 }
1580}
1581
1583{
1584 // NOTE: The private methods do not grab the semaphore; it will have
1585 // been grabbed by the public method that called it.
1586 knownConnection *p;
1587 for (p = d_kcList; p && strcmp(p->name, name); p = p->next) {
1588 // do nothing
1589 }
1590 if (!p) {
1591 return NULL;
1592 }
1593 return p->connection;
1594}
1595
1596vrpn_ConnectionManager::vrpn_ConnectionManager(void)
1597 : d_kcList(NULL)
1598 , d_anonList(NULL)
1599{
1600}
1601
1613
1614static int vrpn_getmyIP(char *myIPchar, unsigned maxlen,
1615 const char *NIC_IP = NULL,
1616 vrpn_SOCKET incoming_socket = INVALID_SOCKET)
1617{
1618 char myname[100]; // Host name of this host
1619 struct hostent *host; // Encoded host IP address, etc.
1620 char myIPstring[100]; // Hold "152.2.130.90" or whatever
1621
1622 if (myIPchar == NULL) {
1623 fprintf(stderr, "vrpn_getmyIP: NULL pointer passed in\n");
1624 return -1;
1625 }
1626
1627 // If we have a specified NIC_IP address, fill it in and return it.
1628 if (NIC_IP) {
1629 if (strlen(NIC_IP) > maxlen) {
1630 fprintf(stderr, "vrpn_getmyIP: Name too long to return\n");
1631 return -1;
1632 }
1633#ifdef VERBOSE
1634 fprintf(stderr, "Was given IP address of %s so returning that.\n",
1635 NIC_IP);
1636#endif
1637 strncpy(myIPchar, NIC_IP, maxlen);
1638 myIPchar[maxlen - 1] = '\0';
1639 return 0;
1640 }
1641
1642 // If we have a valid specified vrpn_SOCKET, then look up its address and
1643 // return it.
1644 if (incoming_socket != INVALID_SOCKET) {
1645 struct sockaddr_in socket_name;
1646 int socket_namelen = sizeof(socket_name);
1647
1648 if (getsockname(incoming_socket, (struct sockaddr *)&socket_name,
1649 GSN_CAST & socket_namelen)) {
1650 fprintf(stderr, "vrpn_getmyIP: cannot get socket name.\n");
1651 return -1;
1652 }
1653
1654 snprintf(myIPstring, 100, "%u.%u.%u.%u",
1655 ntohl(socket_name.sin_addr.s_addr) >> 24,
1656 (ntohl(socket_name.sin_addr.s_addr) >> 16) & 0xff,
1657 (ntohl(socket_name.sin_addr.s_addr) >> 8) & 0xff,
1658 ntohl(socket_name.sin_addr.s_addr) & 0xff);
1659
1660 // Copy this to the output
1661 if ((unsigned)strlen(myIPstring) > maxlen) {
1662 fprintf(stderr, "vrpn_getmyIP: Name too long to return\n");
1663 return -1;
1664 }
1665
1666 vrpn_strncpynull(myIPchar, myIPstring, maxlen);
1667
1668#ifdef VERBOSE
1669 fprintf(stderr, "Decided on IP address of %s.\n", myIPchar);
1670#endif
1671 return 0;
1672 }
1673
1674 // Find out what my name is
1675 // gethostname() is guaranteed to produce something gethostbyname() can
1676 // parse.
1677 if (gethostname(myname, sizeof(myname))) {
1678 fprintf(stderr, "vrpn_getmyIP: Error finding local hostname\n");
1679 return -1;
1680 }
1681
1682 // Find out what my IP address is
1683 host = gethostbyname(myname);
1684 if (host == NULL) {
1685 fprintf(stderr, "vrpn_getmyIP: error finding host by name (%s)\n",
1686 myname);
1687 return -1;
1688 }
1689
1690// Convert this back into a string
1691#ifndef CRAY
1692 if (host->h_length != 4) {
1693 fprintf(stderr, "vrpn_getmyIP: Host length not 4\n");
1694 return -1;
1695 }
1696#endif
1697 snprintf(myIPstring, 100, "%u.%u.%u.%u",
1698 (unsigned int)(unsigned char)host->h_addr_list[0][0],
1699 (unsigned int)(unsigned char)host->h_addr_list[0][1],
1700 (unsigned int)(unsigned char)host->h_addr_list[0][2],
1701 (unsigned int)(unsigned char)host->h_addr_list[0][3]);
1702
1703 // Copy this to the output
1704 if ((unsigned)strlen(myIPstring) > maxlen) {
1705 fprintf(stderr, "vrpn_getmyIP: Name too long to return\n");
1706 return -1;
1707 }
1708
1709 vrpn_strncpynull(myIPchar, myIPstring, maxlen);
1710#ifdef VERBOSE
1711 fprintf(stderr, "Decided on IP address of %s.\n", myIPchar);
1712#endif
1713 return 0;
1714}
1715
1722int vrpn_noint_select(int width, fd_set *readfds, fd_set *writefds,
1723 fd_set *exceptfds, struct timeval *timeout)
1724{
1725 fd_set tmpread, tmpwrite, tmpexcept;
1726 int ret;
1727 int done = 0;
1728 struct timeval timeout2;
1729 struct timeval *timeout2ptr;
1730 struct timeval start, stop, now;
1731
1732 /* If the timeout parameter is non-NULL and non-zero, then we
1733 * may have to adjust it due to an interrupt. In these cases,
1734 * we will copy the timeout to timeout2, which will be used
1735 * to keep track. Also, the stop time is calculated so that
1736 * we can know when it is time to bail. */
1737 if ((timeout != NULL) &&
1738 ((timeout->tv_sec != 0) || (timeout->tv_usec != 0))) {
1739 timeout2 = *timeout;
1740 timeout2ptr = &timeout2;
1741 vrpn_gettimeofday(&start, NULL); /* Find start time */
1742 stop = vrpn_TimevalSum(start, *timeout); /* Find stop time */
1743 }
1744 else {
1745 timeout2ptr = timeout;
1746 stop.tv_sec = 0;
1747 stop.tv_usec = 0;
1748 }
1749
1750 /* Repeat selects until it returns for a reason other than interrupt */
1751 do {
1752 /* Set the temp file descriptor sets to match parameters each time
1753 * through. */
1754 if (readfds != NULL) {
1755 tmpread = *readfds;
1756 }
1757 else {
1758 FD_ZERO(&tmpread);
1759 }
1760 if (writefds != NULL) {
1761 tmpwrite = *writefds;
1762 }
1763 else {
1764 FD_ZERO(&tmpwrite);
1765 }
1766 if (exceptfds != NULL) {
1767 tmpexcept = *exceptfds;
1768 }
1769 else {
1770 FD_ZERO(&tmpexcept);
1771 }
1772
1773 /* Do the select on the temporary sets of descriptors */
1774 ret = select(width, &tmpread, &tmpwrite, &tmpexcept, timeout2ptr);
1775 if (ret >= 0) { /* We are done if timeout or found some */
1776 done = 1;
1777 }
1778 else if (vrpn_socket_error != vrpn_EINTR) { /* Done if non-intr error */
1779 done = 1;
1780 }
1781 else if ((timeout != NULL) &&
1782 ((timeout->tv_sec != 0) || (timeout->tv_usec != 0))) {
1783
1784 /* Interrupt happened. Find new time timeout value */
1785 vrpn_gettimeofday(&now, NULL);
1786 if (vrpn_TimevalGreater(now, stop)) { /* Past stop time */
1787 done = 1;
1788 }
1789 else { /* Still time to go. */
1790 unsigned long usec_left;
1791 usec_left = (stop.tv_sec - now.tv_sec) * 1000000L;
1792 usec_left += stop.tv_usec - now.tv_usec;
1793 timeout2.tv_sec = usec_left / 1000000L;
1794 timeout2.tv_usec = usec_left % 1000000L;
1795 }
1796 }
1797 } while (!done);
1798
1799 /* Copy the temporary sets back to the parameter sets */
1800 if (readfds != NULL) {
1801 *readfds = tmpread;
1802 }
1803 if (writefds != NULL) {
1804 *writefds = tmpwrite;
1805 }
1806 if (exceptfds != NULL) {
1807 *exceptfds = tmpexcept;
1808 }
1809
1810 return (ret);
1811}
1812
1825
1826#ifndef VRPN_USE_WINSOCK_SOCKETS
1827
1828int vrpn_noint_block_write(int outfile, const char buffer[], size_t length)
1829{
1830 int sofar = 0; /* How many characters sent so far */
1831 int ret; /* Return value from write() */
1832
1833 do {
1834 /* Try to write the remaining data */
1835 ret = write(outfile, buffer + sofar, length - sofar);
1836 sofar += ret;
1837
1838 /* Ignore interrupted system calls - retry */
1839 if ((ret == -1) && (vrpn_socket_error == vrpn_EINTR)) {
1840 ret = 1; /* So we go around the loop again */
1841 sofar += 1; /* Restoring it from above -1 */
1842 }
1843
1844 } while ((ret > 0) && (static_cast<size_t>(sofar) < length));
1845
1846 if (ret == -1) return (-1); /* Error during write */
1847 if (ret == 0) return (0); /* EOF reached */
1848
1849 return (sofar); /* All bytes written */
1850}
1851
1862
1863int vrpn_noint_block_read(int infile, char buffer[], size_t length)
1864{
1865 int sofar; /* How many we read so far */
1866 int ret; /* Return value from the read() */
1867
1868 // TCH 4 Jan 2000 - hackish - Cygwin will block forever on a 0-length
1869 // read(), and from the man pages this is close enough to in-spec that
1870 // other OS may do the same thing.
1871
1872 if (!length) {
1873 return 0;
1874 }
1875 sofar = 0;
1876 do {
1877 /* Try to read all remaining data */
1878 ret = read(infile, buffer + sofar, length - sofar);
1879 sofar += ret;
1880
1881 /* Ignore interrupted system calls - retry */
1882 if ((ret == -1) && (vrpn_socket_error == vrpn_EINTR)) {
1883 ret = 1; /* So we go around the loop again */
1884 sofar += 1; /* Restoring it from above -1 */
1885 }
1886 } while ((ret > 0) && (static_cast<size_t>(sofar) < length));
1887
1888 if (ret == -1) return (-1); /* Error during read */
1889 if (ret == 0) return (0); /* EOF reached */
1890
1891 return (sofar); /* All bytes read */
1892}
1893
1894#else /* winsock sockets */
1895
1896int vrpn_noint_block_write(vrpn_SOCKET outsock, char *buffer, size_t length)
1897{
1898 int nwritten;
1899 size_t sofar = 0;
1900 do {
1901 /* Try to write the remaining data */
1902 nwritten =
1903 send(outsock, buffer + sofar, static_cast<int>(length - sofar), 0);
1904
1905 if (nwritten == SOCKET_ERROR) {
1906 return -1;
1907 }
1908
1909 sofar += nwritten;
1910 } while (sofar < length);
1911
1912 return static_cast<int>(sofar); /* All bytes written */
1913}
1914
1915int vrpn_noint_block_read(vrpn_SOCKET insock, char *buffer, size_t length)
1916{
1917 int nread;
1918 size_t sofar = 0;
1919
1920 // TCH 4 Jan 2000 - hackish - Cygwin will block forever on a 0-length
1921 // read(), and from the man pages this is close enough to in-spec that
1922 // other OS may do the same thing.
1923
1924 if (!length) {
1925 return 0;
1926 }
1927
1928 do {
1929 /* Try to read all remaining data */
1930 nread =
1931 recv(insock, buffer + sofar, static_cast<int>(length - sofar), 0);
1932
1933 if (nread == SOCKET_ERROR) {
1934 return -1;
1935 }
1936 if (nread == 0) { /* socket closed */
1937 return 0;
1938 }
1939
1940 sofar += nread;
1941 } while (sofar < length);
1942
1943 return static_cast<int>(sofar); /* All bytes read */
1944}
1945
1946#endif /* VRPN_USE_WINSOCK_SOCKETS */
1947
1959
1960int vrpn_noint_block_read_timeout(vrpn_SOCKET infile, char buffer[], size_t length,
1961 struct timeval *timeout)
1962{
1963 int ret; /* Return value from the read() */
1964 struct timeval timeout2;
1965 struct timeval *timeout2ptr;
1966 struct timeval start, stop, now;
1967
1968 // TCH 4 Jan 2000 - hackish - Cygwin will block forever on a 0-length
1969 // read(), and from the man pages this is close enough to in-spec that
1970 // other OS may do the same thing.
1971
1972 if (!length) {
1973 return 0;
1974 }
1975
1976 /* If the timeout parameter is non-NULL and non-zero, then we
1977 * may have to adjust it due to an interrupt. In these cases,
1978 * we will copy the timeout to timeout2, which will be used
1979 * to keep track. Also, the current time is found so that we
1980 * can track elapsed time. */
1981 if ((timeout != NULL) &&
1982 ((timeout->tv_sec != 0) || (timeout->tv_usec != 0))) {
1983 timeout2 = *timeout;
1984 timeout2ptr = &timeout2;
1985 vrpn_gettimeofday(&start, NULL); /* Find start time */
1986 stop = vrpn_TimevalSum(start, *timeout); /* Find stop time */
1987 }
1988 else {
1989 timeout2ptr = timeout;
1990 }
1991
1992 size_t sofar = 0;/* How many we read so far */
1993 do {
1994 int sel_ret;
1995 fd_set readfds, exceptfds;
1996
1997 /* See if there is a character ready for read */
1998 FD_ZERO(&readfds);
1999 FD_SET(infile, &readfds);
2000 FD_ZERO(&exceptfds);
2001 FD_SET(infile, &exceptfds);
2002 sel_ret = vrpn_noint_select(static_cast<int>(infile) + 1, &readfds,
2003 NULL, &exceptfds, timeout2ptr);
2004 if (sel_ret == -1) { /* Some sort of error on select() */
2005 return -1;
2006 }
2007 if (FD_ISSET(infile, &exceptfds)) { /* Exception */
2008 return -1;
2009 }
2010 if (!FD_ISSET(infile, &readfds)) { /* No characters */
2011 if ((timeout != NULL) && (timeout->tv_sec == 0) &&
2012 (timeout->tv_usec == 0)) { /* Quick poll */
2013 return static_cast<int>(sofar); /* Timeout! */
2014 }
2015 }
2016
2017 /* See what time it is now and how long we have to go */
2018 if (timeout2ptr) {
2019 vrpn_gettimeofday(&now, NULL);
2020 if (vrpn_TimevalGreater(now, stop)) { /* Timeout! */
2021 return static_cast<int>(sofar);
2022 }
2023 else {
2024 timeout2 = vrpn_TimevalDiff(stop, now);
2025 }
2026 }
2027
2028 if (!FD_ISSET(infile, &readfds)) { /* No chars yet */
2029 ret = 0;
2030 continue;
2031 }
2032
2033#ifndef VRPN_USE_WINSOCK_SOCKETS
2034 ret = read(infile, buffer + sofar, length - sofar);
2035 sofar += ret;
2036
2037 /* Ignore interrupted system calls - retry */
2038 if ((ret == -1) && (vrpn_socket_error == vrpn_EINTR)) {
2039 ret = 1; /* So we go around the loop again */
2040 sofar += 1; /* Restoring it from above -1 */
2041 }
2042#else
2043 {
2044 int nread = recv(infile, buffer + sofar,
2045 static_cast<int>(length - sofar), 0);
2046 sofar += nread;
2047 ret = nread;
2048 }
2049#endif
2050
2051 } while ((ret > 0) && (sofar < length));
2052#ifndef VRPN_USE_WINSOCK_SOCKETS
2053 if (ret == -1) return (-1); /* Error during read */
2054#endif
2055 if (ret == 0) return (0); /* EOF reached */
2056
2057 return static_cast<int>(sofar); /* All bytes read */
2058}
2059
2069
2070static vrpn_SOCKET open_socket(int type, unsigned short *portno,
2071 const char *IPaddress)
2072{
2073 struct sockaddr_in name;
2074 struct hostent *phe; /* pointer to host information entry */
2075 int namelen;
2076
2077 // create an Internet socket of the appropriate type
2078 vrpn_SOCKET sock = socket(AF_INET, type, 0);
2079 if (sock == INVALID_SOCKET) {
2080 fprintf(stderr, "open_socket: can't open socket.\n");
2081#ifndef _WIN32_WCE
2082 fprintf(stderr, " -- Error %d (%s).\n", vrpn_socket_error,
2084#endif
2085 return INVALID_SOCKET;
2086 }
2087
2088// Added by Eric Boren to address socket reconnectivity on the Android
2089#ifdef __ANDROID__
2090 vrpn_int32 optval = 1;
2091 vrpn_int32 sockoptsuccess =
2092 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
2093// fprintf(stderr, "setsockopt returned %i, optval: %i\n", sockoptsuccess,
2094// optval);
2095#endif
2096
2097 namelen = sizeof(name);
2098
2099 // bind to local address
2100 memset((void *)&name, 0, namelen);
2101 name.sin_family = AF_INET;
2102 if (portno) {
2103 name.sin_port = htons(*portno);
2104 }
2105 else {
2106 name.sin_port = htons(0);
2107 }
2108
2109 // Map our host name to our IP address, allowing for dotted decimal
2110 if (!IPaddress) {
2111 name.sin_addr.s_addr = INADDR_ANY;
2112 }
2113 else if ((name.sin_addr.s_addr = inet_addr(IPaddress)) == INADDR_NONE) {
2114 if ((phe = gethostbyname(IPaddress)) != NULL) {
2115 memcpy((void *)&name.sin_addr, (const void *)phe->h_addr,
2116 phe->h_length);
2117 }
2118 else {
2119 vrpn_closeSocket(sock);
2120 fprintf(stderr, "open_socket: can't get %s host entry\n",
2121 IPaddress);
2122 return INVALID_SOCKET;
2123 }
2124 }
2125
2126#ifdef VERBOSE3
2127 // NIC will be 0.0.0.0 if we use INADDR_ANY
2128 fprintf(stderr, "open_socket: request port %d, using NIC %d %d %d %d.\n",
2129 portno ? *portno : 0, ntohl(name.sin_addr.s_addr) >> 24,
2130 (ntohl(name.sin_addr.s_addr) >> 16) & 0xff,
2131 (ntohl(name.sin_addr.s_addr) >> 8) & 0xff,
2132 ntohl(name.sin_addr.s_addr) & 0xff);
2133#endif
2134
2135 if (bind(sock, (struct sockaddr *)&name, namelen) < 0) {
2136 fprintf(stderr, "open_socket: can't bind address");
2137 if (portno) {
2138 fprintf(stderr, " %d", *portno);
2139 }
2140#ifndef _WIN32_WCE
2141 fprintf(stderr, " -- %d -- %s\n", vrpn_socket_error,
2143#endif
2144 fprintf(stderr, " (This probably means that another application has "
2145 "the port open already)\n");
2146 vrpn_closeSocket(sock);
2147 return INVALID_SOCKET;
2148 }
2149
2150 // Find out which port was actually bound
2151 if (getsockname(sock, (struct sockaddr *)&name, GSN_CAST & namelen)) {
2152 fprintf(stderr, "vrpn: open_socket: cannot get socket name.\n");
2153 vrpn_closeSocket(sock);
2154 return INVALID_SOCKET;
2155 }
2156 if (portno) {
2157 *portno = ntohs(name.sin_port);
2158 }
2159
2160#ifdef VERBOSE3
2161 // NIC will be 0.0.0.0 if we use INADDR_ANY
2162 fprintf(stderr, "open_socket: got port %d, using NIC %d %d %d %d.\n",
2163 portno ? *portno : ntohs(name.sin_port),
2164 ntohl(name.sin_addr.s_addr) >> 24,
2165 (ntohl(name.sin_addr.s_addr) >> 16) & 0xff,
2166 (ntohl(name.sin_addr.s_addr) >> 8) & 0xff,
2167 ntohl(name.sin_addr.s_addr) & 0xff);
2168#endif
2169
2170 return sock;
2171}
2172
2176
2177static vrpn_SOCKET open_udp_socket(unsigned short *portno, const char *IPaddress)
2178{
2179 return open_socket(SOCK_DGRAM, portno, IPaddress);
2180}
2181
2185
2186static vrpn_SOCKET open_tcp_socket(unsigned short *portno = NULL,
2187 const char *NIC_IP = NULL)
2188{
2189 return open_socket(SOCK_STREAM, portno, NIC_IP);
2190}
2191
2195
2196static vrpn_SOCKET vrpn_connect_udp_port(const char *machineName, int remotePort,
2197 const char *NIC_IP = NULL)
2198{
2199 vrpn_SOCKET udp_socket;
2200 struct sockaddr_in udp_name;
2201 struct hostent *remoteHost;
2202 int udp_namelen;
2203
2204 udp_socket = open_udp_socket(NULL, NIC_IP);
2205
2206 udp_namelen = sizeof(udp_name);
2207
2208 memset((void *)&udp_name, 0, udp_namelen);
2209 udp_name.sin_family = AF_INET;
2210
2211 // gethostbyname() fails on SOME Windows NT boxes, but not all,
2212 // if given an IP octet string rather than a true name.
2213 // MS Documentation says it will always fail and inet_addr should
2214 // be called first. Avoids a 30+ second wait for
2215 // gethostbyname() to fail.
2216
2217 if ((udp_name.sin_addr.s_addr = inet_addr(machineName)) == INADDR_NONE) {
2218 remoteHost = gethostbyname(machineName);
2219 if (remoteHost) {
2220
2221#ifdef CRAY
2222 int i;
2223 u_long foo_mark = 0L;
2224 for (i = 0; i < 4; i++) {
2225 u_long one_char = remoteHost->h_addr_list[0][i];
2226 foo_mark = (foo_mark << 8) | one_char;
2227 }
2228 udp_name.sin_addr.s_addr = foo_mark;
2229#else
2230 memcpy(&(udp_name.sin_addr.s_addr), remoteHost->h_addr,
2231 remoteHost->h_length);
2232#endif
2233 }
2234 else {
2235 vrpn_closeSocket(udp_socket);
2236 fprintf(stderr,
2237 "vrpn_connect_udp_port: error finding host by name (%s).\n",
2238 machineName);
2239 return INVALID_SOCKET;
2240 }
2241 }
2242#ifndef VRPN_USE_WINSOCK_SOCKETS
2243 udp_name.sin_port = htons(remotePort);
2244#else
2245 udp_name.sin_port = htons((u_short)remotePort);
2246#endif
2247
2248 if (connect(udp_socket, (struct sockaddr *)&udp_name, udp_namelen)) {
2249 fprintf(stderr, "vrpn_connect_udp_port: can't bind udp socket.\n");
2250 vrpn_closeSocket(udp_socket);
2251 return INVALID_SOCKET;
2252 }
2253
2254 // Find out which port was actually bound
2255 udp_namelen = sizeof(udp_name);
2256 if (getsockname(udp_socket, (struct sockaddr *)&udp_name,
2257 GSN_CAST & udp_namelen)) {
2258 fprintf(stderr, "vrpn_connect_udp_port: cannot get socket name.\n");
2259 vrpn_closeSocket(udp_socket);
2260 return INVALID_SOCKET;
2261 }
2262
2263#ifdef VERBOSE3
2264 // NOTE NIC will be 0.0.0.0 if we listen on all NICs.
2265 fprintf(stderr,
2266 "vrpn_connect_udp_port: got port %d, using NIC %d %d %d %d.\n",
2267 ntohs(udp_name.sin_port), ntohl(udp_name.sin_addr.s_addr) >> 24,
2268 (ntohl(udp_name.sin_addr.s_addr) >> 16) & 0xff,
2269 (ntohl(udp_name.sin_addr.s_addr) >> 8) & 0xff,
2270 ntohl(udp_name.sin_addr.s_addr) & 0xff);
2271#endif
2272
2273 return udp_socket;
2274}
2275
2299static int get_local_socket_name(char *local_host, size_t max_length,
2300 const char *remote_host)
2301{
2302 const int remote_port = vrpn_DEFAULT_LISTEN_PORT_NO;
2303 struct sockaddr_in udp_name;
2304 int udp_namelen = sizeof(udp_name);
2305
2306 vrpn_SOCKET udp_socket = vrpn_connect_udp_port(remote_host, remote_port, NULL);
2307 if (udp_socket == INVALID_SOCKET) {
2308 fprintf(stderr,
2309 "get_local_socket_name: cannot connect_udp_port to %s.\n",
2310 remote_host);
2311 fprintf(stderr, " (returning 0.0.0.0 so we listen on all ports).\n");
2312 udp_name.sin_addr.s_addr = 0;
2313 }
2314 else {
2315 if (getsockname(udp_socket, (struct sockaddr *)&udp_name,
2316 GSN_CAST & udp_namelen)) {
2317 fprintf(stderr, "get_local_socket_name: cannot get socket name.\n");
2318 vrpn_closeSocket(udp_socket);
2319 return -1;
2320 }
2321 }
2322
2323 // NOTE NIC will be 0.0.0.0 if we listen on all NICs.
2324 char myIPstring[100];
2325 int ret = snprintf(myIPstring, 100, "%d.%d.%d.%d",
2326 ntohl(udp_name.sin_addr.s_addr) >> 24,
2327 (ntohl(udp_name.sin_addr.s_addr) >> 16) & 0xff,
2328 (ntohl(udp_name.sin_addr.s_addr) >> 8) & 0xff,
2329 ntohl(udp_name.sin_addr.s_addr) & 0xff);
2330
2331 // Copy this to the output
2332 if ((unsigned)strlen(myIPstring) > max_length) {
2333 fprintf(stderr, "get_local_socket_name: Name too long to return\n");
2334 vrpn_closeSocket(udp_socket);
2335 return -1;
2336 }
2337
2338 vrpn_strncpynull(local_host, myIPstring, max_length);
2339 return ret;
2340}
2341
2358
2360 vrpn_SOCKET udp_sock, // Socket to use to send
2361 const char *, // Name of the machine to call
2362 const int, // UDP port on remote machine
2363 const int local_port, // TCP port on this machine
2364 const char *NIC_IP = NULL)
2365{
2366 char msg[150]; /* Message to send */
2367 vrpn_int32 msglen; /* How long it is (including \0) */
2368 char myIPchar[100]; /* IP decription this host */
2369
2370 /* Fill in the request message, telling the machine and port that
2371 * the remote server should connect to. These are ASCII, separated
2372 * by a space. vrpn_getmyIP returns the NIC_IP if it is not null,
2373 * or the host name of this machine using gethostname() if it is
2374 * NULL. If the NIC_IP is NULL but we have a socket (as we do here),
2375 * then it returns the address associated with the socket.
2376 */
2377 if (vrpn_getmyIP(myIPchar, sizeof(myIPchar), NIC_IP, udp_sock)) {
2378 fprintf(stderr,
2379 "vrpn_udp_request_lob_packet: Error finding local hostIP\n");
2380 vrpn_closeSocket(udp_sock);
2381 return (-1);
2382 }
2383 snprintf(msg, 150, "%.100s %d", myIPchar, local_port);
2384 msglen = static_cast<vrpn_int32>(strlen(msg) +
2385 1); /* Include the terminating 0 char */
2386
2387 // Lob the message
2388 if (send(udp_sock, msg, msglen, 0) == -1) {
2389 perror("vrpn_udp_request_lob_packet: send() failed");
2390 vrpn_closeSocket(udp_sock);
2391 return -1;
2392 }
2393
2394 return 0;
2395}
2396
2406
2407static int vrpn_get_a_TCP_socket(vrpn_SOCKET*listen_sock, int *listen_portnum,
2408 const char *NIC_IP = NULL)
2409{
2410 struct sockaddr_in listen_name; /* The listen socket binding name */
2411 int listen_namelen;
2412
2413 listen_namelen = sizeof(listen_name);
2414
2415 /* Create a TCP socket to listen for incoming connections from the
2416 * remote server. */
2417
2418 *listen_sock = open_tcp_socket(NULL, NIC_IP);
2419 if (*listen_sock < 0) {
2420 fprintf(stderr, "vrpn_get_a_TCP_socket: socket didn't open.\n");
2421 return -1;
2422 }
2423
2424 if (listen(*listen_sock, 1)) {
2425 fprintf(stderr, "vrpn_get_a_TCP_socket: listen() failed.\n");
2426 vrpn_closeSocket(*listen_sock);
2427 return (-1);
2428 }
2429
2430 if (getsockname(*listen_sock, (struct sockaddr *)&listen_name,
2431 GSN_CAST & listen_namelen)) {
2432 fprintf(stderr, "vrpn_get_a_TCP_socket: cannot get socket name.\n");
2433 vrpn_closeSocket(*listen_sock);
2434 return (-1);
2435 }
2436
2437 *listen_portnum = ntohs(listen_name.sin_port);
2438
2439 // fprintf(stderr, "Listening on port %d, address %d %d %d %d.\n",
2440 //*listen_portnum, listen_name.sin_addr.s_addr >> 24,
2441 //(listen_name.sin_addr.s_addr >> 16) & 0xff,
2442 //(listen_name.sin_addr.s_addr >> 8) & 0xff,
2443 // listen_name.sin_addr.s_addr & 0xff);
2444
2445 return 0;
2446}
2447
2456
2457static int vrpn_poll_for_accept(vrpn_SOCKET listen_sock, vrpn_SOCKET*accept_sock,
2458 double timeout = 0.0)
2459{
2460 fd_set rfds;
2461 struct timeval t;
2462
2463 // See if we have a connection attempt within the timeout
2464 FD_ZERO(&rfds);
2465 FD_SET(listen_sock, &rfds); /* Check for read (connect) */
2466 t.tv_sec = (long)(timeout);
2467 t.tv_usec = (long)((timeout - t.tv_sec) * 1000000L);
2468 if (vrpn_noint_select(static_cast<int>(listen_sock) + 1, &rfds, NULL, NULL,
2469 &t) == -1) {
2470 perror("vrpn_poll_for_accept: select() failed");
2471 return -1;
2472 }
2473 if (FD_ISSET(listen_sock, &rfds)) { /* Got one! */
2474 /* Accept the connection from the remote machine and set TCP_NODELAY
2475 * on the socket. */
2476 if ((*accept_sock = accept(listen_sock, 0, 0)) == -1) {
2477 perror("vrpn_poll_for_accept: accept() failed");
2478 return -1;
2479 }
2480#if !defined(_WIN32_WCE) && !defined(__ANDROID__)
2481 {
2482 struct protoent *p_entry;
2483 int nonzero = 1;
2484
2485 if ((p_entry = getprotobyname("TCP")) == NULL) {
2486 fprintf(stderr,
2487 "vrpn_poll_for_accept: getprotobyname() failed.\n");
2488 vrpn_closeSocket(*accept_sock);
2489 return (-1);
2490 }
2491
2492 if (setsockopt(*accept_sock, p_entry->p_proto, TCP_NODELAY,
2493 SOCK_CAST & nonzero, sizeof(nonzero)) == -1) {
2494 perror("vrpn_poll_for_accept: setsockopt() failed");
2495 vrpn_closeSocket(*accept_sock);
2496 return (-1);
2497 }
2498 }
2499#endif
2500 return 1; // Got one!
2501 }
2502
2503 return 0; // Nobody called
2504}
2505
2506// This is like sdi_start_server except that the convention for
2507// passing information on the client machine to the server program is
2508// different; everything else has been left the same
2519static int vrpn_start_server(const char *machine, char *server_name, char *args,
2520 const char *IPaddress = NULL)
2521{
2522#if __APPLE__
2523 #include <TargetConditionals.h>
2524 #if TARGET_IPHONE_SIMULATOR
2525 // iOS Simulator
2526 #define NO_SYSTEM
2527 #elif TARGET_OS_IPHONE
2528 // iOS device
2529 #define NO_SYSTEM
2530 #endif
2531#endif
2532#if defined(VRPN_USE_WINSOCK_SOCKETS) || defined(__CYGWIN__) || defined(NO_SYSTEM)
2533 fprintf(stderr, "VRPN: vrpn_start_server not ported"
2534 " for windows winsock or cygwin!\n");
2535 IPaddress = IPaddress;
2536 args = args;
2537 server_name = server_name;
2538 machine = machine;
2539 return -1;
2540#else
2541 int pid; /* Child's process ID */
2542 int server_sock; /* Where the accept returns */
2543 int child_socket; /* Where the final socket is */
2544 int PortNum; /* Port number we got */
2545
2546 /* Open a socket and ensure we can bind it */
2547 if (vrpn_get_a_TCP_socket(&server_sock, &PortNum, IPaddress)) {
2548 fprintf(stderr, "vrpn_start_server: Cannot get listen socket\n");
2549 return -1;
2550 }
2551
2552 if ((pid = fork()) == -1) {
2553 fprintf(stderr, "vrpn_start_server: cannot fork().\n");
2554 vrpn_closeSocket(server_sock);
2555 return (-1);
2556 }
2557 if (pid == 0) { /* CHILD */
2558 int loop;
2559 int ret;
2560 int num_descriptors; /* Number of available file descr */
2561 char myIPchar[100]; /* Host name of this host */
2562 char command[600]; /* Command passed to system() call */
2563 const char *rsh_to_use; /* Full path to Rsh command. */
2564
2565 if (vrpn_getmyIP(myIPchar, sizeof(myIPchar), IPaddress, server_sock)) {
2566 fprintf(stderr, "vrpn_start_server: Error finding my IP\n");
2567 vrpn_closeSocket(server_sock);
2568 return (-1);
2569 }
2570
2571 /* Close all files except stdout and stderr. */
2572 /* This prevents a hung child from keeping devices open */
2573#if defined(__ANDROID__)
2574 // When building for Android, and specifically for support of
2575 // VR/GearVR, newer versions of Android (KitKat and up) are
2576 // required. getdtablesize is not provided by these platforms.
2577 num_descriptors = sysconf(_SC_OPEN_MAX);
2578#else
2579 num_descriptors = getdtablesize();
2580#endif
2581
2582 for (loop = 0; loop < num_descriptors; loop++) {
2583 if ((loop != 1) && (loop != 2)) {
2584 close(loop);
2585 }
2586 }
2587
2588 /* Find the RSH command, either from the environment
2589 * variable or the default, and use it to start up the
2590 * remote server. */
2591
2592 if ((rsh_to_use = (char *)getenv("VRPN_RSH")) == NULL) {
2593 rsh_to_use = RSH;
2594 }
2595 snprintf(command, 600, "%.100s %.100s %.100s %.100s -client %.100s %d", rsh_to_use, machine,
2596 server_name, args, myIPchar, PortNum);
2597 ret = system(command);
2598 if ((ret == 127) || (ret == -1)) {
2599 fprintf(stderr, "vrpn_start_server: system() failed !!!!!\n");
2600 perror("Error");
2601 fprintf(stderr, "Attempted command was: '%s'\n", command);
2602 vrpn_closeSocket(server_sock);
2603 exit(-1); /* This should never occur */
2604 }
2605 exit(0);
2606 }
2607 else { /* PARENT */
2608 int waitloop;
2609
2610 /* Check to see if the child
2611 * is trying to call us back. Do SERVCOUNT waits, each of
2612 * which is SERVWAIT long.
2613 * If the child dies while we are waiting, then we can be
2614 * sure that they will not be calling us back. Check for
2615 * this while waiting for the callback. */
2616
2617 for (waitloop = 0; waitloop < (SERVCOUNT); waitloop++) {
2618 int ret;
2619 pid_t deadkid;
2620 int status;
2621
2622 /* Check to see if they called back yet. */
2623 ret = vrpn_poll_for_accept(server_sock, &child_socket, SERVWAIT);
2624 if (ret == -1) {
2625 fprintf(stderr, "vrpn_start_server: Accept poll failed\n");
2626 vrpn_closeSocket(server_sock);
2627 return -1;
2628 }
2629 if (ret == 1) {
2630 break; // Got it!
2631 }
2632
2633 /* Check to see if the child is dead yet */
2634 deadkid = waitpid(-1, &status, WNOHANG);
2635 if (deadkid == pid) {
2636 fprintf(stderr, "vrpn_start_server: server process exited\n");
2637 vrpn_closeSocket(server_sock);
2638 return (-1);
2639 }
2640 }
2641 if (waitloop == SERVCOUNT) {
2642 fprintf(stderr,
2643 "vrpn_start_server: server failed to connect in time\n");
2644 fprintf(stderr, " (took more than %d seconds)\n",
2646 vrpn_closeSocket(server_sock);
2647 kill(pid, SIGKILL);
2648 wait(0);
2649 return (-1);
2650 }
2651
2652 vrpn_closeSocket(server_sock);
2653 return (child_socket);
2654 }
2655 return 0;
2656#endif
2657}
2658
2659//** End of section pulled from SDI library
2660//*********************************************************************
2661
2662// COOKIE MANIPULATION
2663
2672
2673int write_vrpn_cookie(char *buffer, size_t length, long remote_log_mode)
2674{
2675 if (length < vrpn_cookie_size() + 1) return -1;
2676
2677 snprintf(buffer, length, "%.16s %c", vrpn_MAGIC,
2678 static_cast<char>(remote_log_mode + '0'));
2679 return 0;
2680}
2681
2687
2688int check_vrpn_cookie(const char *buffer)
2689{
2690 const char *bp;
2691
2692 // Comparison changed 9 Feb 98 by TCH
2693 // We don't care if the minor version numbers don't match,
2694 // so only check the characters through the last '.' in our
2695 // template. (If there is no last '.' in our template, somebody's
2696 // modified this code to break the constraints above, and we just
2697 // use a maximally restrictive check.)
2698 // XXX This pointer arithmetic isn't completely safe.
2699
2700 bp = strrchr(buffer, '.');
2701 if (strncmp(buffer, vrpn_MAGIC,
2702 (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer))) {
2703 fprintf(stderr, "check_vrpn_cookie: "
2704 "bad cookie (wanted '%s', got '%s'\n",
2705 vrpn_MAGIC, buffer);
2706 return -1;
2707 }
2708
2709 if (strncmp(buffer, vrpn_MAGIC, vrpn_MAGICLEN)) {
2710 fprintf(stderr,
2711 "check_vrpn_cookie(): "
2712 "VRPN Note: minor version number doesn't match: (prefer '%s', "
2713 "got '%s'). This is not normally a problem.\n",
2714 vrpn_MAGIC, buffer);
2715 return 1;
2716 }
2717
2718 return 0;
2719}
2720
2721int check_vrpn_file_cookie(const char *buffer)
2722{
2723 const char *bp;
2724
2725 // Comparison changed 9/1/00 by AAS and KTS
2726 // Here the difference is that we let the major version number be
2727 // less than or equal to our major version number as long as the major
2728 // version number is >= 4
2729
2730 // We don't care if the minor version numbers don't match,
2731 // so only check the characters through the last '.' in our
2732 // template. (If there is no last '.' in our template, somebody's
2733 // modified this code to break the constraints above, and we just
2734 // use a maximally restrictive check.)
2735 // XXX This pointer arithmetic isn't completely safe.
2736
2737 bp = strrchr(buffer, '.');
2738 int majorComparison = strncmp(
2739 buffer, vrpn_MAGIC, (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer));
2740 if (majorComparison > 0 ||
2741 strncmp(buffer, vrpn_FILE_MAGIC,
2742 (bp == NULL ? vrpn_MAGICLEN : bp + 1 - buffer)) < 0) {
2743 fprintf(stderr, "check_vrpn_file_cookie: "
2744 "bad cookie (wanted >='%s' and <='%s', "
2745 "got '%s'\n",
2746 vrpn_FILE_MAGIC, vrpn_MAGIC, buffer);
2747 return -1;
2748 }
2749
2750 if (majorComparison == 0 && strncmp(buffer, vrpn_MAGIC, vrpn_MAGICLEN)) {
2751 fprintf(stderr, "check_vrpn_file_cookie(): "
2752 "Note: Version number doesn't match: (prefer '%s', got "
2753 "'%s'). This is not normally a problem.\n",
2754 vrpn_MAGIC, buffer);
2755 return 1;
2756 }
2757
2758 return 0;
2759}
2760
2762 vrpn_int32 *connectedEndpointCounter)
2763 : status(BROKEN)
2764 , d_remoteLogMode(0)
2765 , d_remoteInLogName(NULL)
2766 , d_remoteOutLogName(NULL)
2767 , d_inLog(NULL)
2768 , d_outLog(NULL)
2769 , d_senders(NULL)
2770 , d_types(NULL)
2771 , d_dispatcher(dispatcher)
2772 , d_connectionCounter(connectedEndpointCounter)
2773{
2775}
2776
2778 vrpn_int32 *connectedEndpointCounter)
2779 : vrpn_Endpoint(dispatcher, connectedEndpointCounter)
2782 , d_tcpListenPort(0)
2784 , d_remote_machine_name(NULL)
2786 , d_tcp_only(vrpn_FALSE)
2793 , d_tcpNumOut(0)
2794 , d_udpNumOut(0)
2797 , d_tcpInbuf((char *)d_tcpAlignedInbuf)
2798 , d_udpInbuf((char *)d_udpAlignedInbuf)
2799 , d_NICaddress(NULL)
2800{
2801 // Keep Valgrind happy.
2802 memset(d_tcpOutbuf, 0, d_tcpBuflen);
2803 memset(d_udpOutbuf, 0, d_udpBuflen);
2804
2806}
2807
2809{
2810
2811 // Delete type and sender arrays
2812 if (d_senders) {
2813 try {
2814 delete d_senders;
2815 } catch (...) {
2816 fprintf(stderr, "vrpn_Endpoint::~vrpn_Endpoint: delete failed\n");
2817 return;
2818 }
2819 }
2820 if (d_types) {
2821 try {
2822 delete d_types;
2823 } catch (...) {
2824 fprintf(stderr, "vrpn_Endpoint::~vrpn_Endpoint: delete failed\n");
2825 return;
2826 }
2827 }
2828
2829 // Delete the log, if any
2830 if (d_inLog) {
2831 // close() is called by destructor IFF necessary
2832 try {
2833 delete d_inLog;
2834 } catch (...) {
2835 fprintf(stderr, "vrpn_Endpoint::~vrpn_Endpoint: delete failed\n");
2836 return;
2837 }
2838 }
2839 if (d_outLog) {
2840 // close() is called by destructor IFF necessary
2841 try {
2842 delete d_outLog;
2843 } catch (...) {
2844 fprintf(stderr, "vrpn_Endpoint::~vrpn_Endpoint: delete failed\n");
2845 return;
2846 }
2847 }
2848
2849 // Delete any file names created during the running
2850 if (d_remoteInLogName) {
2851 try {
2852 delete[] d_remoteInLogName;
2853 } catch (...) {
2854 fprintf(stderr, "vrpn_Endpoint::~vrpn_Endpoint: delete failed\n");
2855 return;
2856 }
2857 }
2858 if (d_remoteOutLogName) {
2859 try {
2860 delete[] d_remoteOutLogName;
2861 } catch (...) {
2862 fprintf(stderr, "vrpn_Endpoint::~vrpn_Endpoint: delete failed\n");
2863 return;
2864 }
2865 }
2866}
2867
2869{
2870 // Close all of the sockets that are left open
2871 if (d_tcpSocket != INVALID_SOCKET) {
2874 d_tcpNumOut = 0; // Ignore characters waiting to go
2875 }
2879 d_udpNumOut = 0; // Ignore characters waiting to go
2880 }
2884 }
2888 }
2892 }
2893
2894 // Delete the buffers created in the constructor
2895 if (d_tcpOutbuf) {
2896 try {
2897 delete[] d_tcpOutbuf;
2898 } catch (...) {
2899 fprintf(stderr, "vrpn_Endpoint_IP::~vrpn_Endpoint_IP: delete failed\n");
2900 return;
2901 }
2902 d_tcpOutbuf = NULL;
2903 }
2904 if (d_udpOutbuf) {
2905 try {
2906 delete[] d_udpOutbuf;
2907 } catch (...) {
2908 fprintf(stderr, "vrpn_Endpoint_IP::~vrpn_Endpoint_IP: delete failed\n");
2909 return;
2910 }
2911 d_udpOutbuf = NULL;
2912 }
2913
2914 // Delete the remote machine name, if it has been set
2916 try {
2917 delete[] d_remote_machine_name;
2918 } catch (...) {
2919 fprintf(stderr, "vrpn_Endpoint_IP::~vrpn_Endpoint_IP: delete failed\n");
2920 return;
2921 }
2922 d_remote_machine_name = NULL;
2923 }
2924}
2925
2927{
2928 return (d_udpOutboundSocket != -1);
2929}
2930
2931int vrpn_Endpoint::local_type_id(vrpn_int32 remote_type) const
2932{
2933 return d_types->mapToLocalID(remote_type);
2934}
2935
2936int vrpn_Endpoint::local_sender_id(vrpn_int32 remote_sender) const
2937{
2938 return d_senders->mapToLocalID(remote_sender);
2939}
2940
2941vrpn_int32 vrpn_Endpoint_IP::tcp_outbuf_size(void) const { return d_tcpBuflen; }
2942
2943vrpn_int32 vrpn_Endpoint_IP::udp_outbuf_size(void) const { return d_udpBuflen; }
2944
2945vrpn_bool vrpn_Endpoint_IP::doing_okay(void) const
2946{
2947 return ((status >= TRYING_TO_CONNECT) || (status == LOGGING));
2948}
2949
2951{
2952 // Set all of the local IDs to -1, in case the other side
2953 // sends a message of a type that it has not yet defined.
2954 // (for example, arriving on the UDP line ahead of its TCP
2955 // definition).
2956 try {
2961 } catch (...) {
2962 fprintf(stderr, "vrpn_Endpoint::init: Out of memory!\n");
2963 status = BROKEN;
2964 return;
2965 }
2966}
2967
2969{
2972 d_tcpListenPort = 0;
2976
2977 // Never tried a reconnect yet
2978 d_last_connect_attempt.tv_sec = 0;
2979 d_last_connect_attempt.tv_usec = 0;
2980}
2981
2982int vrpn_Endpoint_IP::mainloop(timeval *timeout)
2983{
2984 fd_set readfds, exceptfds;
2985 int tcp_messages_read;
2986 int udp_messages_read;
2987 int fd_max = static_cast<int>(d_tcpSocket);
2988 bool time_to_try_again = false;
2989
2990 switch (status) {
2991
2992 case CONNECTED:
2993
2994 // Send all pending reports on the way out
2996
2997 // check for pending incoming tcp or udp reports
2998 // we do this so that we can trigger out of the timeout
2999 // on either type of message without waiting on the other
3000
3001 FD_ZERO(&readfds); /* Clear the descriptor sets */
3002 FD_ZERO(&exceptfds);
3003
3004 // Read incoming messages from both the UDP and TCP channels
3005
3006 FD_SET(d_tcpSocket, &readfds);
3007 FD_SET(d_tcpSocket, &exceptfds);
3008
3009 if (d_udpInboundSocket != -1) {
3010 FD_SET(d_udpInboundSocket, &readfds);
3011 FD_SET(d_udpInboundSocket, &exceptfds);
3013 fd_max = static_cast<int>(d_udpInboundSocket);
3014 }
3015
3016 // Select to see if ready to hear from other side, or exception
3017
3018 if (vrpn_noint_select(fd_max + 1, &readfds, NULL, &exceptfds,
3019 timeout) == -1) {
3020 fprintf(stderr, "vrpn_Endpoint::mainloop: select failed.\n");
3021#ifndef _WIN32_WCE
3022 fprintf(stderr, " Error (%d): %s.\n", vrpn_socket_error,
3024#endif
3025 status = BROKEN;
3026 return -1;
3027 }
3028
3029 // See if exceptional condition on either socket
3030 if (FD_ISSET(d_tcpSocket, &exceptfds) ||
3031 ((d_udpInboundSocket != -1) &&
3032 FD_ISSET(d_udpInboundSocket, &exceptfds))) {
3033 fprintf(stderr, "vrpn_Endpoint::mainloop: Exception on socket\n");
3034 status = BROKEN;
3035 return -1;
3036 }
3037
3038 // Read incoming messages from the UDP channel
3039 if ((d_udpInboundSocket != -1) &&
3040 FD_ISSET(d_udpInboundSocket, &readfds)) {
3041 udp_messages_read = handle_udp_messages(NULL);
3042 if (udp_messages_read == -1) {
3043 fprintf(stderr, "vrpn_Endpoint::mainloop: "
3044 "UDP handling failed, dropping connection\n");
3045 status = BROKEN;
3046 break;
3047 }
3048#ifdef VERBOSE3
3049 if (udp_messages_read != 0)
3050 printf("udp message read = %d\n", udp_messages_read);
3051#endif
3052 }
3053
3054 // Read incoming messages from the TCP channel
3055 if (FD_ISSET(d_tcpSocket, &readfds)) {
3056 tcp_messages_read = handle_tcp_messages(NULL);
3057 if (tcp_messages_read == -1) {
3058 fprintf(stderr, "vrpn: TCP handling failed, dropping "
3059 "connection (this is normal when a connection "
3060 "is dropped)\n");
3061 status = BROKEN;
3062 break;
3063 }
3064#ifdef VERBOSE3
3065 else {
3066 if (tcp_messages_read) {
3067 printf("tcp_message_read %d bytes\n", tcp_messages_read);
3068 }
3069 }
3070#endif
3071 }
3072 break;
3073
3074 case COOKIE_PENDING:
3075
3076 poll_for_cookie(timeout);
3077
3078 break;
3079
3080 case TRYING_TO_CONNECT:
3081 struct timeval now;
3082 int ret;
3083
3084#ifdef VERBOSE
3085 printf("TRYING_TO_CONNECT\n");
3086#endif
3087 // See if it has been long enough since our last attempt
3088 // to try again.
3089 vrpn_gettimeofday(&now, NULL);
3090 if (now.tv_sec - d_last_connect_attempt.tv_sec >= 2) {
3091 d_last_connect_attempt.tv_sec = now.tv_sec;
3092 time_to_try_again = true;
3093 }
3094
3095 // If we are a TCP-only connection, then we retry to establish the
3096 // connection whenever it is time to try again. Otherwise, we're done.
3097 if (d_tcp_only) {
3098 if (time_to_try_again) {
3101 d_remote_port_number) == 0) {
3103 if (setup_new_connection()) {
3104 fprintf(stderr, "vrpn_Endpoint::mainloop: "
3105 "Can't set up new connection!\n");
3106 break;
3107 }
3108 }
3109 }
3110 break;
3111 }
3112
3113 // We are not a TCP-only connect.
3114 // See if we have a connection yet (nonblocking select).
3115 if (status == BROKEN) { break; }
3116 if (d_tcpListenSocket < 0) {
3117 fprintf(stderr, "vrpn_Endpoint: mainloop: Bad listen socket\n");
3118 status = BROKEN;
3119 break;
3120 }
3121 ret = vrpn_poll_for_accept(d_tcpListenSocket, &d_tcpSocket);
3122 if (ret == -1) {
3123 fprintf(stderr, "vrpn_Endpoint: mainloop: Can't poll for accept\n");
3124 status = BROKEN;
3125 break;
3126 }
3127 if (ret == 1) { // Got one!
3129#ifdef VERBOSE
3130 printf("vrpn: Connection established\n");
3131#endif
3132 // Set up the things that need to happen when a new connection
3133 // is established.
3134 if (setup_new_connection()) {
3135 fprintf(stderr, "vrpn_Endpoint: mainloop: "
3136 "Can't set up new connection!\n");
3137 status = BROKEN;
3138 // fprintf(stderr, "BROKEN - vrpn_Endpoint::mainloop.\n");
3139 break;
3140 }
3141 break;
3142 }
3143
3144 // Lob a request-to-connect packet every couple of seconds
3145 // If we don't wait a while between these we flood buffers and
3146 // do BAD THINGS (TM).
3147
3148 if (time_to_try_again) {
3149 // XXX On Linux, if we are talking to a machine that does not
3150 // have a server running, then our connect eventually tells us
3151 // that is was refused, and we can't communicate on that
3152 // UDP socket anymore. We should switch to a connectionless
3153 // sendto() option instead, but this runs the way it used
3154 // to, which worked, but still leaves the socket open after
3155 // the send; closing it right away broke on some Windows
3156 // machines.
3158 d_udpLobSocket = vrpn_connect_udp_port(
3160
3163 d_tcpListenPort, d_NICaddress) == -1) {
3164 fprintf(stderr,
3165 "vrpn_Endpoint: mainloop: Can't lob UDP request\n");
3166 status = BROKEN;
3167 // fprintf(stderr, "BROKEN - vrpn_Endpoint::mainloop.\n");
3168 break;
3169 }
3170 }
3171 break;
3172
3173 case BROKEN:
3175 return -1;
3176
3177 case LOGGING: // Just logging, so go about your business.
3178 break;
3179
3180 default:
3181 fprintf(stderr, "vrpn_Endpoint::mainloop(): "
3182 "Unknown status (%d)\n",
3183 status);
3184 status = BROKEN;
3185 return -1;
3186 }
3187
3188 return 0;
3189} // MAINLOOP
3190
3191// Clear out the remote mapping list. This is done when a
3192// connection is dropped and we want to try and re-establish
3193// it.
3195{
3196 d_senders->clear();
3197 d_types->clear();
3198}
3199
3200// Make the local mapping for the otherside sender with the same
3201// name, if there is one. Return 1 if there was a mapping; this
3202// lets the higher-ups know that there is someone that cares
3203// on the other side.
3204int vrpn_Endpoint::newLocalSender(const char *name, vrpn_int32 which)
3205{
3206 return d_senders->addLocalID(name, which);
3207}
3208
3209// If the other side has declared this type, establish the
3210// mapping for it. Return 1 if there was a mapping; this
3211// lets the higher-ups know that there is someone that cares
3212// on the other side.
3213int vrpn_Endpoint::newLocalType(const char *name, vrpn_int32 which)
3214{
3215 return d_types->addLocalID(name, which);
3216}
3217
3218// Adds a new remote type and returns its index. Returns -1 on error.
3219int vrpn_Endpoint::newRemoteType(vrpn_CNAME type_name, vrpn_int32 remote_id,
3220 vrpn_int32 local_id)
3221{
3222 return d_types->addRemoteEntry(type_name, remote_id, local_id);
3223}
3224
3225// Adds a new remote sender and returns its index. Returns -1 on error.
3226int vrpn_Endpoint::newRemoteSender(vrpn_CNAME sender_name, vrpn_int32 remote_id,
3227 vrpn_int32 local_id)
3228{
3229 return d_senders->addRemoteEntry(sender_name, remote_id, local_id);
3230}
3231
3246
3247int vrpn_Endpoint_IP::pack_message(vrpn_uint32 len, timeval time,
3248 vrpn_int32 type, vrpn_int32 sender,
3249 const char *buffer,
3250 vrpn_uint32 class_of_service)
3251{
3252 int ret;
3253
3254 // Any semantic checking needs to have been done by the Connection
3255 // class: the Endpoint doesn't know enough to do it. Similarly
3256 // for any local callbacks that need to be done. Similarly, filtering.
3257
3258 // Logging must come before filtering and should probably come before
3259 // any other failure-prone action (such as do_callbacks_for()). Only
3260 // semantic checking should precede it.
3261
3262 if (d_outLog->logOutgoingMessage(len, time, type, sender, buffer)) {
3263 fprintf(stderr, "vrpn_Endpoint::pack_message: "
3264 "Couldn't log outgoing message.!\n");
3265 return -1;
3266 }
3267
3268 if (status == LOGGING) {
3269 // No error message; this endpoint is ONLY logging.
3270 return 0;
3271 }
3272
3273 // TCH 26 April 2000
3274 if (status != CONNECTED) {
3275#ifdef VERBOSE2
3276 fprintf(stderr, "vrpn_Endpoint::pack_message: "
3277 "Not connected, so throwing out message.\n");
3278#endif
3279 return 0;
3280 }
3281
3282 // Determine the class of service and pass it off to the
3283 // appropriate service (TCP for reliable, UDP for everything else).
3284 // If we don't have a UDP outbound channel, send everything TCP
3285 if ((d_udpOutboundSocket == -1) ||
3286 (class_of_service & vrpn_CONNECTION_RELIABLE)) {
3287
3288 // Ensure that we have an outgoing TCP buffer. If not, then
3289 // we don't have anywhere to send it.
3290 if (d_tcpSocket == -1) {
3291 ret = 0;
3292 }
3293 else {
3294 ret =
3296 type, sender, buffer, d_tcpSequenceNumber);
3297 d_tcpNumOut += ret;
3298 if (ret > 0) {
3300 }
3301 }
3302 }
3303 else {
3304
3306 type, sender, buffer, d_udpSequenceNumber);
3307 d_udpNumOut += ret;
3308 if (ret > 0) {
3310 }
3311 }
3312 return (!ret) ? -1 : 0;
3313}
3314
3316{
3317 vrpn_int32 ret, sent = 0;
3318 int connection;
3319 timeval timeout;
3320
3321 // If we're broken, clear our buffers and return an error.
3322 if (status == BROKEN) {
3323 clearBuffers();
3324 return -1;
3325 }
3326
3327 // If we don't have a connection, clear our buffers because there is nowhere to send it.
3328 if (status == TRYING_TO_CONNECT) {
3329 clearBuffers();
3330 return 0;
3331 }
3332
3333 // Make sure we've got a valid TCP connection; else we can't send them.
3334 if (d_tcpSocket == -1) {
3335 fprintf(stderr,
3336 "vrpn_Endpoint::send_pending_reports(): No TCP connection\n");
3337 status = BROKEN;
3338 clearBuffers();
3339 return -1;
3340 }
3341
3342 // Check for an exception on the socket. If there is one, shut it
3343 // down and go back to listening.
3344 timeout.tv_sec = 0;
3345 timeout.tv_usec = 0;
3346
3347 fd_set f;
3348 FD_ZERO(&f);
3349 FD_SET(d_tcpSocket, &f);
3350
3351 connection = vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, NULL,
3352 NULL, &f, &timeout);
3353 if (connection) {
3354 fprintf(stderr, "vrpn_Endpoint::send_pending_reports(): "
3355 "select() failed.\n");
3356 fprintf(stderr, "Error (%d): %s.\n", vrpn_socket_error,
3358 status = BROKEN;
3359 return -1;
3360 }
3361
3362// Send all of the messages that have built
3363// up in the TCP buffer. If there is an error during the send, or
3364// an exceptional condition, close the accept socket and go back
3365// to listening for new connections.
3366#ifdef VERBOSE
3367 if (d_tcpNumOut) printf("TCP Need to send %d bytes\n", d_tcpNumOut);
3368#endif
3369 while (sent < d_tcpNumOut) {
3370 ret = send(d_tcpSocket, &d_tcpOutbuf[sent], d_tcpNumOut - sent, 0);
3371#ifdef VERBOSE
3372 printf("TCP Sent %d bytes\n", ret);
3373#endif
3374 if (ret == -1) {
3375 fprintf(stderr, "vrpn_Endpoint::send_pending_reports: "
3376 "TCP send failed.\n");
3377 status = BROKEN;
3378 return -1;
3379 }
3380 sent += ret;
3381 }
3382
3383 // Send all of the messages that have built
3384 // up in the UDP buffer. If there is an error during the send, or
3385 // an exceptional condition, close the accept socket and go back
3386 // to listening for new connections.
3387
3388 if ((d_udpOutboundSocket != -1) && (d_udpNumOut > 0)) {
3389
3391#ifdef VERBOSE
3392 printf("UDP Sent %d bytes\n", ret);
3393#endif
3394 if (ret == -1) {
3395 fprintf(stderr, "vrpn_Endpoint::send_pending_reports: "
3396 " UDP send failed.");
3397 status = BROKEN;
3398 return -1;
3399 }
3400 }
3401
3402 clearBuffers();
3403 return 0;
3404}
3405
3406// Pack a message telling to call back this host on the specified
3407// port number. It is important that the IP address of the host
3408// refers to the one that was used by the original TCP connection
3409// rather than (for example) the default IP address for the host.
3410// This is because the remote machine may not have a route to
3411// that NIC, but only the one used to establish the TCP connection.
3412
3414{
3415 struct timeval now;
3416 vrpn_uint32 portparam = portno;
3417 char myIPchar[1000];
3418 int retval;
3419
3420#ifdef VERBOSE2
3421 fprintf(stderr, "Getting IP address of NIC %s.\n", d_NICaddress);
3422#endif
3423
3424 // Find the local host name that we should be using to connect.
3425 // If d_NICaddress is set, use it; otherwise, use the d_tcpSocket
3426 // if it is valid.
3427 retval =
3428 vrpn_getmyIP(myIPchar, sizeof(myIPchar), d_NICaddress, d_tcpSocket);
3429 if (retval) {
3430 perror("vrpn_Endpoint::pack_udp_description: can't get host name");
3431 return -1;
3432 }
3433
3434// Pack a message with type vrpn_CONNECTION_UDP_DESCRIPTION
3435// whose sender ID is the ID of the port that is to be
3436// used and whose body holds the zero-terminated string
3437// name of the host to contact.
3438
3439#ifdef VERBOSE
3440 fprintf(stderr, "vrpn_Endpoint::pack_udp_description: "
3441 "Packing UDP %s:%d\n",
3442 myIPchar, portno);
3443#endif
3444 vrpn_gettimeofday(&now, NULL);
3445
3446 return pack_message(static_cast<vrpn_uint32>(strlen(myIPchar)) + 1, now,
3447 vrpn_CONNECTION_UDP_DESCRIPTION, portparam, myIPchar,
3449}
3450
3452{
3453 struct timeval now;
3454
3455 // Handle the case of NULL pointers in the log file names
3456 // by pointing local copies at the empty string if they occur.
3457 const char *inName = "";
3458 const char *outName = "";
3459 if (d_remoteInLogName) {
3460 inName = d_remoteInLogName;
3461 }
3462 if (d_remoteOutLogName) {
3463 outName = d_remoteOutLogName;
3464 }
3465
3466 // If we're not requesting remote logging, don't send any message.
3467 if (!d_remoteLogMode) {
3468 return 0;
3469 }
3470
3471 // Include the NULL termination for the strings in the length of the buffer.
3472 size_t bufsize =
3473 2 * sizeof(vrpn_int32) + strlen(inName) + 1 + strlen(outName) + 1;
3474 char *buf = NULL;
3475 try { buf = new char[bufsize]; }
3476 catch (...) { return -1; }
3477
3478 // Pack a message with type vrpn_CONNECTION_LOG_DESCRIPTION whose
3479 // sender ID is the logging mode to be used by the remote connection
3480 // and whose body holds the zero-terminated string name of the file
3481 // to write to.
3482
3483 vrpn_gettimeofday(&now, NULL);
3484 char *bpp = buf;
3485 char **bp = &bpp;
3486 vrpn_int32 bufleft = static_cast<vrpn_int32>(bufsize);
3487 vrpn_buffer(bp, &bufleft, (vrpn_int32)strlen(inName));
3488 vrpn_buffer(bp, &bufleft, (vrpn_int32)strlen(outName));
3489 vrpn_buffer(bp, &bufleft, inName, static_cast<vrpn_int32>(strlen(inName)));
3490 vrpn_buffer(bp, &bufleft, (char)0);
3491 vrpn_buffer(bp, &bufleft, outName,
3492 static_cast<vrpn_int32>(strlen(outName)));
3493 vrpn_buffer(bp, &bufleft, (char)0);
3494 int ret = pack_message(static_cast<vrpn_uint32>(bufsize - bufleft), now,
3497 try {
3498 delete[] buf;
3499 } catch (...) {
3500 fprintf(stderr, "vrpn_Endpoint::pack_log_description: delete failed\n");
3501 return -1;
3502 }
3503 return ret;
3504}
3505
3506// Read all messages available on the given file descriptor (a TCP link).
3507// Handle each message that is received.
3508// Return the number of messages read, or -1 on failure.
3509
3510int vrpn_Endpoint_IP::handle_tcp_messages(const struct timeval *timeout)
3511{
3512 timeval localTimeout;
3513 fd_set readfds, exceptfds;
3514 unsigned num_messages_read = 0;
3515 int retval;
3516 int sel_ret;
3517
3518#ifdef VERBOSE2
3519 printf("vrpn_Endpoint::handle_tcp_messages() called\n");
3520#endif
3521
3522 if (timeout) {
3523 localTimeout.tv_sec = timeout->tv_sec;
3524 localTimeout.tv_usec = timeout->tv_usec;
3525 }
3526 else {
3527 localTimeout.tv_sec = 0;
3528 localTimeout.tv_usec = 0;
3529 }
3530
3531 // Read incoming messages until there are no more characters to
3532 // read from the other side. For each message, determine what
3533 // type it is and then pass it off to the appropriate handler
3534 // routine. If d_stop_processing_messages_after has been set
3535 // to a nonzero value, then stop processing if we have received
3536 // at least that many messages.
3537
3538 do {
3539 // Select to see if ready to hear from other side, or exception
3540 FD_ZERO(&readfds); /* Clear the descriptor sets */
3541 FD_ZERO(&exceptfds);
3542 FD_SET(d_tcpSocket, &readfds); /* Check for read */
3543 FD_SET(d_tcpSocket, &exceptfds); /* Check for exceptions */
3544 sel_ret = vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, &readfds,
3545 NULL, &exceptfds, &localTimeout);
3546 if (sel_ret == -1) {
3547 fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
3548 "select failed");
3549 return (-1);
3550 }
3551
3552 // See if exceptional condition on socket
3553 if (FD_ISSET(d_tcpSocket, &exceptfds)) {
3554 fprintf(stderr, "vrpn_Endpoint::handle_tcp_messages: "
3555 "Exception on socket\n");
3556 return (-1);
3557 }
3558
3559 // If there is anything to read, get the next message
3560 if (FD_ISSET(d_tcpSocket, &readfds)) {
3561 retval = getOneTCPMessage(static_cast<int>(d_tcpSocket), d_tcpInbuf,
3562 sizeof(d_tcpAlignedInbuf));
3563 if (retval) {
3564 return -1;
3565 }
3566
3567 // Got one more message
3568 num_messages_read++;
3569 }
3570
3571 // If we've been asked to process only a certain number of
3572 // messages, then stop if we've gotten at least that many.
3573 if (d_parent->get_Jane_value() != 0) {
3574 if (num_messages_read >= d_parent->get_Jane_value()) {
3575 break;
3576 }
3577 }
3578 } while (sel_ret);
3579
3580 return num_messages_read;
3581}
3582
3583// Read all messages available on the given file descriptor (a UDP link).
3584// Handle each message that is received.
3585// Return the number of messages read, or -1 on failure.
3586// This routine and the TCP read routine are annoyingly similar, so it
3587// seems like they should be merged. They can't though: using read() on
3588// the UDP socket fails, so we need the UDP version. If we use the UDP
3589// version for the TCP code, it hangs when we the client drops its
3590// connection, so we need the TCP code as well.
3591// If d_stop_processing_messages_after has been set
3592// to a nonzero value, then stop processing if we have received
3593// at least that many messages.
3594
3595int vrpn_Endpoint_IP::handle_udp_messages(const struct timeval *timeout)
3596{
3597 timeval localTimeout;
3598 fd_set readfds, exceptfds;
3599 unsigned num_messages_read = 0;
3600 int sel_ret;
3601 int retval;
3602
3603#ifdef VERBOSE2
3604 printf("vrpn_Endpoint::handle_udp_messages() called\n");
3605#endif
3606
3607 if (timeout) {
3608 localTimeout.tv_sec = timeout->tv_sec;
3609 localTimeout.tv_usec = timeout->tv_usec;
3610 }
3611 else {
3612 localTimeout.tv_sec = 0;
3613 localTimeout.tv_usec = 0;
3614 }
3615
3616 // Read incoming messages until there are no more packets to
3617 // read from the other side. Each packet may have more than one
3618 // message in it. For each message, determine what
3619 // type it is and then pass it off to the appropriate handler
3620 // routine.
3621
3622 do {
3623 // Select to see if ready to hear from server, or exception
3624 FD_ZERO(&readfds); /* Clear the descriptor sets */
3625 FD_ZERO(&exceptfds);
3626 FD_SET(d_udpInboundSocket, &readfds); /* Check for read */
3627 FD_SET(d_udpInboundSocket, &exceptfds); /* Check for exceptions */
3628 sel_ret = vrpn_noint_select(static_cast<int>(d_udpInboundSocket) + 1,
3629 &readfds, NULL, &exceptfds, &localTimeout);
3630 if (sel_ret == -1) {
3631 perror("vrpn_Endpoint::handle_udp_messages: select failed()");
3632 return (-1);
3633 }
3634
3635 // See if exceptional condition on socket
3636 if (FD_ISSET(d_udpInboundSocket, &exceptfds)) {
3637 fprintf(stderr, "vrpn: vrpn_Endpoint::handle_udp_messages: "
3638 "Exception on socket\n");
3639 return (-1);
3640 }
3641
3642 // If there is anything to read, get the next message
3643 if (FD_ISSET(d_udpInboundSocket, &readfds)) {
3644 char *inbuf_ptr;
3645 int inbuf_len;
3646
3647 inbuf_ptr = d_udpInbuf;
3648 inbuf_len = recv(d_udpInboundSocket, d_udpInbuf,
3649 sizeof(d_udpAlignedInbuf), 0);
3650 if (inbuf_len == -1) {
3651 fprintf(stderr, "vrpn_Endpoint::handle_udp_message: "
3652 "recv() failed.\n");
3653 return -1;
3654 }
3655
3656 while (inbuf_len) {
3657 retval = getOneUDPMessage(inbuf_ptr, inbuf_len);
3658 if (retval == -1) {
3659 return -1;
3660 }
3661 inbuf_len -= retval;
3662 inbuf_ptr += retval;
3663 // fprintf(stderr, " Advancing inbuf pointer %d bytes.\n",
3664 // retval);
3665 // Got one more message
3666 num_messages_read++;
3667 }
3668 }
3669
3670 // If we've been asked to process only a certain number of
3671 // messages, then stop if we've gotten at least that many.
3672 if (d_parent->get_Jane_value() != 0) {
3673 if (num_messages_read >= d_parent->get_Jane_value()) {
3674 break;
3675 }
3676 }
3677
3678 } while (sel_ret);
3679
3680 return num_messages_read;
3681}
3682
3683//---------------------------------------------------------------------------
3684// This routine opens a TCP socket and connects it to the machine and port
3685// that are passed in the msg parameter. This is a string that contains
3686// the machine name, a space, then the port number.
3687// The routine returns -1 on failure and the file descriptor on success.
3688
3690{
3691 char machine[1000];
3692 int port;
3693
3694 // Find the machine name and port number
3695 if (sscanf(msg, "%999s %d", machine, &port) != 2) {
3696 return -1;
3697 }
3698
3699 return connect_tcp_to(machine, port);
3700}
3701
3702int vrpn_Endpoint_IP::connect_tcp_to(const char *addr, int port)
3703{
3704 struct sockaddr_in client; /* The name of the client */
3705 struct hostent *host; /* The host to connect to */
3706
3707 /* set up the socket */
3708 d_tcpSocket = open_tcp_socket(NULL, d_NICaddress);
3709 if (d_tcpSocket < 0) {
3710 fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: "
3711 "can't open socket\n");
3712 return -1;
3713 }
3714 client.sin_family = AF_INET;
3715
3716 // gethostbyname() fails on SOME Windows NT boxes, but not all,
3717 // if given an IP octet string rather than a true name.
3718 // MS Documentation says it will always fail and inet_addr should
3719 // be called first. Avoids a 30+ second wait for
3720 // gethostbyname() to fail.
3721
3722 if ((client.sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE) {
3723 host = gethostbyname(addr);
3724 if (host) {
3725
3726#ifdef CRAY
3727 {
3728 int i;
3729 u_long foo_mark = 0;
3730 for (i = 0; i < 4; i++) {
3731 u_long one_char = host->h_addr_list[0][i];
3732 foo_mark = (foo_mark << 8) | one_char;
3733 }
3734 client.sin_addr.s_addr = foo_mark;
3735 }
3736#else
3737 memcpy(&(client.sin_addr.s_addr), host->h_addr, host->h_length);
3738#endif
3739 }
3740 else {
3741
3742#if !defined(hpux) && !defined(__hpux) && !defined(_WIN32) && !defined(sparc)
3743 herror("gethostbyname error:");
3744#else
3745 perror("gethostbyname error:");
3746#endif
3747 fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: "
3748 "error finding host by name (%s)\n",
3749 addr);
3750 return -1;
3751 }
3752 }
3753
3754#ifndef VRPN_USE_WINSOCK_SOCKETS
3755 client.sin_port = htons(port);
3756#else
3757 client.sin_port = htons((u_short)port);
3758#endif
3759
3760 if (connect(d_tcpSocket, (struct sockaddr *)&client, sizeof(client)) < 0) {
3761#ifdef VRPN_USE_WINSOCK_SOCKETS
3762 if (!d_tcp_only) {
3763 fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: Could not connect "
3764 "to machine %d.%d.%d.%d port %d\n",
3765 (int)(client.sin_addr.S_un.S_un_b.s_b1),
3766 (int)(client.sin_addr.S_un.S_un_b.s_b2),
3767 (int)(client.sin_addr.S_un.S_un_b.s_b3),
3768 (int)(client.sin_addr.S_un.S_un_b.s_b4),
3769 (int)(ntohs(client.sin_port)));
3770 int error = WSAGetLastError();
3771 fprintf(stderr, "Winsock error: %d\n", error);
3772 }
3773#else
3774 fprintf(stderr, "vrpn_Endpoint::connect_tcp_to: Could not connect to "
3775 "machine %d.%d.%d.%d port %d\n",
3776 (int)((client.sin_addr.s_addr >> 24) & 0xff),
3777 (int)((client.sin_addr.s_addr >> 16) & 0xff),
3778 (int)((client.sin_addr.s_addr >> 8) & 0xff),
3779 (int)((client.sin_addr.s_addr >> 0) & 0xff),
3780 (int)(ntohs(client.sin_port)));
3781#endif
3783 status = BROKEN;
3784 return (-1);
3785 }
3786
3787/* Set the socket for TCP_NODELAY */
3788#if !defined(_WIN32_WCE) && !defined(__ANDROID__)
3789 {
3790 struct protoent *p_entry;
3791 int nonzero = 1;
3792
3793 if ((p_entry = getprotobyname("TCP")) == NULL) {
3794 fprintf(
3795 stderr,
3796 "vrpn_Endpoint::connect_tcp_to: getprotobyname() failed.\n");
3798 status = BROKEN;
3799 return -1;
3800 }
3801
3802 if (setsockopt(d_tcpSocket, p_entry->p_proto, TCP_NODELAY,
3803 SOCK_CAST & nonzero, sizeof(nonzero)) == -1) {
3804 perror("vrpn_Endpoint::connect_tcp_to: setsockopt() failed");
3806 status = BROKEN;
3807 return -1;
3808 }
3809 }
3810#endif
3812
3813 return 0;
3814}
3815
3816int vrpn_Endpoint_IP::connect_udp_to(const char *addr, int port)
3817{
3818 if (!d_tcp_only) {
3819 d_udpOutboundSocket = ::vrpn_connect_udp_port(addr, port, d_NICaddress);
3820 if (d_udpOutboundSocket == -1) {
3821 fprintf(stderr, "vrpn_Endpoint::connect_udp_to: "
3822 "Couldn't open outbound UDP link.\n");
3823 status = BROKEN;
3824 return -1;
3825 }
3826 }
3827 return 0;
3828}
3829
3831{
3832
3833 if (d_tcpSocket != INVALID_SOCKET) {
3836 d_tcpNumOut = 0; // Ignore characters waiting to go
3837 }
3841 d_udpNumOut = 0; // Ignore characters waiting to go
3842 }
3846 }
3847
3848 // Remove the remote mappings for senders and types. If we
3849 // reconnect, we will want to fill them in again. First,
3850 // free the space allocated for the list of names, then
3851 // set all of the local IDs to -1, in case the other side
3852 // sends a message of a type that it has not yet defined.
3853 // (for example, arriving on the UDP line ahead of its TCP
3854 // definition).
3855
3857
3858 // Clear out the buffers; nothing to read or send if no connection.
3859 clearBuffers();
3860
3861 struct timeval now;
3862 vrpn_gettimeofday(&now, NULL);
3863
3864 // If we are logging, put a message in the log telling that we
3865 // have had a disconnection. We don't close the logfile here unless
3866 // there is an error logging the message. This is because we'll want
3867 // to keep logging if there is a reconnection. We close the file when
3868 // the endpoint is destroyed.
3869 if (d_outLog->logMode()) {
3870 if (d_outLog->logMessage(0, now, vrpn_CONNECTION_DISCONNECT_MESSAGE, 0,
3871 NULL, 0) == -1) {
3872 fprintf(stderr, "vrpn_Endpoint::drop_connection: Can't log\n");
3873 d_outLog->close(); // Hope for the best...
3874 }
3875 }
3876
3877 // Recall that the connection counter is a pointer to our parent
3878 // connection's count of active endpoints. If it exists, we need
3879 // to send disconnect messages to those who care. If this is the
3880 // last endpoint, then we send the last endpoint message; we
3881 // always send a connection dropped message.
3882 // Message needs to be dispatched *locally only*, so we do_callbacks_for()
3883 // and never pack_message()
3884
3885 if (d_connectionCounter != NULL) { // Do nothing on NULL pointer
3886
3887 (*d_connectionCounter)--; // One less connection
3888
3889 d_dispatcher->doCallbacksFor(
3891 d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
3892
3893 if (*d_connectionCounter == 0) { // None more left
3894 d_dispatcher->doCallbacksFor(
3896 d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
3897 }
3898 }
3899}
3900
3902{
3903 d_tcpNumOut = 0;
3904 d_udpNumOut = 0;
3905}
3906
3907void vrpn_Endpoint_IP::setNICaddress(const char *address)
3908{
3909 if (d_NICaddress) {
3910 try {
3911 delete[] d_NICaddress;
3912 } catch (...) {
3913 fprintf(stderr, "vrpn_Endpoint_IP::setNICaddress: delete failed\n");
3914 return;
3915 }
3916 }
3917 d_NICaddress = NULL;
3918
3919#ifdef VERBOSE
3920 fprintf(stderr, "Setting endpoint NIC address to %s.\n", address);
3921#endif
3922
3923 if (!address) {
3924 return;
3925 }
3926 try { d_NICaddress = new char[1 + strlen(address)]; }
3927 catch (...) {
3928 fprintf(stderr, "vrpn_Endpoint::setNICaddress: Out of memory.\n");
3929 status = BROKEN;
3930 return;
3931 }
3932 vrpn_strncpynull(d_NICaddress, address, 1 + strlen(address));
3933}
3934
3936{
3937 char sendbuf[501];
3938 vrpn_int32 sendlen;
3939 int retval;
3940
3941 // Keep Valgrind happy
3942 memset(sendbuf, 0, sizeof(sendbuf));
3943 retval = write_vrpn_cookie(sendbuf, sizeof(sendbuf), d_remoteLogMode);
3944 if (retval < 0) {
3945 perror("vrpn_Endpoint::setup_new_connection: "
3946 "Internal error - array too small. The code's broken.");
3947 return -1;
3948 }
3949 sendlen = static_cast<vrpn_int32>(vrpn_cookie_size());
3950
3951 // Write the magic cookie header to the server
3952 if (vrpn_noint_block_write(d_tcpSocket, sendbuf, sendlen) != sendlen) {
3953 fprintf(stderr, "vrpn_Endpoint::setup_new_connection: "
3954 "Can't write cookie.\n");
3955 status = BROKEN;
3956 return -1;
3957 }
3958
3961
3962 return 0;
3963}
3964
3965void vrpn_Endpoint_IP::poll_for_cookie(const timeval *pTimeout)
3966{
3967 timeval timeout;
3968
3969 if (pTimeout) {
3970 timeout = *pTimeout;
3971 }
3972 else {
3973 timeout.tv_sec = 0;
3974 timeout.tv_usec = 0;
3975 }
3976
3977 fd_set readfds, exceptfds;
3978
3979 // most of this code copied from mainloop() case CONNECTED
3980
3981 // check for pending incoming tcp or udp reports
3982 // we do this so that we can trigger out of the timeout
3983 // on either type of message without waiting on the other
3984
3985 FD_ZERO(&readfds); /* Clear the descriptor sets */
3986 FD_ZERO(&exceptfds);
3987
3988 // Read incoming COOKIE from TCP channel
3989
3990 FD_SET(d_tcpSocket, &readfds);
3991 FD_SET(d_tcpSocket, &exceptfds);
3992
3993 // Select to see if ready to hear from other side, or exception
3994
3995 if (vrpn_noint_select(static_cast<int>(d_tcpSocket) + 1, &readfds, NULL,
3996 &exceptfds, &timeout) == -1) {
3997 fprintf(stderr, "vrpn_Endpoint::poll_for_cookie(): select failed.\n");
3998 status = BROKEN;
3999 return;
4000 }
4001
4002 // See if exceptional condition on either socket
4003 if (FD_ISSET(d_tcpSocket, &exceptfds)) {
4004 fprintf(stderr,
4005 "vrpn_Endpoint::poll_for_cookie(): Exception on socket\n");
4006 return;
4007 }
4008
4009 // Read incoming COOKIE from the TCP channel
4010 if (FD_ISSET(d_tcpSocket, &readfds)) {
4012 if (!doing_okay()) {
4013 fprintf(stderr,
4014 "vrpn_Endpoint::poll_for_cookie: cookie handling failed\n"
4015 " while connecting to \"%s\"\n",
4017 return;
4018 }
4019#ifdef VERBOSE3
4020 else if (status == CONNECTED) {
4021 printf("vrpn_Endpoint::poll_for_cookie() got cookie\n");
4022 }
4023#endif
4024 }
4025}
4026
4028{
4029 const vrpn_int32 sendlen = static_cast<vrpn_int32>(vrpn_COOKIE_SIZE);
4030 char recvbuf[vrpn_COOKIE_SIZE];
4031
4032 // Keep Valgrind happy
4033 memset(recvbuf, 0, sizeof(recvbuf));
4034
4035 // Try to read the magic cookie from the server.
4036 int ret = vrpn_noint_block_read(d_tcpSocket, recvbuf, sendlen);
4037 if (ret != sendlen) {
4038 perror("vrpn_Endpoint::finish_new_connection_setup: Can't read cookie");
4039 status = BROKEN;
4040 return -1;
4041 }
4042
4043 if (check_vrpn_cookie(recvbuf) < 0) {
4044 status = BROKEN;
4045 return -1;
4046 }
4047
4048 // Store the magic cookie from the other side into a buffer so
4049 // that it can be put into an incoming log file.
4050 d_inLog->setCookie(recvbuf);
4051
4052 // Find out what log mode they want us to be in BEFORE we pack
4053 // type, sender, and udp descriptions! That is because we will
4054 // need the type and sender messages to go into the log file if
4055 // we're logging outgoing messages. If it's nonzero, the
4056 // filename to use should come in a log_description message later.
4057
4058 long received_logmode = recvbuf[vrpn_MAGICLEN + 2] - '0';
4059 if ((received_logmode < 0) ||
4060 (received_logmode > (vrpn_LOG_INCOMING | vrpn_LOG_OUTGOING))) {
4061 fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
4062 "Got invalid log mode %d\n",
4063 static_cast<int>(received_logmode));
4064 status = BROKEN;
4065 return -1;
4066 }
4067 if (received_logmode & vrpn_LOG_INCOMING) {
4068 d_inLog->logMode() |= vrpn_LOG_INCOMING;
4069 }
4070 if (received_logmode & vrpn_LOG_OUTGOING) {
4071 d_outLog->logMode() |= vrpn_LOG_OUTGOING;
4072 }
4073
4074 // status must be sent to CONNECTED *before* any messages are
4075 // packed; otherwise they're silently discarded in pack_message.
4076 status = CONNECTED;
4077
4078 if (pack_log_description() == -1) {
4079 fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
4080 "Can't pack remote logging instructions.\n");
4081 status = BROKEN;
4082 return -1;
4083 }
4084
4085 // If we do not have a socket for inbound connections open, and if we
4086 // are allowed to do other-than-TCP sockets, then open one and tell the
4087 // other side that it can use it.
4088 if (!d_tcp_only) {
4089
4091 // Open the UDP port to accept time-critical messages on.
4092
4093 unsigned short udp_portnum =
4094 static_cast<unsigned short>(INADDR_ANY);
4095 d_udpInboundSocket = ::open_udp_socket(&udp_portnum, d_NICaddress);
4097 fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
4098 "can't open UDP socket\n");
4099 status = BROKEN;
4100 return -1;
4101 }
4102
4103 // Tell the other side what port number to send its UDP messages to.
4104 if (pack_udp_description(udp_portnum) == -1) {
4105 fprintf(stderr, "vrpn_Endpoint::finish_new_connection_setup: "
4106 "Can't pack UDP msg\n");
4107 status = BROKEN;
4108 return -1;
4109 }
4110 }
4111 }
4112
4113#ifdef VERBOSE
4114 fprintf(stderr,
4115 "CONNECTED - vrpn_Endpoint::finish_new_connection_setup.\n");
4116#endif
4117
4118 // Pack messages that describe the types of messages and sender
4119 // ID mappings that have been described to this connection. These
4120 // messages use special IDs (negative ones).
4121 for (int i = 0; i < d_dispatcher->numSenders(); i++) {
4123 }
4124 for (int i = 0; i < d_dispatcher->numTypes(); i++) {
4126 }
4127
4128 // Send the messages
4129 if (send_pending_reports() == -1) {
4130 fprintf(
4131 stderr,
4132 "vrpn_Endpoint::finish_new_connection_setup: Can't send UDP msg\n");
4133 status = BROKEN;
4134 return -1;
4135 }
4136
4137 // The connection-established messages need to be dispatched *locally only*,
4138 // so we do_callbacks_for and never pack_message()
4139 struct timeval now;
4140 vrpn_gettimeofday(&now, NULL);
4141
4142 // Connection counter gives us a single point to count connections that
4143 // actually make it to CONNECTED, not just constructed, so we send
4144 // got-first-/dropped-last-connection messages properly.
4145
4147 d_dispatcher->doCallbacksFor(
4149 d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
4150 }
4151
4152 d_dispatcher->doCallbacksFor(
4153 d_dispatcher->registerType(vrpn_got_connection),
4154 d_dispatcher->registerSender(vrpn_CONTROL), now, 0, NULL);
4155
4156 if (d_connectionCounter) {
4157 (*d_connectionCounter)++;
4158 }
4159
4160 return 0;
4161}
4162
4163int vrpn_Endpoint_IP::getOneTCPMessage(int fd, char *buf, size_t buflen)
4164{
4165 vrpn_int32 header[5];
4166 struct timeval time;
4167 vrpn_int32 sender, type;
4168 size_t len, payload_len, ceil_len;
4169 int retval;
4170
4171#ifdef VERBOSE2
4172 fprintf(stderr, "vrpn_Endpoint::getOneTCPMessage(): something to read\n");
4173#endif
4174
4175 // Read and parse the header
4176 if (vrpn_noint_block_read(fd, (char *)header, sizeof(header)) !=
4177 sizeof(header)) {
4178 fprintf(stderr, "vrpn_Endpoint::getOneTCPMessage: "
4179 "Can't read header (this is normal when a connection "
4180 "is dropped)\n");
4181 return -1;
4182 }
4183 len = ntohl(header[0]);
4184 time.tv_sec = ntohl(header[1]);
4185 time.tv_usec = ntohl(header[2]);
4186 sender = ntohl(header[3]);
4187 type = ntohl(header[4]);
4188#ifdef VERBOSE2
4189 fprintf(stderr, " header: Len %d, Sender %d, Type %d\n", (int)len,
4190 (int)sender, (int)type);
4191#endif
4192
4193 // skip up to alignment
4194 vrpn_int32 header_len = sizeof(header);
4195 if (header_len % vrpn_ALIGN) {
4196 header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4197 }
4198 if (header_len > static_cast<vrpn_int32>(sizeof(header))) {
4199 // the difference can be no larger than this
4200 char rgch[vrpn_ALIGN];
4201 if (vrpn_noint_block_read(fd, (char *)rgch,
4202 header_len - sizeof(header)) !=
4203 (int)(header_len - sizeof(header))) {
4204 fprintf(stderr, "vrpn_Endpoint::getOneTCPMessage: "
4205 "Can't read header + alignment\n");
4206 return -1;
4207 }
4208 }
4209
4210 // Figure out how long the message body is, and how long it
4211 // is including any padding to make sure that it is a
4212 // multiple of four bytes long.
4213 payload_len = len - header_len;
4214 ceil_len = payload_len;
4215 if (ceil_len % vrpn_ALIGN) {
4216 ceil_len += vrpn_ALIGN - ceil_len % vrpn_ALIGN;
4217 }
4218
4219 // Make sure the buffer is long enough to hold the whole
4220 // message body.
4221 if (buflen < ceil_len) {
4222 fprintf(stderr,
4223 "vrpn: vrpn_Endpoint::getOneTCPMessage: Message too long\n");
4224 return -1;
4225 }
4226
4227 // Read the body of the message
4228 if (static_cast<size_t>(vrpn_noint_block_read(fd, buf, ceil_len)) !=
4229 ceil_len) {
4230 perror("vrpn: vrpn_Endpoint::getOneTCPMessage: Can't read body");
4231 return -1;
4232 }
4233
4234 if (d_inLog->logIncomingMessage(payload_len, time, type, sender, buf)) {
4235 fprintf(stderr, "Couldn't log incoming message.!\n");
4236 return -1;
4237 }
4238
4239 retval = dispatch(type, sender, time, static_cast<vrpn_uint32>(payload_len),
4240 buf);
4241 if (retval) {
4242 return -1;
4243 }
4244
4245 return 0;
4246}
4247
4248int vrpn_Endpoint_IP::getOneUDPMessage(char *inbuf_ptr, size_t inbuf_len)
4249{
4250 vrpn_int32 header[5];
4251 struct timeval time;
4252 vrpn_int32 sender, type;
4253 vrpn_uint32 len, payload_len, ceil_len;
4254 int retval;
4255
4256 // Read and parse the header
4257 // skip up to alignment
4258 vrpn_uint32 header_len = sizeof(header);
4259 if (header_len % vrpn_ALIGN) {
4260 header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4261 }
4262
4263 if (header_len > (vrpn_uint32)inbuf_len) {
4264 fprintf(stderr, "vrpn_Endpoint::getOneUDPMessage: Can't read header");
4265 return -1;
4266 }
4267 memcpy(header, inbuf_ptr, sizeof(header));
4268 inbuf_ptr += header_len;
4269 len = ntohl(header[0]);
4270 time.tv_sec = ntohl(header[1]);
4271 time.tv_usec = ntohl(header[2]);
4272 sender = ntohl(header[3]);
4273 type = ntohl(header[4]);
4274
4275#ifdef VERBOSE
4276 fprintf(stderr, "Message type %ld (local type %ld), sender %ld received\n",
4277 type, local_type_id(type), sender);
4278 fprintf(stderr, "Message length is %d (buffer length %d).\n", len,
4279 inbuf_len);
4280#endif
4281
4282 // Figure out how long the message body is, and how long it
4283 // is including any padding to make sure that it is a
4284 // multiple of vrpn_ALIGN bytes long.
4285 payload_len = len - header_len;
4286 ceil_len = payload_len;
4287 if (ceil_len % vrpn_ALIGN) {
4288 ceil_len += vrpn_ALIGN - ceil_len % vrpn_ALIGN;
4289 }
4290
4291 // Make sure we received enough to cover the entire payload
4292 if (header_len + ceil_len > (vrpn_uint32)inbuf_len) {
4293 fprintf(stderr, "vrpn_Endpoint::getOneUDPMessage: Can't read payload");
4294 return -1;
4295 }
4296
4297 if (d_inLog->logIncomingMessage(payload_len, time, type, sender,
4298 inbuf_ptr)) {
4299 fprintf(stderr, "Couldn't log incoming message.!\n");
4300 return -1;
4301 }
4302
4303 retval = dispatch(type, sender, time, payload_len, inbuf_ptr);
4304 if (retval) {
4305 return -1;
4306 }
4307
4308 return ceil_len + header_len;
4309}
4310
4311int vrpn_Endpoint::dispatch(vrpn_int32 type, vrpn_int32 sender, timeval time,
4312 vrpn_uint32 payload_len, char *bufptr)
4313{
4314
4315 // Call the handler for this message type
4316 // If it returns nonzero, return an error.
4317 if (type >= 0) { // User handler, map to local id
4318
4319 // Only process if local id has been set.
4320
4321 if (local_type_id(type) >= 0) {
4322 if (d_dispatcher->doCallbacksFor(local_type_id(type),
4323 local_sender_id(sender), time,
4324 payload_len, bufptr)) {
4325 return -1;
4326 }
4327 }
4328 }
4329 else { // System handler
4330
4331 if (d_dispatcher->doSystemCallbacksFor(type, sender, time, payload_len,
4332 bufptr, this)) {
4333 fprintf(stderr, "vrpn_Endpoint::dispatch: "
4334 "Nonzero system return\n");
4335 return -1;
4336 }
4337 }
4338
4339 return 0;
4340}
4341
4342int vrpn_Endpoint::tryToMarshall(char *outbuf, vrpn_int32 &buflen,
4343 vrpn_int32 &numOut, vrpn_uint32 len,
4344 timeval time, vrpn_int32 type,
4345 vrpn_int32 sender, const char *buffer,
4346 vrpn_uint32 sequenceNumber)
4347{
4348 int retval;
4349
4350 retval = marshall_message(outbuf, buflen, numOut, len, time, type, sender,
4351 buffer, sequenceNumber);
4352
4353 // If the marshalling failed, try clearing the outgoing buffers
4354 // by sending the stuff in them to see if this makes enough
4355 // room. If not, we'll have to give up.
4356 if (!retval) {
4357 if (send_pending_reports() != 0) {
4358 return 0;
4359 }
4360 retval = marshall_message(outbuf, buflen, numOut, len, time, type,
4361 sender, buffer, sequenceNumber);
4362 }
4363
4364 return retval;
4365}
4366
4372
4373// TCH 22 Feb 99
4374// Marshall the sequence number, but never unmarshall it - it's currently
4375// only provided for the benefit of sniffers.
4376
4378 char *outbuf, // Base pointer to the output buffer
4379 vrpn_uint32 outbuf_size, // Total size of the output buffer
4380 vrpn_uint32 initial_out, // How many characters are already in outbuf
4381 vrpn_uint32 len, // Length of the message payload
4382 struct timeval time, // Time the message was generated
4383 vrpn_int32 type, // Type of the message
4384 vrpn_int32 sender, // Sender of the message
4385 const char *buffer, // Message payload
4386 vrpn_uint32 seqNo) // Sequence number
4387{
4388 vrpn_uint32 ceil_len, header_len, total_len;
4389 vrpn_uint32 curr_out = initial_out; // How many out total so far
4390
4391 // Compute the length of the message plus its padding to make it
4392 // an even multiple of vrpn_ALIGN bytes.
4393
4394 // Compute the total message length and put the message
4395 // into the message buffer (if we have room for the whole message)
4396 ceil_len = len;
4397 if (len % vrpn_ALIGN) {
4398 ceil_len += vrpn_ALIGN - len % vrpn_ALIGN;
4399 }
4400 header_len = 5 * sizeof(vrpn_int32);
4401 if (header_len % vrpn_ALIGN) {
4402 header_len += vrpn_ALIGN - header_len % vrpn_ALIGN;
4403 }
4404 total_len = header_len + ceil_len;
4405 if ((curr_out + total_len) > (vrpn_uint32)outbuf_size) {
4406 return 0;
4407 }
4408
4409 // fprintf(stderr, " Marshalling message type %d, sender %d, length %d.\n",
4410 // type, sender, len);
4411
4412 // The packet header len field does not include the padding bytes,
4413 // these are inferred on the other side.
4414 // Later, to make things clearer, we should probably infer the header
4415 // len on the other side (in the same way the padding is done)
4416 // The reason we don't include the padding in the len is that we
4417 // would not be able to figure out the size of the padding on the
4418 // far side).
4419 *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(header_len + len);
4420 curr_out += sizeof(vrpn_uint32);
4421
4422 // Pack the time (using gettimeofday() format) into the buffer
4423 // and do network byte ordering.
4424 *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(time.tv_sec);
4425 curr_out += sizeof(vrpn_uint32);
4426 *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(time.tv_usec);
4427 curr_out += sizeof(vrpn_uint32);
4428
4429 // Pack the sender and type and do network byte-ordering
4430 *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(sender);
4431 curr_out += sizeof(vrpn_uint32);
4432 *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(type);
4433 curr_out += sizeof(vrpn_uint32);
4434
4435 // Pack the sequence number. If something's really screwy with
4436 // our sizes/types and there isn't room for the sequence number,
4437 // skipping for alignment below will overwrite it!
4438 // Note that the sequence number is not officially part
4439 // of the header. It was added by Tom Hudson for use in his dissertation
4440 // work and is used by packets sniffers if it is present.
4441 *(vrpn_uint32 *)(void *)(&outbuf[curr_out]) = htonl(seqNo);
4442 curr_out += sizeof(vrpn_uint32);
4443
4444 // skip chars if needed for alignment
4445 curr_out = initial_out + header_len;
4446
4447 // Pack the message from the buffer. Then skip as many characters
4448 // as needed to make the end of the buffer fall on an even alignment
4449 // of vrpn_ALIGN bytes (the size of largest element sent via vrpn.
4450 if (buffer != NULL) {
4451 memcpy(&outbuf[curr_out], buffer, len);
4452 }
4453 curr_out += ceil_len;
4454#ifdef VERBOSE
4455 printf("Marshalled: len %d, ceil_len %d: '", len, ceil_len);
4456 printf("'\n");
4457#endif
4458 return curr_out - initial_out; // How many extra bytes we sent
4459}
4460
4461// static
4463{
4464 vrpn_Endpoint *endpoint = static_cast<vrpn_Endpoint *>(userdata);
4465 vrpn_CNAME type_name;
4466 vrpn_int32 i;
4467 vrpn_int32 local_id;
4468
4469 if (static_cast<unsigned>(p.payload_len) > sizeof(vrpn_CNAME)) {
4470 fprintf(stderr, "vrpn: vrpn_Endpoint::handle_type_message: "
4471 "Type name too long\n");
4472 return -1;
4473 }
4474
4475 // Find out the name of the type (skip the length)
4476 strncpy(type_name, p.buffer + sizeof(vrpn_int32),
4477 p.payload_len - sizeof(vrpn_int32));
4478
4479 // Use the exact length packed into the start of the buffer
4480 // to figure out where to put the trailing '\0'
4481 i = ntohl(*((const vrpn_int32 *)p.buffer));
4482 type_name[i] = '\0';
4483
4484#ifdef VERBOSE
4485 printf("Registering other-side type: '%s'\n", type_name);
4486#endif
4487 // If there is a corresponding local type defined, find the mapping.
4488 local_id = endpoint->d_dispatcher->getTypeID(type_name);
4489 // If not, add this type locally
4490 if (local_id == -1) {
4491 if (endpoint->d_parent != NULL) {
4492 local_id = endpoint->d_parent->register_message_type(type_name);
4493 }
4494#ifdef VERBOSE
4495 else {
4496 printf("vrpn_Endpoint::handle_type_message: NULL d_parent "
4497 "when trying to auto-register remote message type %s.\n",
4498 type_name);
4499 }
4500#endif
4501 }
4502 if (endpoint->newRemoteType(type_name, p.sender, local_id) == -1) {
4503 fprintf(stderr, "vrpn: Failed to add remote type %s\n", type_name);
4504 return -1;
4505 }
4506
4507 return 0;
4508}
4509
4510void vrpn_Endpoint::setLogNames(const char *inName, const char *outName)
4511{
4512 if (inName != NULL) {
4513 d_inLog->setName(inName);
4514 }
4515 if (outName != NULL) {
4516 d_outLog->setName(outName);
4517 }
4518}
4519
4521{
4522
4523 if (d_inLog->open()) {
4524 return -1;
4525 }
4526 if (d_outLog->open()) {
4527 return -1;
4528 }
4529
4530 return 0;
4531}
4532
4533// static
4535{
4536 vrpn_Endpoint *endpoint = static_cast<vrpn_Endpoint *>(userdata);
4537 vrpn_CNAME sender_name;
4538 vrpn_int32 i;
4539 vrpn_int32 local_id;
4540
4541 if (static_cast<size_t>(p.payload_len) > sizeof(vrpn_CNAME)) {
4542 fprintf(stderr, "vrpn: vrpn_Endpoint::handle_sender_message():Sender "
4543 "name too long\n");
4544 return -1;
4545 }
4546
4547 // Find out the name of the sender (skip the length)
4548 strncpy(sender_name, p.buffer + sizeof(vrpn_int32),
4549 p.payload_len - sizeof(vrpn_int32));
4550
4551 // Use the exact length packed into the start of the buffer
4552 // to figure out where to put the trailing '\0'
4553 i = ntohl(*((const vrpn_int32 *)p.buffer));
4554 sender_name[i] = '\0';
4555
4556#ifdef VERBOSE
4557 printf("Registering other-side sender: '%s'\n", sender_name);
4558#endif
4559 // If there is a corresponding local sender defined, find the mapping.
4560 local_id = endpoint->d_dispatcher->getSenderID(sender_name);
4561 // If not, add this sender locally
4562 if (local_id == -1) {
4563 if (endpoint->d_parent != NULL) {
4564 local_id = endpoint->d_parent->register_sender(sender_name);
4565 }
4566#ifdef VERBOSE
4567 else {
4568 printf("vrpn_Endpoint::handle_sender_message: NULL d_parent "
4569 "when trying to auto-register remote message sender %s\n",
4570 sender_name);
4571 }
4572#endif
4573 }
4574 if (endpoint->newRemoteSender(sender_name, p.sender, local_id) == -1) {
4575 fprintf(stderr, "vrpn: Failed to add remote sender %s\n", sender_name);
4576 return -1;
4577 }
4578
4579 return 0;
4580}
4581
4583{
4584 struct timeval now;
4585
4586 // need to pack the null char as well
4587 vrpn_uint32 len =
4588 static_cast<vrpn_int32>(strlen(d_dispatcher->typeName(which)) + 1);
4589 vrpn_uint32 netlen;
4590 char buffer[sizeof(len) + sizeof(vrpn_CNAME)];
4591
4592 netlen = htonl(len);
4593// Pack a message with type vrpn_CONNECTION_TYPE_DESCRIPTION
4594// whose sender ID is the ID of the type that is being
4595// described and whose body contains the length of the name
4596// and then the name of the type.
4597
4598#ifdef VERBOSE
4599 printf(" vrpn_Connection: Packing type '%s', %d\n",
4600 d_dispatcher->typeName(which), which);
4601#endif
4602 memcpy(buffer, &netlen, sizeof(netlen));
4603 memcpy(&buffer[sizeof(len)], d_dispatcher->typeName(which),
4604 (vrpn_int32)len);
4605 vrpn_gettimeofday(&now, NULL);
4606
4607 return pack_message((vrpn_uint32)(len + sizeof(len)), now,
4608 vrpn_CONNECTION_TYPE_DESCRIPTION, which, buffer,
4610}
4611
4613{
4614 struct timeval now;
4615
4616 // need to pack the null char as well
4617 vrpn_uint32 len =
4618 static_cast<vrpn_int32>(strlen(d_dispatcher->senderName(which)) + 1);
4619 vrpn_uint32 netlen;
4620 char buffer[sizeof(len) + sizeof(vrpn_CNAME)];
4621
4622 netlen = htonl(len);
4623// Pack a message with type vrpn_CONNECTION_SENDER_DESCRIPTION
4624// whose sender ID is the ID of the sender that is being
4625// described and whose body contains the length of the name
4626// and then the name of the sender.
4627
4628#ifdef VERBOSE
4629 printf(" vrpn_Connection: Packing sender '%s'\n",
4630 d_dispatcher->senderName(which));
4631#endif
4632 memcpy(buffer, &netlen, sizeof(netlen));
4633 memcpy(&buffer[sizeof(len)], d_dispatcher->senderName(which),
4634 (vrpn_int32)len);
4635 vrpn_gettimeofday(&now, NULL);
4636
4637 return pack_message((vrpn_uint32)(len + sizeof(len)), now,
4640}
4641
4642static int flush_udp_socket(vrpn_SOCKET fd)
4643{
4644 timeval localTimeout;
4645 fd_set readfds, exceptfds;
4646 char buf[10000];
4647 int sel_ret;
4648
4649 // fprintf(stderr, "flush_udp_socket().\n");
4650
4651 localTimeout.tv_sec = 0;
4652 localTimeout.tv_usec = 0;
4653
4654 // Empty out any pending UDP messages by reading the socket and
4655 // then throwing it away.
4656
4657 do {
4658 // Select to see if ready to hear from server, or exception
4659 FD_ZERO(&readfds); /* Clear the descriptor sets */
4660 FD_ZERO(&exceptfds);
4661 FD_SET(fd, &readfds); /* Check for read */
4662 FD_SET(fd, &exceptfds); /* Check for exceptions */
4663 sel_ret = vrpn_noint_select(static_cast<int>(fd) + 1, &readfds, NULL,
4664 &exceptfds, &localTimeout);
4665 if (sel_ret == -1) {
4666 fprintf(stderr, "flush_udp_socket: select failed().");
4667 return -1;
4668 }
4669
4670 // See if exceptional condition on socket
4671 if (FD_ISSET(fd, &exceptfds)) {
4672 fprintf(stderr, "flush_udp_socket: Exception on socket.\n");
4673 return -1;
4674 }
4675
4676 // If there is anything to read, get the next message
4677 if (FD_ISSET(fd, &readfds)) {
4678 int inbuf_len;
4679
4680 inbuf_len = recv(fd, buf, 10000, 0);
4681 if (inbuf_len == -1) {
4682 fprintf(stderr, "flush_udp_socket: recv() failed.\n");
4683 return -1;
4684 }
4685 }
4686
4687 } while (sel_ret);
4688
4689 return 0;
4690}
4691
4693{
4694
4695 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
4696 it != e; ++it) {
4697 int retval = it->pack_type_description(which);
4698 if (retval) {
4699 return -1;
4700 }
4701 }
4702
4703 return 0;
4704}
4705
4707{
4708 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
4709 it != e; ++it) {
4710 int retval = it->pack_sender_description(which);
4711 if (retval) {
4712 return -1;
4713 }
4714 }
4715
4716 return 0;
4717}
4718
4719// static
4721{
4722 vrpn_Endpoint *endpoint = (vrpn_Endpoint *)userdata;
4723 int retval = 0;
4724 vrpn_int32 inNameLen, outNameLen;
4725 const char **bp = &p.buffer;
4726
4727 // TCH 16 Feb 01
4728 vrpn_unbuffer(bp, &inNameLen);
4729 vrpn_unbuffer(bp, &outNameLen);
4730
4731 // must deal properly with only opening one log file
4732 // the log message contains "" (an empty string) if
4733 // there is no desire to log that file.
4734 endpoint->setLogNames(inNameLen == 0 ? NULL : *bp,
4735 outNameLen == 0 ? NULL : *bp + inNameLen + 1);
4736 if (inNameLen > 0) retval = endpoint->d_inLog->open();
4737 if (outNameLen > 0) retval = endpoint->d_outLog->open();
4738
4739 // Safety check:
4740 // If we can't log when the client asks us to, close the connection.
4741 // Something more talkative would be useful.
4742 // The problem with implementing this is that it's over-strict: clients
4743 // that assume logging succeeded unless the connection was dropped
4744 // will be running on the wrong assumption if we later change this to
4745 // be a notification message.
4746
4747 if (retval == -1) {
4748 // Will be dropped automatically on next pass through mainloop
4749 endpoint->status = BROKEN;
4750 }
4751 else {
4752 fprintf(stderr, "vrpn_Connection::handle_log_message: "
4753 "Remote connection requested logging.\n");
4754 }
4755
4756 // OR the remotely-requested logging mode with whatever we've
4757 // been told to do locally
4758 if (p.sender & vrpn_LOG_INCOMING) {
4759 endpoint->d_inLog->logMode() |= vrpn_LOG_INCOMING;
4760 }
4761 if (p.sender & vrpn_LOG_OUTGOING) {
4762 endpoint->d_outLog->logMode() |= vrpn_LOG_OUTGOING;
4763 }
4764
4765 return retval;
4766}
4767
4768// Pack a message to all open endpoints. If the pack fails for any of
4769// the endpoints, return failure.
4770
4771int vrpn_Connection::pack_message(vrpn_uint32 len, struct timeval time,
4772 vrpn_int32 type, vrpn_int32 sender,
4773 const char *buffer,
4774 vrpn_uint32 class_of_service)
4775{
4776 // Make sure I'm not broken
4777 if (connectionStatus == BROKEN) {
4778 printf("vrpn_Connection::pack_message: Can't pack because the "
4779 "connection is broken\n");
4780 return -1;
4781 }
4782
4783 // Make sure type is either a system type (-) or a legal user type
4784 if (type >= d_dispatcher->numTypes()) {
4785 printf("vrpn_Connection::pack_message: bad type (%d)\n", type);
4786 return -1;
4787 }
4788
4789 // If this is not a system message, make sure the sender is legal.
4790 if (type >= 0) {
4791 if ((sender < 0) || (sender >= d_dispatcher->numSenders())) {
4792 printf("vrpn_Connection::pack_message: bad sender (%d)\n", sender);
4793 return -1;
4794 }
4795 }
4796
4797 // Pack the message to all open endpoints This must be done before
4798 // yanking local callbacks in order to have message delivery be the
4799 // same on local and remote systems in the case where a local handler
4800 // packs one or more messages in response to this message.
4801 int ret = 0;
4802 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
4803 it != e; ++it) {
4804 if (it->pack_message(len, time, type, sender, buffer,
4805 class_of_service) != 0) {
4806 ret = -1;
4807 }
4808 }
4809
4810 // See if there are any local handlers for this message type from
4811 // this sender. If so, yank the callbacks. This needs to be done
4812 // AFTER the message is packed to open endpoints so that messages
4813 // will be sent in the same order from local and remote senders
4814 // (since a local message handler may pack its own messages before
4815 // returning).
4816
4817 if (do_callbacks_for(type, sender, time, len, buffer)) {
4818 return -1;
4819 }
4820
4821 return ret;
4822}
4823
4824// Returns the time since the connection opened.
4825// Some subclasses may redefine time.
4826
4827// virtual
4828int vrpn_Connection::time_since_connection_open(struct timeval *elapsed_time)
4829{
4830 struct timeval now;
4831 vrpn_gettimeofday(&now, NULL);
4832 *elapsed_time = vrpn_TimevalDiff(now, start_time);
4833
4834 return 0;
4835}
4836
4837// returns the current time in the connection since the epoch (UTC time).
4838// virtual
4840{
4841 struct timeval now;
4842 vrpn_gettimeofday(&now, NULL);
4843 return now;
4844}
4845
4846// Returns the name of the specified sender/type, or NULL
4847// if the parameter is invalid.
4848// virtual
4849const char *vrpn_Connection::sender_name(vrpn_int32 sender)
4850{
4851 return d_dispatcher->senderName(sender);
4852}
4853
4854// virtual
4855const char *vrpn_Connection::message_type_name(vrpn_int32 type)
4856{
4857 return d_dispatcher->typeName(type);
4858}
4859
4860// virtual
4862{
4863
4864 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
4865 it != e; ++it) {
4866 it->d_inLog->addFilter(filter, userdata);
4867 it->d_outLog->addFilter(filter, userdata);
4868 }
4869 return 0;
4870}
4871
4872// virtual
4874{
4875 int final_retval = 0;
4876 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
4877 it != e; ++it) {
4878 final_retval |= it->d_inLog->saveLogSoFar();
4879 final_retval |= it->d_outLog->saveLogSoFar();
4880 }
4881 return final_retval;
4882}
4883
4884// virtual
4889
4890void vrpn_Connection::init(vrpn_EndpointAllocator epa)
4891{
4892 // Lots of constants used to be set up here. They were moved
4893 // into the constructors in 02.10; this will create a slight
4894 // increase in maintenance burden keeping the constructors consistent.
4895
4898
4900
4902
4903 d_dispatcher = NULL;
4904 try { d_dispatcher = new vrpn_TypeDispatcher; }
4905 catch (...) {
4907 return;
4908 }
4909
4910 // These should be among the first senders & types sent over the wire
4911 d_dispatcher->registerSender(vrpn_CONTROL);
4913 d_dispatcher->registerType(vrpn_got_connection);
4916
4923}
4924
4928
4930{
4931 d_endpoints.destroy(endpoint);
4932 return 0;
4933}
4934
4938
4940{
4941 d_endpoints.compact();
4942
4943 return 0;
4944}
4945
4946// Set up to be a server connection, creating a logging connection if
4947// asked for.
4948vrpn_Connection::vrpn_Connection(const char *local_in_logfile_name,
4949 const char *local_out_logfile_name,
4952 , d_references(0)
4953 , d_autoDeleteStatus(false)
4954 , d_dispatcher(NULL)
4955 , d_serverLogCount(0)
4957 (local_in_logfile_name ? vrpn_LOG_INCOMING : vrpn_LOG_NONE) |
4958 (local_out_logfile_name ? vrpn_LOG_OUTGOING : vrpn_LOG_NONE))
4959 , d_serverLogName(NULL)
4960 , d_updateEndpoint(vrpn_FALSE)
4961{
4962 // Initialize the things that must be for any constructor
4963 vrpn_Connection::init(epa);
4964
4965 // Server connections should handle log messages.
4968
4969 if (local_out_logfile_name) {
4970 vrpn_Endpoint *endpoint =
4972 if (!endpoint) {
4973 fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4974 "Couldn't create endpoint for log file.\n",
4975 __LINE__);
4977 return;
4978 }
4979 endpoint->setConnection(this);
4980 d_updateEndpoint = vrpn_TRUE;
4981 endpoint->d_outLog->setName(local_out_logfile_name);
4982 endpoint->d_outLog->logMode() = d_serverLogMode;
4983 int retval = endpoint->d_outLog->open();
4984 if (retval == -1) {
4985 fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
4986 "Couldn't open outgoing log file.\n",
4987 __LINE__);
4988 d_endpoints.destroy(endpoint);
4990 return;
4991 }
4992 endpoint->d_remoteLogMode = vrpn_LOG_NONE;
4993 endpoint->d_remoteInLogName = NULL;
4994 endpoint->d_remoteOutLogName = NULL;
4995 // Outgoing messages are logged regardless of connection status.
4996 endpoint->status = LOGGING;
4997 }
4998
4999 if (local_in_logfile_name) {
5000 try {
5001 d_serverLogName = new char[1 + strlen(local_in_logfile_name)];
5002 vrpn_strncpynull(d_serverLogName, local_in_logfile_name, 1 + strlen(local_in_logfile_name));
5003 } catch (...) {
5005 return;
5006 }
5007 }
5008}
5009
5010vrpn_Connection::vrpn_Connection(const char *local_in_logfile_name,
5011 const char *local_out_logfile_name,
5012 const char *remote_in_logfile_name,
5013 const char *remote_out_logfile_name,
5017 , d_references(0)
5018 , d_autoDeleteStatus(false)
5019 , d_dispatcher(NULL)
5020 , d_serverLogCount(0)
5022 , d_serverLogName(NULL)
5023 , d_updateEndpoint(vrpn_FALSE)
5024{
5025 int retval;
5026
5027 // Initialize the things that must be for any constructor
5028 vrpn_Connection::init(epa);
5029
5030 // We're a client; create our single endpoint and initialize it.
5031 vrpn_Endpoint *endpoint = d_endpoints.acquire(d_boundEndpointAllocator());
5032 if (!endpoint) {
5033 fprintf(stderr, "vrpn_Connection:%d Out of memory.\n", __LINE__);
5035 return;
5036 }
5037 endpoint->setConnection(this);
5038 d_updateEndpoint = vrpn_TRUE;
5039
5040 // Store the remote log file name and the remote log mode
5041 endpoint->d_remoteLogMode =
5042 (((remote_in_logfile_name && strlen(remote_in_logfile_name) > 0)
5044 : vrpn_LOG_NONE) |
5045 ((remote_out_logfile_name && strlen(remote_out_logfile_name) > 0)
5047 : vrpn_LOG_NONE));
5048 if (!remote_in_logfile_name) {
5049 endpoint->d_remoteInLogName = NULL;
5050 } else {
5051 try {
5052 endpoint->d_remoteInLogName =
5053 new char[strlen(remote_in_logfile_name) + 1];
5054 vrpn_strncpynull(endpoint->d_remoteInLogName, remote_in_logfile_name, strlen(remote_in_logfile_name) + 1);
5055 } catch (...) {
5057 return;
5058 }
5059 }
5060
5061 if (!remote_out_logfile_name) {
5062 endpoint->d_remoteOutLogName = NULL;
5063 } else {
5064 try {
5065 endpoint->d_remoteOutLogName =
5066 new char[strlen(remote_out_logfile_name) + 1];
5067 vrpn_strncpynull(endpoint->d_remoteOutLogName, remote_out_logfile_name, strlen(remote_out_logfile_name) + 1);
5068 } catch (...) {
5070 return;
5071 }
5072 }
5073
5074 // If we are doing local logging, turn it on here. If we
5075 // can't open the file, then the connection is broken.
5076
5077 if (local_in_logfile_name && (strlen(local_in_logfile_name) != 0)) {
5078 endpoint->d_inLog->setName(local_in_logfile_name);
5079 endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
5080 retval = endpoint->d_inLog->open();
5081 if (retval == -1) {
5082 fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
5083 "Couldn't open incoming log file.\n",
5084 __LINE__);
5086 return;
5087 }
5088 }
5089
5090 if (local_out_logfile_name && (strlen(local_out_logfile_name) != 0)) {
5091 endpoint->d_outLog->setName(local_out_logfile_name);
5092 endpoint->d_outLog->logMode() = vrpn_LOG_OUTGOING;
5093 retval = endpoint->d_outLog->open();
5094 if (retval == -1) {
5095 fprintf(stderr, "vrpn_Connection::vrpn_Connection:%d "
5096 "Couldn't open local outgoing log file.\n",
5097 __LINE__);
5099 return;
5100 }
5101 }
5102}
5103
5105{
5106 // Remove myself from the "known connections" list
5107 // (or the "anonymous connections" list).
5109
5110 // Clean up the endpoints before the dispatcher
5111 d_endpoints.clear();
5112
5113 // Clean up types, senders, and callbacks.
5114 if (d_dispatcher) {
5115 try {
5116 delete d_dispatcher;
5117 } catch (...) {
5118 fprintf(stderr, "vrpn_Connection::~vrpn_Connection: delete failed\n");
5119 return;
5120 }
5121 d_dispatcher = NULL;
5122 }
5123
5124 if (d_references > 0) {
5125 fprintf(stderr,
5126 "vrpn_Connection::~vrpn_Connection: "
5127 "Connection was deleted while %d references still remain.\n",
5128 d_references);
5129 }
5130}
5131
5132// Some object is now using this connection.
5133void vrpn_Connection::addReference() { d_references++; }
5134
5135// Some object has stopped using this connection. Decrement the ref counter.
5136// If there aren't any references, this connection is no longer in use.
5137// Once it's no longer in use destroy the connection iff d_autoDeleteStatus
5138// has been set to TRUE. If d_autoDeleteStatus is FALSE, the user must
5139// destroy the connection explicitly.
5141{
5142 d_references--;
5143 if (d_references == 0 && d_autoDeleteStatus == true) {
5144 try {
5145 delete this;
5146 } catch (...) {
5147 fprintf(stderr, "vrpn_Connection::removeReference: delete failed\n");
5148 return;
5149 }
5150 } else if (d_references < 0) { // this shouldn't happen.
5151 // sanity check
5152 fprintf(stderr, "vrpn_Connection::removeReference: "
5153 "Negative reference count. This shouldn't happen.");
5154 }
5155}
5156
5157vrpn_int32 vrpn_Connection::register_sender(const char *name)
5158{
5159
5160#ifdef VERBOSE
5161 fprintf(stderr, "vrpn_Connection::register_sender: "
5162 "%d senders; new name \"%s\"\n",
5163 d_dispatcher->numSenders(), name);
5164#endif
5165
5166 // See if the name is already in the list. If so, return it.
5167 vrpn_int32 retval = d_dispatcher->getSenderID(name);
5168 if (retval != -1) {
5169#ifdef VERBOSE
5170 fprintf(stderr, "Sender already defined as id %d.\n", retval);
5171#endif
5172 return retval;
5173 }
5174
5175 retval = d_dispatcher->addSender(name);
5176
5177#ifdef VERBOSE
5178 fprintf(stderr, "Packing sender description for %s, type %d.\n", name,
5179 retval);
5180#endif
5181
5182 // Pack the sender description.
5183 // TCH 24 Jan 00 - Need to do this even if not connected so
5184 // that it goes into the logs (if we're keeping any).
5186
5187 // If the other side has declared this sender, establish the
5188 // mapping for it.
5189 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
5190 it != e; ++it) {
5191 it->newLocalSender(name, retval);
5192 }
5193
5194 // One more in place -- return its index
5195 return retval;
5196}
5197
5198vrpn_int32 vrpn_Connection::register_message_type(const char *name)
5199{
5200
5201#ifdef VERBOSE
5202 fprintf(stderr, "vrpn_Connection::register_message_type: "
5203 "%d type; new name \"%s\"\n",
5204 d_dispatcher->numTypes(), name);
5205#endif
5206
5207 // See if the name is already in the list. If so, return it.
5208 vrpn_int32 retval = d_dispatcher->getTypeID(name);
5209 if (retval != -1) {
5210#ifdef VERBOSE
5211 fprintf(stderr, "Type already defined as id %d.\n", retval);
5212#endif
5213 return retval;
5214 }
5215
5216 retval = d_dispatcher->addType(name);
5217
5218// Pack the type description.
5219// TCH 24 Jan 00 - Need to do this even if not connected so
5220// that it goes into the logs (if we're keeping any).
5221
5222#ifdef VERBOSE
5223 fprintf(stderr, "Packing type description for %s, type %d.\n", name,
5224 retval);
5225#endif
5226
5227 pack_type_description(retval);
5228
5229 // If the other side has declared this type, establish the
5230 // mapping for it.
5231 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
5232 it != e; ++it) {
5233 it->newLocalType(name, retval);
5234 }
5235
5236 // One more in place -- return its index
5237 return retval;
5238}
5239
5240// Yank the callback chain for a message type. Call all handlers that
5241// are interested in messages from this sender. Return 0 if they all
5242// return 0, -1 otherwise.
5243
5244int vrpn_Connection::do_callbacks_for(vrpn_int32 type, vrpn_int32 sender,
5245 struct timeval time,
5246 vrpn_uint32 payload_len, const char *buf)
5247{
5248 return d_dispatcher->doCallbacksFor(type, sender, time, payload_len, buf);
5249}
5250
5252{
5253 return d_dispatcher->doSystemCallbacksFor(p, ud);
5254}
5255
5256void vrpn_Connection::get_log_names(char **local_in_logname,
5257 char **local_out_logname,
5258 char **remote_in_logname,
5259 char **remote_out_logname)
5260{
5261 vrpn_Endpoint *endpoint = d_endpoints.front();
5262 if (!endpoint) {
5263 return;
5264 }
5265 // XXX it is possible to have more than one endpoint, and other endpoints
5266 // may have other log names
5267
5268 if (local_in_logname != NULL)
5269 *local_in_logname = endpoint->d_inLog->getName();
5270 if (local_out_logname != NULL)
5271 *local_out_logname = endpoint->d_outLog->getName();
5272
5273 if (remote_in_logname != NULL) {
5274 if (endpoint->d_remoteInLogName != NULL) {
5275 try {
5276 *remote_in_logname =
5277 new char[strlen(endpoint->d_remoteInLogName) + 1];
5278 vrpn_strncpynull(*remote_in_logname, endpoint->d_remoteInLogName,
5279 strlen(endpoint->d_remoteInLogName) + 1);
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 vrpn_strncpynull(*remote_out_logname, endpoint->d_remoteOutLogName,
5296 strlen(endpoint->d_remoteOutLogName) + 1);
5297 }
5298 catch (...) {
5299 fprintf(stderr, "vrpn_Connection::get_log_names(): Out of memory\n");
5301 *remote_out_logname = NULL;
5302 }
5303 } else {
5304 *remote_out_logname = NULL;
5305 }
5306 }
5307}
5308
5309// virtual
5311
5312// static
5314 vrpn_int32 *connectedEC)
5315{
5316 vrpn_Endpoint_IP *ret = NULL;
5317 try {
5318 ret = new vrpn_Endpoint_IP(me->d_dispatcher, connectedEC);
5319 } catch (...) {
5320 fprintf(stderr, "vrpn_Connection::get_log_names(): Out of memory\n");
5322 }
5323 return ret;
5324}
5325
5326// This is called when a disconnect message is found in the logfile.
5327// It causes the other-side sender and type messages to be cleared,
5328// in anticipation of a possible new set of messages caused by a
5329// reconnected server.
5330
5333{
5334 vrpn_Endpoint *endpoint = (vrpn_Endpoint *)userdata;
5335
5336#ifdef VERBOSE
5337 printf("Just read disconnect message from logfile\n");
5338#endif
5340
5341 return 0;
5342}
5343
5345 vrpn_MESSAGEHANDLER handler,
5346 void *userdata, vrpn_int32 sender)
5347{
5348 return d_dispatcher->addHandler(type, handler, userdata, sender);
5349}
5350
5352 vrpn_MESSAGEHANDLER handler,
5353 void *userdata, vrpn_int32 sender)
5354{
5355 return d_dispatcher->removeHandler(type, handler, userdata, sender);
5356}
5357
5359{
5360 return d_dispatcher->getTypeID(name);
5361}
5362
5363// Changed 8 November 1999 by TCH
5364// With multiple connections allowed, TRYING_TO_CONNECT is an
5365// "ok" status, so we need to admit it. (Used to check >= 0)
5366// XXX What if one endpoint is BROKEN? Don't we need to loop?
5367vrpn_bool vrpn_Connection::doing_okay(void) const
5368{
5369
5370 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
5371 it != e; ++it) {
5372 if (!it->doing_okay()) {
5373 return VRPN_FALSE;
5374 }
5375 }
5376 return (connectionStatus > BROKEN);
5377}
5378
5379// Loop over endpoints and return TRUE if any of them are connected.
5380vrpn_bool vrpn_Connection::connected(void) const
5381{
5382 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
5383 it != e; ++it) {
5384 if (it->status == CONNECTED) {
5385 return VRPN_TRUE;
5386 }
5387 }
5388 return VRPN_FALSE;
5389}
5390
5391//------------------------------------------------------------------------
5392// This section holds data structures and functions to open
5393// connections by name.
5394// The intention of this section is that it can open connections for
5395// objects that are of different types (trackers, buttons and sound),
5396// even if they all refer to the same connection.
5397
5398// This routine will return a pointer to the connection whose name
5399// is passed in. If the routine is called multiple times with the same
5400// name, it will return the same pointer, rather than trying to make
5401// multiple of the same connection (unless force_connection = true).
5402// If the connection is in a bad way, it returns NULL.
5403// This routine will strip off any part of the string before and
5404// including the '@' character, considering this to be the local part
5405// of a device name, rather than part of the connection name. This allows
5406// the opening of a connection to "Tracker0@ioglab" for example, which will
5407// open a connection to ioglab.
5408
5409// This routine adds to the reference count of the connection in question.
5410// This happens regardless of whether the connection already exists
5411// or it is to be created.
5412// Any user code that calls vrpn_get_connection_by_name() directly
5413// should call vrpn_Connection::removeReference() when it is finished
5414// with the pointer. It's ok if you have old code that doesn't do this;
5415// it just means the connection will remain open until the program quits,
5416// which isn't so bad.
5417
5419 const char *cname, const char *local_in_logfile_name,
5420 const char *local_out_logfile_name, const char *remote_in_logfile_name,
5421 const char *remote_out_logfile_name, const char *NIC_IPaddress,
5422 bool force_connection)
5423{
5424 if (cname == NULL) {
5425 fprintf(stderr, "vrpn_get_connection_by_name(): NULL name\n");
5426 return NULL;
5427 }
5428
5429 // Find the relevant part of the name (skip past last '@'
5430 // if there is one)
5431 const char *where_at; // Part of name past last '@'
5432 if ((where_at = strrchr(cname, '@')) != NULL) {
5433 cname = where_at + 1; // Chop off the front of the name
5434 }
5435
5436 vrpn_Connection *c = NULL;
5437 if (!force_connection) {
5439 }
5440
5441 // If its not already open, open it.
5442 // Its constructor will add it to the list (?).
5443 if (!c) {
5444
5445 // connections now self-register in the known list --
5446 // this is kind of odd, but oh well (can probably be done
5447 // more cleanly later).
5448
5449 int is_file = (0 == strncmp(cname, "file:", 5));
5450
5451 if (is_file) {
5452 try {
5453 c = new vrpn_File_Connection(cname, local_in_logfile_name,
5454 local_out_logfile_name);
5455 } catch (...) {
5456 fprintf(stderr, "vrpn_get_connection_by_name(): Out of memory.");
5457 return NULL;
5458 }
5459 } else {
5460 int port = vrpn_get_port_number(cname);
5461 try {
5462 c = new vrpn_Connection_IP(
5463 cname, port, local_in_logfile_name, local_out_logfile_name,
5464 remote_in_logfile_name, remote_out_logfile_name, NIC_IPaddress);
5465 } catch (...) {
5466 fprintf(stderr, "vrpn_get_connection_by_name(): Out of memory.");
5467 return NULL;
5468 }
5469 }
5470
5471 if (c) { // creation succeeded
5472 c->setAutoDeleteStatus(true); // destroy when refcount hits zero.
5473 } else { // creation failed
5474 fprintf(stderr, "vrpn_get_connection_by_name(): Could not create new connection.");
5475 return NULL;
5476 }
5477 }
5478 // else the connection was already open.
5479
5480 c->addReference(); // increment the reference count either way.
5481
5482 // Return a pointer to the connection, even if it is not doing
5483 // okay. This will allow a connection to retry over and over
5484 // again before connecting to the server.
5485 return c;
5486}
5487
5488// Create a server connection that will listen for client connections.
5489// To create a VRPN TCP/UDP server, use a name like:
5490// x-vrpn:machine_name_or_ip:port
5491// x-vrpn::port
5492// machine_name_or_ip:port
5493// machine_name_or_ip
5494// :port
5495// To create a loopback (networkless) server, use the name:
5496// loopback:
5497// To create an MPI server, use a name like:
5498// mpi:MPI_COMM_WORLD
5499// mpi:comm_number
5500//
5501// This routine will strip off any part of the string before and
5502// including the '@' character, considering this to be the local part
5503// of a device name, rather than part of the connection name. This allows
5504// the opening of a connection to "Tracker0@ioglab" for example, which will
5505// open a connection to ioglab.
5506
5509 const char *local_in_logfile_name,
5510 const char *local_out_logfile_name)
5511{
5512 vrpn_Connection *c = NULL;
5513
5514 // Parse the name to find out what kind of connection we are to make.
5515 if (cname == NULL) {
5516 fprintf(stderr, "vrpn_create_server_connection(): NULL name\n");
5517 return NULL;
5518 }
5519 char *location = vrpn_copy_service_location(cname);
5520 if (location == NULL) {
5521 return NULL;
5522 }
5523 int is_loopback = (0 == strncmp(cname, "loopback:", 9));
5524 int is_mpi = (0 == strncmp(cname, "mpi:", 4));
5525 if (is_mpi) {
5526#ifdef VRPN_USE_MPI
5527 XXX_implement_MPI_server_connection;
5528#else
5529 fprintf(stderr, "vrpn_create_server_connection(): MPI support not "
5530 "compiled in. Set VRPN_USE_MPI in vrpn_Configure.h "
5531 "and recompile.\n");
5532 try {
5533 delete[] location;
5534 } catch (...) {
5535 fprintf(stderr, "vrpn_create_server_connection: delete failed\n");
5536 return NULL;
5537 }
5538 return NULL;
5539#endif
5540 } else if (is_loopback) {
5541 try {
5542 c = new vrpn_Connection_Loopback();
5543 } catch (...) {
5544 fprintf(stderr, "vrpn_create_server_connection(): Out of memory\n");
5545 return NULL;
5546 }
5547 } else {
5548 // Not Loopback or MPI port, so we presume that we are a standard VRPN
5549 // UDP/TCP
5550 // port. Open that kind, based on the machine and port name. If we
5551 // don't
5552 // have a machine name, then we pass NULL to the NIC address. If we do
5553 // have
5554 // one, we pass it to the NIC address.
5555 if (strlen(location) == 0) {
5556 try {
5558 local_in_logfile_name,
5559 local_out_logfile_name);
5560 } catch (...) {
5561 fprintf(stderr, "vrpn_create_server_connection(): Out of memory\n");
5562 return NULL;
5563 }
5564 } else {
5565 // Find machine name and port number. Port number returns default
5566 // if there is not one specified. If the machine name is zero
5567 // length
5568 // (just got :port) then use NULL, which means the default NIC.
5569 char *machine = vrpn_copy_machine_name(location);
5570 if (strlen(machine) == 0) {
5571 try {
5572 delete[] machine;
5573 } catch (...) {
5574 fprintf(stderr, "vrpn_create_server_connection(): delete failed\n");
5575 return NULL;
5576 }
5577 machine = NULL;
5578 }
5579 unsigned short port =
5580 static_cast<unsigned short>(vrpn_get_port_number(location));
5581 try {
5582 c = new vrpn_Connection_IP(port, local_in_logfile_name,
5583 local_out_logfile_name, machine);
5584 } catch (...) {
5585 fprintf(stderr, "vrpn_create_server_connection(): Out of memory\n");
5586 return NULL;
5587 }
5588 if (machine) {
5589 try {
5590 delete[] machine;
5591 } catch (...) {
5592 fprintf(stderr, "vrpn_create_server_connection(): delete failed\n");
5593 return NULL;
5594 }
5595 }
5596 }
5597 }
5598 try {
5599 delete[] location;
5600 } catch (...) {
5601 fprintf(stderr, "vrpn_create_server_connection(): delete failed\n");
5602 return NULL;
5603 }
5604
5605 if (!c) { // creation failed
5606 fprintf(stderr, "vrpn_create_server_connection(): Could not create new "
5607 "connection.");
5608 return NULL;
5609 }
5610
5611 c->setAutoDeleteStatus(true); // destroy when refcount hits zero.
5612 c->addReference(); // increment the reference count for the connection.
5613
5614 // Return a pointer to the connection, even if it is not doing
5615 // okay. This will allow a connection to retry over and over
5616 // again before connecting to the server.
5617 return c;
5618}
5619
5628
5629int vrpn_Connection_IP::connect_to_client(const char *machine, int port)
5630{
5631 if (connectionStatus != LISTEN) {
5632 return -1;
5633 };
5634
5635 // Make sure that we have room for a new connection
5636 if (d_endpoints.full()) {
5637 fprintf(stderr, "vrpn_Connection_IP::connect_to_client:"
5638 " Too many existing connections.\n");
5639 return -1;
5640 }
5641 vrpn_Endpoint_IP *endpoint =
5643
5644 if (!endpoint) {
5645 fprintf(stderr, "vrpn_Connection_IP::connect_to_client:"
5646 " Out of memory on new endpoint\n");
5647 return -1;
5648 }
5649 endpoint->setConnection(this);
5650 d_updateEndpoint = vrpn_TRUE;
5651
5652 char msg[256];
5653 snprintf(msg, 256, "%.200s %d", machine, port);
5654 printf("vrpn_Connection_IP::connect_to_client: "
5655 "Connection request received: %s\n",
5656 msg);
5657 endpoint->connect_tcp_to(msg);
5658 if (endpoint->status != COOKIE_PENDING) { // Something broke
5659 endpoint->status = BROKEN;
5660 return -1;
5662 }
5663 handle_connection(endpoint);
5664
5665 return 0;
5666}
5667
5669{
5670 // Set up the things that need to happen when a new connection is
5671 // started.
5672 if (endpoint->setup_new_connection()) {
5673 fprintf(stderr, "vrpn_Connection_IP::handle_connection(): "
5674 "Can't set up new connection!\n");
5676 return;
5677 }
5678}
5679
5680// Get the UDP port description from the other side and connect the
5681// outgoing UDP socket to that port so we can send lossy but time-
5682// critical (tracker) messages that way.
5683
5684// static
5686{
5687 vrpn_Endpoint_IP *endpoint = (vrpn_Endpoint_IP *)userdata;
5688 char rhostname[1000]; // name of remote host
5689
5690#ifdef VERBOSE
5691 printf(" Received request for UDP channel to %s\n", p.buffer);
5692#endif
5693
5694 // Get the name of the remote host from the buffer (ensure terminated)
5695 vrpn_strcpy(rhostname, p.buffer);
5696
5697 // Open the UDP outbound port and connect it to the port on the
5698 // remote machine.
5699 // (remember that the sender field holds the UDP port number)
5700 endpoint->connect_udp_to(rhostname, (int)p.sender);
5701 if (endpoint->status == BROKEN) {
5702 return -1;
5703 }
5704
5705 // Put this here because currently every connection opens a UDP
5706 // port and every host will get this data. Previous implementation
5707 // did it in connect_tcp_to, which only gets called by servers.
5708
5709 vrpn_strcpy(endpoint->rhostname, rhostname);
5710
5711#ifdef VERBOSE
5712 printf(" Opened UDP channel to %s:%d\n", rhostname, p.sender);
5713#endif
5714 return 0;
5715}
5716
5718{
5719 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
5720 it != e; ++it) {
5721 if (it->send_pending_reports() != 0) {
5722 drop_connection(it);
5723 // If we're not a disconnected client connection waiting to connect, report an error.
5724 if (it == NULL) {
5725 fprintf(stderr, "vrpn_Connection_IP::send_pending_reports: "
5726 "Closing failed endpoint.\n");
5727 }
5728 }
5729 }
5730
5732
5733 return 0;
5734}
5735
5737{
5738
5739#ifdef VRPN_USE_WINSOCK_SOCKETS
5740 // Make sure sockets are set up
5741 // TCH 2 Nov 98 after Phil Winston
5742
5743 WSADATA wsaData;
5744 int winStatus;
5745
5746 winStatus = WSAStartup(MAKEWORD(1, 1), &wsaData);
5747 if (winStatus) {
5748 fprintf(stderr, "vrpn_Connection_IP::init(): "
5749 "Failed to set up sockets.\n");
5750 fprintf(stderr, "WSAStartup failed with error code %d\n", winStatus);
5751 exit(0);
5752 }
5753#endif // windows sockets
5754
5755// Ignore SIGPIPE, so that the program does not crash when a
5756// remote client OR SERVER shuts down its TCP connection. We'll find out
5757// about it as an exception on the socket when we select() for
5758// read.
5759// Mips/Ultrix header file signal.h appears to be broken and
5760// require the following cast
5761#ifndef _WIN32 // XXX what about cygwin?
5762#ifdef ultrix
5763 signal(SIGPIPE, (void (*)(int))SIG_IGN);
5764#else
5765 signal(SIGPIPE, SIG_IGN);
5766#endif
5767#endif
5768
5769 // Set up to handle the UDP-request system message.
5772}
5773
5774//---------------------------------------------------------------------------
5775// This routine checks for a request for attention from a remote machine.
5776// The requests come as datagrams to the well-known port number on this
5777// machine.
5778// The datagram includes the machine name and port number on the remote
5779// machine to which this one should establish a connection.
5780// This routine establishes the TCP connection and then sends a magic
5781// cookie describing this as a VRPN connection and telling which port to
5782// use for incoming UDP packets of data associated with the current TCP
5783// session. It reads the associated information from the other side and
5784// sets up the local UDP sender.
5785// It then sends descriptions for all of the known packet types.
5786
5788 const struct timeval *pTimeout)
5789{
5790 int request;
5791 timeval timeout;
5792 int retval;
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 snprintf(fromname, 1024, "%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[200];
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, "%199s %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 checkHost[199] = '\0'; // Ensure null termination.
5877 if (checkPort < 1024) {
5878 fprintf(stderr,
5879 "server_check_for_incoming_connections(): Bad port\n");
5880 try {
5881 delete[] checkHost;
5882 } catch (...) {
5883 fprintf(stderr, "server_check_for_incoming_connections(): delete failed\n");
5884 return;
5885 }
5886 return;
5887 }
5888 // Check all of the characters in the hostname to make sure they are
5889 // either a letter, a digit, or a dot (.).
5890 size_t checkLoop;
5891 for (checkLoop = 0; checkLoop < strlen(checkHost); checkLoop++) {
5892 char checkChar = checkHost[checkLoop];
5893 if (!isalnum(checkChar) && (checkChar != '.')) {
5894 fprintf(
5895 stderr,
5896 "server_check_for_incoming_connections(): Bad hostname\n");
5897 try {
5898 delete[] checkHost;
5899 } catch (...) {
5900 fprintf(stderr, "server_check_for_incoming_connections(): delete failed\n");
5901 return;
5902 }
5903 return;
5904 }
5905 }
5906 try {
5907 delete[] checkHost;
5908 } catch (...) {
5909 fprintf(stderr, "server_check_for_incoming_connections(): delete failed\n");
5910 return;
5911 }
5912
5913 // Make sure that we have room for a new connection
5914 if (d_endpoints.full()) {
5915 fprintf(stderr, "vrpn: Too many existing connections; "
5916 "ignoring request from %s\n",
5917 msg);
5918 return;
5919 }
5920
5921 // Create a new endpoint and start trying to connect it to
5922 // the client.
5923
5924 vrpn_Endpoint_IP *endpoint =
5926 if (!endpoint) {
5927 fprintf(
5928 stderr,
5929 "vrpn_Connection_IP::server_check_for_incoming_connections:\n"
5930 " Out of memory on new endpoint\n");
5931 return;
5932 }
5933 endpoint->setConnection(this);
5934 d_updateEndpoint = vrpn_TRUE;
5935
5936 // Server-side logging under multiconnection - TCH July 2000
5937 // Check for NULL server log name, which happens when the log file
5938 // already exists and it can't save it.
5940 (d_serverLogName != NULL)) {
5944 endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
5945 retval = endpoint->d_inLog->open();
5946 if (retval == -1) {
5947 fprintf(stderr, "vrpn_Connection_IP::server_check_for_incoming_"
5948 "connections: "
5949 "Couldn't open log file.\n");
5951 return;
5952 }
5953 }
5954
5955 endpoint->setNICaddress(d_NIC_IP);
5956 endpoint->status = TRYING_TO_CONNECT;
5957
5958 // Fill in NIC address. Copy the machine name so that we can delete it
5959 // in the destructor.
5961 endpoint->connect_tcp_to(msg);
5962 handle_connection(endpoint);
5963
5964 // HACK
5965 // We don't want to do this, but connection requests are soft state
5966 // that will be restored in 1 second; meanwhile, if we accept multiple
5967 // connection requests from the same source we try to open multiple
5968 // connections to it, which invariably makes SOMEBODY crash sooner or
5969 // later.
5970 flush_udp_socket(listen_udp_sock);
5971 }
5972
5973 // Do a zero-time select() to see if there are incoming TCP requests on
5974 // the listen socket. This is used when the client needs to punch through
5975 // a firewall.
5976
5977 vrpn_SOCKET newSocket;
5978 retval = vrpn_poll_for_accept(listen_tcp_sock, &newSocket);
5979
5980 if (retval == -1) {
5981 fprintf(stderr, "Error accepting on TCP socket.\n");
5982 return;
5983 }
5984 if (retval) { // Some data to read! Go get it.
5985
5986 printf("vrpn: TCP connection request received.\n");
5987
5988 if (d_endpoints.full()) {
5989 fprintf(stderr, "vrpn: Too many existing connections; "
5990 "ignoring request.\n");
5991 return;
5992 }
5993
5994 vrpn_Endpoint_IP *endpoint =
5996 if (!endpoint) {
5997 fprintf(
5998 stderr,
5999 "vrpn_Connection_IP::server_check_for_incoming_connections:\n"
6000 " Out of memory on new endpoint\n");
6001 return;
6002 }
6003 endpoint->setConnection(this);
6004 d_updateEndpoint = vrpn_TRUE;
6005
6006 // Since we're being connected to using a TCP request, tell the endpoint
6007 // not to try and establish any other connections (since the client is
6008 // presumably coming through a firewall or NAT and UDP packets won't get
6009 // through).
6010 endpoint->d_tcp_only = vrpn_TRUE;
6011
6012 // Find out the remote port number and store it.
6013 struct sockaddr_in peer;
6014#ifdef VRPN_USE_WINSOCK_SOCKETS
6015 int peerlen = sizeof(peer);
6016#else
6017#if defined(sgi)
6018 int peerlen = sizeof(peer);
6019#else
6020 socklen_t peerlen = sizeof(peer);
6021#endif
6022#endif
6023 unsigned short peer_port = 0;
6024 if (getpeername(newSocket, static_cast<struct sockaddr *>(
6025 static_cast<void *>(&peer)),
6026 &peerlen) == 0) {
6027 peer_port = ntohs(peer.sin_port);
6028 }
6029 endpoint->d_remote_port_number = peer_port;
6030
6031 // Server-side logging under multiconnection - TCH July 2000
6036 endpoint->d_inLog->logMode() = vrpn_LOG_INCOMING;
6037 retval = endpoint->d_inLog->open();
6038 if (retval == -1) {
6039 fprintf(stderr, "vrpn_Connection_IP::server_check_for_incoming_"
6040 "connections: "
6041 "Couldn't open incoming log file.\n");
6043 return;
6044 }
6045 }
6046
6047 endpoint->setNICaddress(d_NIC_IP);
6048 endpoint->d_tcpSocket = newSocket;
6049
6050 handle_connection(endpoint);
6051 }
6052
6053 return;
6054}
6055
6057{
6058 endpoint->drop_connection();
6059
6060 // If we're a client, try to reconnect to the server
6061 // that just dropped its connection.
6062 // If we're a server, delete the endpoint.
6064 endpoint->status = TRYING_TO_CONNECT;
6065 }
6066 else {
6067 delete_endpoint(endpoint);
6068 }
6069}
6070
6076
6077int vrpn_Connection_IP::mainloop(const struct timeval *pTimeout)
6078{
6079 timeval timeout;
6080
6081 if (d_updateEndpoint) {
6083 d_updateEndpoint = vrpn_FALSE;
6084 }
6085 // struct timeval perSocketTimeout;
6086 // const int numSockets = 2;
6087 // divide timeout over all selects()
6088 // if (timeout) {
6089 // perSocketTimeout.tv_sec = timeout->tv_sec / numSockets;
6090 // perSocketTimeout.tv_usec = timeout->tv_usec / numSockets
6091 // + (timeout->tv_sec % numSockets) *
6092 // (1000000L / numSockets);
6093 // } else {
6094 // perSocketTimeout.tv_sec = 0;
6095 // perSocketTimeout.tv_usec = 0;
6096 // }
6097
6098 // BETTER IDEA: do one select rather than multiple -- otherwise you are
6099 // potentially holding up one or the other. This allows clients which
6100 // should not do anything until they get messages to request infinite
6101 // waits (servers can't usually do infinite waits this because they need
6102 // to service other devices to generate info which they then send to
6103 // clients) . weberh 3/20/99
6104
6105 if (connectionStatus == LISTEN) {
6107 }
6108
6109 for (vrpn::EndpointIterator it = d_endpoints.begin(), e = d_endpoints.end();
6110 it != e; ++it) {
6111
6112 if (pTimeout) {
6113 timeout = *pTimeout;
6114 }
6115 else {
6116 timeout.tv_sec = 0;
6117 timeout.tv_usec = 0;
6118 }
6119
6120 it->mainloop(&timeout);
6121
6122 if (it->status == BROKEN) {
6123 drop_connection(it);
6124 }
6125 }
6126
6127 // Do housekeeping on the endpoint array
6129
6130 return 0;
6131}
6132
6134 unsigned short listen_port_no, const char *local_in_logfile_name,
6135 const char *local_out_logfile_name, const char *NIC_IPaddress,
6136 vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
6137 : vrpn_Connection(local_in_logfile_name, local_out_logfile_name, epa)
6140 , d_NIC_IP(NULL)
6141{
6142 // Copy the NIC_IPaddress so that we do not have to rely on the caller
6143 // to keep it from changing.
6144 if (NIC_IPaddress != NULL) try {
6145 char *IP = new char[strlen(NIC_IPaddress) + 1];
6146 vrpn_strncpynull(IP, NIC_IPaddress, strlen(NIC_IPaddress) + 1);
6147 d_NIC_IP = IP;
6148 } catch (...) {
6149 fprintf(stderr, "vrpn_Connection_IP::vrpn_Connection_IP(): Out of memory.\n");
6151 return;
6152 }
6153
6154 // Initialize the things that must be for any constructor
6156
6157 listen_udp_sock = ::open_udp_socket(&listen_port_no, NIC_IPaddress);
6158 // TCH OHS HACK
6159 listen_tcp_sock = ::open_tcp_socket(&listen_port_no, NIC_IPaddress);
6163 return;
6164 // fprintf(stderr, "BROKEN -
6165 // vrpn_Connection_IP::vrpn_Connection_I{.\n");
6166 }
6167 else {
6169// fprintf(stderr, "LISTEN - vrpn_Connection_IP::vrpn_Connection_IP.\n");
6170#ifdef VERBOSE
6171 printf("vrpn: Listening for requests on port %d\n", listen_port_no);
6172#endif
6173 }
6174
6175 // TCH OHS HACK
6176 if (listen(listen_tcp_sock, 1)) {
6177 fprintf(stderr, "Couldn't listen on TCP listening socket.\n");
6179 return;
6180 }
6181
6182 flush_udp_socket(listen_udp_sock);
6183
6185}
6186
6188 const char *station_name, int port, const char *local_in_logfile_name,
6189 const char *local_out_logfile_name, const char *remote_in_logfile_name,
6190 const char *remote_out_logfile_name, const char *NIC_IPaddress,
6191 vrpn_Endpoint_IP *(*epa)(vrpn_Connection *, vrpn_int32 *))
6192 : vrpn_Connection(local_in_logfile_name, local_out_logfile_name,
6193 remote_in_logfile_name, remote_out_logfile_name, epa)
6196 , d_NIC_IP(NULL)
6197{
6198 vrpn_Endpoint_IP *endpoint;
6199 vrpn_bool isrsh;
6200 vrpn_bool istcp;
6201 int retval;
6202
6203 // Copy the NIC_IPaddress so that we do not have to rely on the caller
6204 // to keep it from changing.
6205 if (NIC_IPaddress != NULL) try {
6206 char *IP = new char[strlen(NIC_IPaddress) + 1];
6207 vrpn_strncpynull(IP, NIC_IPaddress, strlen(NIC_IPaddress) + 1);
6208 d_NIC_IP = IP;
6209 } catch (...) {
6210 fprintf(stderr, "vrpn_Connection_IP::vrpn_Connection_IP(): Out of memory.\n");
6212 return;
6213 }
6214
6215 isrsh = (strstr(station_name, "x-vrsh:") ? VRPN_TRUE : VRPN_FALSE);
6216 istcp = (strstr(station_name, "tcp:") ? VRPN_TRUE : VRPN_FALSE);
6217
6218 // Initialize the things that must be for any constructor
6220
6221 endpoint = d_endpoints.front(); // shorthand
6222 if (!endpoint) {
6223 fprintf(stderr, "vrpn_Connection_IP: First endpoint is null!\n");
6225 return;
6226 }
6227
6228 endpoint->setNICaddress(d_NIC_IP);
6229
6230 // If we are not a TCP-only or remote-server-starting
6231 // type of connection, then set up to lob UDP packets
6232 // to the other side and put us in the mode that will
6233 // wait for the responses. Go ahead and set up the TCP
6234 // socket that we will listen on and lob a packet.
6235
6236 if (!isrsh && !istcp) {
6237 // Open a connection to the station using a UDP request
6238 // that asks to machine to call us back here.
6239 endpoint->d_remote_machine_name = vrpn_copy_machine_name(station_name);
6240 if (!endpoint->d_remote_machine_name) {
6242 fprintf(stderr,
6243 "vrpn_Connection_IP: Can't get remote machine name!\n");
6245 // fprintf(stderr, "BROKEN -
6246 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6247 return;
6248 }
6249 if (port < 0) {
6251 }
6252 else {
6253 endpoint->d_remote_port_number = port;
6254 }
6255
6256 endpoint->status = TRYING_TO_CONNECT;
6257
6258 /* Create a UDP socket and connect it to the port on the remote
6259 * machine. */
6260
6261 endpoint->d_udpLobSocket =
6262 vrpn_connect_udp_port(endpoint->d_remote_machine_name,
6263 endpoint->d_remote_port_number, d_NIC_IP);
6264 if (endpoint->d_udpLobSocket == INVALID_SOCKET) {
6266 fprintf(stderr, "vrpn_Connection_IP: Can't set up socket to lob "
6267 "UDP packets!\n");
6269 // fprintf(stderr, "BROKEN -
6270 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6271 return;
6272 }
6273
6274#ifdef VERBOSE
6275 printf("vrpn_Connection_IP: Getting the TCP port to listen on\n");
6276#endif
6277 // Determine which IP address we should listen on.
6278 // By listening on only localhost (as opposed to all interfaces,
6279 // i.e., 0.0.0.0), we can avoid complaints from the Windows firewall.
6280 char local_host[64];
6281 get_local_socket_name(local_host, sizeof(local_host),
6282 endpoint->d_remote_machine_name);
6283
6284 // Set up the connection that we will listen on.
6285 if (vrpn_get_a_TCP_socket(&endpoint->d_tcpListenSocket,
6286 &endpoint->d_tcpListenPort,
6287 local_host) == -1) {
6289 fprintf(stderr, "vrpn_Connection_IP: Can't create listen socket\n");
6290 endpoint->status = BROKEN;
6292 // fprintf(stderr, "BROKEN -
6293 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6294 return;
6295 }
6296
6297 // Lob a packet asking for a connection on that port.
6298 vrpn_gettimeofday(&endpoint->d_last_connect_attempt, NULL);
6300 endpoint->d_udpLobSocket, endpoint->d_remote_machine_name,
6301 endpoint->d_remote_port_number, endpoint->d_tcpListenPort,
6302 NIC_IPaddress) == -1) {
6304 fprintf(stderr, "vrpn_Connection_IP: Can't lob UDP request\n");
6305 endpoint->status = BROKEN;
6306 // fprintf(stderr, "BROKEN -
6307 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6308 return;
6309 }
6310
6311 // the next line is something jeff added to get vrpn to work on his
6312 // PC. Tom Hudson independently added a line that is similar, but
6313 // different. I'm (jeff) am not sure what the right thing is here.
6314 //
6315 // Let's do both, because otherwise connectionStatus is
6316 // never initialized, and doing_ok() returns FALSE sometimes.
6318
6319 // here is the line that Tom added
6320 endpoint->status = TRYING_TO_CONNECT;
6321
6322 // See if we have a connection yet (wait for 1 sec at most).
6323 // This will allow the connection to come up fast if things are
6324 // all set. Otherwise, we'll drop into re-sends when we get
6325 // to mainloop().
6326 retval = vrpn_poll_for_accept(endpoint->d_tcpListenSocket,
6327 &endpoint->d_tcpSocket, 1.0);
6328 if (retval == -1) {
6330 fprintf(stderr, "vrpn_Connection_IP: Can't poll for accept\n");
6332 return;
6333 }
6334 if (retval == 1) { // Got one!
6335 endpoint->status = COOKIE_PENDING;
6336#ifdef VERBOSE
6337 printf("vrpn: Connection established on initial try "
6338 "(COOKIE_PENDING)\n");
6339#endif
6340 // Set up the things that need to happen when a new connection
6341 // is established.
6342 if (endpoint->setup_new_connection()) {
6343 fprintf(stderr, "vrpn_Connection_IP: "
6344 "Can't set up new connection!\n");
6346 // status = BROKEN;
6347 // fprintf(stderr, "BROKEN -
6348 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6349 return;
6350 }
6351 }
6352 }
6353
6354 // TCH OHS HACK
6355 if (istcp) {
6356 endpoint->d_remote_machine_name = vrpn_copy_machine_name(station_name);
6357 if (!endpoint->d_remote_machine_name) {
6358 fprintf(stderr, "vrpn_Connection_IP: Can't get remote machine name "
6359 "for tcp: connection!\n");
6361 return;
6362 }
6363 endpoint->d_remote_port_number = port;
6364
6365 // Since we are doing a TCP connection, tell the endpoint not to try and
6366 // use any other communication mechanism to get to the server.
6367 endpoint->d_tcp_only = vrpn_TRUE;
6368 endpoint->status = TRYING_TO_CONNECT;
6370
6371#ifdef VERBOSE
6372 printf("vrpn_Connection_IP: Getting the TCP port to connect with.\n");
6373#endif
6374
6375 // Set up the connection that we will connect with.
6376 // Blocks, doesn't it?
6377 retval =
6378 endpoint->connect_tcp_to(endpoint->d_remote_machine_name, port);
6379
6380 if (retval == -1) {
6381 fprintf(stderr,
6382 "vrpn_Connection_IP: Can't create TCP connection.\n");
6383 endpoint->status = BROKEN;
6384 return;
6385 }
6386
6387 endpoint->status = TRYING_TO_CONNECT;
6388
6389 if (endpoint->setup_new_connection()) {
6390 fprintf(stderr, "vrpn_Connection_IP: "
6391 "Can't set up new connection!\n");
6393 return;
6394 }
6395 }
6396
6397 // If we are a remote-server-starting type of connection,
6398 // Try to start the remote server and connect to it. If
6399 // we fail, then the connection is broken. Otherwise, we
6400 // are connected.
6401
6402 if (isrsh) {
6403 // Start up the server and wait for it to connect back
6404 char *machinename;
6405 char *server_program;
6406 char *server_args; // server program plus its arguments
6407 char *token;
6408
6409 machinename = vrpn_copy_machine_name(station_name);
6410 server_program = vrpn_copy_rsh_program(station_name);
6411 server_args = vrpn_copy_rsh_arguments(station_name);
6412 token = server_args;
6413 // replace all argument separators (',') with spaces (' ')
6414 while ((token = strchr(token, ',')) != NULL) {
6415 *token = ' ';
6416 }
6417
6418 endpoint->d_tcpSocket = vrpn_start_server(machinename, server_program,
6419 server_args, NIC_IPaddress);
6420 if (machinename) {
6421 try {
6422 delete[](char *)machinename;
6423 } catch (...) {
6424 fprintf(stderr, "vrpn_Connection_IP: delete failed\n");
6425 return;
6426 }
6427 }
6428 if (server_program) {
6429 try {
6430 delete[](char *)server_program;
6431 } catch (...) {
6432 fprintf(stderr, "vrpn_Connection_IP: delete failed\n");
6433 return;
6434 }
6435 }
6436 if (server_args) {
6437 try {
6438 delete[](char *)server_args;
6439 } catch (...) {
6440 fprintf(stderr, "vrpn_Connection_IP: delete failed\n");
6441 return;
6442 }
6443 }
6444
6445 if (endpoint->d_tcpSocket < 0) {
6446 fprintf(stderr, "vrpn_Connection_IP: "
6447 "Can't open %s\n",
6448 station_name);
6449 endpoint->status = BROKEN;
6450 // fprintf(stderr, "BROKEN -
6451 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6452 return;
6453 }
6454 else {
6455 endpoint->status = COOKIE_PENDING;
6456 // fprintf(stderr, "COOKIE_PENDING -
6457 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6458
6459 if (endpoint->setup_new_connection()) {
6460 fprintf(stderr, "vrpn_Connection_IP: "
6461 "Can't set up new connection!\n");
6464 // fprintf(stderr, "BROKEN -
6465 // vrpn_Connection_IP::vrpn_Connection_IP.\n");
6466 return;
6467 }
6468 }
6469 }
6470
6471 vrpn_ConnectionManager::instance().addConnection(this, station_name);
6472}
6473
6475{
6476 // Send any pending messages
6478
6479 // Close the UDP and TCP listen endpoints if we're a server
6482 }
6485 }
6486
6487 if (d_NIC_IP) {
6488 try {
6489 delete[] d_NIC_IP;
6490 } catch (...) {
6491 fprintf(stderr, "vrpn_Connection_IP::~vrpn_Connection_IP: delete failed\n");
6492 return;
6493 }
6494 d_NIC_IP = NULL;
6495 }
6496
6497 // Clean up the endpoints
6498 d_endpoints.clear();
6499
6500#ifdef VRPN_USE_WINSOCK_SOCKETS
6501
6502 if (WSACleanup() == SOCKET_ERROR) {
6503 fprintf(stderr, "~vrpn_Connection_IP(): "
6504 "WSACleanup() failed with error code %d\n",
6505 WSAGetLastError());
6506 }
6507
6508#endif // VRPN_USE_WINSOCK_SOCKETS
6509}
6510
6511// Set up to be a server connection, which is the only kind we can be.
6513 : vrpn_Connection(NULL, NULL, NULL, NULL)
6514{
6515 // We're always "connected."
6517
6518 // Add this to the list of known connections.
6520}
6521
6525
6526int vrpn_Connection_Loopback::mainloop(const timeval * /*timeout*/)
6527{
6528 return 0;
6529}
6530
6531// utility routines to parse names (<service>@<URL>)
6532char *vrpn_copy_service_name(const char *fullname)
6533{
6534 if (fullname == NULL) {
6535 return NULL;
6536 } else {
6537 size_t len = strcspn(fullname, "@");
6538 if (len >= MAX_SIZE_T) {
6539 fprintf(stderr, "vrpn_copy_service_name: String too long!\n");
6540 return NULL;
6541 }
6542 len++;
6543 char *tbuf = NULL;
6544 try {
6545 tbuf = new char[len];
6546 strncpy(tbuf, fullname, len - 1);
6547 tbuf[len - 1] = 0;
6548 } catch (...) {
6549 fprintf(stderr, "vrpn_copy_service_name: Out of memory!\n");
6550 return NULL;
6551 }
6552 return tbuf;
6553 }
6554}
6555
6556char *vrpn_copy_service_location(const char *fullname)
6557{
6558 char* ret = NULL;
6559
6560 // If there is no "@" sign in the string, copy the whole string.
6561 const char *start = fullname;
6562 size_t len = strlen(fullname);
6563 size_t beforeAt = strcspn(fullname, "@");
6564 if (beforeAt < len) {
6565 // Skip all of the characters before the @ and the @ itself.
6566 start += beforeAt + 1;
6567 len -= beforeAt + 1;
6568 }
6569 len++; // Count the null termination character at the end of the string.
6570 try {
6571 ret = new char[len];
6572 vrpn_strncpynull(ret, start, len);
6573 } catch (...) {
6574 fprintf(stderr, "vrpn_copy_service_location: Out of memory!\n");
6575 return NULL;
6576 }
6577 return ret;
6578}
6579
6580char *vrpn_copy_file_name(const char *filespecifier)
6581{
6582 char *filename = NULL;
6583 const char *fp;
6584 size_t len;
6585
6586 fp = filespecifier;
6587 if (!fp) return NULL;
6588
6589 if (!strncmp(fp, "file://", 7)) {
6590 fp += 7;
6591 } else if (!strncmp(fp, "file:", 5)) {
6592 fp += 5;
6593 }
6594
6595 len = 1 + strlen(fp);
6596 filename = NULL;
6597 try {
6598 filename = new char[len];
6599 strncpy(filename, fp, len);
6600 filename[len - 1] = 0;
6601 } catch (...) {
6602 fprintf(stderr, "vrpn_copy_file_name: Out of memory!\n");
6603 return NULL;
6604 }
6605 return filename;
6606}
6607
6608// Returns the length in characters of the header on the name that is
6609// passed to it. Helper routine for those that follow.
6610
6611static int header_len(const char *hostspecifier)
6612{
6613 // If the name begins with "x-vrpn://" or "x-vrsh://" or "tcp://" skip that
6614 // (also handle the case where there is no // after the colon).
6615 if (!strncmp(hostspecifier, "x-vrpn://", 9) ||
6616 !strncmp(hostspecifier, "x-vrsh://", 9)) {
6617 return 9;
6618 }
6619 else if (!strncmp(hostspecifier, "x-vrpn:", 7) ||
6620 !strncmp(hostspecifier, "x-vrsh:", 7)) {
6621 return 7;
6622 }
6623 else if (!strncmp(hostspecifier, "tcp://", 6)) {
6624 return 6;
6625 }
6626 else if (!strncmp(hostspecifier, "tcp:", 4)) {
6627 return 4;
6628 }
6629 else if (!strncmp(hostspecifier, "mpi://", 6)) {
6630 return 6;
6631 }
6632 else if (!strncmp(hostspecifier, "mpi:", 4)) {
6633 return 4;
6634 }
6635
6636 // No header found.
6637 return 0;
6638}
6639
6640// The caller is responsible for calling delete [] on the
6641// returned pointer if it is not null.
6642
6643char *vrpn_copy_machine_name(const char *hostspecifier)
6644{
6645 size_t nearoffset = 0;
6646 size_t faroffset;
6647 // if it contains a ':', copy only the prefix before the last ':'
6648 // otherwise copy all of it
6649 size_t len;
6650 char *tbuf;
6651
6652 // Skip past the header, if any; this includes any tcp:// or tcp:
6653 // at the beginning of the string.
6654 nearoffset = header_len(hostspecifier);
6655
6656 // stop at first occurrence of :<port #> or /<rsh arguments>.
6657 // Note that this may be the beginning of the string, right at
6658 // nearoffset.
6659 faroffset = strcspn(hostspecifier + nearoffset, ":/");
6660 if (faroffset >= MAX_SIZE_T) {
6661 fprintf(stderr, "vrpn_copy_machine_name: String too long!\n");
6662 return NULL;
6663 }
6664 len = 1 + faroffset;
6665
6666 tbuf = NULL;
6667 try {
6668 tbuf = new char[len];
6669 strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6670 tbuf[len - 1] = 0;
6671 } catch (...) {
6672 fprintf(stderr, "vrpn_copy_machine_name: Out of memory!\n");
6673 return NULL;
6674 }
6675 return tbuf;
6676}
6677
6678int vrpn_get_port_number(const char *hostspecifier)
6679{
6680 const char *pn;
6681 int port = vrpn_DEFAULT_LISTEN_PORT_NO;
6682
6683 pn = hostspecifier;
6684 if (!pn) return -1;
6685
6686 // Skip over the header, if present
6687 pn += header_len(hostspecifier);
6688
6689 pn = strrchr(pn, ':');
6690 if (pn) {
6691 pn++;
6692 port = atoi(pn);
6693 }
6694
6695 return port;
6696}
6697
6698char *vrpn_copy_rsh_program(const char *hostspecifier)
6699{
6700 size_t nearoffset = 0; // location of first char after machine name
6701 size_t faroffset; // location of last character of program name
6702 size_t len;
6703 char *tbuf = NULL;
6704
6705 nearoffset += header_len(hostspecifier);
6706
6707 nearoffset += strcspn(hostspecifier + nearoffset, "/");
6708 nearoffset++; // step past the '/'
6709 faroffset = strcspn(hostspecifier + nearoffset, ",");
6710 len = (faroffset ? faroffset : strlen(hostspecifier) - nearoffset);
6711 if (len >= MAX_SIZE_T) {
6712 fprintf(stderr, "vrpn_copy_rsh_program: String too long!\n");
6713 return NULL;
6714 }
6715 len++;
6716 try {
6717 tbuf = new char[len];
6718 strncpy(tbuf, hostspecifier + nearoffset, len - 1);
6719 tbuf[len - 1] = 0;
6720 // fprintf(stderr, "server program: '%s'.\n", tbuf);
6721 } catch (...) {
6722 fprintf(stderr, "vrpn_copy_rsh_program: Out of memory!\n");
6723 return NULL;
6724 }
6725 return tbuf;
6726}
6727
6728char *vrpn_copy_rsh_arguments(const char *hostspecifier)
6729{
6730 size_t nearoffset = 0; // location of first char after server name
6731 size_t faroffset; // location of last character
6732 size_t len;
6733 char *tbuf = NULL;
6734
6735 nearoffset += header_len(hostspecifier);
6736
6737 nearoffset += strcspn(hostspecifier + nearoffset, "/");
6738 nearoffset += strcspn(hostspecifier + nearoffset, ",");
6739 faroffset = strlen(hostspecifier);
6740 len = (faroffset - nearoffset) + 1;
6741 try {
6742 tbuf = new char[len];
6743 vrpn_strncpynull(tbuf, hostspecifier + nearoffset, len);
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 vrpn_strncpynull(location, specifier, inputLength + 1); // 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 vrpn_strncpynull(newSpecifier, newServiceName, len + 2);
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...
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.
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,...
vrpn_SOCKET listen_udp_sock
UDP Connect requests come here.
virtual void handle_connection(vrpn_Endpoint *endpoint)
This routine is called by a server-side connection when a new connection has just been established,...
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,...
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.
vrpn_SOCKET listen_tcp_sock
TCP Connection requests come here.
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)
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]
vrpn_SOCKET d_tcpSocket
int handle_udp_messages(const timeval *timeout)
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
vrpn_SOCKET d_udpOutboundSocket
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.
vrpn_SOCKET d_udpLobSocket
Socket to use to lob UDP requests asking for the server to call us back.
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)
vrpn_SOCKET d_tcpListenSocket
This section deals with when a client connection is trying to establish (or re-establish) a connectio...
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.
vrpn_SOCKET d_udpInboundSocket
Inbound unreliable messages come here. Need one for each due to different clock synchronization for e...
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
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.
int newRemoteType(vrpn_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.
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
int newRemoteSender(vrpn_CNAME sender_name, vrpn_int32 remote_id, vrpn_int32 local_id)
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)
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.
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.
size_type size() const
void assign(size_type count, const T &value)
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(vrpn_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...
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
int vrpn_noint_block_read_timeout(vrpn_SOCKET infile, char buffer[], size_t length, struct timeval *timeout)
This routine will read in a block from the file descriptor.
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...
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
char vrpn_CNAME[vrpn_CNAME_LENGTH]
@ 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:58
#define vrpn_SOCKET
Definition vrpn_Shared.h: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
char * vrpn_strncpynull(char *dst, const char *src, size_t size)
Version of strncpy that ensures the resulting string is alyways NULL terminated. It also only writes ...