void handleNextMessage(std::shared_ptr<ip::tcp::socket> socket, uint16_t socketID) { // // Validate the socket is still open if (!socket->is_open()) return; // // Perform an asynchronous read so that we don't tie up // a thread waiting on just this socket. // This first read gets the size of the buffer being sent, then the handler takes // care of reading the actual Protocol Buffer message. learn::Line line; auto bufferSize = std::make_shared<decltype(line.ByteSize())>(); boost::asio::async_read(*socket, boost::asio::buffer(bufferSize.get(), sizeof(decltype(line.ByteSize()))), [socket, socketID, bufferSize](const boost::system::error_code& error, std::size_t bytes) { if (!error) { boost::asio::streambuf buffer; boost::asio::streambuf::mutable_buffers_type bufs = buffer.prepare(*bufferSize); boost::asio::read(*socket, bufs); buffer.commit(*bufferSize); std::istream is(&buffer); learn::Line line; line.ParseFromIstream(&is); std::cout << "Received from " << socketID << " : " << line.message() << line.line() << std::endl; handleNextMessage(socket, socketID); } }); }
void handleNewConnection(boost::asio::io_service& ioService, std::shared_ptr<ip::tcp::acceptor> acceptor) { static uint16_t socketID = 1; std::shared_ptr<ip::tcp::socket> socket = std::make_shared<ip::tcp::socket>(ioService); std::shared_ptr<ip::tcp::endpoint> endpoint = std::make_shared<ip::tcp::endpoint>(); acceptor->async_accept(*socket, *endpoint, [&ioService, acceptor, endpoint, socket] (const boost::system::error_code& error) { if (!error) { std::cout << "Received connection from: " << *endpoint; std::cout << " on thread id: "; std::cout << std::this_thread::get_id() << std::endl; // // With the connection made, start listening for messages over the socket handleNextMessage(socket, socketID); socketID++; } handleNewConnection(ioService, acceptor); }); }
static THREAD_RETURN netSenderMain(void *args0) { sender_state_t sendst = (sender_state_t) args0; struct net_config *config = sendst->config; struct timeval tv; struct timespec ts; int atEnd = 0; int nrWaited=0; unsigned long waitAverage=10000; /* Exponential average of last wait times */ struct slice *xmitSlice=NULL; /* slice being transmitted a first time */ struct slice *rexmitSlice=NULL; /* slice being re-transmitted */ int sliceNo = 0; /* transmit the data */ if(config->default_slice_size == 0) { #ifdef BB_FEATURE_UDPCAST_FEC if(config->flags & FLAG_FEC) { config->sliceSize = config->fec_stripesize * config->fec_stripes; } else #endif if(config->flags & FLAG_ASYNC) config->sliceSize = 1024; else if (sendst->config->flags & FLAG_SN) { sendst->config->sliceSize = 112; } else sendst->config->sliceSize = 130; sendst->config->discovery = DSC_DOUBLING; } else { config->sliceSize = config->default_slice_size; #ifdef BB_FEATURE_UDPCAST_FEC if((config->flags & FLAG_FEC) && (config->sliceSize > 128 * config->fec_stripes)) config->sliceSize = 128 * config->fec_stripes; #endif } #ifdef BB_FEATURE_UDPCAST_FEC if( (sendst->config->flags & FLAG_FEC) && config->max_slice_size > config->fec_stripes * 128) config->max_slice_size = config->fec_stripes * 128; #endif if(config->sliceSize > config->max_slice_size) config->sliceSize = config->max_slice_size; assert(config->sliceSize <= MAX_SLICE_SIZE); do { /* first, cleanup rexmit Slice if needed */ if(rexmitSlice != NULL) { if(rexmitSlice->nrReady == udpc_nrParticipants(sendst->rc.participantsDb)){ #if DEBUG flprintf("slice is ready\n"); #endif ackSlice(rexmitSlice, sendst->config, sendst->fifo, sendst->stats); } if(isSliceAcked(rexmitSlice)) { freeSlice(sendst, rexmitSlice); rexmitSlice = NULL; } } /* then shift xmit slice to rexmit slot, if possible */ if(rexmitSlice == NULL && xmitSlice != NULL && isSliceXmitted(xmitSlice)) { rexmitSlice = xmitSlice; xmitSlice = NULL; sendReqack(rexmitSlice, sendst->config, sendst->fifo, sendst->stats, sendst->socket); } /* handle any messages */ if(pc_getWaiting(sendst->rc.incoming)) { #if DEBUG flprintf("Before message %d\n", pc_getWaiting(sendst->rc.incoming)); #endif handleNextMessage(sendst, xmitSlice, rexmitSlice); /* restart at beginning of loop: we may have acked the rxmit * slice, makeing it possible to shift the pipe */ continue; } /* do any needed retransmissions */ if(rexmitSlice != NULL && rexmitSlice->needRxmit) { doRetransmissions(sendst, rexmitSlice); /* restart at beginning: new messages may have arrived during * retransmission */ continue; } /* if all participants answered, send req ack */ if(rexmitSlice != NULL && rexmitSlice->nrAnswered == udpc_nrParticipants(sendst->rc.participantsDb)) { rexmitSlice->rxmitId++; sendReqack(rexmitSlice, sendst->config, sendst->fifo, sendst->stats, sendst->socket); } if(xmitSlice == NULL && !atEnd) { #if DEBUG flprintf("SN=%d\n", sendst->config->flags & FLAG_SN); #endif if((sendst->config->flags & FLAG_SN) || rexmitSlice == NULL) { #ifdef BB_FEATURE_UDPCAST_FEC if(sendst->config->flags & FLAG_FEC) { int i; pc_consume(sendst->fec_data_pc, 1); i = pc_getConsumerPosition(sendst->fec_data_pc); xmitSlice = &sendst->slices[i]; pc_consumed(sendst->fec_data_pc, 1); } else #endif { xmitSlice = makeSlice(sendst, sliceNo++); } if(xmitSlice->bytes == 0) atEnd = 1; } } if(xmitSlice != NULL && xmitSlice->state == SLICE_NEW) { sendSlice(sendst, xmitSlice, 0); #if DEBUG flprintf("%d Interrupted at %d/%d\n", xmitSlice->sliceNo, xmitSlice->nextBlock, getSliceBlocks(xmitSlice, sendst->config)); #endif continue; } if(atEnd && rexmitSlice == NULL && xmitSlice == NULL) break; if(sendst->config->flags & FLAG_ASYNC) break; #if DEBUG flprintf("Waiting for timeout...\n"); #endif gettimeofday(&tv, 0); ts.tv_sec = tv.tv_sec; ts.tv_nsec = (tv.tv_usec + 1.1*waitAverage) * 1000; #ifdef WINDOWS /* Windows has a granularity of 1 millisecond in its timer. Take this * into account here */ #define GRANULARITY 1000000 ts.tv_nsec += 3*GRANULARITY/2; ts.tv_nsec -= ts.tv_nsec % GRANULARITY; #endif #define BILLION 1000000000 while(ts.tv_nsec >= BILLION) { ts.tv_nsec -= BILLION; ts.tv_sec++; } if(rexmitSlice->rxmitId > 10) /* after tenth retransmission, wait minimum one second */ ts.tv_sec++; if(pc_consumeAnyWithTimeout(sendst->rc.incoming, &ts) != 0) { #if DEBUG flprintf("Have data\n"); #endif { struct timeval tv2; unsigned long timeout; gettimeofday(&tv2, 0); timeout = (tv2.tv_sec - tv.tv_sec) * 1000000+ tv2.tv_usec - tv.tv_usec; if(nrWaited) timeout += waitAverage; waitAverage += 9; /* compensate against rounding errors */ waitAverage = (0.9 * waitAverage + 0.1 * timeout); } nrWaited = 0; continue; } if(rexmitSlice == NULL) { udpc_flprintf("Weird. Timeout and no rxmit slice"); break; } if(nrWaited > 5){ #ifndef WINDOWS /* on Cygwin, we would get too many of those messages... */ udpc_flprintf("Timeout notAnswered="); udpc_printNotSet(sendst->rc.participantsDb, rexmitSlice->answeredSet); udpc_flprintf(" notReady="); udpc_printNotSet(sendst->rc.participantsDb, rexmitSlice->sl_reqack.readySet); udpc_flprintf(" nrAns=%d nrRead=%d nrPart=%d avg=%ld\n", rexmitSlice->nrAnswered, rexmitSlice->nrReady, udpc_nrParticipants(sendst->rc.participantsDb), waitAverage); nrWaited=0; #endif } nrWaited++; if(rexmitSlice->rxmitId > config->retriesUntilDrop) { int i; for(i=0; i < MAX_CLIENTS; i++) { if(udpc_isParticipantValid(sendst->rc.participantsDb, i) && !BIT_ISSET(i, rexmitSlice->sl_reqack.readySet)) { udpc_flprintf("Dropping client #%d because of timeout\n", i); #ifdef USE_SYSLOG syslog(LOG_INFO, "dropped client #%d because of timeout", i); #endif udpc_removeParticipant(sendst->rc.participantsDb, i); if(nrParticipants(sendst->rc.participantsDb) == 0) exit(0); } } continue; } rexmitSlice->rxmitId++; sendReqack(rexmitSlice, sendst->config, sendst->fifo, sendst->stats, sendst->socket); } while(udpc_nrParticipants(sendst->rc.participantsDb)|| (config->flags & FLAG_ASYNC)); cancelReturnChannel(&sendst->rc); return 0; }