lib/rudp.c File Reference

#include "common.h"
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "errabort.h"
#include "rudp.h"

Include dependency graph for rudp.c:

Go to the source code of this file.

Defines

#define MAX_TIME_OUT   999999

Functions

static int rudpCalcTimeOut (struct rudp *ru)
static void rudpAddRoundTripTime (struct rudp *ru, int time)
static void rudpTimedOut (struct rudp *ru)
rudprudpNew (int socket)
void rudpFree (struct rudp **pRu)
rudprudpOpen ()
rudprudpMustOpen ()
rudprudpOpenBound (struct sockaddr_in *sai)
rudprudpMustOpenBound (struct sockaddr_in *sai)
void rudpClose (struct rudp **pRu)
static int timeDiff (struct timeval *t1, struct timeval *t2)
static boolean readReadyWait (int sd, int microseconds)
static boolean getOurAck (struct rudp *ru, struct timeval *startTv)
int rudpSend (struct rudp *ru, struct sockaddr_in *sai, void *message, int size)
int rudpReceiveTimeOut (struct rudp *ru, void *messageBuf, int bufSize, struct sockaddr_in *retFrom, int timeOut)
int rudpReceiveFrom (struct rudp *ru, void *messageBuf, int bufSize, struct sockaddr_in *retFrom)
int rudpReceive (struct rudp *ru, void *messageBuf, int bufSize)
void rudpPrintStatus (struct rudp *ru)
void rudpTest ()

Variables

static char const rcsid [] = "$Id: rudp.c,v 1.14 2005/12/12 02:24:47 kent Exp $"


Define Documentation

#define MAX_TIME_OUT   999999

Definition at line 60 of file rudp.c.

Referenced by rudpCalcTimeOut(), and rudpTimedOut().


Function Documentation

static boolean getOurAck ( struct rudp ru,
struct timeval *  startTv 
) [static]

Definition at line 236 of file rudp.c.

References rudp::lastId, readReadyWait(), rudpAck, rudpAddRoundTripTime(), rudp::socket, timeDiff(), rudp::timeOut, and TRUE.

Referenced by rudpSend().

00241 {
00242 struct rudpHeader head;
00243 int readSize;
00244 int timeOut = ru->timeOut;
00245 
00246 for (;;)
00247     {
00248     /* Set up select with our time out. */
00249     int dt;
00250     struct timeval tv;
00251 
00252     if (readReadyWait(ru->socket, timeOut))
00253         {
00254         /* Read message and if it's our ack return true.   */
00255         readSize = recvfrom(ru->socket, &head, sizeof(head), 0, NULL, NULL);
00256         if (readSize >= sizeof(head) && head.type == rudpAck && head.id == ru->lastId)
00257             {
00258             gettimeofday(&tv, NULL);
00259             dt = timeDiff(startTv, &tv);
00260             rudpAddRoundTripTime(ru, dt);
00261             return TRUE;
00262             }
00263         }
00264 
00265     /* If we got to here then we did get a message, but it's not our
00266      * ack.  We ignore the message and loop around again,  but update
00267      * our timeout so that we won't keep getting other people's messages
00268      * forever. */
00269     gettimeofday(&tv, NULL);
00270     timeOut = ru->timeOut - timeDiff(startTv, &tv);
00271     if (timeOut <= 0)
00272         return FALSE;
00273     }
00274 }

Here is the call graph for this function:

Here is the caller graph for this function:

static boolean readReadyWait ( int  sd,
int  microseconds 
) [static]

Definition at line 199 of file rudp.c.

References errno, and warn().

00202 {
00203 struct timeval tv;
00204 fd_set set;
00205 int readyCount;
00206 
00207 for (;;)
00208     {
00209     if (microseconds > 1000000)
00210         {
00211         tv.tv_sec = microseconds/1000000;
00212         tv.tv_usec = microseconds%1000000;
00213         }
00214     else
00215         {
00216         tv.tv_sec = 0;
00217         tv.tv_usec = microseconds;
00218         }
00219     FD_ZERO(&set);
00220     FD_SET(sd, &set);
00221     readyCount = select(sd+1, &set, NULL, NULL, &tv);
00222     if (readyCount < 0) 
00223         {
00224         if (errno == EINTR)     /* Select interrupted, not timed out. */
00225             continue;
00226         else 
00227             warn("select failure in rudp: %s", strerror(errno));
00228         }
00229     else
00230         {
00231         return readyCount > 0;  /* Zero readyCount indicates time out */
00232         }
00233     }
00234 }

Here is the call graph for this function:

static void rudpAddRoundTripTime ( struct rudp ru,
int  time 
) [static]

Definition at line 71 of file rudp.c.

