Beispiel #1
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;
}
Beispiel #2
0
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;
}
/**
 * bring stored packet back up...
 */
int RecvMsg(int s, struct msghdr *msg, int flags) {
    if(read_swap && stashed) {
	if(random() / stashed < read_swap) {
	    int slot = random() % stashed;
	    int iovnr;
	    char *data = packetStash[slot].data;
	    int totalLen = packetStash[slot].size;
	    int retBytes=0;
	    flprintf("Bringing out %d\n", slot);
	    for(iovnr=0; iovnr < msg->msg_iovlen; iovnr++) {
		int len = msg->msg_iov[iovnr].iov_len;
		if(len > totalLen)
		    len = totalLen;
		memcpy(msg->msg_iov[iovnr].iov_base, data, len);
		totalLen -= len;
		data += len;
		retBytes += len;
		if(totalLen == 0)
		    break;
	    }
	    packetStash[slot]=packetStash[stashed];
	    stashed--;
	    return retBytes;
	}
    }
    return recvmsg(s, msg, flags);
}
int addParticipant(participantsDb_t db,
		   struct sockaddr_in *addr, 
		   int capabilities,
		   unsigned int rcvbuf,
		   int pointopoint) {
    int i;

    if((i = lookupParticipant(db, addr)) >= 0)
	return i;

    for (i=0; i < MAX_CLIENTS; i++) {
	if (!db->clientTable[i].used) {
	    char ipBuffer[16];
	    db->clientTable[i].addr = *addr;
	    db->clientTable[i].used = 1;
	    db->clientTable[i].capabilities = capabilities;
	    db->clientTable[i].rcvbuf = rcvbuf;
	    db->nrParticipants++;

	    flprintf("New connection from %s  (#%d) %08x\n", 
			  getIpString(addr, ipBuffer), i, capabilities);
#ifdef USE_SYSLOG
	    syslog(LOG_INFO, "New connection from %s  (#%d)\n",
			    getIpString(addr, ipBuffer), i);
#endif
	    return i;
	} else if(pointopoint)
	    return -1;
    }

    return -1; /* no space left in participant's table */
}
void srandomTime(int printSeed) {
    struct timeval tv;
    long seed;
    gettimeofday(&tv, 0);
    seed = (tv.tv_usec * 2000) ^ tv.tv_sec;
    if(printSeed)
	flprintf("seed=%ld\n", seed);
    srandom(seed);
}
Beispiel #6
0
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;
}
/**
 * Lose a packet
 */
void loseRecvPacket(int s) {
    if(read_loss) {
	while(random() < read_loss) {
	    int x;
	    flprintf("Losing packet\n");
	    recv(s, (void *) &x, sizeof(x),0);
	}
    }
    if(read_swap) {
	while(stashed < STASH_SIZE && random() < read_swap) {
	    int size;
	    flprintf("Stashing packet %d\n", stashed);
	    size = recv(s, packetStash[stashed].data,
			sizeof(packetStash[stashed].data),0);
	    packetStash[stashed].size = size;
	    stashed++;
	}
    }
}
Beispiel #8
0
static int isSliceAcked(struct slice *slice)
{
#if DEBUG
    flprintf("Is slice %d acked?  %d\n", slice->sliceNo,
             slice->state);
#endif
    if(slice->state == SLICE_ACKED) {
        return 1;
    } else {
        return 0;
    }
}
int removeParticipant(struct participantsDb *db, int i) {
    if(db->clientTable[i].used) {
	char ipBuffer[16];	
	flprintf("Disconnecting #%d (%s)\n", i, 
		 getIpString(&db->clientTable[i].addr, ipBuffer));
#ifdef USE_SYSLOG
	syslog(LOG_INFO, "Disconnecting #%d (%s)\n", i,
			getIpString(&db->clientTable[i].addr, ipBuffer));
#endif
	db->clientTable[i].used = 0;
	db->nrParticipants--;
    }
    return 0;
}
Beispiel #10
0
static int doRetransmissions(sender_state_t sendst,
                             struct slice *slice)
{
    if(slice->state == SLICE_ACKED)
        return 0; /* nothing to do */

#if DEBUG
    flprintf("Do retransmissions\n");
#endif
    /* FIXME: reduce slice size if needed */
    if(slice->needRxmit) {
        /* do some retransmissions */
        sendSlice(sendst, slice, 1);
    }
    return 0;
}
Beispiel #11
0
static int freeSlice(sender_state_t sendst, struct slice *slice) {
    int i;
    i = slice - sendst->slices;
#if DEBUG
    flprintf("Freeing slice %p %d %d\n", slice, slice->sliceNo, i);
#endif
    slice->state = SLICE_PRE_FREE;
    while(1) {
        int pos = pc_getProducerPosition(sendst->free_slices_pc);
        if(sendst->slices[pos].state == SLICE_PRE_FREE)
            sendst->slices[pos].state = SLICE_FREE;
        else
            break;
        pc_produce(sendst->free_slices_pc, 1);
    }
    return 0;
}
Beispiel #12
0
static struct slice *makeSlice(sender_state_t sendst, int sliceNo) {
    struct net_config *config = sendst->config;
    struct fifo *fifo = sendst->fifo;
    int i;
    struct slice *slice=NULL;

