1 /* $Id$
2 * --------------------------------------------------------------------------
3 *
4 * //===== //===== ===//=== //===// // // //===//
5 * // // // // // // // // //
6 * //====// // // //===// // // //===<<
7 * // // // // // // // //
8 * ======// //===== // // //===== // //===//
9 *
10 * -------------- An SCTP implementation according to RFC 4960 --------------
11 *
12 * Copyright (C) 2000 by Siemens AG, Munich, Germany.
13 * Copyright (C) 2001-2004 Andreas Jungmaier
14 * Copyright (C) 2004-2019 Thomas Dreibholz
15 *
16 * Acknowledgements:
17 * Realized in co-operation between Siemens AG and the University of
18 * Duisburg-Essen, Institute for Experimental Mathematics, Computer
19 * Networking Technology group.
20 * This work was partially funded by the Bundesministerium fuer Bildung und
21 * Forschung (BMBF) of the Federal Republic of Germany
22 * (Förderkennzeichen 01AK045).
23 * The authors alone are responsible for the contents.
24 *
25 * This library is free software: you can redistribute it and/or modify it
26 * under the terms of the GNU Lesser General Public License as published by
27 * the Free Software Foundation, either version 2.1 of the License, or
28 * (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public License
36 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 *
38 * Contact: sctp-discussion@sctp.de
39 * dreibh@iem.uni-due.de
40 * tuexen@fh-muenster.de
41 * andreas.jungmaier@web.de
42 */
43
44 #include "globals.h"
45 #include "adaptation.h"
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdarg.h>
49 #include <time.h>
50 #include <sys/types.h>
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55
56 #ifdef WIN32
57 #include <process.h>
58 #endif
59
60
61 boolean globalTrace;
62 boolean fileTrace = FALSE;
63 FILE* logfile;
64 static int noOftracedModules;
65 static char tracedModules[50][70];
66 static int errorTraceLevel[50];
67 static int eventTraceLevel[50];
68
69 /**
70 * helper function for sorting list of chunks in tsn order
71 * @param one pointer to chunk data
72 * @param two pointer to other chunk data
73 * @return 0 if chunks have equal tsn, -1 if tsn1 < tsn2, 1 if tsn1 > tsn2
74 */
sort_tsn(chunk_data * one,chunk_data * two)75 int sort_tsn(chunk_data * one, chunk_data * two)
76 {
77 if (before(one->chunk_tsn, two->chunk_tsn)) {
78 return -1;
79 } else if (after(one->chunk_tsn, two->chunk_tsn)) {
80 return 1;
81 } else /* one==two */
82 return 0;
83 }
84
sort_prChunk(pr_stream_data * one,pr_stream_data * two)85 int sort_prChunk(pr_stream_data* one, pr_stream_data* two)
86 {
87 if (one->stream_id < two->stream_id) {
88 return -1;
89 } else if (one->stream_id > two->stream_id) {
90 return 1;
91 } else /* one.sid==two.sid */ {
92 if (sBefore(one->stream_sn, two->stream_sn)) return -1;
93 else if (sAfter(one->stream_sn, two->stream_sn)) return 1;
94 }
95 return 0;
96 }
97
98
99 /**
100 read_tracelevels reads from a file the tracelevels for errors and events for each module.
101 Modules that are not listed in the file will not be traced. if the file does not exist or
102 is empty, the global tracelevel defined in globals.h will be used. THe name of the file has
103 to be {\texttt tracelevels.in} in the current directory where the executable is located.
104 The normal format of the file is:
105 \begin{verbatim}
106 module1.c errorTraceLevel eventTraceLevel
107 module2.c errorTraceLevel eventTraceLevel
108 ....
109 \end{verbatim}
110 The file must be terminated by a null line.
111 Alternatively there may be the entry
112 \begin{verbatim}
113 LOGFILE
114 \end{verbatim}
115 in that file, which causes all output from event_logs() to go into a logfile in the local
116 directory.
117 */
read_tracelevels()118 void read_tracelevels()
119 {
120 FILE *fptr;
121 int i;
122 char filename[100];
123
124 noOftracedModules = 0;
125 fptr = fopen("./tracelevels.in", "r");
126
127 if (fptr != NULL) {
128 globalTrace = TRUE;
129
130 for (i = 0; i < 50; i++) {
131 if(fscanf(fptr, "%s %d %d", tracedModules[i], &errorTraceLevel[i], &eventTraceLevel[i]) >= 1) {
132 if (strcmp(tracedModules[i], "LOGFILE") == 0) {
133 /*
134 printf("Logging all errors and events to file ./tmp%d.log\n", (int)getpid());
135 */
136 fileTrace = TRUE;
137 sprintf(filename, "./tmp%d.log",(int)getpid());
138 logfile = fopen(filename, "w+");
139 return;
140 }
141 }
142 if (ferror(fptr))
143 abort();
144 if (feof(fptr))
145 break;
146 globalTrace = FALSE;
147 }
148 noOftracedModules = i;
149 if (i<= 1) globalTrace = TRUE;
150 /*
151 printf(" globalTrace = %s \n", (globalTrace==TRUE)?"TRUE":"FALSE");
152 */
153 } else {
154 globalTrace = TRUE; /* ??? */
155 }
156 /*
157 printf("global = %d, #of modules = %d\n", (int) globalTrace, noOftracedModules);
158 for (i = 0; i < noOftracedModules; i++)
159 printf("%20s %2d %2d\n", tracedModules[i], errorTraceLevel[i], eventTraceLevel[i]);
160 */
161 }
162
163
164
traceModule(const char * moduleName,int * moduleIndex)165 boolean traceModule(const char *moduleName, int *moduleIndex)
166 {
167 int i;
168 boolean found;
169
170 found = FALSE;
171
172 for (i = 0; i < noOftracedModules; i++)
173 if (!strcmp(tracedModules[i], moduleName)) {
174 found = TRUE;
175 break;
176 }
177
178 *moduleIndex = i;
179
180 return found;
181 }
182
183
184
185
debug_vwrite(FILE * fd,const char * format,va_list ap)186 int debug_vwrite(FILE * fd, const char *format, va_list ap)
187 {
188 struct timeval tv;
189 struct tm *the_time;
190
191 adl_gettime(&tv);
192 the_time = localtime((time_t *) & (tv.tv_sec));
193
194 if (fprintf(fd, "%02d:%02d:%02d.%03d - ",
195 the_time->tm_hour,
196 the_time->tm_min, the_time->tm_sec, (int) (tv.tv_usec / 1000)) < 1)
197 return (-1);
198 if (vfprintf(fd, format, ap) < 1)
199 return (-1);
200 return (0);
201 }
202
203
debug_print(FILE * fd,const char * f,...)204 void debug_print(FILE * fd, const char *f, ...)
205 {
206 va_list va;
207 va_start(va, f);
208 debug_vwrite(fd, f, va);
209 va_end(va);
210 fflush(fd);
211 return;
212 }
213
214
215
perr_exit(const char * infostring)216 void perr_exit(const char *infostring)
217 {
218 perror(infostring);
219 abort();
220 }
221
222
print_time(short level)223 void print_time(short level)
224 {
225 struct timeval now;
226
227 adl_gettime(&now);
228 event_logii(level, "Time now: %ld sec, %ld usec \n", now.tv_sec, now.tv_usec);
229 }
230
231
232
233 /**
234 This function logs events.
235 @param event_log_level INTERNAL_EVENT_0 INTERNAL_EVENT_1 EXTERNAL_EVENT_X EXTERNAL_EVENT
236 @param module_name the name of the module that received the event.
237 @param log_info the info that is printed with the modulename.
238 @param anyno optional pointer to unsigned int, which is printed along with log_info.
239 The conversion specification must be contained in log_info.
240 */
event_log1(short event_log_level,const char * module_name,const char * log_info,...)241 void event_log1(short event_log_level, const char *module_name, const char *log_info, ...)
242 {
243 int mi;
244 struct timeval tv;
245 struct tm *the_time;
246
247 va_list va;
248
249 va_start(va, log_info);
250
251 if ((globalTrace && event_log_level <= Current_event_log_) ||
252 (!globalTrace && traceModule(module_name, &mi)
253 && event_log_level <= eventTraceLevel[mi])) {
254
255 if (event_log_level < VERBOSE) {
256 if (fileTrace == TRUE) {
257 debug_print(logfile, "Event in Module: %s............\n", module_name);
258 } else {
259 debug_print(stdout, "Event in Module: %s............\n", module_name);
260 }
261 }
262 adl_gettime(&tv);
263 the_time = localtime((time_t *) & (tv.tv_sec));
264 if (fileTrace == TRUE) {
265 fprintf(logfile, "%02d:%02d:%02d.%03d - ",
266 the_time->tm_hour, the_time->tm_min, the_time->tm_sec, (int) (tv.tv_usec / 1000));
267 vfprintf(logfile, log_info, va);
268 fprintf(logfile, "\n");
269 fflush(logfile);
270 } else {
271 fprintf(stdout, "%02d:%02d:%02d.%03d - ",
272 the_time->tm_hour, the_time->tm_min, the_time->tm_sec, (int) (tv.tv_usec / 1000));
273 vfprintf(stdout, log_info, va);
274 fprintf(stdout, "\n");
275 fflush(stdout);
276 }
277 }
278 va_end(va);
279 return;
280 }
281
282
283
284
285 /**
286 This function logs errors.
287 @param error_log_level ERROR_MINOR ERROR_MAJOR ERROR_FATAL
288 @param module_name the name of the module that received the event.
289 @param line_no the line number within above module.
290 @param log_info the info that is printed with the modulename.
291 @param anyno optional pointer to unsigned int, which is printed along with log_info.
292 The conversion specification must be contained in log_info.
293
294 */
error_log1(short error_log_level,const char * module_name,int line_no,const char * log_info,...)295 void error_log1(short error_log_level, const char *module_name, int line_no, const char *log_info, ...)
296 {
297 int mi;
298 va_list va;
299
300 va_start(va, log_info);
301
302 if ((globalTrace && error_log_level <= Current_error_log_) ||
303 (!globalTrace && traceModule(module_name, &mi)
304 && error_log_level <= eventTraceLevel[mi])) {
305 if (fileTrace == TRUE) {
306 if (error_log_level > ERROR_MINOR)
307 debug_print(logfile,
308 "+++++++++++++++ Error (Level %2d) in %s at line %d +++++++++++++++++++\n",
309 error_log_level, module_name, line_no);
310 fprintf(logfile, "Error Info: ");
311 debug_vwrite(logfile, log_info, va);
312 fprintf(logfile, "\n");
313 } else {
314 if (error_log_level > ERROR_MINOR)
315 debug_print(stderr,
316 "+++++++++++++++ Error (Level %2d) in %s at line %d +++++++++++++++++++\n",
317 error_log_level, module_name, line_no);
318 fprintf(stderr, "Error Info: ");
319 debug_vwrite(stderr, log_info, va);
320 fprintf(stderr, "\n");
321 }
322 }
323 va_end(va);
324 if (fileTrace == TRUE) {
325 fflush(logfile);
326 } else {
327 fflush(stderr);
328 }
329 if (error_log_level == ERROR_FATAL) {
330 abort();
331 }
332 }
333
334 /**
335 This function logs system call errors. It calls error_log.
336 @param error_log_level ERROR_MINOR ERROR_MAJOR ERROR_FATAL
337 @param module_name the name of the module that received the event.
338 @param line_no the line number within above module.
339 @param errnumber the errno from systemlibrary.
340 @param log_info the info that is printed with the modulename and error text.
341 */
error_log_sys1(short error_log_level,const char * module_name,int line_no,short errnumber)342 void error_log_sys1(short error_log_level, const char *module_name, int line_no, short errnumber)
343 {
344 error_log1(error_log_level, module_name, line_no, strerror(errnumber));
345 }
346
347
348 /**
349 * functions correctly handle wraparound
350 */
before(unsigned int seq1,unsigned int seq2)351 int before(unsigned int seq1, unsigned int seq2)
352 {
353 return (int) (seq1 - seq2) < 0;
354 }
355
after(unsigned int seq1,unsigned int seq2)356 int after(unsigned int seq1, unsigned int seq2)
357 {
358 return (int) (seq2 - seq1) < 0;
359 }
360
sAfter(unsigned short seq1,unsigned short seq2)361 int sAfter(unsigned short seq1, unsigned short seq2)
362 {
363 return (int)((short)(seq2 - seq1)) < 0;
364 }
365
sBefore(unsigned short seq1,unsigned short seq2)366 int sBefore(unsigned short seq1, unsigned short seq2)
367 {
368 return (int)((short) (seq1 - seq2) < 0);
369 }
370
371
372
373 /**
374 * is s1 <= s2 <= s3 ?
375 */
between(unsigned int seq1,unsigned int seq2,unsigned int seq3)376 int between(unsigned int seq1, unsigned int seq2, unsigned int seq3)
377 {
378 return seq3 - seq1 >= seq2 - seq1;
379 }
380
free_list_element(gpointer list_element,gpointer user_data)381 void free_list_element(gpointer list_element, gpointer user_data)
382 {
383 chunk_data * chunkd = (chunk_data*) list_element;
384
385 if (user_data == NULL) {
386 if (list_element != NULL) free (list_element);
387 return;
388 } else if (GPOINTER_TO_INT(user_data) == 1) { /* call from flowcontrol */
389 if (list_element != NULL) {
390 if (chunkd->num_of_transmissions == 0) free (list_element);
391 }
392 } else if (GPOINTER_TO_INT(user_data) == 2) { /* call from reltransfer */
393 if (list_element != NULL) {
394 if (chunkd->num_of_transmissions != 0) free (list_element);
395 }
396 }
397 }
398