vrpn  07.33
Virtual Reality Peripheral Network
vrpn_BaseClass.C
Go to the documentation of this file.
1 // vrpn_BaseClass.C
2 
3 #include <stddef.h> // for size_t
4 #include <stdio.h> // for fprintf, NULL, stderr, etc
5 #include <string.h> // for strcmp, strlen
6 
7 #include "vrpn_BaseClass.h"
8 #include "vrpn_Shared.h" // for timeval, vrpn_buffer, etc
9 
10 //#define VERBOSE
11 
16 
18  : d_first_watched_object(NULL)
19  , d_ostream(stdout)
20  , d_severity_to_print(vrpn_TEXT_WARNING)
21  , d_level_to_print(0)
22 {
23 }
24 
27 {
28  d_semaphore.p();
29 /* XXX No longer removes these. We get into trouble with the
30  system-defined vrpn_System_TextPrinter destructor because it
31  may run after the vrpn_ConnectionManager destructor has run,
32  which (if we have some undeleted objects) will leave objects
33  that don't have a NULL connection pointer, but whose pointers
34  point to already-deleted connections. This causes a crash. */
35 #if 0
36 
37  vrpn_TextPrinter_Watch_Entry *victim, *next;
38  vrpn_BaseClass *obj;
39 
40  victim = d_first_watched_object;
41  while (victim != NULL) {
42  next = victim->next;
43  obj = victim->obj;
44 
45  // Guard against the case where the object has set its connection pointer
46  // to NULL, which is how some objects notify themselves that they are
47  // broken.
48  if (obj->connectionPtr()) {
50  }
51  delete victim;
52  victim = next;
53  }
54 #endif // XXX
55  d_semaphore.v();
56 }
57 
68 {
69  d_semaphore.p();
71 
72  // Make sure we have an actual object.
73  if (o == NULL) {
74  fprintf(stderr,
75  "vrpn_TextPrinter::add_object(): NULL pointer passed\n");
76  d_semaphore.v();
77  return -1;
78  }
79 
80 #ifdef VERBOSE
81  printf("vrpn_TextPrinter: adding object %s\n", o->d_servicename);
82 #endif
83 
84  // If the object is already in the list, we are done. It is considered the
85  // same
86  // object if it has the same connection and the same service name.
87  victim = d_first_watched_object;
88  while (victim != NULL) {
89  if ((o->d_connection == victim->obj->d_connection) &&
90  (strcmp(o->d_servicename, victim->obj->d_servicename) == 0)) {
91  d_semaphore.v();
92  return 0;
93  }
94  victim = victim->next;
95  }
96 
97  // Add the object to the beginning of the list.
98  if ((victim = new vrpn_TextPrinter_Watch_Entry) == NULL) {
99  fprintf(stderr, "vrpn_TextPrinter::add_object(): out of memory\n");
100  d_semaphore.v();
101  return -1;
102  }
103  victim->obj = o;
104  victim->me = this;
105  victim->next = d_first_watched_object;
106  d_first_watched_object = victim;
107 
108  // Register a callback for the object
110  text_message_handler, victim,
111  o->d_sender_id) != 0) {
112  fprintf(stderr,
113  "vrpn_TextPrinter::add_object(): Can't register callback\n");
114  d_first_watched_object = victim->next;
115  delete victim;
116  d_semaphore.v();
117  return -1;
118  }
119 
120  d_semaphore.v();
121  return 0;
122 }
123 
133 {
134  d_semaphore.p();
135  vrpn_TextPrinter_Watch_Entry *victim, **snitch;
136 
137 #ifdef VERBOSE
138  printf("vrpn_TextPrinter: removing object %s\n", o->d_servicename);
139 #endif
140 
141  // Make sure we have an actual object.
142  if (o == NULL) {
143  fprintf(stderr,
144  "vrpn_TextPrinter::remove_object(): NULL pointer passed\n");
145  d_semaphore.v();
146  return;
147  }
148 
149  // Find the entry in the list (if it is there).
150  // Starts this pointing at the first watched object, so it will
151  // update that object if it is the one who pointed us at the one
152  // to be deleted.
153  snitch = &d_first_watched_object;
154  victim = *snitch;
155  while ((victim != NULL) &&
156  ((o->d_connection != victim->obj->d_connection) ||
157  (strcmp(o->d_servicename, victim->obj->d_servicename) != 0))) {
158 
159  snitch = &((*snitch)->next);
160  victim = victim->next;
161  }
162 
163  // If the object is on the list, unregister its callback and delete it.
164  if (victim != NULL) {
165  // Unregister the callback for the object, unless its d_connetion
166  // pointer
167  // is NULL (which is a convention used by devices to indicate that they
168  // are broken, so we need to guard against it here).
169  if (o->d_connection) {
172  o->d_sender_id) != 0) {
173  fprintf(stderr, "vrpn_TextPrinter::remove_object(): Can't "
174  "unregister callback\n");
175  }
176  }
177 
178  // Remove the entry from the list
179  *snitch = victim->next;
180  delete victim;
181 
182  // We're done.
183  d_semaphore.v();
184  return;
185  }
186 
187  // Object not in the list, so we're done.
188  d_semaphore.v();
189  return;
190 }
191 
200 {
202  (vrpn_TextPrinter_Watch_Entry *)userdata;
203  vrpn_TextPrinter *me = entry->me;
204  vrpn_BaseClass *obj = entry->obj;
205  vrpn_TEXT_SEVERITY severity;
206  vrpn_uint32 level;
207  char message[vrpn_MAX_TEXT_LEN];
208 
209  me->d_semaphore.p();
210 
211 #ifdef VERBOSE
212  printf("vrpn_TextPrinter: text handler called\n");
213 #endif
214 
215  // Make sure we have a valid ostream.
216  if (me->d_ostream == NULL) {
217  return 0;
218  };
219 
220  // Decode the message
222  message, &severity, &level, p.buffer) != 0) {
223  fprintf(
224  stderr,
225  "vrpn_TextPrinter::text_message_handler(): Can't decode message\n");
226  me->d_semaphore.v();
227  return -1;
228  }
229 
230  // If the severity and level criteria pass, then print the annotated
231  // message.
232  // The printing is "VRPN", then one of Message/Warning/Error, then the level
233  // of the
234  // text, "from" the name of the service sending the message, and then the
235  // message.
236  if ((severity > me->d_severity_to_print) ||
237  ((severity == me->d_severity_to_print) &&
238  (level >= me->d_level_to_print))) {
239 
240  fprintf(me->d_ostream, "VRPN ");
241 
242  switch (severity) {
243  case vrpn_TEXT_NORMAL:
244  fprintf(me->d_ostream, "Message\n");
245  break;
246  case vrpn_TEXT_WARNING:
247  fprintf(me->d_ostream, "Warning\n");
248  break;
249  case vrpn_TEXT_ERROR:
250  fprintf(me->d_ostream, "Error\n");
251  break;
252  default:
253  fprintf(me->d_ostream, "UNKNOWN SEVERITY\n");
254  break;
255  }
256 
257  fprintf(me->d_ostream, " (%d) from %s: %s\n", level,
258  obj->d_connection->sender_name(p.sender), message);
259  }
260 
261  me->d_semaphore.v();
262  return 0;
263 }
264 
268  vrpn_uint32 level)
269 {
270  d_semaphore.p();
271  d_severity_to_print = severity;
272  d_level_to_print = level;
273  d_semaphore.v();
274 }
275 
279 {
280  d_semaphore.p();
281  d_ostream = o;
282  d_semaphore.v();
283 }
284 
313 {
314  // Has a constructor on this BaseClassUnique been called before?
315  // Note that this might also be true if it was called once before but
316  // failed.
317  bool firstTimeCalled = (d_connection == NULL);
318 
319  if (firstTimeCalled) {
320  // Get the connection for this object established. If the user passed in
321  // a
322  // NULL connection object, then we determine the connection from the
323  // name of
324  // the object itself (for example, Tracker0@mumble.cs.unc.edu will make
325  // a
326  // connection to the machine mumble on the standard VRPN port).
327  //
328  // The vrpn_BaseClassUnique destructor handles telling the connection we
329  // are no longer referring to it. Since we only add the reference once
330  // here (when d_connection is NULL), it is okay for the unique
331  // destructor
332  // to remove the reference.
333  if (c) { // using existing connection.
334  d_connection = c;
336  }
337  else {
338  // This will implicitly add the reference to the connection.
340  }
341 
342  // Get the part of the name for this device that does not include the
343  // connection.
344  // The vrpn_BaseClassUnique destructor handles the deletion of the
345  // space.
347  }
348 }
349 
351 {
352  // Remove us from the list of objects with messages to be printed
354 }
355 
364 {
365  // In the case of multiple inheritance from this base class, the rest of
366  // the code in this function will be executed each time init is called.
367 
368  if (d_connection) {
369  // Register the sender and types
370  // that this device type uses. If one of these fails, set the
371  // connection
372  // for this object to NULL to indicate failure, and print an error
373  // message.
374  if (register_senders() || register_types()) {
375  fprintf(stderr, "vrpn_BaseClassUnique: Can't register IDs\n");
376  d_connection = NULL;
377  return -1;
378  }
379 
380  // Register the text and ping/pong types, which will be available to all
381  // classes for use.
383  d_connection->register_message_type("vrpn_Base text_message");
384  if (d_text_message_id == -1) {
385  fprintf(stderr,
386  "vrpn_BaseClassUnique: Can't register Text type ID\n");
387  d_connection = NULL;
388  return -1;
389  }
391  d_connection->register_message_type("vrpn_Base ping_message");
392  if (d_ping_message_id == -1) {
393  fprintf(stderr,
394  "vrpn_BaseClassUnique: Can't register ping type ID\n");
395  d_connection = NULL;
396  return -1;
397  }
399  d_connection->register_message_type("vrpn_Base pong_message");
400  if (d_pong_message_id == -1) {
401  fprintf(stderr,
402  "vrpn_BaseClassUnique: Can't register pong type ID\n");
403  d_connection = NULL;
404  return -1;
405  }
406 
407  // Sign us up with the standard print function.
409  return 0;
410  }
411  else {
412  // Error if we don't have a connection.
413  return -1;
414  }
415 }
416 
428 {
429  if (d_connection == NULL) {
430  return -1;
431  }
433  if (d_sender_id == -1) {
434  return -1;
435  }
436  else {
437  return 0;
438  }
439 }
440 
442  : shutup(false)
443  , // don't suppress the "No response from server" messages
444  d_connection(NULL)
445  , d_servicename(NULL)
446  , d_num_autodeletions(0)
447  , d_first_mainloop(1)
448  , d_unanswered_ping(0)
449  , d_flatline(0)
450 {
451  // Initialize variables
452  d_time_first_ping.tv_sec = d_time_first_ping.tv_usec = 0;
453 }
454 
460 {
461  int i;
462 
463  // Unregister all of the handlers that were to be autodeleted,
464  // if we have a connection.
465  if (d_connection != NULL) {
466  for (i = 0; i < d_num_autodeletions; i++) {
468  d_handler_autodeletion_record[i].type,
469  d_handler_autodeletion_record[i].handler,
470  d_handler_autodeletion_record[i].userdata,
471  d_handler_autodeletion_record[i].sender);
472  }
473  d_num_autodeletions = 0;
474  }
475 
476  // notify the connection that this object is no longer using it.
477  // This was added in the vrpn_BaseClass constructor for exactly one of the
478  // objects that are sharing this unique destructor.
479  if (d_connection != NULL) {
481  }
482 
483  // Delete the space allocated in the constructor for the servicename
484  // Because this destructor may be called multiple times, set the pointer
485  // to NULL after deleting it, so it won't get deleted again.
486  if (d_servicename != NULL) {
487  delete[] d_servicename;
488  d_servicename = NULL;
489  }
490 }
491 
504  vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata,
505  vrpn_int32 sender)
506 {
507  // Make sure we have a Connection
508  if (d_connection == NULL) {
509  fprintf(stderr, "vrpn_BaseClassUnique::register_autodeleted_handler: "
510  "No vrpn_Connection.\n");
511  return -1;
512  }
513 
514  // Make sure we have an empy entry to fill in.
515  if (d_num_autodeletions >= vrpn_MAX_BCADRS) {
516  fprintf(stderr,
517  "vrpn_BaseClassUnique::register_autodeleted_handler: "
518  "Too many handlers registered. Increase vrpn_MAX_BCADRS "
519  "and recompile VRPN. Please report to vrpn@cs.unc.edu.\n");
520  return -1;
521  }
522 
523  // Fill in the values so we know what to delete, and bump the count
524  d_handler_autodeletion_record[d_num_autodeletions].handler = handler;
525  d_handler_autodeletion_record[d_num_autodeletions].sender = sender;
526  d_handler_autodeletion_record[d_num_autodeletions].type = type;
527  d_handler_autodeletion_record[d_num_autodeletions].userdata = userdata;
528  d_num_autodeletions++;
529 
530  // Call the register command.
532 }
533 
535  char *buf, vrpn_TEXT_SEVERITY severity, vrpn_uint32 level, const char *msg)
536 {
537  char *bufptr = buf;
538  int buflen = 2 * sizeof(vrpn_int32) + vrpn_MAX_TEXT_LEN;
539  vrpn_uint32 severity_as_uint = severity;
540 
541  // Send the type, level and string message
542  vrpn_buffer(&bufptr, &buflen, severity_as_uint);
543  vrpn_buffer(&bufptr, &buflen, level);
544  vrpn_buffer(&bufptr, &buflen, msg, -1); // -1 means "pack until NULL"
545 
546  return 0;
547 }
548 
550  char *msg, vrpn_TEXT_SEVERITY *severity, vrpn_uint32 *level,
551  const char *buf)
552 {
553  const char *bufptr = buf;
554  vrpn_uint32 severity_as_uint;
555 
556  // Read the type, level and message
557  vrpn_unbuffer(&bufptr, &severity_as_uint);
558  *severity = (vrpn_TEXT_SEVERITY)(severity_as_uint);
559  vrpn_unbuffer(&bufptr, level);
560  // Negative length means "unpack until NULL"
561  if (vrpn_unbuffer(&bufptr, msg, -(int)(vrpn_MAX_TEXT_LEN)) != 0) {
562  return -1;
563  }
564 
565  return 0;
566 }
567 
569  struct timeval timestamp,
570  vrpn_TEXT_SEVERITY type,
571  vrpn_uint32 level)
572 {
573  char buffer[2 * sizeof(vrpn_int32) + vrpn_MAX_TEXT_LEN];
574  size_t len = strlen(msg) + 1; // +1 is for the NULL terminator
575 
576  if (len > vrpn_MAX_TEXT_LEN) {
577  fprintf(stderr, "vrpn_BaseClassUnique::send_message: Attempt to encode "
578  "string that is too long\n");
579  return -1;
580  }
581 
582  // send type, level and message
583 
584  encode_text_message_to_buffer(buffer, type, level, msg);
585  if (d_connection) {
586  d_connection->pack_message(sizeof(buffer), timestamp, d_text_message_id,
587  d_sender_id, buffer,
589  }
590 
591  return 0;
592 }
593 
604 {
605  // Set up to handle pong message. This should be sent whenever there is
606  // a ping request from a client.
607 
608  if (d_first_mainloop && (d_connection != NULL)) {
610  d_sender_id);
611  d_first_mainloop = 0;
612  }
613 }
614 
638 {
639  struct timeval now;
640  struct timeval diff;
641 
642  // The first time through, set up a callback handler for the pong message so
643  // that we
644  // know when we are getting them. Also set up a handler for the system
645  // dropped-connection
646  // message so that we can initiate a ping cycle when that happens. Also,
647  // we'll initiate
648  // the ping cycle here.
649 
650  if (d_first_mainloop && (d_connection != NULL)) {
651 
652  // Set up handlers for the pong message and for the system
653  // connection-drop message
655  d_sender_id);
658  handle_connection_dropped, this);
659 
660  // Initiate a ping cycle;
661  initiate_ping_cycle();
662 
663  // No longer first time through mainloop.
664  d_first_mainloop = 0;
665  }
666 
667  // If we are in the middle of a ping cycle...
668  // Check if we've heard, if it has been long enough since we gave a warning
669  // or error (>= 1 sec).
670  // If it has been three seconds or more since we sent our first ping,
671  // start giving warnings. If it has been ten seconds or more since we got
672  // one,
673  // switch to errors. New ping requests go out each second.
674 
675  if (d_unanswered_ping) {
676 
677  vrpn_gettimeofday(&now, NULL);
678  diff = vrpn_TimevalDiff(now, d_time_last_warned);
679  vrpn_TimevalNormalize(diff);
680 
681  if (diff.tv_sec >= 1) {
682 
683  // Send a new ping, since it has been a second since the last one
686 
687  // Send another warning or error, and say if we're flatlined (10+
688  // seconds)
689  d_time_last_warned = now;
690  if (!shutup) {
691  diff = vrpn_TimevalDiff(now, d_time_first_ping);
692  vrpn_TimevalNormalize(diff);
693  if (diff.tv_sec >= 10) {
695  "No response from server for >= 10 seconds", now,
696  vrpn_TEXT_ERROR, diff.tv_sec);
697  d_flatline = 1;
698  }
699  else if (diff.tv_sec >= 3) {
701  "No response from server for >= 3 seconds", now,
702  vrpn_TEXT_WARNING, diff.tv_sec);
703  }
704  }
705  }
706  }
707 }
708 
709 void vrpn_BaseClassUnique::initiate_ping_cycle(void)
710 {
711  // Record when we sent the ping and say that we haven't gotten an answer
712  vrpn_gettimeofday(&d_time_first_ping, NULL);
713  d_connection->pack_message(0, d_time_first_ping, d_ping_message_id,
715  d_unanswered_ping = 1;
716 
717  // We didn't send a warning about this one yet...
718  d_time_last_warned.tv_sec = d_time_last_warned.tv_usec = 0;
719 }
720 
728 int vrpn_BaseClassUnique::handle_pong(void *userdata, vrpn_HANDLERPARAM p)
729 {
731 
732  me->d_unanswered_ping = 0;
733 
734  // If we were flatlined, report that things are okay again.
735  if (me->d_flatline) {
736  me->send_text_message("Server connection re-established!", p.msg_time,
738  me->d_flatline = 0;
739  }
740 
741  return 0;
742 }
743 
752 int vrpn_BaseClassUnique::handle_ping(void *userdata, vrpn_HANDLERPARAM)
753 {
755  struct timeval now;
756 
757  vrpn_gettimeofday(&now, NULL);
758  if (me->d_connection != NULL) {
760  me->d_sender_id, NULL,
762  }
763 
764  return 0;
765 }
766 
773 int vrpn_BaseClassUnique::handle_connection_dropped(void *userdata,
775 {
777  struct timeval now;
778 
779  if (me->d_unanswered_ping != 0) {
780  return 0;
781  }
782 
783  vrpn_gettimeofday(&now, NULL);
784  if (me->d_connection != NULL) {
785  me->initiate_ping_cycle();
786  }
787 
788  return 0;
789 }
virtual int unregister_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
void server_mainloop(void)
Handles functions that all servers should provide in their mainloop() (ping/pong, for example) Should...
virtual ~vrpn_BaseClassUnique()
Unregister all of the message handlers that were to be autodeleted.
struct timeval msg_time
vrpn_TextPrinter_Watch_Entry * d_first_watched_object
Head of list of objects being watched.
vrpn_uint32 d_level_to_print
Minimum level to print.
VRPN_API int vrpn_unbuffer(const char **buffer, timeval *t)
Utility routine for taking a struct timeval from a buffer that was sent as a message.
Definition: vrpn_Shared.C:312
char * d_servicename
Name of this device, not including the connection part.
static int encode_text_message_to_buffer(char *buf, vrpn_TEXT_SEVERITY severity, vrpn_uint32 level, const char *msg)
Encodes the body of the text message into a buffer, preparing for sending.
const char * vrpn_dropped_connection
const vrpn_uint32 vrpn_CONNECTION_RELIABLE
Classes of service for messages, specify multiple by ORing them together Priority of satisfying these...
vrpn_MESSAGEHANDLER handler
Class that handles text/warning/error printing for all objects in the system.
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...
timeval vrpn_TimevalNormalize(const timeval &in_tv)
Definition: vrpn_Shared.C:34
virtual ~vrpn_BaseClass()
vrpn_int32 d_text_message_id
ID for text messages.
const int vrpn_MAX_BCADRS
Internal value for number of BaseClass addresses.
vrpn_int32 d_pong_message_id
Server telling that it is there.
void client_mainloop(void)
Handles functions that all clients should provide in their mainloop() (warning of no server,...
static int VRPN_CALLBACK text_message_handler(void *userdata, vrpn_HANDLERPARAM p)
Handles the text messages that come from the connections for objects we are watching.
const char * buffer
INTERNAL class to hold members that there should only be one copy of even when a class inherits from ...
timeval vrpn_TimevalDiff(const timeval &tv1, const timeval &tv2)
Definition: vrpn_Shared.C:92
vrpn_int32 d_ping_message_id
Ask the server if they are there.
Generic connection class not specific to the transport mechanism.
virtual int register_types(void)=0
Register the types of messages this device sends/receives. Return 0 on success, -1 on fail.
vrpn_TEXT_SEVERITY d_severity_to_print
Minimum severity to print.
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...
int(VRPN_CALLBACK * vrpn_MESSAGEHANDLER)(void *userdata, vrpn_HANDLERPARAM p)
Type of a message handler for vrpn_Connection messages.
All types of client/server/peer objects in VRPN should be derived from the vrpn_BaseClass type descri...
virtual int init(void)
Initialize things that the constructor can't. Returns 0 on success, -1 on failure.
static int decode_text_message_from_buffer(char *msg, vrpn_TEXT_SEVERITY *severity, vrpn_uint32 *level, const char *buf)
Decodes the body of the text message from a buffer from the connection.
vrpn_Semaphore d_semaphore
Mutex to ensure thread safety;.
int register_autodeleted_handler(vrpn_int32 type, vrpn_MESSAGEHANDLER handler, void *userdata, vrpn_int32 sender=vrpn_ANY_SENDER)
Registers a handler with the connection, and remembers to delete at destruction.
vrpn_TextPrinter vrpn_System_TextPrinter
Definition of the system TextPrinter object that prints messages for all created objects.
vrpn_Connection * d_connection
Connection that this object talks to.
int add_object(vrpn_BaseClass *o)
Adds an object to the list of watched objects (multiple registration of the same object will result i...
This structure is what is passed to a vrpn_Connection message callback.
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_TextPrinter()
Deletes any callbacks that are still registered.
vrpn_BaseClass * obj
Object being watched.
vrpn_TextPrinter * me
Pointer to this, because used in a static function.
void set_ostream_to_use(FILE *o)
Change the ostream that will be used to print messages. Setting a NULL ostream results in no printing...
virtual int register_senders(void)
Register the sender for this device (by default, the name of the device). Return 0 on success,...
int send_text_message(const char *msg, struct timeval timestamp, vrpn_TEXT_SEVERITY type=vrpn_TEXT_NORMAL, vrpn_uint32 level=0)
Sends a NULL-terminated text message from the device d_sender_id.
vrpn_BaseClass(const char *name, vrpn_Connection *c=NULL)
Names the device and assigns or opens connection, calls registration methods.
void remove_object(vrpn_BaseClass *o)
Remove an object from the list of watched objects (multiple deletions of the object will not cause an...
FILE * d_ostream
Output stream to use.
const unsigned vrpn_MAX_TEXT_LEN
void set_min_level_to_print(vrpn_TEXT_SEVERITY severity, vrpn_uint32 level=0)
Change the level of printing for the object (sets the minimum level to print). Default is Warnings an...
char * vrpn_copy_service_name(const char *fullname)
virtual const char * sender_name(vrpn_int32 sender)
Returns the name of the specified sender/type, or NULL if the parameter is invalid....
vrpn_TEXT_SEVERITY
Since the sending of text messages has been pulled into the base class (so that every object can send...
#define vrpn_gettimeofday
Definition: vrpn_Shared.h:89
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).
VRPN_API int vrpn_buffer(char **insertPt, vrpn_int32 *buflen, const timeval t)
Utility routine for placing a timeval struct into a buffer that is to be sent as a message.
Definition: vrpn_Shared.C:241
Class from which all user-level (and other) classes that communicate with vrpn_Connections should der...
vrpn_int32 d_sender_id
Sender ID registered with the connection.
Structure to hold the objects that are being watched.
vrpn_Connection * connectionPtr()
Returns a pointer to the connection this object is using.
vrpn_TextPrinter_Watch_Entry * next
Pointer to the next one in the list.
void addReference()
Counting references to this connection.
virtual vrpn_int32 register_message_type(const char *name)