1 /* $Id$
2 * --------------------------------------------------------------------------
3 *
4 * //===== //===== ===//=== //===// // // //===//
5 * // // // // // // // // //
6 * //====// // // //===// // // //===<<
7 * // // // // // // // //
8 * ======// //===== // // //===== // //===//
9 *
10 * -------------- An SCTP implementation according to RFC 4960 --------------
11 *
12 * Copyright (C) 2001 by Andreas Lang
13 *
14 * This library is free software: you can redistribute it and/or modify it
15 * under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation, either version 2.1 of the License, or
17 * (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * Contact: anla@gmx.net
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include "sctp.h"
35 #include "sctptest.h"
36
37
38
39 /* payload: header (6 bytes) and body (initially 26 bytes) */
40 char payloadContents[MAX_PAYLOAD_LENGTH] = "\0\0\0\0\0\0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
41 unsigned int payloadLength = HEADER_LENGTH + 26;
42
43 /* receiver state */
44 int receiveEnabled = 1;
45 int receiveMode = RECEIVE_DISCARD;
46 unsigned int unreceivedChunks = 0;
47
48 /* instance and association IDs (0 indicates that no instance is registered / no association is established) */
49 short instanceID = 0;
50 unsigned int assocID = 0;
51
52 /* association parameters */
53 unsigned short noOfInStreams;
54 unsigned short noOfOutStreams;
55 char localIP[SCTP_MAX_IP_LEN]; /* this is only used in event log messages */
56
57 /* Timer ID (0 indicates that the timer isn't running) */
58 unsigned int pauseTimerID = 0;
59
60
61
62 /**
63 * Execute the script.
64 * @param filename
65 * The name of the script file.
66 * @param mode
67 * For this parameter, use constants CHECK_SCRIPT and RUN_SCRIPT (defined in sctptest.h)
68 * If mode is CHECK_SCRIPT, the script is only checked for errors, but commands are not executed.
69 * This is very useful, because in RUN_SCIPT mode, an error is not detected before the incorrect
70 * command is reached in the script file.
71 *
72 * @return The number of errors that were detected in the script file.
73 */
sctptest_start(char * filename,int mode)74 int sctptest_start(char *filename, int mode)
75 {
76 FILE *scriptFile;
77 unsigned int lineNum = 0, colNum = 0, loopIndex = 0, err = 0;
78 int parseResult, stopParsing = 0, initialized = 0;
79 struct sctptest_scriptCommand scriptCommand;
80 struct loopData {
81 unsigned int currentExec;
82 unsigned int totalExecs;
83 long filePos;
84 unsigned int lineNum;
85 } loop[100];
86
87
88 /* open script file */
89 if ((scriptFile = fopen(filename, "r")) == NULL) {
90 fprintf(stderr, "File not found: %s\n", filename);
91 exit(1);
92 }
93
94
95 while (!stopParsing)
96 {
97 parseResult = getScriptCommand(scriptFile, &scriptCommand, &lineNum, &colNum, mode);
98
99 switch (parseResult)
100 {
101 case PARSE_ERROR:
102 fprintf(stderr, "Line %u, column %u: Parse error\n", lineNum, colNum);
103 err++;
104 stopParsing = 1;
105 break;
106
107 case END_OF_FILE:
108 stopParsing = 1;
109 break;
110
111 case PARSE_OK:
112 /* check if INITIALIZE is the first command */
113 if (initialized == 0) {
114 if (strcmp(scriptCommand.command, "INITIALIZE") != 0) {
115 fprintf(stderr, "Line %u: INITIALIZE expected at beginning of script file.\n", lineNum);
116 err++;
117 }
118 initialized = 1;
119 }
120
121 /* handle loops */
122 if (strcmp(scriptCommand.command, "LOOP") == 0)
123 {
124 if (loopIndex > 99) {
125 fprintf(stderr, "Line %u: Loop stack overflow.\n", lineNum);
126 err++;
127 break;
128 }
129
130 loop[loopIndex].totalExecs = getIntParam(&scriptCommand, "TIMES", 1, 0, DECIMAL,
131 &err, MANDATORY, lineNum);
132 loop[loopIndex].currentExec = 1;
133 loop[loopIndex].filePos = ftell(scriptFile);
134 loop[loopIndex].lineNum = lineNum;
135 loopIndex++;
136 }
137
138 else if (strcmp(scriptCommand.command, "ENDLOOP") == 0)
139 {
140 if (loopIndex == 0) {
141 fprintf(stderr, "Line %u: ENDLOOP without LOOP\n", lineNum);
142 err++;
143 break;
144 }
145
146 if ((loop[loopIndex-1].currentExec >= loop[loopIndex-1].totalExecs) || (mode != RUN_SCRIPT)) {
147 loopIndex--;
148 break;
149 } else {
150 loop[loopIndex-1].currentExec++;
151 fseek(scriptFile, loop[loopIndex-1].filePos, SEEK_SET);
152 lineNum = loop[loopIndex-1].lineNum;
153 break;
154 }
155 }
156
157 /* process script command */
158 else {
159 err += processScriptCommand(&scriptCommand, lineNum, mode);
160 break;
161 }
162 }
163 }
164
165 fclose(scriptFile);
166 return err;
167 }
168
169
170 /**
171 * Process a script command.
172 * @param sc
173 * pointer to the sctptest_scriptCommand structure
174 * @param lineNum
175 * the line number that is to be printed in error and event messages
176 * @param mode
177 * see the description at sctptest_start()
178 *
179 * @return the number of script errors that were detected by this function (0 if successful)
180 */
processScriptCommand(struct sctptest_scriptCommand * sc,unsigned int lineNum,int mode)181 int processScriptCommand(struct sctptest_scriptCommand *sc, unsigned int lineNum, int mode)
182 {
183 unsigned int errors = 0;
184
185 /* nur zum Testen... */
186 /* printCommand(sc, lineNum); */
187
188 /* Of course, a hashtable would be much more elegant... ;-) */
189
190 /* INITIALIZE */
191 if (strcmp(sc->command, "INITIALIZE") == 0)
192 {
193 unsigned char ip[1][SCTP_MAX_IP_LEN], *ipStr;
194 unsigned short port, instreams, outstreams;
195
196 ipStr = (unsigned char *)getStrParam(sc, "IP", &errors, MANDATORY, lineNum);
197 if (strlen((char *)ipStr) > SCTP_MAX_IP_LEN - 1) {
198 fprintf(stderr, "Line %u: Invalid IP-Address\n", lineNum);
199 errors++;
200 }
201
202 port = (unsigned short) getIntParam(sc, "PORT", 1, 0xFFFF, DECIMAL, &errors, MANDATORY, lineNum);
203 instreams = (unsigned short) getIntParam(sc, "INSTREAMS", 1, 0, DECIMAL, &errors, MANDATORY, lineNum);
204 outstreams = (unsigned short) getIntParam(sc, "OUTSTREAMS", 1, 0, DECIMAL, &errors, MANDATORY, lineNum);
205
206 if (errors == 0 && mode == RUN_SCRIPT) {
207 SCTP_ulpCallbacks ulpCallbacks;
208
209 printf("\n%s ---> INITIALIZE in line %u\n", getTimeString(), lineNum);
210
211 if (instanceID != 0) {
212 printf("Exception in line %u: INITIALIZE: SCTP instance already initialized\n", lineNum);
213 return 0;
214 }
215
216 strcpy((char *)ip[0], (const char *)ipStr);
217
218 ulpCallbacks.dataArriveNotif = &dataArriveNotif;
219 ulpCallbacks.sendFailureNotif = &sendFailureNotif;
220 ulpCallbacks.networkStatusChangeNotif = &networkStatusChangeNotif;
221 ulpCallbacks.communicationUpNotif = &communicationUpNotif;
222 ulpCallbacks.communicationLostNotif = &communicationLostNotif;
223 ulpCallbacks.communicationErrorNotif = &communicationErrorNotif;
224 ulpCallbacks.restartNotif = &restartNotif;
225 ulpCallbacks.shutdownCompleteNotif = &shutdownCompleteNotif;
226 ulpCallbacks.peerShutdownReceivedNotif = NULL;
227
228 instanceID = sctp_registerInstance(port, instreams, outstreams, 1, ip, ulpCallbacks);
229
230 if (instanceID > 0) {
231 printf("SCTP instance successfully initialized\n");
232 strcpy((char *)localIP, (const char *)ipStr);
233 } else {
234 fprintf(stderr, "Initialize FAILED. Please check your parameters!\n");
235 exit(1);
236 }
237 }
238 }
239
240
241 /* WAIT_FOR_ASSOC */
242 else if (strcmp(sc->command, "WAIT_FOR_ASSOC") == 0)
243 {
244 if (mode == RUN_SCRIPT) {
245 printf("\n%s (%s) ---> WAIT_FOR_ASSOC in line %u\n", getTimeString(), localIP, lineNum);
246
247 if (assocID != 0) {
248 printf("Exception in line %u: WAIT_FOR_ASSOC: Association already exists\n", lineNum);
249 return 0;
250 }
251
252 while (assocID == 0)
253 sctp_eventLoop();
254 }
255 }
256
257
258 /* SHUTDOWN */
259 else if (strcmp(sc->command, "SHUTDOWN") == 0)
260 {
261 if (mode == RUN_SCRIPT) {
262 printf("\n%s (%s) ---> SHUTDOWN in line %u\n", getTimeString(), localIP, lineNum);
263
264 if (assocID == 0) {
265 printf("Exception in line %u: SHUTDOWN: Association does not exist!\n",
266 lineNum);
267 return 0;
268 }
269 sctp_shutdown(assocID);
270 }
271 }
272
273
274 /* ABORT */
275 else if (strcmp(sc->command, "ABORT") == 0)
276 {
277 if (mode == RUN_SCRIPT) {
278 printf("\n%s (%s) ---> ABORT in line %u\n", getTimeString(), localIP, lineNum);
279
280 if (assocID == 0) {
281 printf("Exception in line %u: ABORT: Association does not exist!\n",
282 lineNum);
283 return 0;
284 }
285 sctp_abort(assocID);
286 }
287 }
288
289
290 /* SET_PAYLOAD_HEADER */
291 else if (strcmp(sc->command, "SET_PAYLOAD_HEADER") == 0)
292 {
293 unsigned short type;
294 unsigned char mbu, mch, jc1, jc2;
295
296 type = (unsigned short) getIntParam(sc, "TYPE", 0, 0xFFFF, HEXADECIMAL, &errors, MANDATORY, lineNum);
297 mbu = (unsigned char) getIntParam(sc, "MBU", 0, 0xFF, HEXADECIMAL, &errors, MANDATORY, lineNum);
298 mch = (unsigned char) getIntParam(sc, "MCH", 0, 0xFF, HEXADECIMAL, &errors, MANDATORY, lineNum);
299 jc1 = (unsigned char) getIntParam(sc, "JC1", 0, 0xFF, HEXADECIMAL, &errors, MANDATORY, lineNum);
300 jc2 = (unsigned char) getIntParam(sc, "JC2", 0, 0xFF, HEXADECIMAL, &errors, MANDATORY, lineNum);
301
302 if (errors == 0 && mode == RUN_SCRIPT) {
303 printf("\n%s (%s) ---> SET_PAYLOAD_HEADER in line %u\n", getTimeString(), localIP, lineNum);
304
305 payloadContents[0] = (type & 0xFF00) >> 8;
306 payloadContents[1] = (type & 0x00FF);
307 payloadContents[2] = mbu;
308 payloadContents[3] = mch;
309 payloadContents[4] = jc1;
310 payloadContents[5] = jc2;
311
312 printf("Payload header changed: TYPE=%04X, MBU=%02X, MCH=%02X, JC1=%02X, JC2=%02X\n",
313 type, mbu, mch, jc1, jc2);
314 }
315 }
316
317
318 /* SET_PAYLOAD_BODY */
319 else if (strcmp(sc->command, "SET_PAYLOAD_BODY") == 0)
320 {
321 char *contentsStr, contentsBuf[MAX_WORD_LENGTH];
322 unsigned int length, i, j, contentsStrLen;
323 unsigned char asciichar, asciival[3];
324 char *endp;
325
326 contentsStr = getStrParam(sc, "CONTENTS", &errors, MANDATORY, lineNum);
327 length = (unsigned int) getIntParam(sc, "LENGTH", MIN_PAYLOAD_LENGTH - HEADER_LENGTH,
328 MAX_PAYLOAD_LENGTH - HEADER_LENGTH, DECIMAL, &errors, MANDATORY, lineNum);
329
330 contentsStrLen = strlen(contentsStr);
331 for (i = j = 0; i < contentsStrLen; i++) {
332 if (contentsStr[i] == '\\') {
333 asciival[0] = contentsStr[++i];
334 asciival[1] = contentsStr[++i];
335 asciival[2] = '\0';
336 asciichar = (unsigned char) strtoul((char *)asciival, &endp, 16);
337 if (*endp != '\0') {
338 fprintf(stderr, "Error in line %u: ASCII code expected after '\\'\n", lineNum);
339 return (++errors);
340 }
341 contentsBuf[j++] = asciichar;
342 } else {
343 contentsBuf[j++] = contentsStr[i];
344 }
345 }
346
347 contentsStrLen = j;
348 for (i = 0; j < length; ) {
349 contentsBuf[j++] = contentsBuf[i++];
350 if (i == contentsStrLen)
351 i = 0;
352 }
353
354 contentsBuf[j] = '\0';
355 length = j;
356
357 if (errors == 0 && mode == RUN_SCRIPT) {
358 printf("\n%s (%s) ---> SET_PAYLOAD_BODY in line %u\n", getTimeString(), localIP, lineNum);
359
360 for (i = 0; (i < length) && (i < MAX_PAYLOAD_LENGTH); i++) {
361 payloadContents[HEADER_LENGTH + i] = contentsBuf[i];
362 }
363 payloadLength = HEADER_LENGTH + i;
364
365 printf("Payload body changed.\n");
366 }
367 }
368
369 /* SET_PAYLOAD_BODY */
370 else if (strcmp(sc->command, "SET_PAYLOAD") == 0)
371 {
372 char *contentsStr, contentsBuf[MAX_WORD_LENGTH];
373 unsigned int length, i, j, contentsStrLen;
374 unsigned char asciichar, asciival[3];
375 char *endp;
376
377 contentsStr = getStrParam(sc, "CONTENTS", &errors, MANDATORY, lineNum);
378 length = (unsigned int) getIntParam(sc, "LENGTH", MIN_PAYLOAD_LENGTH - HEADER_LENGTH,
379 MAX_PAYLOAD_LENGTH - HEADER_LENGTH, DECIMAL, &errors, MANDATORY, lineNum);
380
381 contentsStrLen = strlen(contentsStr);
382 for (i = j = 0; i < contentsStrLen; i++) {
383 if (contentsStr[i] == '\\') {
384 asciival[0] = contentsStr[++i];
385 asciival[1] = contentsStr[++i];
386 asciival[2] = '\0';
387 asciichar = (unsigned char) strtoul((char *)asciival, &endp, 16);
388 if (*endp != '\0') {
389 fprintf(stderr, "Error in line %u: ASCII code expected after '\\'\n", lineNum);
390 return (++errors);
391 }
392 contentsBuf[j++] = asciichar;
393 } else {
394 contentsBuf[j++] = contentsStr[i];
395 }
396 }
397
398 contentsStrLen = j;
399 for (i = 0; j < length; ) {
400 contentsBuf[j++] = contentsBuf[i++];
401 if (i == contentsStrLen)
402 i = 0;
403 }
404
405 contentsBuf[j] = '\0';
406 length = j;
407
408 if (errors == 0 && mode == RUN_SCRIPT) {
409 printf("\n%s (%s) ---> SET_PAYLOAD in line %u\n", getTimeString(), localIP, lineNum);
410
411 for (i = 0; (i < length) && (i < MAX_PAYLOAD_LENGTH); i++) {
412 payloadContents[i] = contentsBuf[i];
413 }
414 payloadLength = i;
415
416 printf("Payload changed.\n");
417 }
418 }
419 /* DISABLE_RECEIVE */
420 else if (strcmp(sc->command, "DISABLE_RECEIVE") == 0)
421 {
422 if (mode == RUN_SCRIPT) {
423 printf("\n%s (%s) ---> DISABLE_RECEIVE in line %u\n", getTimeString(), localIP, lineNum);
424 receiveEnabled = 0;
425 }
426 }
427
428
429 /* ENABLE_RECEIVE */
430 else if (strcmp(sc->command, "ENABLE_RECEIVE") == 0)
431 {
432 if (mode == RUN_SCRIPT) {
433 printf("\n%s (%s) ---> ENABLE_RECEIVE in line %u\n", getTimeString(), localIP, lineNum);
434
435 receiveEnabled = 1;
436
437 if (unreceivedChunks > 0)
438 doReceive(assocID);
439 }
440 }
441
442
443 /* PAUSE */
444 else if (strcmp(sc->command, "PAUSE") == 0)
445 {
446 unsigned int delay;
447
448 delay = (unsigned int) getIntParam(sc, "TIME", 1, 0, DECIMAL, &errors, MANDATORY, lineNum);
449
450 if (errors == 0 && mode == RUN_SCRIPT) {
451 printf("\n%s (%s) ---> PAUSE in line %u (%u msec)\n", getTimeString(), localIP, lineNum, delay);
452
453 pauseTimerID = sctp_startTimer(delay/1000, (delay%1000)*1000, &timerCallback, NULL, NULL);
454 while(pauseTimerID != 0)
455 sctp_eventLoop();
456 }
457 }
458
459 /* SEND_CHUNKS */
460 else if (strcmp(sc->command, "SEND_CHUNKS") == 0)
461 {
462 unsigned int num, delay;
463 unsigned short stream;
464
465 num = (unsigned int) getIntParam(sc, "NUM", 1, 0, DECIMAL, &errors, MANDATORY, lineNum);
466 delay = (unsigned int) getIntParam(sc, "DELAY", 0, 0, DECIMAL, &errors, OPTIONAL, lineNum);
467 stream = (unsigned short) getIntParam(sc, "STREAM", 0, 0, DECIMAL, &errors, OPTIONAL, lineNum);
468
469 if (errors == 0 && mode == RUN_SCRIPT)
470 {
471 int sendRes;
472 unsigned int n = 1;
473
474 printf("\n%s (%s) ---> SEND_CHUNKS in line %u (%u chunks, %u msec delay, stream %u)\n",
475 getTimeString(), localIP, lineNum, num, delay, stream);
476
477 if (assocID == 0) {
478 printf("Exception in line %u: SEND_CHUNKS: Association does not exist!\n",
479 lineNum);
480 return 0;
481 }
482
483
484 while (n <= num)
485 {
486 sendRes = sctp_send(assocID, stream, (unsigned char *)payloadContents, payloadLength, /*protoID*/ 0,
487 SCTP_USE_PRIMARY, SCTP_NO_CONTEXT, SCTP_INFINITE_LIFETIME,
488 SCTP_ORDERED_DELIVERY, SCTP_BUNDLING_DISABLED);
489 n++;
490
491 /* handle sctp_send errors */
492 if (sendRes == 1)
493 printf("Exception in line %u: sctp_send returned association error\n", lineNum);
494 else if (sendRes == -1)
495 printf("Exception in line %u: sctp_send returned send error\n", lineNum);
496
497 /* start delay timer */
498 if (delay > 0) {
499 pauseTimerID = sctp_startTimer(delay/1000, (delay%1000)*1000, &timerCallback, NULL, NULL);
500 while (pauseTimerID != 0)
501 sctp_eventLoop();
502 }
503 /* unn�tig(?) sctp_getEvents(); */
504 }
505 }
506 }
507
508 #ifdef BAKEOFF
509 /* SEND_RAWDATA */
510 else if (strcmp(sc->command, "SEND_RAWDATA") == 0)
511 {
512 short pathId;
513
514 pathId = (short) getIntParam(sc, "PATH", 0, 20, DECIMAL, &errors, OPTIONAL, lineNum);
515
516 if (errors == 0 && mode == RUN_SCRIPT)
517 {
518 int sendRes;
519 printf("\n%s (%s) ---> SEND_RAWDATA in line %u)\n", getTimeString(), localIP, lineNum);
520
521 if (assocID == 0) {
522 printf("Exception in line %u: SEND_RAWDATA: Association does not exist!\n", lineNum);
523 return 0;
524 }
525
526 sendRes = sctp_sendRawData(assocID, pathId, payloadContents, payloadLength);
527
528 /* handle sctp_send errors */
529 if (sendRes == 1)
530 printf("Exception in line %u: sctp_sendRawData returned association error\n", lineNum);
531 else if (sendRes == -1)
532 printf("Exception in line %u: sctp_sendRawData returned send error\n", lineNum);
533 }
534 }
535 #endif
536
537 /* SET_RWND */
538 else if (strcmp(sc->command, "SET_RWND") == 0)
539 {
540 unsigned int rwnd;
541
542 rwnd = (unsigned int) getIntParam(sc, "SIZE", 0, 0, DECIMAL, &errors, MANDATORY, lineNum);
543
544 if (errors == 0 && mode == RUN_SCRIPT) {
545 SCTP_InstanceParameters iparams;
546 SCTP_AssociationStatus astatus;
547
548 printf("\n%s (%s) ---> SET_RWND in line %u (new size: %u bytes)\n",
549 getTimeString(), localIP, lineNum, rwnd);
550
551 sctp_getAssocDefaults(instanceID, &iparams);
552 iparams.myRwnd = rwnd;
553 sctp_setAssocDefaults(instanceID, &iparams);
554
555 if (assocID != 0) {
556 sctp_getAssocStatus(assocID, &astatus);
557 astatus.myRwnd = rwnd;
558 sctp_setAssocStatus(assocID, &astatus);
559 }
560 }
561 }
562
563
564
565 /* SET_RECV_QUEUE */
566 else if (strcmp(sc->command, "SET_RECV_QUEUE") == 0)
567 {
568 unsigned int recvQueue;
569
570 recvQueue = (unsigned int) getIntParam(sc, "SIZE", 0, 0, DECIMAL, &errors, MANDATORY, lineNum);
571
572 if (errors == 0 && mode == RUN_SCRIPT) {
573 SCTP_InstanceParameters iparams;
574 SCTP_AssociationStatus astatus;
575
576 printf("\n%s (%s) ---> SET_RECV_QUEUE in line %u (%u chunks)\n",
577 getTimeString(), localIP, lineNum, recvQueue);
578
579 sctp_getAssocDefaults(instanceID, &iparams);
580 iparams.maxRecvQueue = recvQueue;
581 sctp_setAssocDefaults(instanceID, &iparams);
582
583 if (assocID != 0) {
584 sctp_getAssocStatus(assocID, &astatus);
585 astatus.maxRecvQueue = recvQueue;
586 sctp_setAssocStatus(assocID, &astatus);
587 }
588 }
589 }
590
591
592
593 /* SET_ACK_DELAY */
594 else if (strcmp(sc->command, "SET_ACK_DELAY") == 0)
595 {
596 unsigned int ackDelay;
597
598 ackDelay = (unsigned int) getIntParam(sc, "DELAY", 0, 0, DECIMAL, &errors, MANDATORY, lineNum);
599
600 if (errors == 0 && mode == RUN_SCRIPT) {
601 SCTP_InstanceParameters iparams;
602 SCTP_AssociationStatus astatus;
603
604 printf("\n%s (%s) ---> SET_ACK_DELAY in line %u (%u msec)\n",
605 getTimeString(), localIP, lineNum, ackDelay);
606
607 sctp_getAssocDefaults(instanceID, &iparams);
608 iparams.delay = ackDelay;
609 sctp_setAssocDefaults(instanceID, &iparams);
610
611 if (assocID != 0) {
612 sctp_getAssocStatus(assocID, &astatus);
613 astatus.delay = ackDelay;
614 sctp_setAssocStatus(assocID, &astatus);
615 }
616 }
617 }
618
619
620
621 /* SET_HEARTBEAT */
622 else if (strcmp(sc->command, "SET_HEARTBEAT") == 0)
623 {
624 unsigned int time;
625 int res;
626
627 time = (unsigned int) getIntParam(sc, "TIMEINTERVAL", 0, 0, DECIMAL, &errors, MANDATORY, lineNum);
628
629 if (errors == 0 && mode == RUN_SCRIPT) {
630 printf("\n%s (%s) ---> SET_HEARTBEAT in line %u (timeinterval = %u msec)\n",
631 getTimeString(), localIP, lineNum, time);
632
633 res = sctp_changeHeartBeat(assocID, SCTP_USE_PRIMARY,
634 (time > 0) ? SCTP_HEARTBEAT_ON : SCTP_HEARTBEAT_OFF, time);
635 if (res != 0)
636 printf("Exception in line %u: SET_HEARTBEAT failed.\n", lineNum);
637 }
638 }
639
640
641
642 /* SET_RECEIVE_MODE */
643 else if (strcmp(sc->command, "SET_RECEIVE_MODE") == 0)
644 {
645 char *recModeStr;
646 int recMode=RECEIVE_DISCARD;
647
648 recModeStr = getStrParam(sc, "MODE", &errors, MANDATORY, lineNum);
649
650 if (strcmp(recModeStr, "DISCARD") == 0)
651 recMode = RECEIVE_DISCARD;
652 else if (strcmp(recModeStr, "MIRROR") == 0)
653 recMode = RECEIVE_MIRROR;
654 else {
655 fprintf(stderr, "Error in line %u: Parameter MODE must be either MIRROR or DISCARD\n", lineNum);
656 errors++;
657 }
658
659 if (errors == 0 && mode == RUN_SCRIPT) {
660 printf("\n%s (%s) ---> SET_RECEIVE_MODE in line %u (-> %s)\n", getTimeString(), localIP,
661 lineNum, (recMode == RECEIVE_MIRROR) ? "MIRROR" : "DISCARD");
662
663 receiveMode = recMode;
664 }
665 }
666
667 /* ASSOCIATE */
668 else if (strcmp(sc->command, "ASSOCIATE") == 0)
669 {
670 char *ip;
671 unsigned short port, outstreams;
672
673 ip = getStrParam(sc, "IP", &errors, MANDATORY, lineNum);
674 port = (unsigned short) getIntParam(sc, "PORT", 1, 0xFFFF, DECIMAL, &errors, MANDATORY, lineNum);
675 outstreams = (unsigned short) getIntParam(sc, "OUTSTREAMS", 1, 0, DECIMAL, &errors, MANDATORY, lineNum);
676
677 if (strlen(ip) > SCTP_MAX_IP_LEN - 1) {
678 fprintf(stderr, "Line %u: Invalid IP-Address", lineNum);
679 errors++;
680 }
681
682 if (errors == 0 && mode == RUN_SCRIPT) {
683 printf("\n%s (%s) ---> ASSOCIATE in line %u (Destination: %s)\n",
684 getTimeString(), localIP, lineNum, ip);
685
686 if (assocID != 0) {
687 printf("Exception in line %u: Association already exists\n", lineNum);
688 return 0;
689 }
690
691 if (sctp_associate(instanceID, outstreams, (unsigned char *)ip, port, NULL) == 0) {
692 printf("Exception in line %u: ASSOCIATE failed.\n", lineNum);
693 }
694
695 /* wait until assoc is established */
696 while(assocID == 0)
697 sctp_eventLoop();
698 }
699 }
700
701
702 /* Unknown Command */
703 else {
704 fprintf(stderr, "Line %u: Unknown command\n", lineNum);
705 errors++;
706 }
707
708
709 /* Get outstanding events */
710 if (mode == RUN_SCRIPT)
711 sctp_getEvents();
712
713 return errors;
714 }
715
716
717 /**
718 * Retrieve a string parameter from an sctptest_scriptCommand structure
719 * @param sc
720 * pointer to the sctptest_scriptCommand structure
721 * @param key
722 * the key that belongs to the parameter that shall be retrieved
723 * @param err
724 * pointer to an integer variable. This variable is increased when an error occurs,
725 * i.e. when the structure does not contain the specified (mandatory) parameter
726 * @param paramType
727 * use the constants MANDATORY and OPTIONAL (defined in sctptest.h)
728 * If the parameter is OPTIONAL, no error message is printed and *err is not increased when
729 * the parameter does not exist
730 * @param lineNum
731 * The line number that is to be printed in error messages
732 *
733 * @return a pointer to the string that contains the parameter value,
734 * or NULL if the parameter does not exist
735 */
getStrParam(struct sctptest_scriptCommand * sc,const char * key,unsigned int * err,int paramType,unsigned int lineNum)736 char *getStrParam(struct sctptest_scriptCommand *sc, const char *key, unsigned int *err,
737 int paramType, unsigned int lineNum)
738 {
739 int i;
740 for (i = 0; i < (int)sc->numOfParams; i++)
741 if (strcmp(sc->param[i].key, key) == 0)
742 return sc->param[i].value;
743
744 if (paramType == MANDATORY) {
745 fprintf(stderr, "Line %u: Command %s requires parameter %s\n", lineNum, sc->command, key);
746 (*err)++;
747 }
748 return NULL;
749 }
750
751
752 /**
753 * Retrieve an integer parameter from an sctptest_scriptCommand structure
754 * @param sc
755 * pointer to the sctptest_scriptCommand structure
756 * @param key
757 * the key that belongs to the parameter that shall be retrieved
758 * @param lowLimit
759 * If the parameter value is less than "lowLimit", an error message is printed,
760 * and *err is increased.
761 * @param highLimit
762 * If the parameter value is greater than "highLimit", an error message is printed,
763 * and *err is increased.
764 * If "highLimit" equals or is lower than "lowLimit", it is ignored. This is useful
765 * if no upper limit shall be specified.
766 * @param base
767 * The base of the integer parameter, which can be either DECIMAL or HEXADECIMAL (these constants
768 * are defined in sctptest.h) If the parameter is not written in that base or if it is no integer
769 * at all, an error message is printed and *err is increased.
770 * @param err
771 * pointer to an integer variable which is increased when an error occurs.
772 * @param paramType
773 * use the constants MANDATORY and OPTIONAL (defined in sctptest.h)
774 * If the parameter is OPTIONAL, no error message is printed and *err is not increased when
775 * the parameter does not exist
776 * @param lineNum
777 * The line number that is to be printed in error messages
778 *
779 * @return the retrieved parameter value, or 0 in case of errors
780 *
781 */
getIntParam(struct sctptest_scriptCommand * sc,const char * key,unsigned long lowLimit,unsigned long highLimit,int base,unsigned int * err,int paramType,unsigned int lineNum)782 unsigned long getIntParam(struct sctptest_scriptCommand *sc, const char *key, unsigned long lowLimit,
783 unsigned long highLimit, int base, unsigned int *err, int paramType, unsigned int lineNum)
784 {
785 /* Maybe there should be a parameter for the (default) value that */
786 /* shall be returned if an optional parameter has been omitted */
787
788 char *str, *endp;
789 unsigned long res;
790
791 str = getStrParam(sc, key, err, paramType, lineNum);
792
793 if (str == NULL)
794 return 0;
795
796 res = strtoul(str, &endp, (base == DECIMAL) ? 10 : 16);
797
798 if (*endp != '\0') {
799 fprintf(stderr, "Line %u: Parameter %s must have an integer value%s.\n",
800 lineNum, key, (base == HEXADECIMAL) ? " in hexadecimal format" : "");
801 (*err)++;
802 return 0;
803 }
804 else if (res < lowLimit) {
805 fprintf(stderr, "Line %u: The value of parameter %s must be greater than %lu\n",
806 lineNum, key, lowLimit - 1);
807 (*err)++;
808 return 0;
809 }
810 else if ((res > highLimit) && (highLimit > lowLimit)) {
811 fprintf(stderr, "Line %u: The value of parameter %s cannot be greater than %lu\n",
812 lineNum, key, highLimit);
813 (*err)++;
814 return 0;
815 }
816
817 return res;
818 }
819
820
821
doReceive(unsigned int assoc)822 void doReceive(unsigned int assoc)
823 {
824 char chunk[MAX_PAYLOAD_LENGTH];
825 unsigned int length = MAX_PAYLOAD_LENGTH;
826 unsigned short seqno;
827 unsigned int tsn;
828
829 while (unreceivedChunks > 0) {
830 sctp_receive(assoc, /*stream*/ 0, (unsigned char *)chunk, &length, &seqno, &tsn, SCTP_MSG_DEFAULT);
831 unreceivedChunks--;
832 printf("Data received (%u bytes) -- %u chunks in receive queue\n", length, unreceivedChunks);
833 length = MAX_PAYLOAD_LENGTH;
834 }
835 }
836
837
838
getTimeString()839 char *getTimeString()
840 {
841 static char timeStr[9];
842 time_t t1;
843 struct tm *t;
844
845 t1 = time(NULL);
846 t = localtime(&t1);
847 sprintf(timeStr, "%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec);
848
849 return timeStr;
850 }
851
852
853
854
855 /* ----- CALLBACK FUNCTIONS ----- */
856
857
timerCallback(unsigned int timerID,void * ptr1,void * ptr2)858 void timerCallback(unsigned int timerID, void *ptr1, void *ptr2)
859 {
860 if (timerID == pauseTimerID)
861 pauseTimerID = 0;
862 }
863
864
dataArriveNotif(unsigned int assoc,unsigned short stream,unsigned int len,unsigned short streamSN,unsigned int TSN,unsigned int protoID,unsigned int unordered,void * ulpDataPtr)865 void dataArriveNotif(unsigned int assoc, unsigned short stream, unsigned int len,
866 unsigned short streamSN,unsigned int TSN, unsigned int protoID,
867 unsigned int unordered, void* ulpDataPtr)
868 {
869 unsigned char chunk[MAX_PAYLOAD_LENGTH];
870 unsigned int length = MAX_PAYLOAD_LENGTH;
871 unsigned short seqno;
872 unsigned int tsn;
873
874 /* if data unexpectedly arrives on a stream > 0 */
875 if (stream != 0) {
876 printf("%s (%s) - Data arrived on stream %u -- receiving %u bytes\n",
877 getTimeString(), localIP, stream, len);
878 sctp_receive(assoc, stream, chunk, &length, &seqno, &tsn, SCTP_MSG_DEFAULT);
879 return;
880 }
881
882 unreceivedChunks++;
883
884 printf("%s (%s) - Data arrived (%u bytes %s) -- %u chunks in receive queue\n", getTimeString(), localIP,
885 len, (unordered == SCTP_ORDERED_DELIVERY) ? "ordered" : "unordered", unreceivedChunks);
886
887 if (receiveEnabled)
888 doReceive(assoc);
889
890 if (receiveMode == RECEIVE_MIRROR) {
891 int sendRes;
892 sendRes = sctp_send(assocID, stream, (unsigned char *)payloadContents, (unsigned int)payloadLength, /*protoID*/ 0,
893 SCTP_USE_PRIMARY, SCTP_NO_CONTEXT, SCTP_INFINITE_LIFETIME,
894 SCTP_ORDERED_DELIVERY, SCTP_BUNDLING_DISABLED);
895
896 /* handle sctp_send errors */
897 if (sendRes == 1)
898 printf("Exception in mirror process: sctp_send returned association error\n");
899 else if (sendRes == -1)
900 printf("Exception in mirror process: sctp_send returned send error\n");
901 }
902 }
903
904
sendFailureNotif(unsigned int assoc,unsigned char * unsentData,unsigned int dataLength,unsigned int * context,void * dummy)905 void sendFailureNotif(unsigned int assoc, unsigned char *unsentData,
906 unsigned int dataLength, unsigned int *context, void *dummy)
907 {
908 printf("%s (%s) - Send failure\n", getTimeString(), localIP);
909 }
910
911
networkStatusChangeNotif(unsigned int assoc,short destAddrIndex,unsigned short newState,void * ulpDataPtr)912 void networkStatusChangeNotif(unsigned int assoc, short destAddrIndex,
913 unsigned short newState, void *ulpDataPtr)
914 {
915 printf("%s (%s) - Network status change: path %u is now %s\n", getTimeString(), localIP,
916 destAddrIndex, ((newState == SCTP_PATH_OK) ? "ACTIVE" : "INACTIVE"));
917 }
918
919
communicationUpNotif(unsigned int assoc,int status,unsigned int noOfDestinations,unsigned short instreams,unsigned short outstreams,int associationSupportsPRSCTP,void * dummy)920 void *communicationUpNotif(unsigned int assoc, int status, unsigned int noOfDestinations,
921 unsigned short instreams, unsigned short outstreams,
922 int associationSupportsPRSCTP, void *dummy)
923 {
924 /* abort if association already exists */
925 if (assocID != 0) {
926 printf("%s (%s) - Communication up notification arrived -> sending ABORT (only one association allowed)",
927 getTimeString(), localIP);
928 sctp_abort(assoc);
929 return NULL;
930 }
931
932 printf("%s (%s) - Communication up: %u path(s), %u in-stream(s), %u out-stream(s)\n",
933 getTimeString(), localIP, noOfDestinations, instreams, outstreams);
934 noOfInStreams = instreams;
935 noOfOutStreams = outstreams;
936 assocID = assoc;
937 return NULL;
938
939 }
940
941
communicationLostNotif(unsigned int assoc,unsigned short status,void * ulpDataPtr)942 void communicationLostNotif(unsigned int assoc, unsigned short status, void *ulpDataPtr)
943 {
944 unsigned char buffer[MAX_PAYLOAD_LENGTH];
945 unsigned int bufferLength = sizeof(buffer);
946 unsigned short streamID, streamSN;
947 unsigned int protoID;
948 unsigned int tsn;
949 unsigned char flags;
950 void* ctx;
951
952 printf("%s (%s) - Communication lost (status %u)\n", getTimeString(), localIP, status);
953
954 /* retrieve data */
955 while (sctp_receiveUnsent(assoc, buffer, &bufferLength, &tsn,
956 &streamID, &streamSN, &protoID, &flags, &ctx) >= 0) {
957 /* do something with the retrieved data */
958 /* after that, reset bufferLength */
959 bufferLength = sizeof(buffer);
960 }
961
962 while (sctp_receiveUnacked(assoc, buffer, &bufferLength, &tsn,
963 &streamID, &streamSN, &protoID,&flags, &ctx) >= 0) {
964 /* do something with the retrieved data */
965 /* after that, reset bufferLength */
966 bufferLength = sizeof(buffer);
967 }
968
969 if (unreceivedChunks > 0) {
970 printf("Receiving chunks from receive queue before association is deleted\n");
971 doReceive(assoc);
972 }
973
974 /* delete the association */
975 sctp_deleteAssociation(assoc);
976 noOfInStreams = 0;
977 noOfOutStreams = 0;
978 assocID = 0;
979 }
980
981
communicationErrorNotif(unsigned int assoc,unsigned short status,void * dummy)982 void communicationErrorNotif(unsigned int assoc, unsigned short status, void *dummy)
983 {
984 printf("%s (%s) - Communication error (status %u)\n", getTimeString(), localIP, status);
985 }
986
987
restartNotif(unsigned int assoc,void * ulpDataPtr)988 void restartNotif(unsigned int assoc, void *ulpDataPtr)
989 {
990 printf("%s (%s) - Association restarted\n", getTimeString(), localIP);
991 }
992
993
shutdownCompleteNotif(unsigned int assoc,void * ulpDataPtr)994 void shutdownCompleteNotif(unsigned int assoc, void *ulpDataPtr)
995 {
996 printf("%s (%s) - Shutdown complete\n", getTimeString(), localIP);
997 if (unreceivedChunks > 0) {
998 printf("Receiving chunks from receive queue before association is deleted\n");
999 doReceive(assoc);
1000 }
1001 sctp_deleteAssociation(assoc);
1002 noOfInStreams = 0;
1003 noOfOutStreams = 0;
1004 assocID = 0;
1005 }
1006