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