    pc_consume(sendst->free_slices_pc, 1);
    i = pc_getConsumerPosition(sendst->free_slices_pc);
    slice = &sendst->slices[i];
    assert(slice->state == SLICE_FREE);
    BZERO(*slice);
    pc_consumed(sendst->free_slices_pc, 1);

    slice->base = pc_getConsumerPosition(sendst->fifo->data);
    slice->sliceNo = sliceNo;
    slice->bytes = pc_consume(fifo->data, 10*config->blockSize);

    /* fixme: use current slice size here */
    if(slice->bytes > config->blockSize * config->sliceSize)
	slice->bytes = config->blockSize * config->sliceSize;

    if(slice->bytes > config->blockSize)
	slice->bytes -= slice->bytes % config->blockSize;

    pc_consumed(fifo->data, slice->bytes);
    slice->nextBlock = 0;
    slice->state = SLICE_NEW;
#if 0
    flprintf("Made slice %p %d\n", slice, slice->sliceNo);
#endif
    BZERO(slice->sl_reqack.readySet);
    slice->nrReady = 0;
#ifdef BB_FEATURE_UDPCAST_FEC
    slice->fec_data = sendst->fec_data + (i * config->fec_stripes * 
					  config->fec_redundancy *
					  config->blockSize);
#endif
    return slice;
}
Beispiel #13
0
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;
}
Beispiel #14
0
static int sendReqack(struct slice *slice, struct net_config *net_config,
                      struct fifo *fifo, sender_stats_t stats,
                      int sock)
{
    /* in async mode, just confirm slice... */
    if((net_config->flags & FLAG_ASYNC) && slice->bytes != 0) {
        ackSlice(slice, net_config, fifo, stats);
        return 0;
    }

    if((net_config->flags & FLAG_ASYNC)
#ifdef BB_FEATURE_UDPCAST_FEC
       && 
       (net_config->flags & FLAG_FEC)
#endif
       ) {
        return 0;
    }

    if(!(net_config->flags & FLAG_SN) && slice->rxmitId != 0) {
        int nrBlocks;
        nrBlocks = getSliceBlocks(slice, net_config);
#if DEBUG
        flprintf("nrBlocks=%d lastGoodBlock=%d\n",
                 nrBlocks, slice->lastGoodBlock);
#endif
        if(slice->lastGoodBlock != 0 && slice->lastGoodBlock < nrBlocks) {
            net_config->discovery = DSC_REDUCING;
            if (slice->lastGoodBlock < net_config->sliceSize / 2) {
                net_config->sliceSize = net_config->sliceSize / 2;
            } else {
                net_config->sliceSize = slice->lastGoodBlock;
            }
            if(net_config->sliceSize < 32) {
                /* a minimum of 32 */
                net_config->sliceSize = 32;
            }
            udpc_logprintf(udpc_log, "Slice size=%d\n", net_config->sliceSize);
        }
    }

    slice->lastGoodBlock = 0;
#if DEBUG
    flprintf("Send reqack %d.%d\n", slice->sliceNo, slice->rxmitId);
#endif
    slice->sl_reqack.ra.opCode = htons(CMD_REQACK);
    slice->sl_reqack.ra.sliceNo = htonl(slice->sliceNo);
    slice->sl_reqack.ra.bytes = htonl(slice->bytes);

    slice->sl_reqack.ra.reserved = 0;
    memcpy((void*)&slice->answeredSet,(void*)&slice->sl_reqack.readySet,
           sizeof(slice->answeredSet));
    slice->nrAnswered = slice->nrReady;

    /* not everybody is ready yet */
    slice->needRxmit = 0;
    memset(slice->rxmitMap, 0, sizeof(slice->rxmitMap));
    memset(slice->isXmittedMap, 0, sizeof(slice->isXmittedMap));
    slice->sl_reqack.ra.rxmit = htonl(slice->rxmitId);
    
    doRateLimit(net_config->rateLimit, sizeof(slice->sl_reqack));
#ifdef FLAG_AUTORATE
    if(net_config->flags & FLAG_AUTORATE)
        doAutoRateLimit(sock, net_config->dir, net_config->sendbuf,
                        sizeof(slice->sl_reqack));
#endif
#if DEBUG
    flprintf("sending reqack for slice %d\n", slice->sliceNo);
#endif
    BCAST_DATA(sock, slice->sl_reqack);
    return 0;
}
Beispiel #15
0
static int sendSlice(sender_state_t sendst, struct slice *slice,
                     int retransmitting)
{    
    struct net_config *config = sendst->config;

    int nrBlocks, i;
#ifdef BB_FEATURE_UDPCAST_FEC
    int fecBlocks;
#endif
    int retransmissions=0;

    if(retransmitting) {
        slice->nextBlock = 0;
        if(slice->state != SLICE_XMITTED)
            return 0;
    } else {
        if(slice->state != SLICE_NEW)
            return 0;
    }

    nrBlocks = getSliceBlocks(slice, config);
#ifdef BB_FEATURE_UDPCAST_FEC
    if((config->flags & FLAG_FEC) && !retransmitting) {
        fecBlocks = config->fec_redundancy * config->fec_stripes;
    } else {
        fecBlocks = 0;
    }
#endif

#if DEBUG
    if(retransmitting) {
        flprintf("%s slice %d from %d to %d (%d bytes) %d\n",
                retransmitting ? "Retransmitting" : "Sending", 
                slice->sliceNo, slice->nextBlock, nrBlocks, slice->bytes,
                config->blockSize);
    }
#endif

    /* transmit the data */
    for(i = slice->nextBlock; i < nrBlocks
#ifdef BB_FEATURE_UDPCAST_FEC
          + fecBlocks
#endif
          ; i++) {
        if(retransmitting) {
            if(!BIT_ISSET(i, slice->rxmitMap) ||
               BIT_ISSET(i, slice->isXmittedMap)) {
                /* if slice is not in retransmit list, or has _already_
                 * been retransmitted, skip it */
                if(i > slice->lastGoodBlock)
                    slice->lastGoodBlock = i;
                continue;
            }
            SET_BIT(i, slice->isXmittedMap);
            retransmissions++;
#if DEBUG
            flprintf("Retransmitting %d.%d\n", slice->sliceNo, i);
#endif
        }
        if(i < nrBlocks)
            transmitDataBlock(sendst, slice, i);
#ifdef BB_FEATURE_UDPCAST_FEC
        else
            transmitFecBlock(sendst, slice, i - nrBlocks);
#endif
        if(!retransmitting && pc_getWaiting(sendst->rc.incoming)) {
            i++;
            break;
        }
    }

    if(retransmissions)
        senderStatsAddRetransmissions(sendst->stats, retransmissions);
    slice->nextBlock = i;
    if(i == nrBlocks
#ifdef BB_FEATURE_UDPCAST_FEC
       + fecBlocks
#endif
       ) {
        slice->needRxmit = 0;
        if(!retransmitting)
            slice->state = SLICE_XMITTED;
#if DEBUG
        flprintf("Done: at block %d %d %d\n", i, retransmitting,
                 slice->state);
#endif
        return 2;
    }
#if DEBUG
    flprintf("Done: at block %d %d %d\n", i, retransmitting,
             slice->state);
#endif
    return 1;
}