Exemplo n.º 1
0
static THREAD_RETURN returnChannelMain(void *args) {
    struct returnChannel *returnChannel = (struct returnChannel *) args;
    fd_set read_set;
    int r=0;
    FD_ZERO(&read_set);

    while(1) {
        struct sockaddr_in from;
        int clNo;
        int pos = pc_getConsumerPosition(returnChannel->freeSpace);
        pc_consumeAny(returnChannel->freeSpace);
        do {
            struct timeval tv;
            if(returnChannel->stopIt)
                return 0;
            FD_SET(returnChannel->rcvSock,&read_set);
            tv.tv_sec=0;
            tv.tv_usec=100;
            r = select(returnChannel->rcvSock+1,
                       &read_set, NULL, NULL, &tv);
        } while(r==0);

        RECV(returnChannel->rcvSock, 
             returnChannel->q[pos].msg, from,
             returnChannel->config->portBase);
        clNo = udpc_lookupParticipant(returnChannel->participantsDb, &from);
        if (clNo < 0) { 
            /* packet from unknown provenance */
            continue;
        }
        returnChannel->q[pos].clNo = clNo;
        pc_consumed(returnChannel->freeSpace, 1);
        pc_produce(returnChannel->incoming, 1);
    }
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
static THREAD_RETURN returnChannelMain(void *args) {
    struct returnChannel *returnChannel = (struct returnChannel *) args;

    while(1) {
	struct sockaddr_in from;
	int clNo;
	int pos = pc_getConsumerPosition(returnChannel->freeSpace);
	pc_consumeAny(returnChannel->freeSpace);

	RECV(returnChannel->rcvSock, 
	     returnChannel->q[pos].msg, from,
	     returnChannel->config->portBase);
	clNo = udpc_lookupParticipant(returnChannel->participantsDb, &from);
	if (clNo < 0) { 
	    /* packet from unknown provenance */
	    continue;
	}
	returnChannel->q[pos].clNo = clNo;
	pc_consumed(returnChannel->freeSpace, 1);
	pc_produce(returnChannel->incoming, 1);
    }
    return 0;
}
Exemplo n.º 5
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;
}