Ejemplo n.º 1
0
bool
TransportSendBuffer::resend(const SequenceRange& range)
{
  ACE_GUARD_RETURN( TransportSendStrategy::LockType,
                    guard,
                    this->strategy_->lock_,
                    false);

  for (SequenceNumber sequence(range.first);
       sequence <= range.second; ++sequence) {
    // Re-send requested sample if still buffered; missing samples
    // will be scored against the given DisjointSequence:
    BufferMap::iterator it(this->buffers_.find(sequence));
    if (it != this->buffers_.end()) {
      if (OpenDDS::DCPS::Transport_debug_level >= 4) {
        ACE_DEBUG((LM_DEBUG,
                   ACE_TEXT("(%P|%t) TransportSendBuffer::resend() - ")
                   ACE_TEXT("resending PDU: 0x%x, (0x%x,0x%x)\n"),
                   sequence.getValue(),
                   it->second.first,
                   it->second.second));
      }
      resend(it->second);
    }
  }

  // Have we resent all requested data?
  return range.first >= low() && range.second <= high();
}
Ejemplo n.º 2
0
int tonokip_handle_reply(rr_dev device, const char *reply, size_t nbytes) {
  if(!strncmp("ok", reply, 2)) {
    if(device->onreply) {
      device->onreply(device, device->onreply_data, RR_OK, 0);
    }
  } else if(!strncmp("Resend:", reply, 7)) {
    /* Line number begins 7 bytes in */
    return resend(device, atoll(reply + 7), reply, nbytes);
  } else if(!strncmp("T:", reply, 2)) {
    if(device->onreply) {
      char *point;
      device->onreply(device, device->onreply_data, RR_BED_TEMP,
                      strtof(reply+2, &point));
      if(!strncmp("B:", point+1, 2)) {
        device->onreply(device, device->onreply_data, RR_BED_TEMP,
                        strtof(point+3, NULL));
      }
    }
  } else {
    if(device->onerr) {
      device->onerr(device, device->onerr_data, RR_E_UNKNOWN_REPLY, reply, nbytes);
    }
    return RR_E_UNKNOWN_REPLY;
  }

  return 0;
}
Ejemplo n.º 3
0
void
Reliable::processZeroSend()
{
	if ( m_zeroSendCount == 0 && 
		 m_outstandingSegs >= MAX_OUTSTANDING_SEGMENTS )
	{
		return;
	}

	SendBlockList::iterator i( m_sendList.begin() );

	for ( ; i != m_sendList.end(); ++i )
	{
		UdpSendBlock* sb = *i;
		K_ASSERT( sb != 0 );

		if ( sb->rxCount == 0 )
		{
			if ( resend( sb ) )
			{
				--m_zeroSendCount;

				K_ASSERT( m_zeroSendCount >= 0 );
			}
			else
			{
				return; // we still cannot send 'cause there are too many outstanding segments
			}
		}
	}
}
Ejemplo n.º 4
0
void 
Reliable::processResend()
{
	uint rtt = m_averageRtt;

	int resendCount = 0;

	if ( m_tickResend.Elapsed() > RESEND_CHECK_INTERVAL )
	{
		SendBlockList::iterator i( m_sendList.begin() );
		SendBlockList::iterator iEnd( m_sendList.end() );

		for ( ; i != iEnd; ++i )
		{
			UdpSendBlock* sb = *i;
			K_ASSERT( sb != 0 );

			if ( sb->rxmt.Elapsed() > rtt + rtt * sb->rxCount )
			{
				resend( sb, true );

				++resendCount;
			}
		}

		m_tickResend.Reset();
	}
}
Ejemplo n.º 5
0
static void
cectimer(void * v)
{
	Conn *cp;

	for(;;){
		tsleep(&trendez, icansleep, 0, 250);
		tcond = 0;
		for(cp = conn; cp < conn + Nconns; cp++){
			qlock(cp);
			if(cp->bp != nil){
				if(--cp->to <= 0){
					if(--cp->retries <= 0){
						freeb(cp->bp);
						cp->bp = 0;
//						cp->state = Cunused;
					}else
						resend(cp);
				}
			}else if(cp->stalled){
				cp->stalled = 0;
				start(cp);
			}
			qunlock(cp);
		}
	}
}
Ejemplo n.º 6
0
void
docopy(Display * s, Window s_w, Display * d, Window d_w)
{
	XSelectInput(s, s_w, KeyPressMask);
	while (1) {
		XEvent          xev;
		XNextEvent(s, &xev);
		resend(d, &xev, d_w);
	}
}
void
resolver::pktready (bool tcp, u_char *qb, ssize_t n)
{
  if (n <= 0) {
    if (tcp) {
      tcpsock = NULL;
      if (!last_resp)
	setsock (true);
      last_resp = 0;
      resend (false, true);
    }
    else {
      udpsock = NULL;
      setsock (true);
    }
    return;
  }

  nbump = 0;
  last_resp = timenow;

  dnsparse reply (qb, n);
  question q;
  if (!reply.qparse (&q) || q.q_class != C_IN)
    return;

  dnsreq *r;
  for (r = reqtab[reply.hdr->id];
       r && (r->usetcp != tcp || r->type != q.q_type
	     || strcasecmp (r->name, q.q_name));
       r = reqtab.nextkeq (r))
    ;
  if (!r)
    return;

  if (reply.error && !r->error)
    r->error = reply.error;
  if (r->error == NXDOMAIN) {
    r->error = 0;
    r->start (true);
  }
  else if (!r->error && !r->usetcp && reply.hdr->tc) {
    reqtoq.remove (r);
    r->usetcp = true;
    r->xmit (0);
  }
  else
    r->readreply (r->error ? NULL : &reply);
}
Ejemplo n.º 8
0
int MiLightRadio::write(uint8_t frame[], size_t frame_length)
{
  if (frame_length > sizeof(_out_packet) - 1) {
    return -1;
  }

  memcpy(_out_packet + 1, frame, frame_length);
  _out_packet[0] = frame_length;

  int retval = resend();
  if (retval < 0) {
    return retval;
  }
  return frame_length;
}
Ejemplo n.º 9
0
void check_timer(ChannelState *s){
	if (s == NULL) return; 
		if (s->state % 2 != 0){
			if (s->ticks == 0){
				if (s == &home_channel_state || s->pingOUT < 3){
					PRINTF("Retrying\n");
					resend(s);
					s->pingOUT++;
					s->ticks = s->pingOUT * 10;
				} else {
					printf("PING OUT = %d\n", s->pingOUT);
					printf("CLOSING CHANNEL DUE TO TIMEOUT\n");
					close_graceful(s);
					remove_channel(s->chan_num);
				}

			}
		}
		s->ticks --;
}
bool
resolver::setsock (bool failure)
{
  if (udpcheck_req) {
    delete udpcheck_req;
    udpcheck_req = NULL;
  }

  do {
    if ((failure || !addr) && !bumpsock (failure))
      return false;
    failure = true;
    nbump++;
    last_resp = 0;
    last_bump = timenow;
    tcpsock = NULL;
  } while (!udpinit () || !tcpinit ());

  return resend (true, true);
}
Ejemplo n.º 11
0
void 
Reliable::runEak( int seq )
{
	SendBlockList::iterator i( m_sendList.begin() );
	SendBlockList::iterator iEnd( m_sendList.end() );

	for ( ; i != iEnd; ++i )
	{
		UdpSendBlock* sb = *i;
		K_ASSERT( sb != 0 );

		if ( sb->header.seq == seq )
		{
			LOG( FT_DEBUG, _T("Reliable::runEak> self[%d] remote[%d] %d acked") , 
		 		 m_connection->GetSelfTag(), 
		 		 m_connection->GetRemoteTag(),
				 seq );

			m_sendList.erase( i );

			delete sb;

			return;
		}
	}

	i    = m_sendList.begin();
	iEnd = m_sendList.end();

	for ( ; i != iEnd; ++i )
	{
		UdpSendBlock* sb = *i;

		if ( sb->header.seq > seq )
		{
			return;
		}

		resend( sb );
	}
}
Ejemplo n.º 12
0
P_NPC cPlayer::unmount()
{
	P_ITEM pi = atLayer( Mount );
	if ( pi && !pi->free )
	{
		P_NPC pMount = dynamic_cast<P_NPC>( FindCharBySerial( pi->getTag( "pet" ).toInt() ) );
		if ( pMount && !pMount->free )
		{
			pMount->setWanderType( enHalt );
			pMount->setStablemasterSerial( INVALID_SERIAL );
			pMount->moveTo( pos() );
			pMount->setDirection( direction_ );
			pMount->resend( false );
			pMount->bark( Bark_Idle );
		}
		pi->remove();
		resend( false );
		return pMount;
	}
	return NULL;
}
Ejemplo n.º 13
0
void Connection::onMessage( Stanza st )
{
    std::cout << "OnMessage" << std::endl;
    std::string target = st.getTo().getNode();

    if ( _myServer.checkAccount( target ) == false )
    {
        Stanza ans;
        ans.setStanzaType( Stanza::IQ );
        ans.setSubType( Stanza::ERROR );
        //std::string strAns;
        //ans.save( strAns );
        _received.push_back( ans );
        //doWriteQuick( strAns );

        doReadSize();
        return;
    }

    resend( st );
    doReadSize();
}
Ejemplo n.º 14
0
/*
 * Action Expression Functions.
 */
