1 /** \file alc_list.c \brief Receive packets to the list
2  *
3  *  $Author: peltotal $ $Date: 2007/02/28 08:58:00 $ $Revision: 1.15 $
4  *
5 *   MAD-ALCLIB: Implementation of ALC/LCT protocols, Compact No-Code FEC,
6 *   Simple XOR FEC, Reed-Solomon FEC, and RLC Congestion Control protocol.
7 *   Copyright (c) 2003-2007 TUT - Tampere University of Technology
8 *   main authors/contacts: jani.peltotalo@tut.fi and sami.peltotalo@tut.fi
9 *
10 *   This program is free software; you can redistribute it and/or modify
11 *   it under the terms of the GNU General Public License as published by
12 *   the Free Software Foundation; either version 2 of the License, or
13 *   (at your option) any later version.
14 *
15 *   This program is distributed in the hope that it will be useful,
16 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *   GNU General Public License for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with this program; if not, write to the Free Software
22 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 *
24  *  In addition, as a special exception, TUT - Tampere University of Technology
25  *  gives permission to link the code of this program with the OpenSSL library (or
26  *  with modified versions of OpenSSL that use the same license as OpenSSL), and
27  *  distribute linked combinations including the two. You must obey the GNU
28  *  General Public License in all respects for all of the code used other than
29  *  OpenSSL. If you modify this file, you may extend this exception to your version
30  *  of the file, but you are not obligated to do so. If you do not wish to do so,
31  *  delete this exception statement from your version.
32 */
33 
34 #ifdef _MSC_VER
35 #else
36 #include <sys/time.h>
37 #endif
38 
39 #include <assert.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <time.h>
43 
44 #include "alc_list.h"
45 
46 #ifdef _MSC_VER
47 
48 /**
49  * This is a private function, which returns time value.
50  *
51  * @param tv stores time value
52  *
53  * @return 0
54  *
55  */
56 
get_time_of_day(struct timeval * tv)57 int get_time_of_day(struct timeval *tv) {
58   time_t tempo_t;
59   time(&tempo_t);
60 
61   tv->tv_sec = tempo_t;
62   tv->tv_usec = 0;
63 
64   return 0;
65 }
66 #else
67 
68 /**
69  * This is a private function, which returns time value.
70  *
71  * @param tv stores time value
72  *
73  * @return 0 in success, -1 otherwise
74  *
75  */
76 
get_time_of_day(struct timeval * tv)77 int get_time_of_day(struct timeval *tv){
78   return gettimeofday(tv, NULL);
79 }
80 
81 #endif
82 
83 /**
84  * This is a private function, which locks the list.
85  *
86  * @param a_list the list to be locked
87  *
88  */
89 
lock_list(alc_list_t * a_list)90 void lock_list(alc_list_t *a_list) {
91 #ifdef _MSC_VER
92   EnterCriticalSection(&(a_list->session_variables_semaphore));
93 #else
94   pthread_mutex_lock(&(a_list->session_variables_semaphore));
95 #endif
96 }
97 
98 /**
99  * This is a private function, which unlocks the list.
100  *
101  * @param a_list the list to be unlocked
102  *
103  */
104 
unlock_list(alc_list_t * a_list)105 void unlock_list(alc_list_t *a_list) {
106 #ifdef _MSC_VER
107   LeaveCriticalSection(&(a_list->session_variables_semaphore));
108 #else
109   pthread_mutex_unlock(&(a_list->session_variables_semaphore));
110 #endif
111 }
112 
113 /**
114  * This is a private function, which checks if the list is empty.
115  *
116  * @param a_list the list to be checked
117 *
118  * @return 1 if the list is empty, 0 if not
119 *
120 */
121 
is_empty_private(const alc_list_t * a_list)122 int is_empty_private(const alc_list_t *a_list) {
123 	return a_list->first_elem == NULL;
124 }
125 
126 /**
127 * This is a private function, which prepares the node to be inserted.
128 *
129 * @param a_data the container to be inserted in list
130 *
131 * @return the node to be inserted, NULL if the container is too old
132 *
133 */
134 
prepare_insert(alc_rcv_container_t * a_data)135 struct alc_list_node* prepare_insert(alc_rcv_container_t *a_data) {
136   struct alc_list_node *my_node;
137   struct timeval now;
138   double container_age;
139 
140   assert(a_data != NULL);
141 
142   if(a_data->time_stamp.tv_sec == 0) {
143     /* mark the timestamp first time the container is inserted */
144     get_time_of_day(&(a_data->time_stamp));
145     assert(a_data->time_stamp.tv_sec != 0);
146   }
147   else {
148     /* check if the container is too old, in case I discard it */
149     get_time_of_day(&now);
150 
151     container_age =  now.tv_sec  - a_data->time_stamp.tv_sec +
152       (now.tv_usec - a_data->time_stamp.tv_usec ) / 1E6;
153     assert(container_age >= 0);
154 
155     if(container_age > 3) {
156       /* containers older than 3 secs are discarded */
157       return NULL;
158     }
159   }
160 
161   my_node = malloc(1 * sizeof(struct alc_list_node));
162   my_node->next = NULL;
163   my_node->data = a_data;
164 
165   return my_node;
166 }
167 
push_back(alc_list_t * a_list,alc_rcv_container_t * a_data)168 void push_back(alc_list_t *a_list, alc_rcv_container_t *a_data) {
169   struct alc_list_node *my_node;
170 
171   my_node = prepare_insert(a_data);
172 
173   if(my_node == NULL) {
174     return;
175   }
176 
177   lock_list(a_list);
178 
179   if(is_empty_private(a_list)) {
180     a_list->first_elem = my_node;
181     a_list->last_elem = my_node;
182   }
183   else {
184     a_list->last_elem->next = my_node;
185     a_list->last_elem = my_node;
186   }
187 
188   unlock_list(a_list);
189 }
190 
push_front(alc_list_t * a_list,alc_rcv_container_t * a_data)191 void push_front(alc_list_t *a_list, alc_rcv_container_t *a_data) {
192   struct alc_list_node *my_node;
193 
194   my_node = prepare_insert(a_data);
195 
196   if(my_node == NULL) {
197     return;
198   }
199 
200   lock_list(a_list);
201 
202   if(is_empty_private(a_list)) {
203     a_list->first_elem = my_node;
204     a_list->last_elem = my_node;
205   }
206   else {
207     my_node->next = a_list->first_elem;
208     a_list->first_elem = my_node;
209   }
210 
211   unlock_list(a_list);
212 }
213 
pop_front(alc_list_t * a_list)214 alc_rcv_container_t* pop_front(alc_list_t *a_list) {
215   struct alc_list_node *my_node = NULL;
216   void *my_ret = NULL;
217 
218   lock_list(a_list);
219 
220   if(is_empty_private(a_list)) {
221   }
222   else {
223     my_node = a_list->first_elem;
224 
225     if(a_list->first_elem == a_list->last_elem) {  /* last element in list */
226       assert(my_node->next == NULL);
227 
228       a_list->first_elem = NULL;
229       a_list->last_elem = NULL;
230     }
231     else {
232       a_list->first_elem = my_node->next;
233     }
234 
235     my_ret = my_node->data;
236   }
237 
238   unlock_list(a_list);
239   free(my_node);
240 
241   return my_ret;
242 }
243 
is_empty(const alc_list_t * a_list)244 int is_empty(const alc_list_t *a_list) {
245   int my_ret;
246 
247   lock_list((alc_list_t*)a_list);
248 
249   my_ret = (a_list->first_elem == NULL);
250 
251 	unlock_list((alc_list_t*)a_list);
252 
253 	return my_ret;
254 }
255 
build_list(void)256 alc_list_t* build_list(void) {
257   alc_list_t *my_list;
258 
259   my_list = calloc(1, sizeof(alc_list_t));
260 
261 #ifdef _MSC_VER
262   InitializeCriticalSection(&(my_list->session_variables_semaphore));
263 #else
264   my_list->session_variables_semaphore = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
265 #endif
266 
267   return my_list;
268 }
269 
destroy_list(alc_list_t * a_list)270 void destroy_list(alc_list_t *a_list) {
271   struct alc_list_node *my_node = NULL;
272   struct alc_list_node *my_currentnode = NULL;
273 
274   if(a_list == NULL) {
275     return;
276   }
277 
278   lock_list(a_list);
279 
280   for(my_node = a_list->first_elem; my_node != NULL;) {
281     my_currentnode = my_node;
282     my_node = my_node->next;
283 
284     free(my_currentnode->data);
285     free(my_currentnode);
286   }
287 
288   unlock_list(a_list);
289 
290 #ifdef _MSC_VER
291   DeleteCriticalSection(&(a_list->session_variables_semaphore));
292 #else
293 #endif
294 
295   free(a_list);
296 }
297