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