#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) |
| rudp * | rudpNew (int socket) |
| void | rudpFree (struct rudp **pRu) |
| rudp * | rudpOpen () |
| rudp * | rudpMustOpen () |
| rudp * | rudpOpenBound (struct sockaddr_in *sai) |
| rudp * | rudpMustOpenBound (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 MAX_TIME_OUT 999999 |
| 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.
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 | ) |
| 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:

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