VS_VOID MultiplierVSAction_0 (VS_VOID)
{
  resend(VSDBVar.DB1.VS_VOIDPTRVar[0]);
}
Ejemplo n.º 15
0
/*
 * Check all frames on device and resend any frames that have been
 * outstanding for 200% of the device round trip time average.
 */
static void
aoesweepproc(void*)
{
	ulong i, tx, timeout, nbc;
	vlong starttick;
	enum { Nms = 100, Nbcms = 30*1000, };		/* magic */
	uchar *ea;
	Aoeata *a;
	Aoedev *d;
	Devlink *l;
	Frame *f, *e;

	nbc = Nbcms/Nms;
loop:
	if(nbc-- == 0){
		if(rediscover && !waserror()){
			discover(0xffff, 0xff);
			poperror();
		}
		nbc = Nbcms/Nms;
	}
	starttick = MACHP(0)->ticks;
	rlock(&devs);
	for(d = devs.d; d; d = d->next){
		if(!canqlock(d))
			continue;
		if(!UP(d)){
			qunlock(d);
			continue;
		}
		tx = 0;
		f = d->frames;
		e = f + d->nframes;
		for (; f < e; f++){
			if(f->tag == Tfree)
				continue;
			l = f->dl;
			timeout = l->rttavg << 1;
			i = tsince(f->tag);
			if(i < timeout)
				continue;
			if(d->nout == d->maxout){
				if(d->maxout > 1)
					d->maxout--;
				d->lastwadj = MACHP(0)->ticks;
			}
			a = (Aoeata*)f->hdr;
			if(a->scnt > Dbcnt / Aoesectsz &&
			   ++f->nl->lostjumbo > (d->nframes << 1)){
				ea = f->dl->eatab[f->eaidx];
				eventlog("%æ: jumbo failure on %s:%E; lba%lld\n",
					d, f->nl->path, ea, f->lba);
				d->maxbcnt = Dbcnt;
				d->flag &= ~Djumbo;
			}
			resend(d, f);
			if(tx++ == 0){
				if((l->rttavg <<= 1) > Rtmax)
					l->rttavg = Rtmax;
				eventlog("%æ: rtt %ldms\n", d, TK2MS(l->rttavg));
			}
		}
		if(d->nout == d->maxout && d->maxout < d->nframes &&
		   TK2MS(MACHP(0)->ticks - d->lastwadj) > 10*1000){ /* more magic */
			d->maxout++;
			d->lastwadj = MACHP(0)->ticks;
		}
		qunlock(d);
	}
	runlock(&devs);
	i = Nms - TK2MS(MACHP(0)->ticks - starttick);
	if(i > 0)
		tsleep(&up->sleep, return0, 0, i);
	goto loop;
}
Ejemplo n.º 16
0
int finAndAck(int* seq_no, struct Info *c,struct sockaddr_in cli_addr, \
						 int sockfd,char * sip,char* spt,char*rip,char* rpt, int * last_sig, int* last_ack_val){
	char * finpack = (char *) malloc(MAXBUFLEN * sizeof(char));
    FILE *redun1;
    int redun2;
    finpack = returnPack(seq_no,redun1,4,&redun2,last_sig,last_ack_val);

    struct timeval timer= (struct timeval){0};
    timer.tv_sec=TIMEOUT;
    timer.tv_usec= 0;

    int charsent;
    socklen_t cli_len = sizeof(cli_addr);

	int count=0;
	int flag=0;

	//SENT FIN PACK

    if ((charsent = sendto(sockfd, finpack, strlen(finpack), 0,(struct sockaddr *)&cli_addr, cli_len) == -1)) {
       	perror("sws: error in sendto()");
       	exit(1);
   	}

	printEvent(1,2,finpack,"FIN",sip,spt,rip,rpt);
	c->fin_sent+=1;
	c->unique_bytes_sent+=strlen(finpack);
	c->total_bytes_sent+=strlen(finpack);
	c->unique_packets+=1;
	c->total_packets_sent+=1;
		
	
		

	//*seq_no+=strlen(finpack);
	//dont increase seq no since no packet will be sent after this one
	//also seqn_no used to compare returning packet
	

    fd_set readfds;
	int retval;
	int i;
	for(i=0;i<RETRY;i++){
    	FD_ZERO(&readfds);
    	FD_SET(sockfd, &readfds);
		
		timer.tv_sec=TIMEOUT;		
		retval = select(sockfd+1, &readfds, NULL, NULL, &timer);
		timer.tv_sec=1;

		if(retval == -1){
			printf("Error on select()..\nExit\n");
			exit(1);
		}
	
		if(retval == 0){
			continue;
		}

		else{
			break;
		}
	
	}

		
	//packet recieved
	

	int numbytes;
   	char * buffer= (char*)malloc(MAXBUFLEN*sizeof(char));
	
    if ((numbytes = recvfrom(sockfd, buffer, MAXBUFLEN-1 , 0,(struct sockaddr *)&cli_addr, &cli_len)) == -1) {
      	perror("sws: error on recvfrom()!");
       	return -1;
    }
	

	int ty = isA(buffer);
	
	free(buffer);
	free(finpack);

	if(ty != 2){
		return -1;  //did not receive right packet type, exit
	}

	int rec_ack = get(buffer,1);
		
	printEvent(2,2,buffer,"ACK",sip,spt,rip,rpt);
	c->ack_received+=1;
		

	//printf("expected ACK=%d\n",*seq_no);
	//printf("recvd ACK = %d\n",rec_ack);
	
	if(rec_ack == *seq_no){
		return 1;
	}

	return -1;
	

	
}

