/* * Active Router Transport Protocol (ARTP) implementation * Copyright (c) 2004, Tomas Rebok * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the "BSD License" which is * distributed with the software in the file LICENSE. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the BSD * License for more details. */ /** @file * @c ARTP library for receive buffers. * @author Tomas Rebok * @date 2004 */ #include #include #include #include #include "rbuffers.h" #include "setting.h" #include "net.h" #include "errors.h" #include "config.h" /** Structure for determining duplicities. * The items of this structure consist of minimal and maximal incoming * sequence number (it means that all sequence numbers between this values * already came). These items are joined to the list ordered by their minimal * sequence number. */ struct Tdupple { /** minimal seq */ SEQ_TYPE min_seq; /** maximal incoming seq */ SEQ_TYPE max_seq; /** incoming time of maximal seq */ double max_seq_time; /** last item */ struct Tdupple *last; /** next item */ struct Tdupple *next; }; /** Structure for saving incoming data fragments */ struct fragment_item { /** fragment id (it's equal to 1 if we're saving control packet */ FRAGMENTS_TYPE frag_id; /** fragment payload */ char *payload; /** fragment payload size */ int payload_size; /** next fragment */ struct fragment_item *next_fragment; /** last fragment */ struct fragment_item *last_fragment; }; /** Structure for saving whole datagram information. */ struct item { /** data sequence number */ DSEQ_TYPE dseq; /** actual fragments count (count of saved fragments from this datagram). */ FRAGMENTS_TYPE act_frag; /** total fragments count */ FRAGMENTS_TYPE frag_count; /** datagram type */ enum packet_type dgram_type; /** item validity sign */ int invalid; /** fragments start */ struct fragment_item *fragments_start; /** fragments end */ struct fragment_item *fragments_end; /** next item in buffer */ struct item *next; /** last item in buffer */ struct item *last; }; /** Structure for buffer identified by 0. * This structure is used for saving information about non-established * sessions - we must remember some more information about each datagram. */ struct ext_item { /** generic datagram structure */ struct item main_item; /** datagram's sender */ union artp_receiver sender; /** datagram's session identifier */ SID_TYPE sid; }; /** receive buffers structure */ struct Trcving_buffers { /** complete buffer start */ struct item *complete_start; /** complete buffer end */ struct item *complete_end; /** incomplete buffer start */ struct item *incomplete_start; /** incomplete buffer end */ struct item *incomplete_end; /** start of structure for determining duplicities */ struct Tdupple *dupple_start; /** end of structure for determining duplicities */ struct Tdupple *dupple_end; /** counter of buffer size */ unsigned long int buffer_size; /** mutex used for mutual exclusion of threads manipulating with buffer * size counter */ pthread_mutex_t buffer_size_mutex; /** mutex used for mutual exclusion of threads reading from complete * buffer */ pthread_mutex_t complete_start_mutex; }; /** The total count of receive buffers (corresponds to the count of the * pointers in receive buffers array described below). */ static int rbuffers_count = 0; /** The array of pointers to receive buffers structures. */ static struct Trcving_buffers **rbuffers; int rbuffers_init(void) { return 0; } int rbuffers_create(int id_buffer) { struct item *p; /* check whether given buffer id is valid */ if ((id_buffer < 0) || (id_buffer > rbuffers_count) || ((id_buffer != rbuffers_count) && (rbuffers[id_buffer] != NULL))) return E_INVALID_BUFFER_ID; if (id_buffer == rbuffers_count) { /* whole array is full - we has to enlarge the array size */ if ((rbuffers = (struct Trcving_buffers**) realloc(rbuffers, (rbuffers_count + 1) * sizeof(struct Trcving_buffers*))) == NULL) return E_MEMORY_FAIL; else ++rbuffers_count; } /* allocate the place for buffer structure */ if ((rbuffers[id_buffer] = (struct Trcving_buffers*) malloc(sizeof(struct Trcving_buffers))) == NULL) return E_MEMORY_FAIL; /* create slipper */ if (id_buffer == 0) { /* extended slipper */ if ((p = (struct item *) malloc(sizeof(struct ext_item))) == NULL) return E_MEMORY_FAIL; } else { /* typical slipper */ if ((p = (struct item *) malloc(sizeof(struct item))) == NULL) return E_MEMORY_FAIL; } p->invalid = 1; p->fragments_start = NULL; p->fragments_end = NULL; /* set initial values to all buffer parameters */ rbuffers[id_buffer]->complete_start = p; rbuffers[id_buffer]->complete_end = p; rbuffers[id_buffer]->incomplete_start = NULL; rbuffers[id_buffer]->incomplete_end = NULL; rbuffers[id_buffer]->dupple_start = NULL; rbuffers[id_buffer]->dupple_end = NULL; rbuffers[id_buffer]->buffer_size = 0; /* try to initialize semaphores and mutexes */ if ((pthread_mutex_init(&rbuffers[id_buffer]->complete_start_mutex, NULL) != 0) || (pthread_mutex_init(&rbuffers[id_buffer]->buffer_size_mutex, NULL) != 0)) return E_MEMORY_FAIL; return 0; } int rbuffers_destroy(int id_buffer) { struct item *p; struct fragment_item *q; struct Tdupple *r; /* check whether the buffer identification number is correct. We ban * destroying buffer identified by 0. */ if ((id_buffer < 1) || (id_buffer >= rbuffers_count) || (rbuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* delete all items in complete buffer */ while (rbuffers[id_buffer]->complete_start != NULL) { p = rbuffers[id_buffer]->complete_start; rbuffers[id_buffer]->complete_start = p->next; /* delete all fragments of this item */ while (p->fragments_start != NULL) { q = p->fragments_start; p->fragments_start = q->next_fragment; /* free memory */ free(q->payload); q->payload = NULL; free(q); q = NULL; } /* free this item */ free(p); p = NULL; } /* delete all items in incomplete buffer */ while (rbuffers[id_buffer]->incomplete_start != NULL) { p = rbuffers[id_buffer]->incomplete_start; rbuffers[id_buffer]->incomplete_start = p->next; /* delete all fragments of this item */ while (p->fragments_start != NULL) { q = p->fragments_start; p->fragments_start = q->next_fragment; /* free memory */ free(q->payload); q->payload = NULL; free(q); q = NULL; } /* free this item */ free(p); p = NULL; } /* delete all items in the structure for determining duplicities */ while (rbuffers[id_buffer]->dupple_start != NULL) { r = rbuffers[id_buffer]->dupple_start; rbuffers[id_buffer]->dupple_start = r->next; /* free memory */ free(r); r = NULL; } /* clean memory */ rbuffers[id_buffer]->complete_start = NULL; rbuffers[id_buffer]->complete_end = NULL; rbuffers[id_buffer]->incomplete_start = NULL; rbuffers[id_buffer]->incomplete_end = NULL; rbuffers[id_buffer]->dupple_start = NULL; rbuffers[id_buffer]->dupple_end = NULL; /* destroy all mutexes and semaphores */ pthread_mutex_destroy(&rbuffers[id_buffer]->complete_start_mutex); pthread_mutex_destroy(&rbuffers[id_buffer]->buffer_size_mutex); /* unallocate buffer */ free(rbuffers[id_buffer]); rbuffers[id_buffer] = NULL; return 0; } /** Adds datagram to complete buffer. * This function adds datagram pointed by p to complete buffer. This adding is * a bit complicated because of slipper (this is made for mutual exclusion * of reading and adding threads). First of all this new item is inserted to the * end of complete buffer (after slipper). This new item is signed as a new * slipper and all item's values are copied to the old one. Finally, the * old slipper is signed as a valid item. * * @param id_buffer * identification number of receive buffer. * * @param p * the pointer to the place where moved datagram information is saved. * * @return zero * success. * * @return nonzero * Some error happened (for further information see documentation of file * @c errors.h). */ static int add_complete_datagram(int id_buffer, struct item *p) { /* check whether given buffer id is valid */ if ((id_buffer < 0) || (id_buffer >= rbuffers_count) || (rbuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* add this item to the end of complete buffer */ p->next = NULL; p->last = NULL; rbuffers[id_buffer]->complete_end->next = p; /* sign it as a new slipper */ p->invalid = 1; /* copy its values to the old slipper */ rbuffers[id_buffer]->complete_end->dseq = p->dseq; rbuffers[id_buffer]->complete_end->act_frag = p->act_frag; rbuffers[id_buffer]->complete_end->frag_count = p->frag_count; rbuffers[id_buffer]->complete_end->dgram_type = p->dgram_type; rbuffers[id_buffer]->complete_end->fragments_start = p->fragments_start; rbuffers[id_buffer]->complete_end->fragments_end = p->fragments_end; if (id_buffer == 0) { /* in non-established sessions we have to copy more values */ rcvrcpy((struct sockaddr *) &(((struct ext_item *) rbuffers[id_buffer]->complete_end)->sender), (struct sockaddr *) &(((struct ext_item *) p)->sender)); ((struct ext_item *) rbuffers[id_buffer]->complete_end)->sid = ((struct ext_item *) p)->sid; } p->fragments_start = NULL; p->fragments_end = NULL; /* sign it as a valid item */ rbuffers[id_buffer]->complete_end->invalid = 0; rbuffers[id_buffer]->complete_end = p; return 0; } /** Determine duplicities. * This function checks and determines duplicities in incoming packets. If * incoming packet is unique, it saves its sequence number to the structure * for further purposes. * When our information is too old (determined by retransmits_timeout * parameter), it's deleted. * * @param id_buffer * identification number of receive buffer. * * @param seq * checked sequence number. * * @param current_time * current time (it's equal to packet incoming time) * * @param retransmits_timeout * retransmits_timeout sent by our partner to determine old packets in * structure for duplicity check. It's set to 0 if our partner doesn't * send this option. * * @return zero * incoming packet is unique. * * @return nonzero * incoming packet is a duplicity of previous packet or some error * happened (for further information see documentation of file * @c errors.h). */ static int search_dupple(int id_buffer, SEQ_TYPE seq, double current_time, unsigned int retransmits_timeout) { struct Tdupple *greater; struct Tdupple *lesser; struct Tdupple *p; int create_new; /* check whether given buffer id is valid */ if ((id_buffer < 0) || (id_buffer >= rbuffers_count) || (rbuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* Try to find first item whose minimal sequence number is greater than * added. Simultaneously delete items with old information (and one after * maximal found, too). */ greater = rbuffers[id_buffer]->dupple_start; while ((greater != NULL) && (greater->min_seq <= seq)) { /* check whether this item carries too old information (if wanted) */ if ((retransmits_timeout != 0) && (greater->max_seq_time + retransmits_timeout < current_time)) { /* yes, it's too old. Delete it. */ p = greater; if (greater == rbuffers[id_buffer]->dupple_start) { /* it's the first item */ rbuffers[id_buffer]->dupple_start = greater->next; if (rbuffers[id_buffer]->dupple_start != NULL) rbuffers[id_buffer]->dupple_start->last = NULL; greater = rbuffers[id_buffer]->dupple_start; } else if (greater == rbuffers[id_buffer]->dupple_end) { /* it's the last item */ rbuffers[id_buffer]->dupple_end = greater->last; rbuffers[id_buffer]->dupple_end->next = NULL; greater = NULL; } else if ((greater->last != NULL) && (greater->next != NULL)) { /* it's somewhere in the middle */ greater->last->next = greater->next; greater->next->last = greater->last; greater = greater->next; } /* unallocate it */ free(p); p = NULL; continue; } if ((greater->min_seq <= seq) && (seq <= greater->max_seq)) return E_DUPLICITY_PACKET; greater = greater->next; } /* check whether first greater item carries too old information */ if ((greater != NULL) && (retransmits_timeout != 0) && (greater->max_seq_time + retransmits_timeout < current_time)) { /* yes, it's too old. Delete it. */ p = greater; if (greater == rbuffers[id_buffer]->dupple_start) { /* it's the first item */ rbuffers[id_buffer]->dupple_start = greater->next; if (rbuffers[id_buffer]->dupple_start != NULL) rbuffers[id_buffer]->dupple_start->last = NULL; greater = rbuffers[id_buffer]->dupple_start; } else if (greater == rbuffers[id_buffer]->dupple_end) { /* it's the last item */ rbuffers[id_buffer]->dupple_end = greater->last; rbuffers[id_buffer]->dupple_end->next = NULL; greater = NULL; } else if ((greater->last != NULL) && (greater->next != NULL)) { /* it's somewhere in the middle */ greater->last->next = greater->next; greater->next->last = greater->last; greater = greater->next; } /* unallocate it */ free(p); p = NULL; } /* add this sequence number to the structure. But we allow only specified * count of sequence numbers in one item as specified in DUPPLE_SEQ_COUNT * macro. */ if (rbuffers[id_buffer]->dupple_start == NULL) { /* adding first item to the structure - allocate it */ if ((rbuffers[id_buffer]->dupple_start = (struct Tdupple *) malloc(sizeof(struct Tdupple))) == NULL) return E_MEMORY_FAIL; /* set its parameters */ rbuffers[id_buffer]->dupple_start->min_seq = seq; rbuffers[id_buffer]->dupple_start->max_seq = seq; rbuffers[id_buffer]->dupple_start->max_seq_time = current_time; rbuffers[id_buffer]->dupple_start->last = NULL; rbuffers[id_buffer]->dupple_start->next = NULL; rbuffers[id_buffer]->dupple_end = rbuffers[id_buffer]->dupple_start; } else if (greater == rbuffers[id_buffer]->dupple_start) { /* minimal sequence number came */ /* is it possible to decrease found minimal sequence number? */ if ((greater->min_seq == seq + 1) && (greater->max_seq - greater->min_seq + 1 < DUPPLE_SEQ_COUNT)) { greater->min_seq = seq; } else { /* create new leading item */ if ((p = (struct Tdupple *) malloc(sizeof(struct Tdupple))) == NULL) return E_MEMORY_FAIL; /* set its parameters */ p->min_seq = seq; p->max_seq = seq; p->max_seq_time = current_time; p->last = NULL; p->next = rbuffers[id_buffer]->dupple_start; rbuffers[id_buffer]->dupple_start->last = p; rbuffers[id_buffer]->dupple_start = p; } } else if (greater == NULL) { /* maximal sequence number came */ /* is it possible to increase found maximal sequence number? */ if ((rbuffers[id_buffer]->dupple_end->max_seq == seq - 1) && (rbuffers[id_buffer]->dupple_end->max_seq - rbuffers[id_buffer]->dupple_end->min_seq + 1 < DUPPLE_SEQ_COUNT)) { rbuffers[id_buffer]->dupple_end->max_seq = seq; rbuffers[id_buffer]->dupple_end->max_seq_time = current_time; } else { /* create new last item */ p = (struct Tdupple *) malloc(sizeof(struct Tdupple)); /* set its parameters */ p->min_seq = seq; p->max_seq = seq; p->max_seq_time = current_time; p->last = rbuffers[id_buffer]->dupple_end; p->next = NULL; rbuffers[id_buffer]->dupple_end->next = p; rbuffers[id_buffer]->dupple_end = p; } } else { /* we have to insert new item somewhere in the middle */ lesser = greater->last; create_new = 1; if ((greater->min_seq == seq + 1) && (greater->max_seq - greater->min_seq + 1 < DUPPLE_SEQ_COUNT)) { /* decreasing minimal sequence number is enough */ greater->min_seq = seq; create_new = 0; } else if ((lesser->max_seq == seq - 1) && (lesser->max_seq - lesser->min_seq + 1 < DUPPLE_SEQ_COUNT)) { /* increasing maximal sequence number is enough */ lesser->max_seq = seq; lesser->max_seq_time = current_time; create_new = 0; } /* alloying adjacent items */ if ((lesser->max_seq + 1 == greater->min_seq) && ((lesser->max_seq - lesser->min_seq + 1) + (greater->max_seq - greater->min_seq + 1) <= DUPPLE_SEQ_COUNT)) { p = greater; lesser->max_seq = greater->max_seq; lesser->max_seq_time = greater->max_seq_time; lesser->next = greater->next; if (greater->next != NULL) greater->next->last = lesser; if (rbuffers[id_buffer]->dupple_end == greater) rbuffers[id_buffer]->dupple_end = lesser; p->next=NULL; p->last=NULL; free(p); p = NULL; create_new = 0; } if (create_new == 1) { /* create new item */ if ((p = (struct Tdupple *) malloc(sizeof(struct Tdupple))) == NULL) return E_MEMORY_FAIL; /* set its parameters */ p->min_seq = seq; p->max_seq = seq; p->max_seq_time = current_time; p->last = lesser; p->next = greater; lesser->next = p; greater->last = p; } } return 0; } int rbuffers_get_size(int id_buffer, unsigned long int *buffer_size) { /* check whether given buffer identification number is correct */ if ((id_buffer < 0) || (id_buffer >= rbuffers_count) || (rbuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; *buffer_size = rbuffers[id_buffer]->buffer_size; return 0; } int rbuffers_add_packet(int id_buffer, char *value, int payload_size, struct sockaddr *sender, SID_TYPE sid, enum packet_type type, SEQ_TYPE seq, DSEQ_TYPE dseq, FRAGMENTS_TYPE frag_id, FRAGMENTS_TYPE frag_count, double current_time, unsigned int retransmits_timeout) { struct item *p, *r; struct fragment_item *q, *s; /* check whether given buffer identification number is valid */ if ((id_buffer < 0) || (id_buffer >= rbuffers_count) || (rbuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* check whether incoming packet is a duplicity of some previous packet */ if ((id_buffer != 0) && (search_dupple(id_buffer, seq, current_time, retransmits_timeout) != 0)) { /* yes, it is. Return relevant error code. */ return E_DUPLICITY_PACKET; } /* if the whole datagram consists of more than one fragment, find out the * proper place in incomplete buffer for it (if there's an item describing * this datagram in that buffer, find it. If there isn't, find the first * item thats data sequence number is greater than added. */ p = NULL; if (frag_count > 1) { p = rbuffers[id_buffer]->incomplete_start; while ((p != NULL) && (p->dseq < dseq)) p = p->next; } /* there's no item for this datagram in incomplete buffer (or none is * needed). */ if ((p == NULL) || (p->dseq != dseq)) { if (id_buffer != 0) { /* try to allocate new item */ if ((r = (struct item *) malloc(sizeof(struct item))) == NULL) return E_MEMORY_FAIL; } else { /* try to allocate new item */ if ((r = (struct item *) malloc(sizeof(struct ext_item))) == NULL) return E_MEMORY_FAIL; /* save there sender address and session identification * number. */ rcvrcpy((struct sockaddr *) &(((struct ext_item *) r)->sender), sender); ((struct ext_item *) r)->sid = sid; } /* set its parameters to default values (or the given ones) */ r->dseq = dseq; r->frag_count = frag_count; r->act_frag = 0; r->invalid = 0; r->dgram_type = type; r->fragments_start = NULL; r->fragments_end = NULL; /* we have created new item. If datagram for this item consists of * more than one fragment, we have to insert this item to incomplete * buffer. */ if (frag_count > 1) { if (rbuffers[id_buffer]->incomplete_start == NULL) { /* inserting into empty buffer */ r->next = NULL; r->last = NULL; rbuffers[id_buffer]->incomplete_start = r; rbuffers[id_buffer]->incomplete_end = r; } else if (p == rbuffers[id_buffer]->incomplete_start) { /* inserting to the beginning of buffer */ r->next = rbuffers[id_buffer]->incomplete_start; r->last = NULL; rbuffers[id_buffer]->incomplete_start->last = r; rbuffers[id_buffer]->incomplete_start = r; } else if (p == NULL) { /* inserting to the end of buffer */ r->next = NULL; r->last = rbuffers[id_buffer]->incomplete_end; rbuffers[id_buffer]->incomplete_end->next = r; rbuffers[id_buffer]->incomplete_end = r; } else { /* inserting somewhere in the middle */ r->next = p; r->last = p->last; r->next->last = r; r->last->next = r; } } p = r; } /* add given fragment to its right position in found (created) item */ s = p->fragments_start; while ((s != NULL) && (s->frag_id < frag_id)) s = s->next_fragment; /* try to allocate memory for it */ if ((q = (struct fragment_item *) malloc(sizeof(struct fragment_item))) == NULL) return E_MEMORY_FAIL; /* save packet payload and its size */ q->payload = value; q->payload_size = payload_size; q->frag_id = frag_id; /* insert it into fragments chain */ if (p->fragments_start == NULL) { /* inserting into empty chain */ q->next_fragment = NULL; q->last_fragment = NULL; p->fragments_start = q; p->fragments_end = q; } else if (s == p->fragments_start) { /* inserting the first fragment */ q->next_fragment = p->fragments_start; q->last_fragment = NULL; p->fragments_start->last_fragment = q; p->fragments_start = q; } else if (s == NULL) { /* inserting the last fragment */ q->next_fragment = NULL; q->last_fragment = p->fragments_end; p->fragments_end->next_fragment = q; p->fragments_end = q; } else { /* inserting somewhere in the middle */ q->next_fragment = s; q->last_fragment = s->last_fragment; q->next_fragment->last_fragment = q; q->last_fragment->next_fragment = q; } /* increase received fragment count for this datagram */ ++(p->act_frag); /* check whether we can move this datagram to the complete buffer (all * fragments were received. */ if (p->act_frag == p->frag_count) { if (p->frag_count > 1) { /* this datagram was saved in incomplete buffer - remove it */ if (p == rbuffers[id_buffer]->incomplete_start) { /* removing first item */ rbuffers[id_buffer]->incomplete_start = p->next; if (rbuffers[id_buffer]->incomplete_start != NULL) rbuffers[id_buffer]->incomplete_start->last = NULL; } else if (p == rbuffers[id_buffer]->incomplete_end) { /* removing last item */ rbuffers[id_buffer]->incomplete_end = p->last; rbuffers[id_buffer]->incomplete_end->next = NULL; } else { /* removing item somewhere in the middle */ p->last->next = p->next; p->next->last = p->last; } } /* add this datagram to complete buffer */ add_complete_datagram(id_buffer, p); } /* increase counter of buffer size */ pthread_mutex_lock(&rbuffers[id_buffer]->buffer_size_mutex); rbuffers[id_buffer]->buffer_size += payload_size; pthread_mutex_unlock(&rbuffers[id_buffer]->buffer_size_mutex); return 0; } int rbuffers_get_dgram(int id_buffer, char **value, int *payload_size, enum packet_type *type, DSEQ_TYPE *dseq, struct sockaddr **sender, SID_TYPE *sid) { struct item *p; struct fragment_item *q; int act_position; struct sockaddr *returned_sender; /* check whether given buffer identification number is valid */ if ((id_buffer < 0) || (id_buffer >= rbuffers_count) || (rbuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* lock buffer for reading */ pthread_mutex_lock(&rbuffers[id_buffer]->complete_start_mutex); if (rbuffers[id_buffer]->complete_start->invalid == 1) { /* no datagrams are available, unlock buffer */ pthread_mutex_unlock(&rbuffers[id_buffer]->complete_start_mutex); return E_EMPTY_BUFFER; } p = rbuffers[id_buffer]->complete_start; rbuffers[id_buffer]->complete_start = rbuffers[id_buffer]->complete_start->next; /* lock isn't necessary any more */ pthread_mutex_unlock(&rbuffers[id_buffer]->complete_start_mutex); /* count total size of this datagram (including all fragments) */ *payload_size = 0; q = p->fragments_start; while (q != NULL) { *payload_size += q->payload_size; q = q->next_fragment; } /* allocate memory for payload */ if ((*value = (char *) malloc(sizeof(char) * (*payload_size))) == NULL) return E_MEMORY_FAIL; /* copy all fragments to allocated space */ act_position = 0; while (p->fragments_start != NULL) { q = p->fragments_start; p->fragments_start = p->fragments_start->next_fragment; memcpy(*value + (act_position * sizeof(char)), q->payload, (q->payload_size) * sizeof(char)); act_position += q->payload_size; /* free this fragment */ free(q->payload); q->payload = NULL; free(q); q = NULL; } /* set and return some parameters which are necessary */ *type = p->dgram_type; *dseq = p->dseq; if (id_buffer == 0) { /* for non-established sessions there are some others parameters * which we have to return. */ /* allocate new space for sender - we are going to deallocate the space * previously created for this datagram. */ returned_sender = (struct sockaddr *) malloc(rcvrsz((struct sockaddr *) &(((struct ext_item *) p)->sender))); /* copy the sender address */ rcvrcpy(returned_sender, (struct sockaddr *) &(((struct ext_item *) p)->sender)); *sender = returned_sender; *sid = ((struct ext_item *) p)->sid; } /* decrease buffer size */ pthread_mutex_lock(&rbuffers[id_buffer]->buffer_size_mutex); rbuffers[id_buffer]->buffer_size -= *payload_size; pthread_mutex_unlock(&rbuffers[id_buffer]->buffer_size_mutex); /* deallocate space allocated for this datagram */ if (id_buffer ==0) free((struct ext_item *) p); else free(p); p = NULL; return 0; } /* vim: set ts=4 : */