static int handleRetransmit(sender_state_t sendst, struct slice *slice, int clNo, unsigned char *map, int rxmit) { unsigned int i; #if DEBUG flprintf("Handle retransmit %d @%d\n", slice->sliceNo, clNo); #endif if(!udpc_isParticipantValid(sendst->rc.participantsDb, clNo)) { udpc_flprintf("Invalid participant %d\n", clNo); return 0; } if(slice == NULL) return 0; if (rxmit < slice->rxmitId) { #if 0 flprintf("Late answer\n"); #endif /* late answer to previous Req Ack */ return 0; } #if DEBUG logprintf(udpc_log, "Received retransmit request for slice %d from client %d\n", slice->sliceNo,clNo); #endif for(i=0; i <sizeof(slice->rxmitMap) / sizeof(char); i++) { slice->rxmitMap[i] |= ~map[i]; } slice->needRxmit = 1; markParticipantAnswered(slice, clNo); return 0; }
/** * Handles ok message */ static int handleOk(sender_state_t sendst, struct slice *slice, int clNo) { if(slice == NULL) return 0; if(!udpc_isParticipantValid(sendst->rc.participantsDb, clNo)) { udpc_flprintf("Invalid participant %d\n", clNo); return 0; } if (BIT_ISSET(clNo, slice->sl_reqack.readySet)) { /* client is already marked ready */ #if DEBUG flprintf("client %d is already ready\n", clNo); #endif } else { SET_BIT(clNo, slice->sl_reqack.readySet); slice->nrReady++; #if DEBUG flprintf("client %d replied ok for %p %d ready=%d\n", clNo, slice, slice->sliceNo, slice->nrReady); #endif senderSetAnswered(sendst->stats, clNo); markParticipantAnswered(slice, clNo); } return 0; }
void printMyIp(net_if_t *net_if) { char buffer[16]; struct sockaddr_in myaddr; getMyAddress(net_if, &myaddr); udpc_flprintf("%s", udpc_getIpString(&myaddr,buffer)); }
void sendDisconnect(int exitStatus, struct client_config *client_config) { struct disconnect disconnect; disconnect.opCode = htons(CMD_DISCONNECT); disconnect.reserved = 0; SSEND(disconnect); if (exitStatus == 0) udpc_flprintf("Transfer complete.\007\n"); }
static int handleNextMessage(sender_state_t sendst, struct slice *xmitSlice, struct slice *rexmitSlice) { int pos = pc_getConsumerPosition(sendst->rc.incoming); union message *msg = &sendst->rc.q[pos].msg; int clNo = sendst->rc.q[pos].clNo; #if DEBUG flprintf("handle next message\n"); #endif pc_consumeAny(sendst->rc.incoming); switch(ntohs(msg->opCode)) { case CMD_OK: handleOk(sendst, findSlice(xmitSlice, rexmitSlice, ntohl(msg->ok.sliceNo)), clNo); break; case CMD_DISCONNECT: handleDisconnect(sendst->rc.participantsDb, xmitSlice, rexmitSlice, clNo); break; case CMD_RETRANSMIT: #if DEBUG flprintf("Received retransmittal request for %ld from %d:\n", (long) xtohl(msg->retransmit.sliceNo), clNo); #endif handleRetransmit(sendst, findSlice(xmitSlice, rexmitSlice, ntohl(msg->retransmit.sliceNo)), clNo, msg->retransmit.map, msg->retransmit.rxmit); break; default: udpc_flprintf("Bad command %04x\n", (unsigned short) msg->opCode); break; } pc_consumed(sendst->rc.incoming, 1); pc_produce(sendst->rc.freeSpace, 1); return 0; }
int doReceive(int s, void *message, size_t len, struct sockaddr_in *from, int portBase) { socklen_t slen; int r; unsigned short port; char ipBuffer[16]; slen = sizeof(*from); #ifdef LOSSTEST loseRecvPacket(s); #endif r = recvfrom(s, message, len, 0, (struct sockaddr *)from, &slen); if (r < 0) return r; port = ntohs(from->sin_port); if(port != RECEIVER_PORT(portBase) && port != SENDER_PORT(portBase)) { udpc_flprintf("Bad message from port %s.%d\n", getIpString(from, ipBuffer), ntohs(((struct sockaddr_in *)from)->sin_port)); return -1; } /* flprintf("recv: %08x %d\n", *(int*) message, r);*/ return r; }
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; }
int startReceiver(int doWarn, struct disk_config *disk_config, struct net_config *net_config, struct stat_config *stat_config, const char *ifName) { char ipBuffer[16]; union serverControlMsg Msg; int connectReqSent=0; struct client_config client_config; int outFile=1; int pipedOutFile; struct sockaddr_in myIp; int pipePid = 0; int origOutFile; int haveServerAddress; client_config.sender_is_newgen = 0; net_config->net_if = getNetIf(ifName); zeroSockArray(client_config.socks, NR_CLIENT_SOCKS); client_config.S_UCAST = makeSocket(ADDR_TYPE_UCAST, net_config->net_if, 0, RECEIVER_PORT(net_config->portBase)); client_config.S_BCAST = makeSocket(ADDR_TYPE_BCAST, net_config->net_if, 0, RECEIVER_PORT(net_config->portBase)); if(net_config->ttl == 1 && net_config->mcastRdv == NULL) { getBroadCastAddress(net_config->net_if, &net_config->controlMcastAddr, SENDER_PORT(net_config->portBase)); setSocketToBroadcast(client_config.S_UCAST); } else { getMcastAllAddress(&net_config->controlMcastAddr, net_config->mcastRdv, SENDER_PORT(net_config->portBase)); if(isMcastAddress(&net_config->controlMcastAddr)) { setMcastDestination(client_config.S_UCAST, net_config->net_if, &net_config->controlMcastAddr); setTtl(client_config.S_UCAST, net_config->ttl); client_config.S_MCAST_CTRL = makeSocket(ADDR_TYPE_MCAST, net_config->net_if, &net_config->controlMcastAddr, RECEIVER_PORT(net_config->portBase)); // TODO: subscribe address as receiver to! } } clearIp(&net_config->dataMcastAddr); udpc_flprintf("%sUDP receiver for %s at ", disk_config->pipeName == NULL ? "" : "Compressed ", disk_config->fileName == NULL ? "(stdout)":disk_config->fileName); printMyIp(net_config->net_if); udpc_flprintf(" on %s\n", net_config->net_if->name); connectReqSent = 0; haveServerAddress = 0; client_config.clientNumber= 0; /*default number for asynchronous transfer*/ while(1) { // int len; int msglen; int sock; if (!connectReqSent) { if (sendConnectReq(&client_config, net_config, haveServerAddress) < 0) { perror("sendto to locate server"); } connectReqSent = 1; } haveServerAddress=0; sock = udpc_selectSock(client_config.socks, NR_CLIENT_SOCKS, net_config->startTimeout); if(sock < 0) { return -1; } // len = sizeof(server); msglen=RECV(sock, Msg, client_config.serverAddr, net_config->portBase); if (msglen < 0) { perror("recvfrom to locate server"); exit(1); } if(getPort(&client_config.serverAddr) != SENDER_PORT(net_config->portBase)) /* not from the right port */ continue; switch(ntohs(Msg.opCode)) { case CMD_CONNECT_REPLY: client_config.clientNumber = ntohl(Msg.connectReply.clNr); net_config->blockSize = ntohl(Msg.connectReply.blockSize); udpc_flprintf("received message, cap=%08lx\n", (long) ntohl(Msg.connectReply.capabilities)); if(ntohl(Msg.connectReply.capabilities) & CAP_NEW_GEN) { client_config.sender_is_newgen = 1; copyFromMessage(&net_config->dataMcastAddr, Msg.connectReply.mcastAddr); } if (client_config.clientNumber == -1) { udpc_fatal(1, "Too many clients already connected\n"); } goto break_loop; case CMD_HELLO_STREAMING: case CMD_HELLO_NEW: case CMD_HELLO: connectReqSent = 0; if(ntohs(Msg.opCode) == CMD_HELLO_STREAMING) net_config->flags |= FLAG_STREAMING; if(ntohl(Msg.hello.capabilities) & CAP_NEW_GEN) { client_config.sender_is_newgen = 1; copyFromMessage(&net_config->dataMcastAddr, Msg.hello.mcastAddr); net_config->blockSize = ntohs(Msg.hello.blockSize); if(ntohl(Msg.hello.capabilities) & CAP_ASYNC) net_config->flags |= FLAG_PASSIVE; if(net_config->flags & FLAG_PASSIVE) goto break_loop; } haveServerAddress=1; continue; case CMD_CONNECT_REQ: case CMD_DATA: case CMD_FEC: continue; default: break; } udpc_fatal(1, "Bad server reply %04x. Other transfer in progress?\n", (unsigned short) ntohs(Msg.opCode)); } break_loop: udpc_flprintf("Connected as #%d to %s\n", client_config.clientNumber, getIpString(&client_config.serverAddr, ipBuffer)); getMyAddress(net_config->net_if, &myIp); if(!ipIsZero(&net_config->dataMcastAddr) && !ipIsEqual(&net_config->dataMcastAddr, &myIp) && (ipIsZero(&net_config->controlMcastAddr) || !ipIsEqual(&net_config->dataMcastAddr, &net_config->controlMcastAddr) )) { udpc_flprintf("Listening to multicast on %s\n", getIpString(&net_config->dataMcastAddr, ipBuffer)); client_config.S_MCAST_DATA = makeSocket(ADDR_TYPE_MCAST, net_config->net_if, &net_config->dataMcastAddr, RECEIVER_PORT(net_config->portBase)); } if(net_config->requestedBufSize) { int i; for(i=0; i<NR_CLIENT_SOCKS; i++) if(client_config.socks[i] != -1) setRcvBuf(client_config.socks[i],net_config->requestedBufSize); } outFile=openOutFile(disk_config); origOutFile = outFile; pipedOutFile = openPipe(outFile, disk_config, &pipePid); global_client_config= &client_config; atexit(sendDisconnectWrapper); { struct fifo fifo; int printUncompressedPos = udpc_shouldPrintUncompressedPos(stat_config->printUncompressedPos, origOutFile, pipedOutFile); receiver_stats_t stats = allocReadStats(origOutFile, stat_config->statPeriod, printUncompressedPos); udpc_initFifo(&fifo, net_config->blockSize); fifo.data = pc_makeProduconsum(fifo.dataBufSize, "receive"); client_config.isStarted = 0; if((net_config->flags & (FLAG_PASSIVE|FLAG_NOKBD))) { /* No console used */ client_config.console = NULL; } else { if(doWarn) udpc_flprintf("WARNING: This will overwrite the hard disk of this machine\n"); client_config.console = prepareConsole(0); atexit(fixConsole); } spawnNetReceiver(&fifo,&client_config, net_config, stats); writer(&fifo, pipedOutFile); if(pipePid) { close(pipedOutFile); } pthread_join(client_config.thread, NULL); /* if we have a pipe, now wait for that too */ if(pipePid) { udpc_waitForProcess(pipePid, "Pipe"); } #ifndef __MINGW32__ fsync(origOutFile); #endif /* __MINGW32__ */ displayReceiverStats(stats, 1); } fixConsole(); sendDisconnectWrapper(); global_client_config= NULL; return 0; }