/* * 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 ack buffers. * @author Tomas Rebok * @date 2004 */ #include #include #include #include #include "abuffers.h" #include "config.h" #include "net.h" /** Ack buffers' main structure. */ struct Tabuffers { /** Place for storing sequence numbers to be acknowledged. */ char acks[MAX_ARTP_PACKET_SIZE]; /** Actual acks (sequence numbers to be acknowledged) count */ int acks_count; /** The latest time when this acknowledgement must be sent. */ double latest_send_time; /** Identification number of the session which this acknowledgement * belongs to. */ SID_TYPE sid; /** Receiver of the session which this acknowledgement belongs to. */ union artp_receiver receiver; /** Next element in structure for sending ack packets (next ack buffer). */ struct Tabuffers *next; /** Last element in structure for sending ack packets (last ack buffer). */ struct Tabuffers *last; }; /** The beginning of the structure for sending ack packets. */ static struct Tabuffers *sending_order_start = NULL; /** The end of the structure for sending ack packets. */ static struct Tabuffers *sending_order_end = NULL; /** The total count of ack buffers (corresponds to the count of pointers * in buffers array described below). */ static int abuffers_count = 0; /** The array of pointers to ack buffers structures. */ static struct Tabuffers **abuffers; int abuffers_init(void) { return 0; } int abuffers_create(int id_buffer, SID_TYPE sid, struct sockaddr *receiver) { /* check whether the buffer identification number is correct */ if ((id_buffer < 0) || (id_buffer > abuffers_count) || ((id_buffer != abuffers_count) && (abuffers[id_buffer] != NULL))) return E_INVALID_BUFFER_ID; if (id_buffer == abuffers_count) { /* whole array is full - we have to enlarge the array size */ if ((abuffers = (struct Tabuffers**) realloc(abuffers, (abuffers_count + 1) * sizeof(struct Tabuffers*))) == NULL) return E_MEMORY_FAIL; else ++abuffers_count; } /* allocate the place for buffer structure */ if ((abuffers[id_buffer] = (struct Tabuffers*) malloc(sizeof(struct Tabuffers))) == NULL) return E_MEMORY_FAIL; /* set initial values to all buffer parameters */ abuffers[id_buffer]->acks_count = 0; abuffers[id_buffer]->latest_send_time = 0; abuffers[id_buffer]->last = NULL; abuffers[id_buffer]->next = NULL; if (id_buffer != 0) { /* set the session identification number and its receiver to correct * ones */ abuffers[id_buffer]->sid = sid; rcvrcpy((struct sockaddr *) &abuffers[id_buffer]->receiver, receiver); } return 0; } int abuffers_destroy(int id_buffer) { /* check whether the buffer identification number is correct. * Note: We ban destroying buffer identified by 0. */ if ((id_buffer < 1) || (id_buffer >= abuffers_count) || (abuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* remove wanted buffer from structure for sending ack packets */ if (abuffers[id_buffer] == sending_order_start) { sending_order_start = abuffers[id_buffer]->next; if (sending_order_start != NULL) sending_order_start->last = NULL; } else if (abuffers[id_buffer] == sending_order_end) { sending_order_end = abuffers[id_buffer]->last; if (sending_order_end != NULL) sending_order_end->next = NULL; } else if ((abuffers[id_buffer]->last != NULL) && (abuffers[id_buffer]->next != NULL)) { abuffers[id_buffer]->last->next = abuffers[id_buffer]->next; abuffers[id_buffer]->next->last = abuffers[id_buffer]->last; } /* set all pointers to NULL */ abuffers[id_buffer]->next = NULL; abuffers[id_buffer]->last = NULL; /* unallocate buffer */ free(abuffers[id_buffer]); abuffers[id_buffer] = NULL; return 0; } int abuffers_add_seq(int id_buffer, SID_TYPE sid, struct sockaddr *receiver, SEQ_TYPE seq, double latest_send_time, int max_count) { struct Tabuffers *p; /* check whether the buffer identification number is correct */ if ((id_buffer < 0) || (id_buffer >= abuffers_count) || (abuffers[id_buffer] == NULL)) return E_INVALID_BUFFER_ID; /* save given sequence number */ *((SEQ_TYPE *) (abuffers[id_buffer]->acks + (abuffers[id_buffer]->acks_count++ * sizeof(SEQ_TYPE)))) = htonl(seq); if (id_buffer == 0) { /* save the session idetification number and its receiver, too */ abuffers[id_buffer]->sid = sid; rcvrcpy((struct sockaddr *) &abuffers[id_buffer]->receiver, receiver); return 0; } /* if we're adding the first sequence number, we have to put this buffer * to the proper * position in the structure for sending ack packets. This structure is * ordered by the latest time of sending buffer's ack packet. */ if (abuffers[id_buffer]->acks_count == 1) { abuffers[id_buffer]->latest_send_time = latest_send_time; p = sending_order_start; while ((p != NULL) && (p->latest_send_time <= latest_send_time)) p = p->next; /* we're adding before the element where p points to */ if (sending_order_start == NULL) { /* structure is empty */ sending_order_start = abuffers[id_buffer]; sending_order_end = abuffers[id_buffer]; abuffers[id_buffer]->next = NULL; abuffers[id_buffer]->last = NULL; } else if (p == sending_order_start) { /* adding the first element */ abuffers[id_buffer]->next = sending_order_start; abuffers[id_buffer]->last = NULL; sending_order_start->last = abuffers[id_buffer]; sending_order_start = abuffers[id_buffer]; } else if (p == NULL) { /* adding the last element */ abuffers[id_buffer]->next = NULL; abuffers[id_buffer]->last = sending_order_end; sending_order_end->next = abuffers[id_buffer]; sending_order_end = abuffers[id_buffer]; } else { /* adding somewhere in the middle */ abuffers[id_buffer]->next = p; abuffers[id_buffer]->last = p->last; abuffers[id_buffer]->last->next = abuffers[id_buffer]; abuffers[id_buffer]->next->last = abuffers[id_buffer]; } } else if (abuffers[id_buffer]->acks_count >= max_count) { /* if the count of sequence numbers is greater or equal to the * maximal count, move this buffer to the first position (the acking * packet will be sent immediately). */ /* this time MUST be set to zero when we want to send this ack packet * immediatelly. */ abuffers[id_buffer]->latest_send_time = 0; if (abuffers[id_buffer] == sending_order_start) /* this buffer is already the first in that structure - there's * nothing to do. */ return 0; else if (abuffers[id_buffer] == sending_order_end) { sending_order_end = abuffers[id_buffer]->last; sending_order_end->next = NULL; } else { abuffers[id_buffer]->last->next = abuffers[id_buffer]->next; abuffers[id_buffer]->next->last = abuffers[id_buffer]->last; } abuffers[id_buffer]->next = sending_order_start; abuffers[id_buffer]->last = NULL; sending_order_start = abuffers[id_buffer]; } return 0; } int abuffers_get_ack(double actual_time, SID_TYPE *sid, struct sockaddr **receiver, char **value, int *size) { struct Tabuffers *p; /* Check whether there's any ack packet to send. First check the zero * buffer (the buffer of non-established sessions). */ if (abuffers[0]->acks_count != 0) p = abuffers[0]; else { if ((sending_order_start == NULL) || (sending_order_start->latest_send_time > actual_time)) return E_NO_ACK; p = sending_order_start; sending_order_start = p->next; if (sending_order_start != NULL) sending_order_start->last = NULL; } /* return all necessary information */ *sid = p->sid; *receiver = (struct sockaddr *) &(p->receiver); *value = p->acks; *size = (p->acks_count) * sizeof(SEQ_TYPE); /* set all parameters to init values */ p->acks_count = 0; p->latest_send_time = 0; p->next = NULL; p->last = NULL; return 0; } /* vim: set ts=4 : */