References rudp::rttAve, rudp::rttLast, rudp::rttVary, rudpCalcTimeOut(), and rudp::timeOut.

Referenced by getOurAck(), and rudpTest().

00074 {
00075 int delta;
00076 ru->rttLast = time;
00077 delta = time - ru->rttAve;
00078 ru->rttAve += (delta>>3);                     /* g = 1/8 */
00079 if (delta < 0) delta = -delta;
00080 ru->rttVary += ((delta - ru->rttVary) >> 2);  /* h = 1/4 */
00081 ru->timeOut = rudpCalcTimeOut(ru);
00082 }

Here is the call graph for this function:

Here is the caller graph for this function:

static int rudpCalcTimeOut ( struct rudp ru  )  [static]

Definition at line 62 of file rudp.c.

References MAX_TIME_OUT, rudp::rttAve, and rudp::rttVary.

Referenced by rudpAddRoundTripTime(), and rudpNew().

00064 {
00065 int timeOut = ru->rttAve + (ru->rttVary<<2);
00066 if (timeOut > MAX_TIME_OUT) timeOut = MAX_TIME_OUT; /* No more than a second. */
00067 if (timeOut < 10000) timeOut = 10000;   /* No less than 1/100th second */
00068 return timeOut;
00069 }

Here is the caller graph for this function:

void rudpClose ( struct rudp **  pRu  ) 

Definition at line 165 of file rudp.c.

References freez(), and rudp::socket.

Referenced by rudpOpenBound().

00167 {
00168 struct rudp *ru = *pRu;
00169 if (ru != NULL)
00170     {
00171     close(ru->socket);
00172     freez(pRu);
00173     }
00174 }

Here is the call graph for this function:

Here is the caller graph for this function:

void rudpFree ( struct rudp **  pRu  ) 

Definition at line 106 of file rudp.c.

References freez().

00108 {
00109 freez(pRu);
00110 }

Here is the call graph for this function:

struct rudp* rudpMustOpen (  )  [read]

Definition at line 129 of file rudp.c.

References noWarnAbort(), and rudpOpen().

00131 {
00132 struct rudp *ru = rudpOpen();
00133 if (ru == NULL)
00134     noWarnAbort();
00135 return ru;
00136 }

Here is the call graph for this function:

struct rudp* rudpMustOpenBound ( struct sockaddr_in *  sai  )  [read]

Definition at line 155 of file rudp.c.

References noWarnAbort(), and rudpOpenBound().

00158 {
00159 struct rudp *ru = rudpOpenBound(sai);
00160 if (ru == NULL)
00161     noWarnAbort();
00162 return ru;
00163 }

Here is the call graph for this function:

struct rudp* rudpNew ( int  socket  )  [read]

Definition at line 92 of file rudp.c.

References AllocVar, rudp::maxRetries, rudp::rttVary, rudpCalcTimeOut(), rudp::socket, and rudp::timeOut.

Referenced by rudpOpen(), and rudpTest().

00095 {
00096 struct rudp *ru;
00097 assert(socket >= 0);
00098 AllocVar(ru);
00099 ru->socket = socket;
00100 ru->rttVary = 250;      /* Initial variance 250 microseconds. */
00101 ru->timeOut = rudpCalcTimeOut(ru);
00102 ru->maxRetries = 7;
00103 return ru;
00104 }

Here is the call graph for this function:

Here is the caller graph for this function:

struct rudp* rudpOpen (  )  [read]

Definition at line 112 of file rudp.c.

References errno, rudpNew(), rudp::socket, and warn().

Referenced by rudpMustOpen(), and rudpOpenBound().

00119 {
00120 int sd = socket(AF_INET,  SOCK_DGRAM, IPPROTO_UDP);
00121 if (sd < 0)
00122     {
00123     warn("Couldn't open socket in rudpOpen %s", strerror(errno));
00124     return NULL;
00125     }
00126 return rudpNew(sd);
00127 }

Here is the call graph for this function:

Here is the caller graph for this function:

struct rudp* rudpOpenBound ( struct sockaddr_in *  sai  )  [read]

Definition at line 138 of file rudp.c.

References errno, rudpClose(), rudpOpen(), rudp::socket, and warn().

Referenced by rudpMustOpenBound().

00142 {
00143 struct rudp *ru = rudpOpen();
00144 if (ru != NULL)
00145     {
00146     if (bind(ru->socket, (struct sockaddr *)sai, sizeof(*sai)) < 0)
00147         {
00148         warn("Couldn't bind rudp socket: %s", strerror(errno));
00149         rudpClose(&ru);
00150         }
00151     }
00152 return ru;
00153 }

Here is the call graph for this function:

Here is the caller graph for this function:

void rudpPrintStatus ( struct rudp ru  ) 

Definition at line 421 of file rudp.c.

References rudp::failCount, rudp::receiveCount, rudp::resendCount, rudp::rttAve, rudp::rttLast, rudp::rttVary, rudp::sendCount, and rudp::timeOut.

00423 {
00424 printf("rudp status:\n");
00425 printf("  receiveCount %d\n", ru->receiveCount);
00426 printf("  sendCount %d\n", ru->sendCount);
00427 printf("  resendCount %d\n", ru->resendCount);
00428 printf("  failCount %d\n", ru->failCount);
00429 printf("  timeOut %d\n", ru->timeOut);
00430 printf("  rttVary %d\n", ru->rttVary);
00431 printf("  rttAve %d\n", ru->rttAve);
00432 printf("  rttLast %d\n", ru->rttLast);
00433 }

int rudpReceive ( struct rudp ru,
void *  messageBuf,
int  bufSize 
)

Definition at line 414 of file rudp.c.

References rudpReceiveFrom().

00417 {
00418 return rudpReceiveFrom(ru, messageBuf, bufSize, NULL);
00419 }

Here is the call graph for this function:

int rudpReceiveFrom ( struct rudp ru,
void *  messageBuf,
int  bufSize,
struct sockaddr_in *  retFrom 
)

Definition at line 405 of file rudp.c.

References rudpReceiveTimeOut().

Referenced by rudpReceive().

00410 {
00411 return rudpReceiveTimeOut(ru, messageBuf, bufSize, retFrom, 0);
00412 }

Here is the call graph for this function:

Here is the caller graph for this function:

int rudpReceiveTimeOut ( struct rudp ru,
void *  messageBuf,
int  bufSize,
struct sockaddr_in *  retFrom,
int  timeOut 
)

Definition at line 335 of file rudp.c.

References errno, rudp::failCount, readReadyWait(), rudp::receiveCount, rudpAck, rudpData, rudpMaxSize, rudp::socket, rudpHeader::type, udpEthMaxSize, and warn().

Referenced by rudpReceiveFrom().

00342 {
00343 char inBuf[udpEthMaxSize];
00344 struct rudpHeader *head = (struct rudpHeader *)inBuf;
00345 struct rudpHeader ackHead;
00346 struct sockaddr_in sai;
00347 socklen_t saiSize = sizeof(sai);
00348 int readSize, err;
00349 assert(bufSize <= rudpMaxSize);
00350 ru->receiveCount += 1;
00351 for (;;)
00352     {
00353     if (timeOut != 0)
00354         {
00355         if (!readReadyWait(ru->socket, timeOut))
00356             {
00357             warn("rudpReceive timed out\n");
00358             errno = ETIMEDOUT;
00359             return -1;
00360             }
00361         }
00362     readSize = recvfrom(ru->socket, inBuf, sizeof(inBuf), 0, 
00363         (struct sockaddr*)&sai, &saiSize);
00364     if (retFrom != NULL)
00365         *retFrom = sai;
00366     if (readSize < 0)
00367         {
00368         if (errno == EINTR)
00369             continue;
00370         warn("recvfrom error: %s", strerror(errno));
00371         ru->failCount += 1;
00372         return readSize;
00373         }
00374     if (readSize < sizeof(*head))
00375         {
00376         warn("rudpRecieve truncated message");
00377         continue;
00378         }
00379     if (head->type != rudpData)
00380         {
00381         if (head->type != rudpAck)
00382             warn("skipping non-data message %d in rudpReceive", head->type);
00383         continue;
00384         }
00385     ackHead = *head;
00386     ackHead.type = rudpAck;
00387     err = sendto(ru->socket, &ackHead, sizeof(ackHead), 0, 
00388         (struct sockaddr *)&sai, sizeof(sai));
00389     if (err < 0)
00390         {
00391         warn("problem sending ack in rudpRecieve: %s", strerror(errno));
00392         }
00393     readSize -= sizeof(*head);
00394     if (readSize > bufSize)
00395         {
00396         warn("read more bytes than have room for in rudpReceive");
00397         readSize = bufSize;
00398         }
00399     memcpy(messageBuf, head+1, readSize);
00400     break;
00401     }
00402 return readSize;
00403 }

Here is the call graph for this function:

Here is the caller graph for this function:

int rudpSend ( struct rudp ru,
struct sockaddr_in *  sai,
void *  message,
int  size 
)

Definition at line 276 of file rudp.c.

References errno, rudp::failCount, getOurAck(), rudp::lastId, rudp::maxRetries, rudp::resendCount, rudpData, rudpMaxSize, rudpTimedOut(), rudp::sendCount, rudp::socket, rudp::timeOut, udpEthMaxSize, and warn().

