int vrpn_BaseClassUnique::send_text_message(const char *msg, struct timeval timestamp, vrpn_TEXT_SEVERITY type, vrpn_uint32 level) { char buffer[2 * sizeof(vrpn_int32) + vrpn_MAX_TEXT_LEN]; size_t len = strlen(msg) + 1; // +1 is for the NULL terminator if (len > vrpn_MAX_TEXT_LEN) { fprintf(stderr, "vrpn_BaseClassUnique::send_message: Attempt to encode " "string that is too long\n"); return -1; } // send type, level and message encode_text_message_to_buffer(buffer, type, level, msg); if (d_connection) { d_connection->pack_message(sizeof(buffer), timestamp, d_text_message_id, d_sender_id, buffer, vrpn_CONNECTION_RELIABLE); } return 0; }
int vrpn_Imager_Stream_Buffer::handle_server_messages( const vrpn_HANDLERPARAM &p) { // Handle begin_frame message very specially, because it has all sorts // of interactions with throttling and missed-frame reporting. if (p.type == d_server_begin_frame_m_id) { // This duplicates code from the send_begin_frame() method in // the vrpn_Imager_Server base class that handles throttling. // It further adds code to handle throttling when the queue to // the initial thread is too full. // If we are throttling frames and the frame count has gone to zero, // then increment the number of frames missed and do not add this // message to the queue. if (d_server_frames_to_send == 0) { d_server_dropped_due_to_throttle++; return 0; } // If there are too many frames in the queue already, // add one to the number lost due to throttling (which // will prevent region and end-of-frame messages until the next // begin_frame message) and break without forwarding the message. if (d_shared_state.get_frames_in_queue() >= 2) { d_server_dropped_due_to_throttle++; return 0; } // If we missed some frames due to throttling, but are now // sending frames again, report how many we lost due to // throttling. This is incremented both for client-requested // throttling and to queue-overflow throttling. if (d_server_dropped_due_to_throttle > 0) { // We create a new message header and body, using the server's // type IDs, and then transcode and send the message through // the initial connection. vrpn_HANDLERPARAM tp = p; vrpn_float64 fbuf[vrpn_CONNECTION_TCP_BUFLEN / sizeof(vrpn_float64)]; char *msgbuf = (char *)fbuf; int buflen = sizeof(fbuf); tp.type = d_server_discarded_frames_m_id; if (vrpn_buffer(&msgbuf, &buflen, d_server_dropped_due_to_throttle)) { fprintf(stderr, "vrpn_Imager_Stream_Buffer::handle_server_" "messages: Can't pack count\n"); return -1; } tp.buffer = static_cast<char *>(static_cast<void *>(fbuf)); tp.payload_len = sizeof(fbuf) - buflen; if (!transcode_and_send(tp)) { fprintf(stderr, "vrpn_Imager_Stream_Buffer::handle_server_" "messages: Can't send discarded frames " "count\n"); return -1; } d_server_dropped_due_to_throttle = 0; } // If we are throttling, then decrement the number of frames // left to send. if (d_server_frames_to_send > 0) { d_server_frames_to_send--; } // No throttling going on, so add the message to the outgoing queue and // also increment the count of how many outstanding frames are in the // queue. if (!transcode_and_send(p)) { fprintf(stderr, "vrpn_Imager_Stream_Buffer::handle_server_messages:" " Can't transcode and send\n"); return -1; } d_shared_state.increment_frames_in_queue(); // Handle the end_frame and all of the region messages in a similar // manner, // dropping them if throttling is going on and passing them on if not. // This duplicates code from the send_end_frame() and the region // send methods in the vrpn_Imager_Server base class that handles // throttling. } else if ((p.type == d_server_end_frame_m_id) || (p.type == d_server_regionu8_m_id) || (p.type == d_server_regionu12in16_m_id) || (p.type == d_server_regionu16_m_id) || (p.type == d_server_regionf32_m_id)) { // If we are discarding frames, do not queue this message. if (d_server_dropped_due_to_throttle > 0) { return 0; } // No throttling going on, so add this message to the outgoing queue. if (!transcode_and_send(p)) { fprintf(stderr, "vrpn_Imager_Stream_Buffer::handle_server_messages:" " Can't transcode and send\n"); return -1; } // Send these messages on without modification // (Currently, these are description messages and discarded-frame // messages. It also includes the generic pong response and any // text messages.) } else if ((p.type == d_server_description_m_id) || (p.type == d_server_discarded_frames_m_id) || (p.type == d_server_text_m_id) || (p.type == d_server_pong_m_id)) { if (!transcode_and_send(p)) { fprintf(stderr, "vrpn_Imager_Stream_Buffer::handle_server_messages:" " Can't transcode and send\n"); return -1; } // Ignore these messages without passing them on. } else if ((p.type == d_server_ping_m_id)) { return 0; // We need to throw a warning here on unexpected types so that we get // some // warning if additional messages are added. This code is fragile // because it // relies on us knowing the types of base-level and imager messages and // catching // them all. This way, at least we'll know if we miss one. } else { // We create a new message header and body, using the server's // type IDs, and then transcode and send the message through // the initial connection. This is a text message saying that we // got a message of unknown type. vrpn_HANDLERPARAM tp = p; char buffer[2 * sizeof(vrpn_int32) + vrpn_MAX_TEXT_LEN]; char msg[vrpn_MAX_TEXT_LEN]; tp.type = d_server_text_m_id; tp.buffer = buffer; tp.payload_len = sizeof(buffer); sprintf(msg, "Unknown message type from server: %d", static_cast<int>(p.type)); encode_text_message_to_buffer(buffer, vrpn_TEXT_ERROR, 0, msg); if (!transcode_and_send(tp)) { fprintf(stderr, "vrpn_Imager_Stream_Buffer::handle_server_messages:" " Can't transcode text message\n"); return -1; } } return 0; }