src/vfer_packet.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2005, 2006, Internet2
00003  * Legal conditions are in file LICENSE
00004  * (MD5 = c434f2e53b8089d8b4d0172c7ce07360).
00005  */
00006 /**
00007  * @file   vfer_packet.c
00008  * @author Ivan Beschastnikh
00009  * @brief  Implements packetizing and depacketizing functions.
00010  *
00011  * This file contains usefull functions to compose and decompose
00012  * packets. It also includes some handy utilities for printing packets
00013  * out to stdout.
00014  *
00015  * -     07/26/06        ivan            removed vector ack packet type
00016  * -     12/28/05        ivan            tsci2 integration ; Packet_Set_Header return value bug fix ; packet delay computing func coded
00017  * -     10/16/05        ivan            added Packet_Seq_Set function
00018  * -     10/15/05        ivan            bugfix of rand gen functions and byte ordering functions
00019  * -     09/01/05        ivan            modified to use new packet structures ; coded packet printing functions
00020  * -     08/30/05        ivan            use uint32_t for opts instead of char[3] ; added option interpretation and setting support ; added packet structs
00021  * -     08/29/05        ivan            changed Packet_Read to take and set by ref an error argument
00022  * -     08/28/05        ivan            added many new functions to do packet reading,writing,validation, seq and frame num generation
00023  * -     07/15/05        ivan            new api packet print and form functions added
00024  * -     05/18/05        ivan            created
00025  */
00026 
00027 #include "vfer_packet.h"
00028 
00029 /* private function prototypes */
00030 /* helpers */
00031 static inline int Packet_Set_Header     (packet* p, unsigned char type, uint32_t opts, uint32_t seq);
00032 static inline void Packet_Get_Header    (packet* p); 
00033 static inline void Packet_Get_Type      (char* buf, unsigned char* type);
00034 static inline void Packet_Get_Version   (char* buf, unsigned char* version);
00035 static inline void Packet_Compute_Delay (char* pack_buf, struct timeval* tv, packet* p);
00036 static inline packet* Packet_PrepIov    (int num_bufs, int first_buf_len);
00037 
00038 /* option helper functions */
00039 static inline int Packet_Get_Opt        (uint32_t opts, int opt);
00040 static inline void Packet_Set_Opt       (uint32_t* opts, int opt);
00041 static inline void Packet_Unset_Opt     (uint32_t* opts, int opt);
00042 
00043 /****************************************************************
00044  * PRINTING FUNCTIONS
00045  ****************************************************************/
00046 
00047 /**
00048  * String type of packet
00049  * @param p packet pointer
00050  * @return 
00051  *      string describing the type of the packet parameter
00052  */
00053 char* Packet_Str_Type(packet* p) {
00054         switch (p->type) {
00055         case REQUEST:
00056                 return "REQUEST";
00057         case RESPONSE:
00058                 return "RESPONSE";
00059         case DATA:
00060                 return "DATA";
00061         case CC_ACK:
00062                 return "CC_ACK";
00063         case CLOSE:
00064                 return "CLOSE";
00065         default:
00066                 return "UNKNOWN";
00067         }
00068 } /* Packet_Str_Type() */
00069 
00070 /**
00071  * Create a string description of the packet
00072  * @param p packet pointer
00073  * @return string describing the packet parameter
00074  */
00075 char* Packet_Str(packet* p) {
00076         char* str;
00077         str = (char*)malloc(1024);      /* 1024 should be enough... */
00078 
00079         sprintf(str, "%u %s [%d us] opt[%u] v[%u] ", p->seq, Packet_Str_Type(p), p->delay, p->opts, p->version);
00080         switch (p->type) {
00081         case REQUEST:
00082                 sprintf(str + strlen(str), "max_frame_len[%u] rcv_buf[%u] snd_buf[%u] init_frame[%u]",
00083                         p->u.req.max_frame_size, p->u.req.recv_buf_size, p->u.req.send_buf_size, p->u.req.init_frame_num);
00084                 break;
00085         case RESPONSE:
00086                 sprintf(str + strlen(str), "max_frame_len[%u] rcv_buf[%u] snd_buf[%u] init_frame[%u] port[%u] req_delay[%d]",
00087                         p->u.res.max_frame_size, p->u.res.recv_buf_size, p->u.res.send_buf_size, p->u.res.init_frame_num, p->u.res.connection_port, p->u.res.request_delay); 
00088                 break;
00089         case DATA:
00090                 sprintf(str + strlen(str), "frame[%u] data_offset[%u] frame_len[%u] data_len[%u]",
00091                         p->u.data.frame_num, p->u.data.data_offset, p->u.data.frame_len, p->u.data.data_len);
00092                 break;
00093         case CC_ACK:
00094                 sprintf(str + strlen(str), "last_seq[%u] lost[%u] oldest_f[%u] newest_f[%u] dlay_dlta[%d] dlay[%d] bytes[%d]", p->u.ccack.last_seq, p->u.ccack.packets_lost, p->u.ccack.oldest_frame, p->u.ccack.newest_frame, p->u.ccack.delay_delta, p->u.ccack.delay, p->u.ccack.bytes_total);
00095                 if (Packet_Get_Opt(p->opts, OPT_VEC)) {
00096                         sprintf(str + strlen(str), " intervals_frame[%u] num_intervals[%d]", p->u.ccack.intervals_frame_num, p->u.ccack.interval_count);
00097                 }
00098                 break;
00099         }
00100         return str;
00101 } /* Packet_Str() */
00102 
00103 /**
00104  * Prints a description of the packet onto stdout
00105  * @param p packet pointer
00106  */
00107 void Packet_Print (packet* p) {
00108         char* str;
00109         str = Packet_Str(p);
00110         printf("%s", str);
00111         free(str);
00112 } /* Packet_Print() */
00113         
00114 /****************************************************************
00115  * FORMATION FUNCTIONS (return a void* buffer network byte ordered and
00116  * ready for transmission ; and sets a reference param to length of
00117  * the buffer)
00118  ****************************************************************/
00119 
00120 /**
00121  * Forms a Request packet
00122  *
00123  * @param opts          options for the generic header of the packet
00124  * @param init_seq_num  initial sequence number for the sender's half of connection
00125  * @param max_frame_size maximum frame size the sender is willing to receive
00126  * @param recv_buf_size receive buffer size at the sender
00127  * @param send_buf_size sending buffer size at the sender
00128  * @param init_frame_num initial frame number for the sender's half of connection
00129  *
00130  * @return 
00131  *      NULL on error
00132  *      pointer to an allocated packet on success
00133  */
00134 packet* Packet_Form_Request(uint32_t opts, uint32_t init_seq_num,
00135                             uint32_t max_frame_size, uint32_t recv_buf_size,
00136                             uint32_t send_buf_size, uint16_t init_frame_num) {
00137         char* buf;
00138         int offset;
00139         packet* p;
00140 
00141         if ((p = Packet_PrepIov(1, REQUEST_LENGTH)) == NULL) return NULL;
00142 
00143         buf = p->iov[0].iov_base;
00144         offset = Packet_Set_Header(p, REQUEST, opts, init_seq_num);
00145         
00146         p->u.req.max_frame_size = max_frame_size;
00147         max_frame_size = htonl(max_frame_size);
00148         memcpy(buf + offset, &max_frame_size, 4);
00149         
00150         p->u.req.recv_buf_size = recv_buf_size;
00151         recv_buf_size = htonl(recv_buf_size);
00152         memcpy(buf + offset + 4, &recv_buf_size, 4);
00153 
00154         p->u.req.send_buf_size = send_buf_size;
00155         send_buf_size = htonl(send_buf_size);
00156         memcpy(buf + offset + 8, &send_buf_size, 4);
00157 
00158         p->u.req.init_frame_num = init_frame_num;
00159         init_frame_num = htons(init_frame_num);
00160         memcpy(buf + offset + 12, &init_frame_num, 2);
00161 
00162         return p;
00163 } /* Packet_Form_Request() */
00164 
00165 
00166 /**
00167  * Forms a Response packet
00168  *
00169  * @param opts          options for the generic header of the packet
00170  * @param init_seq_num  initial sequence number for the sender's half of connection
00171  * @param init_frame_num initial frame number for the sender's half of connection
00172  * @param connection_port the connection port to which the sender
00173  *                        should connect and use for the remained of this connection
00174  * @param max_frame_size maximum frame size the sender is willing to receive
00175  * @param recv_buf_size receive buffer size at the sender
00176  * @param send_buf_size sending buffer size at the sender
00177  * @param request_delay the delay computed for the request packet
00178  *
00179  * @return 
00180  *      NULL on error
00181  *      pointer to an allocated packet on success
00182  */
00183 packet* Packet_Form_Response(uint32_t opts, uint32_t init_seq_num, uint16_t init_frame_num,
00184                            uint16_t connection_port, uint32_t max_frame_size,
00185                            uint32_t recv_buf_size, uint32_t send_buf_size, int32_t request_delay) {
00186         char* buf;
00187         int offset;
00188         packet* p;
00189 
00190         if ((p = Packet_PrepIov(1, RESPONSE_LENGTH)) == NULL) return NULL;
00191 
00192         buf = p->iov[0].iov_base;
00193         offset = Packet_Set_Header(p, RESPONSE, opts, init_seq_num);
00194         
00195         p->u.res.init_frame_num = init_frame_num;
00196         init_frame_num = htons(init_frame_num);
00197         memcpy(buf + offset, &init_frame_num, 2);
00198 
00199         p->u.res.connection_port = connection_port;
00200         connection_port = htons(connection_port);
00201         memcpy(buf + offset + 2, &connection_port, 2);
00202 
00203         p->u.res.max_frame_size = max_frame_size;
00204         max_frame_size = htonl(max_frame_size);
00205         memcpy(buf + offset + 4, &max_frame_size, 4);
00206 
00207         p->u.res.recv_buf_size = recv_buf_size;
00208         recv_buf_size = htonl(recv_buf_size);
00209         memcpy(buf + offset + 8, &recv_buf_size, 4);
00210 
00211         p->u.res.send_buf_size = send_buf_size;
00212         send_buf_size = htonl(send_buf_size);
00213         memcpy(buf + offset + 12, &send_buf_size, 4);
00214 
00215         p->u.res.request_delay = request_delay;
00216         request_delay = htonl(request_delay);
00217         memcpy(buf + offset + 16, &request_delay, 4);
00218 
00219         return p;
00220 } /* Packet_Form_Response() */
00221 
00222 
00223 /**
00224  * Forms a Data packet
00225  *
00226  * @param opts          options for the generic header of the packet
00227  * @param seq_num       sequence number for the generic header of the packet
00228  * @param frame_num     frame number this data packet carries a frag for
00229  * @param data_offset   offset of the data in the frame
00230  * @param frame_len     either -1 (do not include in the data header)
00231  *                      (opts will be set and send accordingly) or is not -1,
00232  *                      in which case it is included in the data header
00233  * @param data          data buffer to send in the body of the data packet
00234  * @param data_len      tells us how the span of the data buffer pointed to by the data arg
00235  *
00236  * @return 
00237  *      NULL on error
00238  *      pointer to an allocated packet on success
00239  */
00240 packet* Packet_Form_Data(uint32_t opts, uint32_t seq_num, uint16_t frame_num,
00241                          uint32_t data_offset, uint32_t frame_len, void* data, int data_len) {
00242         char* buf;
00243         int offset;
00244         packet* p;
00245 
00246         if (frame_len != -1) {
00247                 if ((p = Packet_PrepIov(2, DATA_LENGTH)) == NULL) return NULL;
00248                 Packet_Set_Opt(&opts, OPT_FRAME_LEN);
00249         } else {
00250                 if ((p = Packet_PrepIov(2, DATA_LENGTH)) == NULL) return NULL;
00251                 Packet_Unset_Opt(&opts, OPT_FRAME_LEN);
00252         }
00253         buf = p->iov[0].iov_base;
00254         offset = Packet_Set_Header(p, DATA, opts, seq_num);
00255         
00256         p->u.data.frame_num = frame_num;
00257         frame_num = htons(frame_num);
00258         memcpy(buf + offset, &frame_num, 2);
00259         offset += 2;
00260         
00261         p->u.data.data_offset = data_offset;
00262         data_offset = htonl(data_offset);
00263         memcpy(buf + offset, &data_offset, 4);
00264         offset += 4;
00265         
00266         if (frame_len != -1) {
00267                 p->u.data.frame_len = frame_len;
00268                 frame_len = htonl(frame_len);
00269                 memcpy(buf + offset, &frame_len, 4);
00270                 offset += 4;
00271         } else {
00272                 offset += 4; /* just skip the space for now */
00273         }
00274         
00275         p->u.data.data          = data;
00276         p->u.data.data_len      = data_len;
00277         /* no data copying here */
00278         p->iov[1].iov_base      = data;
00279         p->iov[1].iov_len       = data_len;
00280 
00281         DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Form_Data", "iov[0]: %d ; iov[1]: %d ; frame_len[%u]", (int)(p->iov[0].iov_len), (int)(p->iov[1].iov_len), ntohl(frame_len)); 
00282         return p;
00283 } /* Packet_Form_Data() */
00284 
00285 /**
00286  * Forms a CC Ack packet
00287  *
00288  * @param opts          options for the generic header of the packet
00289  * @param seq_num       sequence number for the generic header of the packet
00290  * @param last_seq_received     last sequence number received by this connection
00291  * @param packets_lost  estimated lost number of frags
00292  * @param oldest_frame  oldest frame the received of this packet should resend
00293  * @param newest_frame  oldest frame the received of this packet should resend
00294  * @param delay_delta   current delay on the reverse path (not the path of this ack)
00295  * @param delay         current delay for the reverse path
00296  * @param bytes_total   total data bytes received by the endpoint
00297  * @param intervals_frame_num   the frame number corresponding to the missing data intervals
00298  * @param intervals     intervals structure (defined in datagram.h) If intervals->head == 0 then no intervals will be sent in the ack packet
00299  *
00300  * @return 
00301  *      NULL on error
00302  *      pointer to an allocated packet on success
00303  */
00304 packet* Packet_Form_CCAck(uint32_t opts, uint32_t seq_num, uint32_t last_seq_received,
00305                           uint16_t packets_lost, uint16_t oldest_frame, uint16_t newest_frame,
00306                           int32_t delay_delta, int32_t delay, uint32_t bytes_total,
00307                           uint16_t intervals_frame_num, intervals_t* intervals) {
00308         char* buf;
00309         int offset;
00310         packet* p;
00311         interval_t* current;
00312         uint32_t tmp;
00313 
00314         if (intervals != NULL) {
00315 //              printf("setting OPT_VEC\n");
00316                 if (intervals->head != NULL) {
00317 //                      printf("intervals->head != NULL ; setting up iov buffer[%d]\n", CCACK_LENGTH + 8*intervals->count + 6);
00318                         // 4*(2*intervals->count)+2+4
00319                         // 52 = 8 + 6 = 14 + 38 (ccack_length)
00320                         if ((p = Packet_PrepIov(1, CCACK_LENGTH + 8*intervals->count + 6)) == NULL) return NULL;
00321                 } else {
00322 //                      printf("intervals->head == NULL ; setting up iov buffer[%d]\n", CCACK_LENGTH + 14);
00323                         // 4*(2)+2+4
00324                         if ((p = Packet_PrepIov(1, CCACK_LENGTH + 14)) == NULL) return NULL;
00325                 }
00326                 Packet_Set_Opt(&opts, OPT_VEC);
00327         } else { 
00328                 if ((p = Packet_PrepIov(1, CCACK_LENGTH)) == NULL) return NULL;
00329         }
00330         buf = p->iov[0].iov_base;
00331         
00332         offset = Packet_Set_Header(p, CC_ACK, opts, seq_num);
00333         
00334         p->u.ccack.last_seq = last_seq_received;
00335         last_seq_received = htonl(last_seq_received);
00336         memcpy(buf + offset, &last_seq_received, 4);
00337 
00338         p->u.ccack.packets_lost = packets_lost;
00339         packets_lost = htons(packets_lost);
00340         memcpy(buf + offset + 4, &packets_lost, 2);
00341 
00342         p->u.ccack.oldest_frame = oldest_frame;
00343         oldest_frame = htons(oldest_frame);
00344         memcpy(buf + offset + 6, &oldest_frame, 2);
00345         
00346         p->u.ccack.newest_frame = newest_frame;
00347         newest_frame = htons(newest_frame);
00348         memcpy(buf + offset + 8, &newest_frame, 2);
00349 
00350         p->u.ccack.delay_delta = delay_delta;
00351         delay_delta = htonl(delay_delta);
00352         memcpy(buf + offset + 10, &delay_delta, 4);
00353 
00354         p->u.ccack.delay = delay;
00355         delay = htonl(delay);
00356         memcpy(buf + offset + 14, &delay, 4);
00357 
00358 //      printf("** sending delay [%d]\n", p->u.ccack.delay);
00359         
00360         p->u.ccack.bytes_total = bytes_total;
00361         bytes_total = htonl(bytes_total);
00362         memcpy(buf + offset + 18, &bytes_total, 4);
00363         
00364         if (intervals != NULL) {
00365 //              printf("sending intervals_frame_num[%d] ", intervals_frame_num);
00366                 if (intervals->head != NULL) {
00367                         //printf(" interval_count[%d]\n", intervals->count);
00368                         p->u.ccack.interval_count = intervals->count;
00369                         p->u.ccack.intervals_frame_num = intervals_frame_num;
00370                         intervals_frame_num = htons(intervals_frame_num);
00371                         memcpy(buf + offset + 22, &intervals_frame_num, 2);
00372                         
00373                         tmp = htonl(intervals->count);
00374                         memcpy(buf + offset + 24, &tmp, 4);
00375                         offset += 28;
00376                         
00377                         current = intervals->head;
00378                         //printf("ccack intervals: ");
00379                         while (current != NULL) {
00380                                 //printf("writing to offset[%d]\n", offset);
00381                                 tmp = htonl(current->start);
00382                                 memcpy(buf + offset, &tmp, 4);
00383                                 tmp = htonl(current->end);
00384                                 //printf("writing to offset+4[%d]\n", offset+4);
00385                                 memcpy(buf + offset + 4, &tmp, 4);
00386                                 offset += 8;
00387                                 // printf("[%d %d] ", current->start, current->end);
00388                                 current = current->next;
00389                         } 
00390                         // printf("\n"); 
00391                 } else {
00392                         // printf(" interval_count[0!]\n");
00393                         p->u.ccack.interval_count = 0;
00394                         p->u.ccack.intervals_frame_num = intervals_frame_num;
00395                         intervals_frame_num = htons(intervals_frame_num);
00396                         memcpy(buf + offset + 22, &intervals_frame_num, 2);
00397                         tmp = htonl(1);
00398                         memcpy(buf + offset + 24, &tmp, 4);
00399                         tmp = 0;
00400                         memcpy(buf + offset + 28, &tmp, 4);
00401                         memcpy(buf + offset + 32, &tmp, 4);
00402                 }
00403         }
00404         return p;
00405 } /* Packet_Form_CCAck() */
00406 
00407 /**
00408  * Forms a Close packet
00409  *
00410  * @param opts          options for the generic header of the packet
00411  * @param seq_num       sequence number for the generic header of the packet
00412  *
00413  * @return 
00414  *      NULL on error
00415  *      pointer to an allocated packet on success
00416  */
00417 packet* Packet_Form_Close(uint32_t opts, uint32_t seq_num) {
00418         packet* p;
00419         if ((p = Packet_PrepIov(1, CLOSE_LENGTH)) == NULL) return NULL;
00420         Packet_Set_Header(p, CLOSE, opts, seq_num);
00421         return p;
00422 } /* Packet_Form_Close() */
00423 
00424 /****************************************************************
00425  * TRANSLATION FUNCTIONS (translate a void* buf of correct length into
00426  * references passed as args)
00427  ****************************************************************/
00428 
00429 /**
00430  * Fills in the request union memeber with values from a raw packet
00431  *
00432  * @param p packet pointer to traslate
00433  * @return
00434  *      0 on success
00435  *      -1 packet with incorrect length
00436  */
00437 int Packet_Translate_Request(packet* p) {
00438         char* buf = p->iov[0].iov_base;
00439         int offset = TOPH_LENGTH;
00440         
00441         if (p->iov[0].iov_len != REQUEST_LENGTH) return -1;
00442         Packet_Get_Header(p);
00443         
00444         memcpy(&(p->u.req.max_frame_size), buf + offset, 4);
00445         p->u.req.max_frame_size = ntohl(p->u.req.max_frame_size);
00446 
00447         memcpy(&(p->u.req.recv_buf_size), buf + offset + 4, 4);
00448         p->u.req.recv_buf_size = ntohl(p->u.req.recv_buf_size);
00449 
00450         memcpy(&(p->u.req.send_buf_size), buf + offset + 8, 4);
00451         p->u.req.send_buf_size = ntohl(p->u.req.send_buf_size);
00452 
00453         memcpy(&(p->u.req.init_frame_num), buf + offset + 12, 2);
00454         p->u.req.init_frame_num = ntohs(p->u.req.init_frame_num);
00455         return 0;
00456 } /* Packet_Translate_Request() */
00457 
00458 /**
00459  * Fills in the response union memeber with values from a raw packet
00460  *
00461  * @param p packet pointer to traslate
00462  * @return
00463  *      0 on success
00464  *      -1 packet with incorrect length
00465  */
00466 int Packet_Translate_Response(packet* p) {
00467         char* buf = p->iov[0].iov_base;
00468         int offset = TOPH_LENGTH;
00469         
00470         if (p->iov[0].iov_len != RESPONSE_LENGTH) return -1;
00471         Packet_Get_Header(p);
00472 
00473         memcpy(&(p->u.res.init_frame_num), buf + offset, 2);
00474         p->u.res.init_frame_num = ntohs(p->u.res.init_frame_num);
00475 
00476         memcpy(&(p->u.res.connection_port), buf + offset + 2, 2);
00477         p->u.res.connection_port = ntohs(p->u.res.connection_port);
00478 
00479         memcpy(&(p->u.res.max_frame_size), buf + offset + 4, 4);
00480         p->u.res.max_frame_size = ntohl(p->u.res.max_frame_size);
00481 
00482         memcpy(&(p->u.res.recv_buf_size), buf + offset + 8, 4);
00483         p->u.res.recv_buf_size = ntohl(p->u.res.recv_buf_size);
00484 
00485         memcpy(&(p->u.res.send_buf_size), buf + offset + 12, 4);
00486         p->u.res.send_buf_size = ntohl(p->u.res.send_buf_size);
00487 
00488         memcpy(&(p->u.res.request_delay), buf + offset + 16, 4);
00489         p->u.res.request_delay = ntohl(p->u.res.request_delay);
00490         
00491         return 0;
00492 } /* Packet_Translate_Response() */
00493 
00494 /**
00495  * Fills in the data union memeber with values from a raw packet
00496  *
00497  * @param p packet pointer to traslate
00498  * @return
00499  *      0 on success
00500  *      -1 packet with incorrect length
00501  */
00502 int Packet_Translate_Data(packet* p) {
00503         char* buf = p->iov[0].iov_base;
00504         int offset = TOPH_LENGTH;
00505         
00506         if (p->iov[0].iov_len < DATA_LENGTH) return -1;
00507         Packet_Get_Header(p);
00508 
00509         memcpy(&(p->u.data.frame_num), buf + offset, 2);
00510         p->u.data.frame_num = ntohs(p->u.data.frame_num);
00511         offset += 2;
00512         
00513         memcpy(&(p->u.data.data_offset), buf + offset, 4);
00514         p->u.data.data_offset = ntohl(p->u.data.data_offset);
00515         offset += 4;
00516         
00517         /* evaluate opts to see if the option for frame_len is set or not */
00518         if (Packet_Get_Opt(p->opts, OPT_FRAME_LEN) == 1) {
00519                 memcpy(&(p->u.data.frame_len), buf + offset, 4);
00520                 p->u.data.frame_len = ntohl(p->u.data.frame_len);
00521                 offset += 4;
00522         } else {
00523                 p->u.data.frame_len = 0;
00524                 offset += 4; /* just skip the space for now */
00525         }
00526 
00527         /* data_len should depend on whether this packet is carrying
00528          * the frame_len field */
00529         p->u.data.data_len = p->iov[0].iov_len - offset;
00530         p->u.data.data = buf + offset;
00531         DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Translate_Data", "len[%d] ; offset[%d] ; data_len[%u]\n", (int)(p->iov[0].iov_len), offset, (int)(p->u.data.data_len));
00532         return 0;
00533 } /* Packet_Translate_Data() */
00534 
00535 /**
00536  * Fills in the cc_ack union memeber with values from a raw packet
00537  *
00538  * @param p packet pointer to traslate
00539  * @return
00540  *      0 on success
00541  *      -1 packet with incorrect length
00542  */
00543 int Packet_Translate_CCAck(packet* p) {
00544         char* buf = p->iov[0].iov_base;
00545         int offset = TOPH_LENGTH;
00546         
00547         if (p->iov[0].iov_len < CCACK_LENGTH) return -1;
00548         Packet_Get_Header(p);
00549 
00550         memcpy(&(p->u.ccack.last_seq), buf + offset, 4);
00551         p->u.ccack.last_seq = ntohl(p->u.ccack.last_seq);
00552 
00553         memcpy(&(p->u.ccack.packets_lost), buf + offset + 4, 2);
00554         p->u.ccack.packets_lost = ntohs(p->u.ccack.packets_lost);
00555         
00556         memcpy(&(p->u.ccack.oldest_frame), buf + offset + 6, 2);
00557         p->u.ccack.oldest_frame = ntohs(p->u.ccack.oldest_frame);
00558 
00559         memcpy(&(p->u.ccack.newest_frame), buf + offset + 8, 2);
00560         p->u.ccack.newest_frame = ntohs(p->u.ccack.newest_frame);
00561 
00562         memcpy(&(p->u.ccack.delay_delta), buf + offset + 10, 4);
00563         p->u.ccack.delay_delta = ntohl(p->u.ccack.delay_delta);
00564 
00565         memcpy(&(p->u.ccack.delay), buf + offset + 14, 4);
00566         p->u.ccack.delay = ntohl(p->u.ccack.delay);
00567 
00568 //      printf("** received delay [%d]\n", p->u.ccack.delay);
00569 
00570         memcpy(&(p->u.ccack.bytes_total), buf + offset + 18, 4);
00571         p->u.ccack.bytes_total = ntohl(p->u.ccack.bytes_total);
00572         
00573         if (Packet_Get_Opt(p->opts, OPT_VEC)) {
00574 //              printf("OPT_VEC is set\n");
00575                 memcpy(&(p->u.ccack.intervals_frame_num), buf + offset + 22, 2);
00576                 p->u.ccack.intervals_frame_num = ntohs(p->u.ccack.intervals_frame_num);
00577                 
00578                 memcpy(&(p->u.ccack.interval_count), buf + offset + 24, 4);
00579                 p->u.ccack.interval_count = ntohl(p->u.ccack.interval_count);
00580 
00581                 // printf("received intervals_frame_num[%d] and interval_count[%d]\n",
00582                 //p->u.ccack.intervals_frame_num, p->u.ccack.interval_count);
00583                 
00584                 p->u.ccack.raw_intervals = (uint32_t*)(buf + offset + 28);
00585         } else {
00586                 p->u.ccack.intervals_frame_num = 0;
00587                 p->u.ccack.interval_count = 0;
00588                 p->u.ccack.raw_intervals = NULL;
00589         } 
00590         return 0;
00591 } /* Packet_Translate_CCAck() */
00592 
00593 /**
00594  * Fills in the close union memeber with values from a raw packet
00595  *
00596  * @param p packet pointer to traslate
00597  * @return
00598  *      0 on success
00599  *      -1 packet with incorrect length
00600  */
00601 int Packet_Translate_Close(packet* p) {
00602         if (p->iov[0].iov_len != CLOSE_LENGTH) return -1;
00603         Packet_Get_Header(p);
00604         return 0;
00605 } /* Packet_Translate_Close() */
00606 
00607 /****************************************************************
00608  * Helper functions
00609  ****************************************************************/
00610 
00611 /**
00612  * Sets the sequence number in the packet header
00613  *
00614  * @param p pointer to the packet in which to set the header
00615  * @param seq sequence number to set in the header
00616  */
00617 
00618 inline void Packet_Set_Seq(packet* p, uint32_t seq) {
00619         char* buf = p->iov[0].iov_base;
00620         /* seq */
00621         p->seq = seq;
00622         seq = htonl(seq);
00623         memcpy(buf + 4, &(seq), 4);
00624 }
00625 
00626 /**
00627  * Sets the packet header into a packet buffer
00628  *
00629  * @param p pointer to the packet in which to set the header
00630  * @param type type of packet
00631  * @param opts opts to store in packet
00632  * @param seq sequence number to set in packet
00633  *
00634  * @return
00635  *      number of bytes of buf that are used by the header
00636  */
00637 static inline int Packet_Set_Header(packet* p, unsigned char type, uint32_t opts, uint32_t seq) {
00638         /* type[s] + VFER_VERSION (global vars defined in globals.h) */
00639         char* buf = p->iov[0].iov_base;
00640 
00641         p->type = type;
00642         p->version = VFER_VERSION;
00643         p->opts = opts;
00644 //      printf("SET_HEADER0: opts: %x\n", p->opts);
00645         opts = opts | ((0xF0000000 & (p->type << 24)) | (0x0F000000 & (p->version << 24)));
00646 //      printf("SET_HEDAER1: opts: %x\n", p->opts);
00647         /* opts */
00648         opts = htonl(opts);
00649         memcpy(buf, &(opts), 4);
00650         /* seq */
00651         Packet_Set_Seq(p, seq);
00652         return TOPH_LENGTH;
00653 } /* Packet_Set_Header() */
00654 
00655 /**
00656  * Gets the packet header from a packet buffer and writes into the packet structure
00657  * @param p pointer to the packet in which get and get the header
00658  */
00659 static inline void Packet_Get_Header(packet* p) {
00660         uint32_t tmp;
00661         char* buf = p->iov[0].iov_base;
00662         
00663         /* type + version */
00664         Packet_Get_Type(buf, &(p->type));
00665         Packet_Get_Version(buf, &(p->version));
00666 
00667         /* opts */
00668         memcpy(&(tmp), buf, 4);
00669         ((char*)(&tmp))[0] = 0; /* because network byte order is big endian, otherwise it would be [3]=0 */
00670         tmp = ntohl(tmp);
00671         p->opts = 0;
00672         memcpy(&(p->opts), &tmp, 4);
00673         
00674         /* seq */
00675         memcpy(&(p->seq), buf + 4, 4);
00676         p->seq = ntohl(p->seq);
00677         
00678 } /* Packet_Get_Header() */
00679 
00680 /**
00681  * Extracts the type in a bufer interpreted as packet header
00682  *
00683  * @param buf packet buffer
00684  * @param type reference arg type of packet
00685  */
00686 static inline void Packet_Get_Type(char* buf, unsigned char* type) {
00687         /* type */
00688         uint32_t tmp;
00689         memcpy(&(tmp), buf, 4);
00690         tmp = ntohl(tmp);
00691         *type   = (tmp & 0xF0000000) >> 24;
00692 } /* Packet_Get_Type() */
00693 
00694 /**
00695  * Extracts the version in a buffer interpreted as packet header
00696  *
00697  * @param buf packet buffer
00698  * @param version reference argument into which the version will be stored
00699  */
00700 static inline void Packet_Get_Version(char* buf, unsigned char* version) {
00701         /* version */
00702         uint32_t tmp;
00703         memcpy(&(tmp), buf, 4);
00704         tmp = ntohl(tmp);
00705         *version = (tmp & 0x0F000000) >> 24;
00706 } /* Packet_Get_Version() */
00707 
00708 /**
00709  * Computes the delay for a packet based on the raw packet buffer,
00710  * sets the value computed in the packet structure and also extracts
00711  * the time stamp from the raw packet buffer into the structure
00712  *
00713  * @param pack_buf raw packet buffer
00714  * @param tv time structure marking receipt time for the packet
00715  * @param p packet structure for the packet buffer
00716  */
00717 static inline void Packet_Compute_Delay(char* pack_buf, struct timeval* tv, packet* p) {
00718         uint32_t tmp;
00719         int micro;
00720         memcpy(&(tmp), pack_buf + 8, 4);
00721         tmp = ntohl(tmp);
00722         p->tv_sec = tmp;
00723         memcpy(&(tmp), pack_buf + 12, 4);
00724         tmp = ntohl(tmp);
00725         p->tv_usec = tmp;
00726 //      printf("computing delay with sent:[%d,%d] received:[%d,%d]: ", (int)p->tv_sec, (int)p->tv_usec, (int)tv->tv_sec, (int)tv->tv_usec);
00727         /* micro contains the microseconds delay difference */
00728         micro = (int)(((int)p->tv_usec - (int)tv->tv_usec));
00729         p->delay = (int32_t)((((int)p->tv_sec - (int)tv->tv_sec) * 1000000) + micro);
00730         if (p->delay == 0) {
00731                 /* avoid delay of 0us */
00732                 if (((int)p->tv_usec - (int)tv->tv_usec) < 0)
00733                         p->delay = -1;
00734                 else
00735                         p->delay = 1;
00736         }
00737 }
00738 
00739 /**
00740  * Prepares the iov strucutre for a packet
00741  *
00742  * @param num_bufs number of iov buffers to allocate
00743  * @param first_buf_len length of the first buffer to allocate
00744  * @return
00745  *      NULL on error
00746  *      newly allocated packet pointer with allocated buffers
00747  */
00748 static inline packet* Packet_PrepIov(int num_bufs, int first_buf_len) {
00749         char* buf;
00750         packet* p;
00751         if (ALLOC(p, struct packet*, struct packet, 1)== NULL) return NULL;
00752         if (ALLOC(p->iov, struct iovec*, struct iovec, num_bufs)== NULL) {
00753                 RELEASE(p, sizeof(packet));
00754                 return NULL;
00755         }
00756         if (ALLOC(buf, char*, char, first_buf_len) == NULL) {
00757                 RELEASE(p->iov, sizeof(struct iovec));
00758                 RELEASE(p, sizeof(packet));
00759                 return NULL;
00760         }
00761         p->iov[0].iov_base      = buf;
00762         p->iov[0].iov_len       = first_buf_len;
00763         p->iovlen               = num_bufs;
00764         return p;
00765 } /* Packet_PrepIov() */
00766 
00767 /**
00768  * Reads from a file descriptor into an iov buffer.
00769  *
00770  * Does minor validation of the generic header. Returns either an
00771  * error or the packet_type of the received packet. Set iov as return
00772  * by reference.
00773  *
00774  * @param fd file descriptor to which to write the buffer
00775  * @param p packet strucutre to read the packet into
00776  * @param addr pointer that is either NULL or address to which we send the iov
00777  * @param addr_len pointer to be set by reference to length of addr param
00778  * @return 
00779  *      0 on success (p contains a valid packet)
00780  *      errno on syscall error
00781  *      -1 received packet has incorrect length (validation err)
00782  *      -2 received packet has incorrect type (validation err)
00783  *      -3 received packet has incorrect version (validation err)
00784  *      -4 on unknown packet type
00785  *      -5 on error (shutdown socket)
00786  *      -6 on error (ALLOC macro)
00787  *      -7 on error (other) - such as mismatched recv sizes (see below)
00788  */
00789 int Packet_Read(int fd, packet** p, struct sockaddr* addr, socklen_t* addr_len) {
00790         int n;
00791         unsigned char packet_type;
00792         unsigned char packet_version;
00793         int ret;
00794         struct timeval tv;
00795         int err_val_len;
00796         int err_val;
00797 
00798         /* quit if there is a pending error on this socket */
00799         err_val_len = 4;
00800         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err_val, &err_val_len) == -1) perror("Packet_Read :: getsockopt");
00801         if (err_val != 0) {
00802                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "socket has a pending error[%d]:[%s]", err_val, strerror(err_val));
00803                 return err_val;
00804         }
00805         
00806         /* read packet into a temporary buffer of max UDP packet length */
00807         n = recvfrom(fd, pack_buf, 65535, MSG_DONTWAIT, addr, addr_len);
00808 
00809         // DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "fd[%d] recvfrom returned %d", fd, n);
00810         // DEBUG_PRINT(1, "packet.c", "Packet_Read", "fd[%d] recvfrom returned %d", fd, n);
00811 
00812         /* mark receipt time */
00813         GET_TIME_OF_DAY(&(tv));
00814         
00815         if (n == -1) {
00816                 ret = errno;
00817                 if (ret != EAGAIN) {
00818                         perror("packet_read :: recvfrom");
00819                 }
00820                 return ret;
00821         } else if (n == 0) {
00822                 return -5;
00823         }
00824 
00825         Packet_Get_Type(pack_buf, &packet_type);
00826         Packet_Get_Version(pack_buf, &packet_version);
00827         //DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "Received: bytes[%d] type[%d] version[%d]", n, (int)(packet_type), (int)(packet_version));
00828 
00829         /* discard incorrect packets */
00830         if (packet_version != VFER_VERSION) {
00831                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "received packet with bad version: version[%d] ; my version[%d]", packet_version, VFER_VERSION);
00832                 return -3;
00833         } else if (packet_type != REQUEST       &&
00834                    packet_type != RESPONSE      &&
00835                    packet_type != DATA          &&
00836                    packet_type != CC_ACK        && 
00837                    packet_type != DATA_ACK      &&
00838                    packet_type != CLOSE) {
00839                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "received packet with bad type: type[%d]", (int)(packet_type));
00840                 return -2;
00841         }           
00842         
00843         /* allocate the packet structure to hold the received packet */
00844         if (ALLOC(*p, struct packet*, struct packet, 1) == NULL) {
00845                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "could not allocate packet");
00846                 return -6;
00847         }
00848         if (ALLOC((*p)->iov, struct iovec*, struct iovec, 1) == NULL) { 
00849                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "could not allocate iovec array of size 1");
00850                 RELEASE((*p), sizeof(struct packet));
00851                 return -6;
00852         }
00853         if (ALLOC((*p)->iov[0].iov_base, char*, char, n) == NULL) { 
00854                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "could not allocate %d bytes", n);
00855                 RELEASE((*p)->iov, sizeof(struct iovec));
00856                 RELEASE((*p), sizeof(struct packet));
00857                 return -6;
00858         }
00859         
00860         /* copy packet from tmp buffer to persistent mem buffer */
00861         (*p)->iov[0].iov_len    = n;
00862         (*p)->iovlen            = 1;
00863         memcpy((*p)->iov[0].iov_base, pack_buf, n);
00864 
00865         /* interpret the packet */
00866         switch (packet_type) {
00867         case REQUEST:
00868                 ret = Packet_Translate_Request(*p);
00869                 break;
00870         case RESPONSE:
00871                 ret = Packet_Translate_Response(*p);
00872                 break;
00873         case DATA:
00874                 ret = Packet_Translate_Data(*p);
00875                 break;
00876         case CC_ACK:
00877                 ret = Packet_Translate_CCAck(*p);
00878                 break;
00879         case DATA_ACK:
00880 //              ret = Packet_Translate_DataAck(*p);
00881                 ret = -4;       /* for now */
00882                 break;
00883         case CLOSE:
00884                 ret = Packet_Translate_Close(*p);
00885                 break;
00886         default:
00887                 ret = -4;
00888                 break;
00889         }
00890 
00891         if (ret != 0) {
00892                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Read", "Packet discarded with error [%d]", ret);
00893                 RELEASE((*p)->iov[0].iov_base, n);
00894                 RELEASE((*p)->iov, sizeof(struct iovec));
00895                 RELEASE((*p), sizeof(struct packet));
00896         }
00897         /* compute and set the delay for this packet, including the time on the packet */
00898         Packet_Compute_Delay(pack_buf, &tv, *p);
00899         
00900         /* DEBUG_PACK(DEBUG_PACKET, "packet.c", "Packet_Read", *p, "Received"); */
00901         return ret;
00902 } /* Packet_Read() */
00903 
00904 /**
00905  * Reads ICMP packets and makes any necessary adjustments to the path MTU.
00906  *
00907  * @param icmp_fd file descriptor of icmp socket
00908  * @param pmtu pmtu structure to modify if we read an ICMP packet
00909  * @return 
00910  *      0 on success (p contains a valid packet)
00911  *  -1 no ICMP packets to be read
00912  */
00913 int Packet_Read_ICMP(int icmp_fd, void* pmtu){
00914         if(icmp_fd == -1){
00915                 return 1;
00916         }
00917         char buf[1024];
00918         int n = recvfrom(icmp_fd, &buf, 1024, MSG_DONTWAIT, NULL, NULL);
00919         path_mtu* pmtu_vals = (path_mtu*)pmtu;
00920         
00921         if(n == -1){
00922                 return 1;
00923         }else{
00924                 int type = buf[20];
00925                 int code = buf[21];
00926                 int udp_size = ((int)buf[52] << 8) + buf[53] - 8;
00927                 
00928                 /* PMTU: If Type = Destination Unreachable and Code = Fragmentation Needed then decrease MTU probe size
00929                    if UDP length indicates packet the same size as the probe */
00930                 if(type == DEST_UNREACHABLE && code == FRAG_NEEDED && udp_size == *(pmtu_vals->probe_size)){
00931                         pmtu_vals->probe_state = MTU_FOUND;
00932                         pmtu_vals->search_high = pmtu_vals->probe_size;
00933                         struct timeval tv;
00934                         GET_TIME_OF_DAY(&tv);
00935                         pmtu_vals->next_probe_time = tv.tv_sec + PMTUD_TIME_INTERVAL;
00936                         DEBUG_PMTUD_PRINT(DEBUG_PMTUD, "packet.c", "Packet_Read_ICMP", "Found MTU based on ICMP. Next probe begins at %lu", (long int)tv.tv_sec);
00937                 }
00938                 
00939                 DEBUG_PMTUD_PRINT(DEBUG_PMTUD, "packet.c", "Packet_Read_ICMP", "Received ICMP packet. [Size=> %d, Type=> %d, Code=>%d]", n, type, code);
00940         }
00941         
00942         return 0;
00943 }/* Packet_Read_ICMP() */
00944 
00945 /**
00946  * Writes a packet of a certain length to a file descriptor.
00947  *
00948  * @param p packet structure containing the packet to write out
00949  * @param fd file descriptor to which to write the buffer
00950  * @param addr is the address to send the packet to (eg. for unconnected sockets - used in server.c Server_Accept() )
00951  * @param addr_len is the length of the addr param
00952  * @return
00953  *       0 on success
00954  *       errno generated by sendmsg or writev on error
00955  */
00956 int Packet_Write(packet* p, int fd, struct sockaddr* addr, socklen_t addr_len) {
00957         int n;
00958         int err_val;
00959         socklen_t err_val_len;
00960         struct timeval tv;
00961         uint32_t int32;
00962 
00963         DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "sending packet: type[%s] iovlen[%d] fd[%d]", Packet_Str_Type(p), p->iovlen, fd);
00964 
00965         /* randomly drop every 2nd data packet: */
00966         /* if (p->type == DATA) {
00967                 n = (2 * 1.0 * rand() / (RAND_MAX + 1.0));
00968                 if (n == 1) {
00969                         // DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "Random DROP: frame[%d] data_offset[%d] len[%d]", p->u.data.frame_num, p->u.data.data_offset, p->u.data.data_len);
00970                         goto random_end;
00971                 }
00972         }
00973         */
00974         
00975         /* quit if there is a pending error on this socket */
00976         err_val_len = 4;
00977         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err_val, &err_val_len) == -1) perror("Packet_Write :: getsockopt");
00978         if (err_val != 0) {
00979                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "socket has a pending error[%d]:[%s]", err_val, strerror(err_val));
00980                 return err_val;
00981         }
00982 
00983         /* time stamp this packet with local time, the stamp goes into
00984          * the header of every packet at the 8th byte for 8 bytes :
00985          * two integers, check packet.h for more */
00986         GET_TIME_OF_DAY(&(tv));
00987         
00988         int32 = (uint32_t) (tv.tv_sec);
00989         int32 = htonl(int32);
00990         memcpy(p->iov[0].iov_base + 8, &(int32), 4);
00991                 
00992         int32 = (uint32_t) (tv.tv_usec);
00993         int32 = htonl(int32);
00994         memcpy(p->iov[0].iov_base + 12, &(int32), 4);
00995 
00996         /* send iov */
00997         if (addr != NULL) {
00998                 if (p->iovlen != 1) {
00999                         DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "can't send more than a vector of 1 element on unconnected socket");
01000                         return -1;
01001                 }
01002                 n = sendto(fd, p->iov[0].iov_base, p->iov[0].iov_len, MSG_DONTWAIT, addr, addr_len);
01003                 if (n == -1) {
01004                         err_val = errno;
01005                         DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "sendto generated an error, %s", strerror(err_val));
01006                         return err_val;
01007                 }
01008         } else {
01009                 if ((n = writev(fd, p->iov, p->iovlen)) == -1) {
01010                         err_val = errno;
01011                         DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "writev generated an error, %s", strerror(err_val));
01012                         return err_val;
01013                 }
01014                 /* DEBUG_PMTUD_PRINT(DEBUG_PMTUD, "vfer_packet.c", "Packet_Write()", "Sent packet of size %d", n); */
01015                 /* DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "writev returned [%d] ; p->iov[0].iov_len[%d]", n, (int)(p->iov[0].iov_len)); */
01016         }
01017 
01018         /* check any pending errors on the socket */
01019         err_val_len = 4;
01020         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err_val, &err_val_len) == -1) perror("packet_write :: getsockopt");
01021         if (n == -1 || err_val != 0) {
01022                 DEBUG_PRINT(DEBUG_PACKET, "packet.c", "Packet_Write", "socket generated error[%s]", strerror(err_val));
01023                 return err_val;
01024         }
01025         DEBUG_PACK(DEBUG_PACKET, "packet.c", "Packet_Write", p, "Sent");
01026 /* random_end: */
01027         return 0;
01028 } /* Packet_Write() */
01029 
01030 
01031 /**
01032  * Generates a random (2 bytes) frame number
01033  *
01034  * @return
01035  *      generated frame number
01036  */
01037 inline uint16_t Packet_Gen_FrameNum() {
01038         // return (uint16_t)(USHRT_MAX * 1.0 * rand() / (RAND_MAX + 1.0)); /* USHRT_MAX is defined in <limits.h> */
01039         return 0;
01040 } /* Packet_Gen_FrameNum() */
01041 
01042 /**
01043  * Generates a random (4 byte) sequence number.
01044  *
01045  * @return
01046  *      generated sequence number
01047  */
01048 inline uint32_t Packet_Gen_SeqNum() {
01049         // return (uint32_t)(UINT_MAX * 1.0 * rand() / (RAND_MAX + 1.0)); /* USHRT_MAX is defined in <limits.h> */
01050         return 0;
01051 } /* Packet_Gen_SeqNum() */
01052 
01053 /****************************************************************
01054  * Option helper functions
01055  ****************************************************************/
01056 
01057 /**
01058  * Sets an option in an options pointer
01059  *
01060  * @param opts options pointer
01061  * @param opt option to set
01062  */
01063 static inline void Packet_Set_Opt(uint32_t* opts, int opt) {
01064 //      printf("set opt1: %d\n", *opts);
01065         *opts = (*opts) | opt;
01066 //      printf("set opt2: %d\n", *opts);
01067 } /* Packet_Set_Opt() */
01068 
01069 /**
01070  * Unsets an option in an options pointer
01071  *
01072  * @param opts options pointer
01073  * @param opt option to unset
01074  */
01075 static inline void Packet_Unset_Opt(uint32_t* opts, int opt) {
01076 //      printf("unset opt1: %d\n", *opts);
01077         *opts = (*opts) & (~opt);
01078 //      printf("unset opt2: %d\n", *opts);
01079 } /* Packet_Unset_Opt() */
01080 
01081 /**
01082  * Boolean function that checks if an option is set
01083  *
01084  * @param opts options pointer
01085  * @param opt option to check for
01086  *
01087  * @return
01088  *      0 if option is not set
01089  *      1 if the option is set
01090  */
01091 static inline int Packet_Get_Opt(uint32_t opts, int opt) {
01092 //      printf("get opts[%d] | opt[%d] = %d\n", opts, opt, opts & opt;)
01093         return (opts & opt);
01094 } /* Packet_Get_Opt() */

Generated on Tue Aug 8 16:07:19 2006 for VFER by  doxygen 1.4.7