void vrpn_BaseClassUnique::client_mainloop(void) { struct timeval now; struct timeval diff; // The first time through, set up a callback handler for the pong message so that we // know when we are getting them. Also set up a handler for the system dropped-connection // message so that we can initiate a ping cycle when that happens. Also, we'll initiate // the ping cycle here. if (d_first_mainloop && (d_connection != NULL)) { // Set up handlers for the pong message and for the system connection-drop message register_autodeleted_handler(d_pong_message_id, handle_pong, this, d_sender_id); register_autodeleted_handler(d_connection->register_message_type(vrpn_dropped_connection), handle_connection_dropped, this); // Initiate a ping cycle; initiate_ping_cycle(); // No longer first time through mainloop. d_first_mainloop = 0; } // If we are in the middle of a ping cycle... // Check if we've heard, if it has been long enough since we gave a warning or error (>= 1 sec). // If it has been three seconds or more since we sent our first ping, // start giving warnings. If it has been ten seconds or more since we got one, // switch to errors. New ping requests go out each second. if (d_unanswered_ping) { vrpn_gettimeofday(&now, NULL); diff = vrpn_TimevalDiff(now, d_time_last_warned); vrpn_TimevalNormalize(diff); if (diff.tv_sec >= 1) { // Send a new ping, since it has been a second since the last one d_connection->pack_message(0, now, d_ping_message_id, d_sender_id, NULL, vrpn_CONNECTION_RELIABLE); // Send another warning or error, and say if we're flatlined (10+ seconds) d_time_last_warned = now; if (!shutup) { diff = vrpn_TimevalDiff(now, d_time_first_ping); vrpn_TimevalNormalize(diff); if (diff.tv_sec >= 10) { send_text_message("No response from server for >= 10 seconds", now, vrpn_TEXT_ERROR, diff.tv_sec); d_flatline = 1; } else if (diff.tv_sec >= 3) { send_text_message("No response from server for >= 3 seconds", now, vrpn_TEXT_WARNING, diff.tv_sec); } } } } }
int main(int argc, char* argv[]) { // Declare a new text receiver (all objects are text senders) // and find out what connection it is using. r = new vrpn_Text_Receiver (argv[1]); c = r->connectionPtr(); // Declare the same sender and message types that the BaseClass // will use for doing the ping/pong, so we can use the same // mechanism. Register a handler for the pong message, so we // can deal with them. ping_message_id = c->register_message_type("Server, are you there?"); pong_message_id = c->register_message_type("Server is here!"); sender = c->register_sender(vrpn_copy_service_name(argv[1])); c->register_handler(pong_message_id, my_pong_handler, NULL, sender); // Let the user kill the program "nicely." signal(SIGINT, handle_cntl_c); // Wait a few seconds (spinning while we do) in order to allow the // real pong message to clear from the system. struct timeval then, diff; vrpn_gettimeofday(&then, NULL); do { vrpn_gettimeofday(&now, NULL); r->mainloop(); diff = vrpn_TimevalDiff(now, then); } while ( vrpn_TimevalMsecs(vrpn_TimevalNormalize(diff)) < 2000); // Send a new ping request to the server, and start counting how // long it takes to respond. vrpn_gettimeofday(&last_ping, NULL); c->pack_message(0, last_ping, ping_message_id, sender, NULL, vrpn_CONNECTION_RELIABLE); // Loop forever. while (1) { r->mainloop(); } }
int VRPN_CALLBACK my_pong_handler(void *userdata, vrpn_HANDLERPARAM p) { static int count = 0; static double min = 10000, max = 0, sum = 0; // See how long it has been between the ping request and // the pong response. struct timeval diff; vrpn_gettimeofday(&now, NULL); double msecs; diff = vrpn_TimevalDiff(now, last_ping); msecs = vrpn_TimevalMsecs(vrpn_TimevalNormalize(diff)); // Keep statistics on the length (min, max, average) if (msecs < min) { min = msecs; }; if (msecs > max) { max = msecs; }; sum += msecs; // Print and reset the statistics every once in a while if (++count == 500) { printf("Min = %4.2g, Max = %4.2g, Mean = %4.2g\n", min, max, sum / count); count = 0; min = 10000; max = sum = 0.0; } // Send a new ping request, and record when we sent it. // REMEMBER not to call mainloop() within the handler. vrpn_gettimeofday(&last_ping, NULL); c->pack_message(0, last_ping, ping_message_id, sender, NULL, vrpn_CONNECTION_RELIABLE); c->send_pending_reports(); return 0; }