void lcm_frag_buf_store_add (lcm_frag_buf_store *store, lcm_frag_buf_t *fbuf) { while (store->total_size > store->max_total_size || g_hash_table_size (store->frag_bufs) > store->max_n_frag_bufs) { // find and remove the least recently updated fragment buffer lcm_frag_buf_t *lru_fbuf = NULL; g_hash_table_foreach (store->frag_bufs, _find_lru_frag_buf, &lru_fbuf); if (lru_fbuf){ lcm_frag_buf_store_remove (store, lru_fbuf); } } g_hash_table_insert (store->frag_bufs, &fbuf->from, fbuf); store->total_size += fbuf->data_size; }
static int _recv_message_fragment (lcm_udpm_t *lcm, lcm_buf_t *lcmb, uint32_t sz) { lcm2_header_long_t *hdr = (lcm2_header_long_t*) lcmb->buf; // any existing fragment buffer for this message source? lcm_frag_buf_t *fbuf = lcm_frag_buf_store_lookup(lcm->frag_bufs, &lcmb->from); uint32_t msg_seqno = ntohl (hdr->msg_seqno); uint32_t data_size = ntohl (hdr->msg_size); uint32_t fragment_offset = ntohl (hdr->fragment_offset); // uint16_t fragment_no = ntohs (hdr->fragment_no); uint16_t fragments_in_msg = ntohs (hdr->fragments_in_msg); uint32_t frag_size = sz - sizeof (lcm2_header_long_t); char *data_start = (char*) (hdr + 1); // discard any stale fragments from previous messages if (fbuf && ((fbuf->msg_seqno != msg_seqno) || (fbuf->data_size != data_size))) { lcm_frag_buf_store_remove (lcm->frag_bufs, fbuf); dbg(DBG_LCM, "Dropping message (missing %d fragments)\n", fbuf->fragments_remaining); fbuf = NULL; } // printf ("fragment %d/%d (offset %d/%d) seq %d packet sz: %d %p\n", // ntohs(hdr->fragment_no) + 1, fragments_in_msg, // fragment_offset, data_size, msg_seqno, sz, fbuf); if (data_size > LCM_MAX_MESSAGE_SIZE) { dbg (DBG_LCM, "rejecting huge message (%d bytes)\n", data_size); return 0; } // create a new fragment buffer if necessary if (!fbuf && hdr->fragment_no == 0) { char *channel = (char*) (hdr + 1); int channel_sz = strlen (channel); if (channel_sz > LCM_MAX_CHANNEL_NAME_LENGTH) { dbg (DBG_LCM, "bad channel name length\n"); lcm->udp_discarded_bad++; return 0; } // if the packet has no subscribers, drop the message now. if(!lcm_has_handlers(lcm->lcm, channel)) return 0; fbuf = lcm_frag_buf_new (*((struct sockaddr_in*) &lcmb->from), channel, msg_seqno, data_size, fragments_in_msg, lcmb->recv_utime); lcm_frag_buf_store_add (lcm->frag_bufs, fbuf); data_start += channel_sz + 1; frag_size -= (channel_sz + 1); } if (!fbuf) return 0; #ifdef __linux__ if(lcm->kernel_rbuf_sz < 262145 && data_size > lcm->kernel_rbuf_sz && ! lcm->warned_about_small_kernel_buf) { fprintf(stderr, "==== LCM Warning ===\n" "LCM detected that large packets are being received, but the kernel UDP\n" "receive buffer is very small. The possibility of dropping packets due to\n" "insufficient buffer space is very high.\n" "\n" "For more information, visit:\n" " http://lcm-proj.github.io/multicast_setup.html\n\n"); lcm->warned_about_small_kernel_buf = 1; } #endif if (fragment_offset + frag_size > fbuf->data_size) { dbg (DBG_LCM, "dropping invalid fragment (off: %d, %d / %d)\n", fragment_offset, frag_size, fbuf->data_size); lcm_frag_buf_store_remove (lcm->frag_bufs, fbuf); return 0; } // copy data memcpy (fbuf->data + fragment_offset, data_start, frag_size); fbuf->last_packet_utime = lcmb->recv_utime; fbuf->fragments_remaining --; if (0 == fbuf->fragments_remaining) { // complete message received. Is there a subscriber that still // wants it? (i.e., does any subscriber have space in its queue?) if(!lcm_try_enqueue_message(lcm->lcm, fbuf->channel)) { // no... sad... free the fragment buffer and return lcm_frag_buf_store_remove (lcm->frag_bufs, fbuf); return 0; } // yes, transfer the message into the lcm_buf_t // deallocate the ringbuffer-allocated buffer g_static_rec_mutex_lock (&lcm->mutex); lcm_buf_free_data(lcmb, lcm->ringbuf); g_static_rec_mutex_unlock (&lcm->mutex); // transfer ownership of the message's payload buffer lcmb->buf = fbuf->data; fbuf->data = NULL; strcpy (lcmb->channel_name, fbuf->channel); lcmb->channel_size = strlen (lcmb->channel_name); lcmb->data_offset = 0; lcmb->data_size = fbuf->data_size; lcmb->recv_utime = fbuf->last_packet_utime; // don't need the fragment buffer anymore lcm_frag_buf_store_remove (lcm->frag_bufs, fbuf); return 1; } return 0; }