//_______________________________________________MAIN_____________________________________________________________

int main(int argc, char *argv[]){


	struct timeval start =(struct timeval){0};
	struct timeval end = (struct timeval){0};

	gettimeofday(&start,NULL);

    int sockfd, portno, cliport;
    socklen_t cli_len;
    char buffer[MAXBUFLEN];
    struct sockaddr_in serv_addr, cli_addr;
    int numbytes;

    //verify cmd line params..
    if (argc < 4) {
        printf( "Usage: %s <s:ip> <s:pt> <r:ip> <r:port> <file_name>\n\n", argv[0] );
        fprintf(stderr,"ERROR, not enough parameters. Graceful exit...\n");
        return -1;
    }



    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
        perror("sws: error on socket(), Graceful exit..");
        return -1;
    }

    char * file = argv[5];
    char * sip = argv[1];
    char * spt = argv[2];
    char * dip = argv[3];
    char * dpt = argv[4];

    printf("\nSending file: %s from: %s:%s  to: %s:%s\n\n",file,sip,spt,dip,dpt);

    //SERVER configuration
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(spt);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(sip);
    serv_addr.sin_port = htons(portno);

    //CLIENT configuration
    bzero((char *) & cli_addr,sizeof(cli_addr));
    cliport = atoi(dpt);
    cli_addr.sin_family = AF_INET;
    cli_addr.sin_addr.s_addr = inet_addr(dip);
    cli_addr.sin_port = htons(cliport);



    int optval = 1;
    if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0 ) {
        perror("sws: error on set socket option!");
        return -1;
    }


    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
        close(sockfd);
        perror("sws: error on binding! Graceful exit...");
        return -1;
    }


    struct Info stat;
    assignDef(&stat);

    srand(time(NULL));
    int seq_no = rand() % 10000;
	printf("start seq=%d\n",seq_no);
 

    int chars_taken=0;
    FILE *fp = fopen(file,"r");
    FILE *fp2= fopen(file,"r");
    if(fp==NULL || fp2==NULL){
        printf("Could not open file..\nProgram exit\n");
        exit(1);
    }


    int len=0;
    int c;
    while((c=fgetc(fp))){
        if(c==EOF) break;
        len+=1;
    }

    fclose(fp);

    int sendby = 5;
    char ** tosend = (char **) malloc(sendby*sizeof(char *));  //will contain the packets "to be sent" or "waiting on ACK"
    int q;
    for(q=0;q<sendby;q++){
        tosend[q] = (char *) malloc(MAXBUFLEN*sizeof(char));
    }
	
	int loc1=0;
	int loc2=0;
	int loc3=0;		//boolean variable keeping track of FILL of tosend[locX]
	int loc4=0;		//there are 5 because sendby == 5
	int loc5=0;

	int status1;
	int status2;
	int status3;	//values keep track of status of packet in tosend[statusX]
	int status4;	//2 = waiting on ACK, 1 = not sent yet
	int status5;
	

	struct timeval timeout = (struct timeval){0};
    timeout.tv_sec=TIMEOUT;
    timeout.tv_usec= 0;

	fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);
	
	int syn=1;
	int can_send;
	int most_recent_ACK;
	int winsz=0;
	int maxbuf = MAXBUFLEN;
	float num;
	int retval;
	int retried =0;
	int pkty;


	char rcv [MAXBUFLEN];

	int last_pk_prep=0;
	int last_ack=0;
	int last_ack_val=0;


	//struct timeval te;
	//gettimeofday(&te,NULL);
	//printf("%ld.%06ld\n",te.tv_sec,te.tv_usec);

	int loop=1;

    while(last_ack==0){ //while last_ack no rcvd
		
		if( syn == 1 ){
			if(estConn(&seq_no, &stat, cli_addr, sockfd, &winsz,sip,spt,dip,dpt,&last_pk_prep,&last_ack_val,&most_recent_ACK)==0){
				printf("Establishing connection..\n");
        		printf("Could not establist connection..\nProgram exit..\n");
         		exit(1);
			}
			syn=0;
		}

	
		//sleep(1);

		num = winsz/maxbuf;
		can_send = (int) floor(num); // how many packets the receiver can buffer

	
		//fill tosend[] and update status variables via pointer	

		if(last_pk_prep!=1){	
			filltosend(tosend,&loc1,&loc2,&loc3,&loc4,&loc5,&seq_no,fp2,&chars_taken, \
								&status1,&status2,&status3,&status4,&status5,&last_pk_prep,&last_ack_val);
		}
		/*int f;
		printf("in tosend\n");
		for(f=0;f<5;f++){
			printf("[%d] seq = %d\n",f,get(tosend[f],3));
		}
		printf("--\n");*/

		if(can_send>=1){
			sndpackets(tosend,&stat,can_send,cli_addr,sockfd,&status1,&status2,&status3,&status4,&status5,sip,spt,dip,dpt);
		}


		FD_ZERO(&readfds);
   		FD_SET(sockfd, &readfds);
		timeout.tv_sec=1;
	
		retval = select(sockfd+1, &readfds, NULL, NULL, &timeout);	
	
		if(retval==-1){
            printf("select() error...\nExit\n");
            exit(1);
        }
        if(retval==0){ // if select() has timed out
			retried+=1;
			//printf("retry\n");
			if(retried == 5){
				printf("Number of retries timed out..\nExit\n");
				exit(1);
			}
			else {
				if(can_send>=1){ // if select() has timed out, resend last packet that was not ack
					//printf("had to resend\n");
					resend(most_recent_ACK,tosend,&stat,can_send,cli_addr,sockfd,sip,spt,dip,dpt,&loc1,&loc2,&loc3,&loc4,&loc5);
					//printf("resent!\n");
				}
					continue;
			}			 
          
        }
		
		retried = 0;

		//select() has noticed content at socket! -> proceed

		
		if ((numbytes = recvfrom(sockfd, rcv, MAXBUFLEN-1 , 0,(struct sockaddr *)&cli_addr, &cli_len)) == -1) {
        	perror("sws: error on recvfrom()!");
        	return -1;
    	}
		

		pkty = isA(rcv);
		if(pkty==2){	//received ACK packet

			//printf("last ack val =%d, is last pk prep?%d\n",last_ack_val,last_pk_prep);
			if(get(rcv,1) <= most_recent_ACK){ //recvd dupACK
				//printf("DUP ACK\n");
				printEvent(2,1,rcv,"ACK",sip,spt,dip,dpt);
				stat.ack_received+=1;
				dupAckSendData(tosend,most_recent_ACK,sockfd,cli_addr,&stat,sip,spt,dip,dpt,&loc1,&loc2,&loc3,&loc4,&loc5);
				//dupAckSendData(tosend,get(rcv,1),sockfd,cli_addr,&stat,sip,spt,dip,dpt);
				continue;
			}

			else{   // ACK is not dupACK
				
				stat.ack_received+=1;
				printEvent(2,2,rcv,"ACK",sip,spt,dip,dpt);

				//check if it is the last ACK
				if(last_pk_prep == 1 && last_ack_val == get(rcv,1)){
					break;
				}

				else{ //ACK is in sequence, proceed..
					most_recent_ACK = get(rcv,1);
					winsz = get(rcv,2);	
					//printf("Clear to send[]\n");

					/*int v;
					for(v=0;v<5;v++){
						printf("[%d] seq = %d\n",v,get(tosend[v],3));
					}*/
					
					clearTosend(tosend,most_recent_ACK,&loc1, &loc2, &loc3, &loc4, &loc5);
					continue;
				}
			}
			

		}

		if(pkty==5){  //received RST packet
			
			stat.rst_received+=1;
			syn=1;
		}
	
		else{		//received unknow packet... dont do anything
			continue;
		}
		
       
		

    }///while

	finAndAck(&seq_no, &stat, cli_addr, sockfd,sip,spt,dip,dpt,&last_pk_prep,&last_ack_val);


	printf("\n\n");
	printStats(&stat);

	
	//end program timer

    int h;
    for(h=0;h<sendby;h++){
        free(tosend[h]);
    }
    free(tosend);


	gettimeofday(&end,NULL);

	double et = end.tv_usec - start.tv_usec;
	et/=1000000;
	et= et + (end.tv_sec - start.tv_sec);

	printf("\nExecution time = %fs\n",et); 


}
Ejemplo n.º 17
0
int fived_handle_reply(rr_dev device, const char *reply, size_t nbytes) {
  if(!strncasecmp("ok", reply, 2)) {
    if(device->onreply) {
      device->onreply(device, device->onreply_data, RR_OK, 0);
      /* Parse values */
      char *i;
      for(i = (char*)reply; i < reply + nbytes; ++i) {
        switch(toupper(*i)) {
        case 'T':
          device->onreply(device, device->onreply_data, RR_NOZZLE_TEMP,
                          strtof(i+2, &i));
          break;

        case 'B':
          device->onreply(device, device->onreply_data, RR_BED_TEMP,
                          strtof(i+2, &i));
          break;

        case 'C':
          break;

        case 'X':
          device->onreply(device, device->onreply_data, RR_X_POS,
                          strtof(i+2, &i));
          break;

        case 'Y':
          device->onreply(device, device->onreply_data, RR_Y_POS,
                          strtof(i+2, &i));
          break;

        case 'Z':
          device->onreply(device, device->onreply_data, RR_Z_POS,
                          strtof(i+2, &i));
          break;

        case 'E':
          device->onreply(device, device->onreply_data, RR_E_POS,
                          strtof(i+2, &i));
          break;

        default:
          if(device->onerr) {
            device->onerr(device, device->onerr_data, RR_E_UNKNOWN_REPLY, reply, nbytes);
          }
          break;
        }
      }
    }
  } else if(!strncasecmp("rs", reply, 2) || !strncasecmp("resend", reply, 6)) {
    /* check where the line number starts */
    size_t n_start = strcspn(reply, "123456789");
    if(n_start) {
      long long lineno = strtoll(reply + n_start, NULL, 10);
      /* check if lineno is in the range of sent lines*/
      if(lineno < device->lineno && strncmp("-", reply + n_start - 1, 1)) {
        return resend(device, lineno, reply, nbytes);
      } else {
        if(device->onerr) {
          device->onerr(device, device->onerr_data, RR_E_UNSENT_RESEND, reply, nbytes);
        }
        return RR_E_UNSENT_RESEND;
      }
    } else {
      if(device->onerr) {
        device->onerr(device, device->onerr_data, RR_E_MALFORMED_RESEND_REQUEST, reply, nbytes);
      }
    return RR_E_MALFORMED_RESEND_REQUEST;
    }
  } else if(!strncmp("!!", reply, 2)) {
    if(device->onerr) {
      device->onerr(device, device->onerr_data, RR_E_HARDWARE_FAULT, reply, nbytes);
    }
    return RR_E_HARDWARE_FAULT;
  } else if (!strncasecmp ("start", reply, 5)) {
    /*
     * This is non-intuitive. If we reset the controller, when we next send
     * a command sequence, on the first command we will get a 'start',
     * meaning we should reset the line number. Problem is we then send
     * the rest of the command sequence and get another 'start' in mid
     * flow for some controllers, which gets us out of sync. Ergo we need
     * to reset the line number with a command each time we hit one of
     * these.
     */
    rr_reset_lineno (device);
  } else {
    if(device->onerr) {
      device->onerr(device, device->onerr_data, RR_E_UNKNOWN_REPLY, reply, nbytes);
    }
    return RR_E_UNKNOWN_REPLY;
  }

  return 0;
}