00001 /* rudp - (semi) reliable UDP communication. This adds an 00002 * acknowledgement and resend layer on top of UDP. 00003 * 00004 * UDP is a packet based rather than stream based internet communication 00005 * protocol. Messages sent by UDP are checked for integrety by the UDP layer, 00006 * and discarded if transmission errors are detected. However packets are 00007 * not necessarily received in the same order that they are sent, 00008 * and packets may be duplicated or lost. 00009 00010 * Using rudp packets are only very rarely lost, and the sender is 00011 * notified if they are. After rudp there are still duplicate 00012 * packets that may arrive out of order. Aside from the duplicates 00013 * the packets are in order though. 00014 * 00015 * For many, perhaps most applications, TCP/IP is a saner choice 00016 * than UDP or rudp. If the communication channel is between just 00017 * two computers you can pretty much just treat TCP/IP as a fairly 00018 * reliable pipe. However if the communication involves many 00019 * computers sometimes UDP can be a better choice. It is possible to 00020 * do broadcast and multicast with UDP but not with TCP/IP. Also 00021 * for systems like parasol, where a server may be making and breaking 00022 * connections rapidly to thousands of computers, TCP paradoxically 00023 * can end up less reliable than UDP. Though TCP is relatively 00024 * robust when a connection is made, it can relatively easily fail 00025 * to make a connection in the first place, and spend quite a long 00026 * time figuring out that the connection can't be made. Moreover at 00027 * the end of each connection TCP goes into a 'TIMED_WAIT' state, which 00028 * prevents another connection from coming onto the same port for a 00029 * time that can be as long as 255 seconds. Since there are only 00030 * about 15000 available ports, this limits TCP/IP to 60 connections 00031 * per second in some cases. Generally the system does not handle 00032 * running out of ports gracefully, and this did occur with the 00033 * TCP/IP based version of Parasol. 00034 * 00035 * This module puts a thin layer around UDP to make it a little bit more 00036 * reliable. Currently the interface is geared towards Parasol rather 00037 * than broadcast type applications. This module will try to send 00038 * a message a limited number of times before giving up. It puts 00039 * a small header containing a message ID and timestamp on each message. 00040 * This header is echoed back in acknowledgment by the reciever. This 00041 * echo lets the sender know if it needs to resend the message, and 00042 * lets it know how long a message takes to get to the destination and 00043 * back. It uses this round trip time information to figure out how 00044 * long to wait between resends. 00045 * 00046 * Much of this code is based on the 'Adding Reliability to a UDP Application 00047 * section in volume I, chapter 20, section 5, of _UNIX Network Programming_ 00048 * by W. Richard Stevens. */ 00049 00050 #ifndef RUDP_H 00051 #define RUDP_H 00052 00053 #ifndef INTERNET_H 00054 #include "internet.h" 00055 #endif 00056 00057 struct rudp 00058 /* A UDP socket and a little bit of stuff to help keep track 00059 * of how often we should resend unacknowledged messages. */ 00060 { 00061 int socket; /* The associated UDP socket. */ 00062 int rttLast; /* Last round trip time (RTT) for a message/ack in microseconds. */ 00063 int rttAve; /* Approximate average of recent RTTs. */ 00064 int rttVary; /* Approximate variation of recent RTTs. */ 00065 int timeOut; /* Ideal timeout for next receive. */ 00066 int receiveCount; /* Number of packets attempted to receive. */ 00067 int sendCount; /* Number of packets attempted to send. */ 00068 int resendCount; /* Number of resends. */ 00069 int failCount; /* Number of failures. */ 00070 bits32 lastId; /* Id number of last message sent. */ 00071 int maxRetries; /* Maximum number of retries per message. */ 00072 }; 00073 00074 enum rudpType 00075 { 00076 rudpAck = 199, /* Acknowledge message. */ 00077 rudpData = 200, /* Message with some data. */ 00078 }; 00079 00080 struct rudpHeader 00081 /* The header to a rudp message. */ 00082 { 00083 bits32 id; /* Message id. Returned with ack. */ 00084 bits32 sendSec; /* Time sent in seconds. Returned with ack. */ 00085 bits32 sendMicro; /* Time sent microseconds. Returned with ack. */ 00086 bits8 type; /* One of rudpType above. */ 00087 bits8 reserved1; /* Reserved, always zero for now. */ 00088 bits8 reserved2; /* Reserved, always zero for now. */ 00089 bits8 reserved3; /* Reserved, always zero for now. */ 00090 }; 00091 00092 typedef bits32 rudpHost; /* The IP address (in host order) of another computer. */ 00093 00094 #define udpEthMaxSize 1444 00095 /* Max data size that will fit into a single ethernet packet after UDP and IP 00096 * headers. Things are faster & more reliable if you stay below this */ 00097 00098 #define rudpMaxSize (udpEthMaxSize - sizeof(struct rudpHeader) ) 00099 00100 struct rudp *rudpNew(int socket); 00101 /* Wrap a rudp around a socket. Call rudpFree when done, or 00102 * rudpClose if you also want to close(socket). */ 00103 00104 void rudpFree(struct rudp **pRu); 00105 /* Free up rudp. Note this does *not* close the associated socket. */ 00106 00107 struct rudp *rudpOpen(); 00108 /* Open up an unbound rudp. This is suitable for 00109 * writing to and for reading responses. However 00110 * you'll want to rudpOpenBound if you want to listen for 00111 * incoming messages. Call rudpClose() when done 00112 * with this one. Warns and returns NULL if there is 00113 * a problem. */ 00114 00115 struct rudp *rudpMustOpen(); 00116 /* Open up unbound rudp. Warn and die if there is a problem. */ 00117 00118 struct rudp *rudpOpenBound(struct sockaddr_in *sai); 00119 /* Open up a rudp socket bound to a particular port and address. 00120 * Use this rather than rudpOpen if you want to wait for 00121 * messages at a specific address in a server or the like. */ 00122 00123 struct rudp *rudpMustOpenBound(struct sockaddr_in *sai); 00124 /* Open up a rudp socket bound to a particular port and address 00125 * or die trying. */ 00126 00127 void rudpClose(struct rudp **pRu); 00128 /* Close socket and free memory. */ 00129 00130 int rudpSend(struct rudp *ru, struct sockaddr_in *sai, void *message, int size); 00131 /* Send message of given size to port at host via rudp. Prints a warning and 00132 * sets errno and returns -1 if there's a problem. */ 00133 00134 int rudpReceive(struct rudp *ru, void *messageBuf, int bufSize); 00135 /* Read message into buffer of given size. Returns actual size read on 00136 * success. On failure prints a warning, sets errno, and returns -1. */ 00137 00138 int rudpReceiveFrom(struct rudp *ru, void *messageBuf, int bufSize, 00139 struct sockaddr_in *retFrom); 00140 /* Read message into buffer of given size. Returns actual size read on 00141 * success. On failure prints a warning, sets errno, and returns -1. 00142 * Also returns ip address of message source. */ 00143 00144 int rudpReceiveTimeOut(struct rudp *ru, void *messageBuf, int bufSize, 00145 struct sockaddr_in *retFrom, int timeOut); 00146 /* Like rudpReceive from above, but with a timeOut (in microseconds) 00147 * parameter. If timeOut is zero then it will wait forever. */ 00148 00149 void rudpPrintStatus(struct rudp *ru); 00150 /* Print out status info. */ 00151 00152 void rudpTest(); 00153 /* Test out rudp stuff. */ 00154 00155 #endif /* RUDP_H */
1.5.2