00279 {
00280 struct timeval sendTv;  /* Current time. */
00281 
00282 char outBuf[udpEthMaxSize];
00283 struct rudpHeader *head;
00284 int fullSize = size + sizeof(*head);
00285 int i, err = 0, maxRetry = ru->maxRetries;
00286 
00287 
00288 /* Make buffer with header in front of message. 
00289  * At some point we might replace this with a scatter/gather
00290  * iovector. */
00291 ru->sendCount += 1;
00292 assert(size <= rudpMaxSize);
00293 head = (struct rudpHeader *)outBuf;
00294 memcpy(head+1, message, size);
00295 head->id = ++ru->lastId;
00296 head->type = rudpData;
00297 
00298 /* Go into send/wait for ack/retry loop. */
00299 for (i=0; i<maxRetry; ++i)
00300     {
00301     gettimeofday(&sendTv, NULL);
00302     head->sendSec = sendTv.tv_sec;
00303     head->sendMicro = sendTv.tv_usec;
00304     err =  sendto(ru->socket, outBuf, fullSize, 0, 
00305         (struct sockaddr *)sai, sizeof(*sai));
00306     if (err < 0) 
00307         {
00308         /* Warn, wait, and retry. */
00309         struct timeval tv;
00310         warn(" sendto problem %s", strerror(errno));
00311         tv.tv_sec = 0;
00312         tv.tv_usec = ru->timeOut;
00313         select(0, NULL, NULL, NULL, &tv);
00314         ru->resendCount += 1;
00315         rudpTimedOut(ru);
00316         continue;
00317         }
00318     if (getOurAck(ru, &sendTv))
00319         {
00320         return 0;
00321         }
00322     rudpTimedOut(ru);
00323     ru->resendCount += 1;
00324     }
00325 if (err >= 0)
00326     {
00327     err = ETIMEDOUT;
00328     warn("rudpSend timed out");
00329     }
00330 ru->failCount += 1;
00331 return err;
00332 }

Here is the call graph for this function:

void rudpTest (  ) 

Definition at line 435 of file rudp.c.

References ArraySize, rudpAddRoundTripTime(), rudpNew(), and rudp::timeOut.

00437 {
00438 static int times[] = {1000, 200, 200, 100, 200, 200, 200, 400, 200, 200, 200, 200, 1000, 
00439         200, 200, 200, 200};
00440 struct rudp *ru = rudpNew(0);
00441 int i;
00442 
00443 for (i=0; i<ArraySize(times); ++i)
00444     {
00445     int oldTimeOut = ru->timeOut;
00446     rudpAddRoundTripTime(ru, times[i]);
00447     printf("%d\t%d\t%d\t%d\n", i, oldTimeOut, times[i], ru->timeOut);
00448     }
00449 }

Here is the call graph for this function:

static void rudpTimedOut ( struct rudp ru  )  [static]

Definition at line 84 of file rudp.c.

References MAX_TIME_OUT, and rudp::timeOut.

Referenced by rudpSend().

00086 {
00087 ru->timeOut <<=  1;   /* Back off exponentially. */
00088 if (ru->timeOut >= MAX_TIME_OUT)
00089     ru->timeOut = MAX_TIME_OUT;
00090 }

Here is the caller graph for this function:

static int timeDiff ( struct timeval *  t1,
struct timeval *  t2 
) [static]

Definition at line 176 of file rudp.c.

References warn().

Referenced by getOurAck().

00179 {
00180 int secDiff = t2->tv_sec - t1->tv_sec;
00181 int microDiff = 0;
00182 if (secDiff != 0)
00183     microDiff = secDiff * 1000000;
00184 microDiff += (t2->tv_usec - t1->tv_usec);
00185 if (microDiff < 0)
00186     {
00187     /* Note, this case actually happens, currently particularly on
00188      * kkr2u62 and kkr8u19.  I think this is just a bug in their clock
00189      * hardware/software.  However in general it _could_ happen very
00190      * rarely on normal machines when the clock is reset by the
00191      * network time protocol thingie. */
00192     warn("t1 %u.%u, t2 %u.%u.  t1 > t2 but later?!", (unsigned)t1->tv_sec,
00193          (unsigned)t1->tv_usec, (unsigned)t2->tv_sec, (unsigned)t2->tv_usec);
00194     microDiff = 0;
00195     }
00196 return microDiff;
00197 }

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

char const rcsid[] = "$Id: rudp.c,v 1.14 2005/12/12 02:24:47 kent Exp $" [static]

Definition at line 58 of file rudp.c.


Generated on Tue Dec 25 20:15:53 2007 for blat by  doxygen 1.5.2