1 /*
2  *  $Id$
3  *
4  * SocketAPI implementation for the sctplib.
5  * Copyright (C) 1999-2020 by Thomas Dreibholz
6  *
7  * Realized in co-operation between
8  * - Siemens AG
9  * - University of Essen, Institute of Computer Networking Technology
10  * - University of Applied Sciences, Muenster
11  *
12  * Acknowledgement
13  * This work was partially funded by the Bundesministerium fuer Bildung und
14  * Forschung (BMBF) of the Federal Republic of Germany (Foerderkennzeichen 01AK045).
15  * The authors alone are responsible for the contents.
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
29  *
30  * Contact: discussion@sctp.de
31  *          dreibh@iem.uni-due.de
32  *          tuexen@fh-muenster.de
33  *
34  * Purpose: SCTP Socket Master
35  *
36  */
37 
38 
39 
40 #include "tdsystem.h"
41 #include "tools.h"
42 #include "sctpsocketmaster.h"
43 #include "extsocketdescriptor.h"
44 
45 
46 #include <signal.h>
47 #include <poll.h>
48 #if (SYSTEM == OS_SOLARIS)
49 #include <sys/types.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #endif
53 
54 
55 // #define PRINT_NOTIFICATIONS
56 // #define PRINT_ARRIVENOTIFICATION
57 // #define PRINT_USERCALLBACK
58 // #define PRINT_ASSOC_USECOUNT
59 // #define PRINT_RTOMAXRESTORE
60 //
61 // #define PRINT_PIPE
62 // #define PRINT_GC
63 
64 // Do not show a warning on initialization failure.
65 // #define NO_INITFAIL_WARNING
66 
67 
68 
69 // ###### SCTPSocketMaster static attributes ################################
70 int                              SCTPSocketMaster::InitializationResult     = -1000;
71 int                              SCTPSocketMaster::GarbageCollectionTimerID = -1;
72 cardinal                         SCTPSocketMaster::LockLevel                = 0;
73 cardinal                         SCTPSocketMaster::OldCancelState           = true;
74 card64                           SCTPSocketMaster::LastGarbageCollection;
75 std::set<int>                    SCTPSocketMaster::ClosingSockets;
76 std::multimap<unsigned int, int> SCTPSocketMaster::ClosingAssociations;
77 std::multimap<int, SCTPSocket*>  SCTPSocketMaster::SocketList;
78 SCTP_ulpCallbacks                SCTPSocketMaster::Callbacks;
79 SCTPSocketMaster                 SCTPSocketMaster::MasterInstance;
80 Randomizer                       SCTPSocketMaster::Random;
81 int                              SCTPSocketMaster::BreakPipe[2];
82 SCTPSocketMaster::UserSocketNotification
83                                  SCTPSocketMaster::BreakNotification;
84 
85 ExtSocketDescriptor              ExtSocketDescriptorMaster::Sockets[ExtSocketDescriptorMaster::MaxSockets];
86 ExtSocketDescriptorMaster        ExtSocketDescriptorMaster::MasterInstance;
87 
88 
89 
90 // ###### Library version check #############################################
versionCheck()91 static bool versionCheck()
92 {
93    bool result = true;
94 
95    const unsigned int sctplibLinkedVersion   = sctp_getLibraryVersion();
96    const unsigned int sctplibCompiledVersion = (SCTP_MAJOR_VERSION << 16) | SCTP_MINOR_VERSION;
97 
98    if(sctplibLinkedVersion != sctplibCompiledVersion) {
99       std::cerr << "INTERNAL ERROR: sctp.h and linked sctplib library are different!" << std::endl;
100       result = false;
101    }
102 
103    if(result == false) {
104       char str[128];
105       snprintf((char*)&str, sizeof(str),
106                "Compiled = $%04x\nLinked   = $%04x\n",
107                sctplibCompiledVersion, sctplibLinkedVersion);
108       std::cerr << str;
109    }
110 
111    return(result);
112 }
113 
114 
115 // ###### Constructor #######################################################
SCTPSocketMaster()116 SCTPSocketMaster::SCTPSocketMaster()
117    : Thread("SCTPSocketMaster")
118 {
119    if(InitializationResult == -1000) {
120       Callbacks.dataArriveNotif           = &dataArriveNotif;
121       Callbacks.sendFailureNotif          = &sendFailureNotif;
122       Callbacks.networkStatusChangeNotif  = &networkStatusChangeNotif;
123       Callbacks.communicationUpNotif      = &communicationUpNotif;
124       Callbacks.communicationLostNotif    = &communicationLostNotif;
125       Callbacks.communicationErrorNotif   = &communicationErrorNotif;
126       Callbacks.restartNotif              = &restartNotif;
127       Callbacks.shutdownCompleteNotif     = &shutdownCompleteNotif;
128       Callbacks.peerShutdownReceivedNotif = &shutdownReceivedNotif;
129       Callbacks.queueStatusChangeNotif    = &queueStatusChangeNotif;
130 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
131       Callbacks.asconfStatusNotif         = &asconfStatusNotif;
132 #endif
133 
134       if(!versionCheck()) {
135          return;
136       }
137 
138       int sd;
139       sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
140       if(sd >= 0) {
141 #ifndef SCTP_OVER_UDP
142          close(sd);
143          std::cerr << "ERROR: Kernel SCTP seems to be available! You cannout use sctplib and kernel SCTP simultaneously!" << std::endl;
144          ::abort();
145 #else
146          std::cerr << "NOTE: The socket API assumes SCTP over UDP. Kernel SCTP has been found, but this should be okay." << std::endl;
147 #endif
148       }
149 
150       InitializationResult = sctp_initLibrary();
151       if(InitializationResult == 0) {
152          enableOOTBHandling(false);
153          enableCRC32(true);
154          LastGarbageCollection = getMicroTime();
155 
156          if(pipe((int*)&BreakPipe) == 0) {
157 #ifdef PRINT_PIPE
158             std::cout << "Break Pipe: in=" << BreakPipe[0] << " out=" << BreakPipe[1] << std::endl;
159 #endif
160             int flags = fcntl(BreakPipe[0],F_GETFL,0);
161             if(flags != -1) {
162                flags |= O_NONBLOCK;
163                if(fcntl(BreakPipe[0],F_SETFL,flags) == 0) {
164                   BreakNotification.FileDescriptor = BreakPipe[0];
165                   BreakNotification.EventMask      = POLLIN|POLLPRI;
166                   BreakNotification.UpdateCondition.setName("BreakPipe");
167                   SCTPSocketMaster::MasterInstance.addUserSocketNotification(&BreakNotification);
168 
169                   // The thread may not be started here, since
170                   // its static initializers may *not* be initialized!
171                }
172                else {
173 #ifndef DISABLE_WARNINGS
174                   std::cerr << "WARNING: SCTPSocketMaster::SCTPSocketMaster() - Failed to set Break Pipe to non-blocking mode!" << std::endl;
175 #endif
176                   close(BreakPipe[0]);
177                   close(BreakPipe[1]);
178                   BreakPipe[0] = -1;
179                   BreakPipe[1] = -1;
180                }
181             }
182             else {
183 #ifndef DISABLE_WARNINGS
184                std::cerr << "WARNING: SCTPSocketMaster::SCTPSocketMaster() - Failed reading Break Pipe flags!" << std::endl;
185 #endif
186                close(BreakPipe[0]);
187                close(BreakPipe[1]);
188                BreakPipe[0] = -1;
189                BreakPipe[1] = -1;
190             }
191          }
192          else {
193             BreakPipe[0] = -1;
194             BreakPipe[1] = -1;
195 #ifndef DISABLE_WARNINGS
196             std::cerr << "WARNING: SCTPSocketMaster::SCTPSocketMaster() - Break Pipe not available!" << std::endl;
197 #endif
198          }
199       }
200       else {
201          BreakPipe[0] = -1;
202          BreakPipe[1] = -1;
203 #ifndef NO_INITFAIL_WARNING
204          std::cerr << "ERROR: SCTP Library initialization failed!" << std::endl;
205          if(getuid() != 0) {
206             std::cerr << "       You need root permissions to use the SCTP Library!" << std::endl;
207          }
208 #endif
209       }
210    }
211    else {
212 #ifndef DISABLE_WARNINGS
213       std::cerr << "ERROR: SCTPSocketMaster::SCTPSocketMaster() - "
214               "Do not try to initialice SCTPSocketMaster singleton twice!" << std::endl;
215 #endif
216    }
217 }
218 
219 
220 // ###### Destructor ########################################################
~SCTPSocketMaster()221 SCTPSocketMaster::~SCTPSocketMaster()
222 {
223 #ifdef PRINT_GC
224    std::cout << "garbageCollection: SocketMaster destructor..." << std::endl;
225 #endif
226 
227    // ====== Stop master thread =============================================
228    lock();
229    cancel();
230    PThread = 0;
231    unlock();
232 
233    // ====== Do garbage collection for associations =========================
234    lock();
235    if(GarbageCollectionTimerID != -1) {
236       sctp_stopTimer(GarbageCollectionTimerID);
237       GarbageCollectionTimerID = -1;
238    }
239 
240    std::multimap<unsigned int, int>::iterator iterator = ClosingAssociations.begin();
241    while(iterator != ClosingAssociations.end()) {
242       // associationGarbageCollection(iterator->first,true) may not be called
243       // here, since sctp_abort() directly calls communicationLostNotification(),
244       // which itself calls associationGarbageCollection(iterator->first,true)
245       // again. Therefore, sctp_abort() is used here.
246 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
247       sctp_abort(iterator->first, 0, NULL);
248 #else
249       sctp_abort(iterator->first);
250 #endif
251       iterator = ClosingAssociations.begin();
252    }
253    unlock();
254 
255    // ====== Do garbage collection for sockets ==============================
256    socketGarbageCollection();
257 
258    // ====== Wait for thread to finish ======================================
259    join();
260 
261    // ====== Remove break pipe ==============================================
262    if(BreakPipe[0] != -1) {
263       SCTPSocketMaster::MasterInstance.deleteUserSocketNotification(&BreakNotification);
264       close(BreakPipe[0]);
265       close(BreakPipe[1]);
266       BreakPipe[0] = -1;
267       BreakPipe[1] = -1;
268    }
269 
270 #ifdef PRINT_GC
271    std::cout << "garbageCollection: SocketMaster destructor completed!" << std::endl;
272 #endif
273 }
274 
275 
276 // ###### SCTP event loop thread ############################################
run()277 void SCTPSocketMaster::run()
278 {
279    for(;;) {
280       card64 now         = getMicroTime();
281       const card64 usecs =
282          (LastGarbageCollection + GarbageCollectionInterval > now) ?
283              (LastGarbageCollection + GarbageCollectionInterval - now) : 0;
284 
285       MasterInstance.lock();
286       GarbageCollectionTimerID = sctp_startTimer((unsigned int)(usecs / 1000000),
287                                                  (unsigned int)(usecs % 1000000),
288                                                  timerCallback, NULL, NULL);
289       MasterInstance.unlock();
290 
291       sctp_extendedEventLoop(lock,unlock,(void*)this);
292 
293       MasterInstance.lock();
294       sctp_stopTimer(GarbageCollectionTimerID);
295       GarbageCollectionTimerID = -1;
296       MasterInstance.unlock();
297 
298       now = getMicroTime();
299       if(now - LastGarbageCollection >= GarbageCollectionInterval) {
300          socketGarbageCollection();
301       }
302    }
303 }
304 
305 
306 // ###### SCTP timer callback ###############################################
timerCallback(unsigned int tid,void * param1,void * param2)307 void SCTPSocketMaster::timerCallback(unsigned int tid,
308                                      void*        param1,
309                                      void*        param2)
310 {
311 }
312 
313 
314 // ###### Enable or disable OOTB handling ###################################
enableOOTBHandling(const bool enable)315 bool SCTPSocketMaster::enableOOTBHandling(const bool enable)
316 {
317    bool result = true;
318    MasterInstance.lock();
319    SCTP_Library_Parameters parameters;
320    if(sctp_getLibraryParameters(&parameters) == SCTP_SUCCESS) {
321       parameters.sendOotbAborts    = (enable == false) ? 0 : 1;
322       if(sctp_setLibraryParameters(&parameters) != SCTP_SUCCESS) {
323 #ifndef DISABLE_WARNINGS
324          std::cerr << "WARNING: SCTPSocketMaster::enableOOTBHandling() - Setting of SCTP Library parameters failed!" << std::endl;
325 #endif
326          result = false;
327       }
328    }
329    else {
330 #ifndef DISABLE_WARNINGS
331       std::cerr << "WARNING: SCTPSocketMaster::enableOOTBHandling() - Getting of SCTP Library parameters failed!" << std::endl;
332 #endif
333       result = false;
334    }
335    MasterInstance.unlock();
336    return(result);
337 }
338 
339 
340 // ###### Enable or disable CRC32 checksum ##################################
enableCRC32(const bool enable)341 bool SCTPSocketMaster::enableCRC32(const bool enable)
342 {
343    bool result = true;
344    MasterInstance.lock();
345    SCTP_Library_Parameters parameters;
346    if(sctp_getLibraryParameters(&parameters) == SCTP_SUCCESS) {
347       parameters.checksumAlgorithm =
348          (enable == true) ? SCTP_CHECKSUM_ALGORITHM_CRC32C : SCTP_CHECKSUM_ALGORITHM_ADLER32;
349       if(sctp_setLibraryParameters(&parameters) != SCTP_SUCCESS) {
350 #ifndef DISABLE_WARNINGS
351          std::cerr << "WARNING: SCTPSocketMaster::enableOOTBHandling() - Setting of SCTP Library parameters failed!" << std::endl;
352 #endif
353          result = false;
354       }
355    }
356    else {
357 #ifndef DISABLE_WARNINGS
358       std::cerr << "WARNING: SCTPSocketMaster::enableOOTBHandling() - Getting of SCTP Library parameters failed!" << std::endl;
359 #endif
360       result = false;
361    }
362    MasterInstance.unlock();
363    return(result);
364 }
365 
366 
367 // ###### Add AssociationID to be deleted ###################################
delayedDeleteAssociation(const unsigned short instanceID,const unsigned int assocID)368 void SCTPSocketMaster::delayedDeleteAssociation(const unsigned short instanceID,
369                                                 const unsigned int   assocID)
370 {
371 #ifdef PRINT_GC
372    std::cout << "delayedDeleteAssociation: A=" << assocID << " I=" << instanceID << std::endl;
373 #endif
374    ClosingAssociations.insert(std::pair<unsigned int, unsigned short>(assocID,instanceID));
375 }
376 
377 
378 // ###### Add InstanceID to be deleted ######################################
delayedDeleteSocket(const unsigned short instanceID)379 void SCTPSocketMaster::delayedDeleteSocket(const unsigned short instanceID)
380 {
381 #ifdef PRINT_GC
382    std::cout << "delayedDeleteSocket: I=" << instanceID << std::endl;
383 #endif
384    ClosingSockets.insert(instanceID);
385 }
386 
387 
388 // ###### Try to delete instance ############################################
socketGarbageCollection()389 void SCTPSocketMaster::socketGarbageCollection()
390 {
391 #ifdef PRINT_GC
392    std::cout << "Socket garbage collection..." << std::endl;
393 #endif
394    MasterInstance.lock();
395    LastGarbageCollection = getMicroTime();
396 
397    // ====== Try to auto-close connectionless associations ==================
398    std::multimap<int, SCTPSocket*>::iterator socketIterator = SocketList.begin();
399    while(socketIterator != SCTPSocketMaster::SocketList.end()) {
400       SCTPSocket* socket = socketIterator->second;
401       socket->checkAutoClose();
402       socketIterator++;
403    }
404 
405    // ====== Try to delete already removed sockets using sctplib ============
406    std::set<int>::iterator iterator = ClosingSockets.begin();
407    while(iterator != ClosingSockets.end()) {
408       const unsigned short instanceID = *iterator;
409 
410       bool used = false;
411       std::multimap<unsigned int, int>::iterator assocIterator = ClosingAssociations.begin();
412       while(assocIterator != ClosingAssociations.end()) {
413          if(instanceID == assocIterator->second) {
414             used = true;
415             break;
416          }
417          assocIterator++;
418       }
419 
420       if(!used) {
421 #ifdef PRINT_GC
422          std::cout << "socketGarbageCollection: Removing instance #" << instanceID << "." << std::endl;
423 #endif
424          iterator++;
425          ClosingSockets.erase(instanceID);
426          if(sctp_unregisterInstance(instanceID) != SCTP_SUCCESS) {
427 #ifndef DISABLE_WARNINGS
428             std::cerr << "INTERNAL ERROR: SCTPSocketMaster::socketGarbageCollection() - sctp_unregisterInstance() failed!" << std::endl;
429 #endif
430             ::abort();
431          }
432       }
433       else {
434          iterator++;
435       }
436    }
437 
438    MasterInstance.unlock();
439 #ifdef PRINT_GC
440    std::cout << "Socket garbage collection completed in "
441              << getMicroTime() - LastGarbageCollection << " s" << std::endl;
442 #endif
443 }
444 
445 
446 // ###### Try to delete association and instance ############################
associationGarbageCollection(const unsigned int assocID,const bool sendAbort)447 bool SCTPSocketMaster::associationGarbageCollection(const unsigned int assocID,
448                                                     const bool         sendAbort)
449 {
450    // ====== Delayed removal ================================================
451    std::multimap<unsigned int, int>::iterator iterator = ClosingAssociations.find(assocID);
452    if(iterator != ClosingAssociations.end()) {
453 #ifdef PRINT_GC
454       std::cout << "associationGarbageCollection: Removing association #" << assocID << "." << std::endl;
455 #endif
456 
457       // ====== Delete association ==========================================
458       if(sendAbort) {
459 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
460          sctp_abort(assocID, 0, NULL);
461 #else
462          sctp_abort(assocID);
463 #endif
464       }
465       if(sctp_deleteAssociation(assocID) != SCTP_SUCCESS) {
466 #ifndef DISABLE_WARNINGS
467          std::cerr << "INTERNAL ERROR: SCTPSocketMaster::associationGarbageCollection() - sctp_deleteAssociation() failed!" << std::endl;
468 #endif
469          ::abort();
470       }
471       ClosingAssociations.erase(iterator);
472 
473       socketGarbageCollection();
474       return(true);
475    }
476    return(false);
477 }
478 
479 
480 // ###### SCTP data arrive notification callback ############################
dataArriveNotif(unsigned int assocID,unsigned short streamID,unsigned int length,unsigned short ssn,unsigned int tsn,unsigned int protoID,unsigned int unordered,void * ulpDataPtr)481 void SCTPSocketMaster::dataArriveNotif(unsigned int   assocID,
482                                        unsigned short streamID,
483                                        unsigned int   length,
484                                        unsigned short ssn,
485                                        unsigned int   tsn,
486                                        unsigned int   protoID,
487                                        unsigned int   unordered,
488                                        void*          ulpDataPtr)
489 {
490 #ifdef PRINT_ARRIVENOTIFICATION
491    char str[256];
492    snprintf((char*)&str,sizeof(str),
493                "A%04d S%02d: Data Arrive Notification - length=%d, PPID=%u",
494                assocID, streamID, length, protoID);
495    std::cerr << str << std::endl;
496 #endif
497 
498 
499    SCTPSocket* socket = getSocketForAssociationID(assocID);
500    if(socket != NULL) {
501       SCTPNotification notification;
502       initNotification(notification, assocID, streamID);
503       sctp_data_arrive* sda = &notification.Content.sn_data_arrive;
504       sda->sda_type          = SCTP_DATA_ARRIVE;
505       sda->sda_flags         = (unordered == 1) ? SCTP_ARRIVE_UNORDERED : 0;
506       sda->sda_length        = sizeof(sctp_data_arrive);
507       sda->sda_assoc_id      = assocID;
508       sda->sda_stream        = streamID;
509       sda->sda_ppid          = protoID;
510       sda->sda_bytes_arrived = length;
511       addNotification(socket,assocID,notification);
512    }
513 }
514 
515 
516 // ###### SCTP send failure notification callback ###########################
sendFailureNotif(unsigned int assocID,unsigned char * unsent_data,unsigned int dataLength,unsigned int * context,void * dummy)517 void SCTPSocketMaster::sendFailureNotif(unsigned int   assocID,
518                                         unsigned char* unsent_data,
519                                         unsigned int   dataLength,
520                                         unsigned int*  context,
521                                         void*          dummy)
522 {
523 #ifdef PRINT_NOTIFICATIONS
524    char str[256];
525    snprintf((char*)&str,sizeof(str),
526                "A%04d: Send Failure Notification",assocID);
527    std::cerr << str << std::endl;
528 #endif
529 
530 
531    // ====== Generate "Send Failure" notification ===========================
532    SCTPSocket* socket = getSocketForAssociationID(assocID);
533    if(socket != NULL) {
534       SCTPNotification notification;
535       initNotification(notification, assocID, 0);
536       sctp_send_failed* ssf = &notification.Content.sn_send_failed;
537       ssf->ssf_type     = SCTP_REMOTE_ERROR;
538       ssf->ssf_flags    = 0;
539       ssf->ssf_length   = sizeof(sctp_send_failed);
540       ssf->ssf_error    = 0;
541       ssf->ssf_assoc_id = assocID;
542       ssf->ssf_info.sinfo_stream     = 0;
543       ssf->ssf_info.sinfo_ssn        = 0;
544       ssf->ssf_info.sinfo_flags      = 0;
545       ssf->ssf_info.sinfo_ppid       = 0;
546       ssf->ssf_info.sinfo_context    = 0;
547       ssf->ssf_info.sinfo_timetolive = 0;
548       ssf->ssf_info.sinfo_assoc_id   = assocID;
549       // ??? Sufficient space within SCTPNotification ???
550       // memcpy((char*)&ssf->ssf_data,(char*)unsent_data,dataLength);
551       addNotification(socket,assocID,notification);
552    }
553 }
554 
555 
556 // ###### SCTP network status change notification callback ##################
557 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
networkStatusChangeNotif(unsigned int assocID,short destAddrIndex,unsigned short newState,void * ulpDataPtr)558 void SCTPSocketMaster::networkStatusChangeNotif(unsigned int   assocID,
559                                                 short          destAddrIndex,
560                                                 unsigned short newState,
561                                                 void*          ulpDataPtr)
562 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
563 void SCTPSocketMaster::networkStatusChangeNotif(unsigned int assocID,
564                                                 unsigned int affectedPathID,
565                                                 int          newState,
566                                                 void*        ulpDataPtr)
567 #else
568 #error Wrong sctplib version!
569 #endif
570 {
571 #ifdef PRINT_NOTIFICATIONS
572    char str[256];
573    snprintf((char*)&str,sizeof(str),
574                "A%04d: Network Status Change",assocID);
575    std::cerr << str << std::endl;
576 #endif
577 
578 
579    // ====== Select new primary path, if it has become inactive ============
580    SCTP_PathStatus pathStatus;
581 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
582    const int ok = sctp_getPathStatus(assocID,destAddrIndex,&pathStatus);
583 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
584    const int ok = sctp_getPathStatus(assocID,affectedPathID,&pathStatus);
585 #else
586 #error Wrong sctplib version!
587 #endif
588    if(ok != 0) {
589 #ifndef DISABLE_WARNINGS
590       std::cerr << "INTERNAL ERROR: SCTPSocketMaster::networkStatusChangeNotif() - sctp_getPathStatus() failed!" << std::endl;
591 #endif
592       return;
593    }
594 
595 
596    // ====== Get new destination address ====================================
597    SocketAddress* destination = NULL;
598    destination = SocketAddress::createSocketAddress(
599                                       SocketAddress::PF_HidePort,
600                                       (char*)&pathStatus.destinationAddress);
601    if(destination == NULL) {
602 #ifndef DISABLE_WARNINGS
603       std::cerr << "INTERNAL ERROR: SCTPSocketMaster::networkStatusChangeNotif() - Bad destination address!" << std::endl;
604 #endif
605       return;
606    }
607 
608    // ====== Generate "Network Status Change" notification ==================
609    SCTPSocket* socket = getSocketForAssociationID(assocID);
610    if(socket != NULL) {
611       SCTPNotification notification;
612       initNotification(notification, assocID, 0);
613       sctp_paddr_change* spc = &notification.Content.sn_paddr_change;
614       spc->spc_type     = SCTP_PEER_ADDR_CHANGE;
615       spc->spc_flags    = 0;
616       spc->spc_error    = 0;
617       spc->spc_length   = sizeof(sctp_paddr_change);
618       spc->spc_assoc_id = assocID;
619       switch(newState) {
620          case SCTP_PATH_OK:
621             spc->spc_state = SCTP_ADDR_REACHABLE;
622           break;
623          case SCTP_PATH_UNREACHABLE:
624             spc->spc_state = SCTP_ADDR_UNREACHABLE;
625           break;
626          case SCTP_PATH_ADDED:
627             spc->spc_state = SCTP_ADDR_ADDED;
628           break;
629          case SCTP_PATH_REMOVED:
630             spc->spc_state = SCTP_ADDR_REMOVED;
631           break;
632 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20)
633          case SCTP_ASCONF_CONFIRMED:
634             spc->spc_state = SCTP_ADDR_CONFIRMED;
635           break;
636          case SCTP_ASCONF_FAILED:
637             spc->spc_state = SCTP_ADDR_CONFIRMED;
638             spc->spc_error = 1;
639           break;
640 #elif  (SCTPLIB_VERSION == SCTPLIB_1_3_0)
641          case SCTP_ASCONF_SUCCEEDED:
642             spc->spc_state = SCTP_ADDR_CONFIRMED;
643           break;
644          case SCTP_ASCONF_FAILED:
645             spc->spc_state = SCTP_ADDR_CONFIRMED;
646             spc->spc_error = 1;
647           break;
648 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
649 #else
650 #error Wrong sctplib version!
651 #endif
652          default:
653             spc->spc_state = 0;
654           break;
655       }
656       cardinal addrlen = 0;
657       if(destination) {
658          if(destination->getFamily() == AF_INET6) {
659             addrlen = destination->getSystemAddress((sockaddr*)&spc->spc_aaddr,
660                                                     sizeof(sockaddr_storage),
661                                                     AF_INET);
662          }
663          if(addrlen == 0) {
664             addrlen = destination->getSystemAddress((sockaddr*)&spc->spc_aaddr,
665                                                     sizeof(sockaddr_storage));
666          }
667       }
668       else {
669          memset((char*)&spc->spc_aaddr, 0, sizeof(spc->spc_aaddr));
670       }
671       addNotification(socket,assocID,notification);
672    }
673 
674    delete destination;
675 }
676 
677 
678 // ###### SCTP communication up notification callback #######################
communicationUpNotif(unsigned int assocID,int status,unsigned int noOfDestinations,unsigned short noOfInStreams,unsigned short noOfOutStreams,int supportPRSCTP,int adaptationLayerIndicationLen,void * adaptationLayerIndication,void * dummy)679 void* SCTPSocketMaster::communicationUpNotif(unsigned int   assocID,
680                                              int            status,
681                                              unsigned int   noOfDestinations,
682                                              unsigned short noOfInStreams,
683                                              unsigned short noOfOutStreams,
684                                              int            supportPRSCTP,
685 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
686                                              int            adaptationLayerIndicationLen,
687                                              void*          adaptationLayerIndication,
688 #endif
689                                              void*          dummy)
690 {
691    SCTPAssociation* association = NULL;
692    SCTPNotification notification;
693    initNotification(notification, assocID, 0);
694 
695 #ifdef PRINT_NOTIFICATIONS
696    char str[256];
697    snprintf((char*)&str,sizeof(str),
698                "A%04d: Communication Up Notification",assocID);
699    std::cerr << str << std::endl;
700 #endif
701 
702    SCTPSocket* socket = getSocketForAssociationID(assocID);
703    if(socket != NULL) {
704       // ====== Successfull associate() execution ===========================
705       association = socket->getAssociationForAssociationID(assocID);
706       if(association != NULL) {
707          // ====== Correct RTOMax ============================================
708          if(association->RTOMaxIsInitTimeout) {
709             SCTP_Association_Status status;
710             if(socket->getAssocStatus(assocID,status)) {
711 #ifdef PRINT_RTOMAXRESTORE
712                char str[256];
713                snprintf((char*)&str,sizeof(str),
714                            "A%04d: Setting InitTimeout %d to saved RTOMax %d",assocID,status.rtoMax,association->RTOMax);
715                std::cerr << str << std::endl;
716 #endif
717                status.rtoMax = association->RTOMax;
718                socket->setAssocStatus(assocID,status);
719             }
720             association->RTOMaxIsInitTimeout = false;
721          }
722 
723          association->CommunicationUpNotification = true;
724          association->EstablishCondition.broadcast();
725          association->WriteReady   = true;
726          association->HasException = false;
727 
728          if(association->PreEstablishmentAddressList) {
729             SocketAddress::deleteAddressList(association->PreEstablishmentAddressList);
730             association->PreEstablishmentAddressList = NULL;
731          }
732          association->sendPreEstablishmentPackets();
733       }
734       // ====== Incoming connection =========================================
735       else if(socket->Flags & SCTPSocket::SSF_Listening) {
736          association = new SCTPAssociation(socket, assocID, socket->NotificationFlags,
737                                            socket->Flags & SCTPSocket::SSF_GlobalQueue);
738          if(association != NULL) {
739             association->CommunicationUpNotification = true;
740             SCTPSocket::IncomingConnection* newConnection = new SCTPSocket::IncomingConnection;
741             if(newConnection != NULL) {
742                newConnection->NextConnection = NULL;
743                newConnection->Association    = association;
744                newConnection->Notification   = notification;
745 
746                if(socket->ConnectionRequests == NULL) {
747                   socket->ConnectionRequests = newConnection;
748                }
749                else {
750                   SCTPSocket::IncomingConnection* c = socket->ConnectionRequests;
751                   while(c->NextConnection != NULL) {
752                      c = c->NextConnection;
753                   }
754                   c->NextConnection = newConnection;
755                }
756 
757                socket->ReadReady = true;
758                socket->EstablishCondition.broadcast();
759             }
760             association->WriteReady   = true;
761             association->HasException = false;
762          }
763       }
764       // ====== Unwanted incoming association ===============================
765       else {
766          std::cerr << "Incoming association, but not in listen mode -> rejecting association!" << std::endl;
767          association = NULL;
768       }
769    }
770 
771    // ====== Generate "Communication Up" notification =======================
772    if(association != NULL) {
773       sctp_assoc_change* sac = &notification.Content.sn_assoc_change;
774       sac->sac_type   = SCTP_ASSOC_CHANGE;
775       sac->sac_flags  = 0;
776       sac->sac_length = sizeof(sctp_assoc_change);
777       sac->sac_state  = SCTP_COMM_UP;
778       sac->sac_error  = 0;
779       sac->sac_outbound_streams = noOfOutStreams;
780       sac->sac_inbound_streams  = noOfInStreams;
781       sac->sac_assoc_id         = assocID;
782       addNotification(socket,assocID,notification);
783    }
784    // ====== We do not want this new association -> remove it! ==============
785    else {
786 #ifdef PRINT_NOTIFICATIONS
787       std::cerr << "Aborting and deleting unwanted incoming association!" << std::endl;
788 #endif
789 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
790       sctp_abort(assocID, 0, NULL);
791 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
792       sctp_abort(assocID);
793 #else
794 #error Wrong sctplib version!
795 #endif
796       if(sctp_deleteAssociation(assocID) != SCTP_SUCCESS) {
797 #ifndef DISABLE_WARNINGS
798          std::cerr << "INTERNAL ERROR: SCTPSocketMaster::communicationUpNotif() - sctp_deleteAssociation() or rejected association failed!" << std::endl;
799 #endif
800          ::abort();
801       }
802    }
803 
804    return(NULL);
805 }
806 
807 
808 // ###### SCTP communication lost notification callback #####################
809 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
communicationLostNotif(unsigned int assocID,unsigned short status,void * ulpDataPtr)810 void SCTPSocketMaster::communicationLostNotif(unsigned int   assocID,
811                                               unsigned short status,
812                                               void*          ulpDataPtr)
813 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
814 void SCTPSocketMaster::communicationLostNotif(unsigned int assocID,
815                                               int          status,
816                                               void*        ulpDataPtr)
817 #else
818 #error Wrong sctplib version!
819 #endif
820 {
821 #ifdef PRINT_NOTIFICATIONS
822    char str[256];
823    snprintf((char*)&str,sizeof(str),
824                "A%04d: Communication Lost Notification, Status=%d",assocID,status);
825    std::cerr << str << std::endl;
826 #endif
827 
828 
829    // ====== Delayed removal ================================================
830    if(associationGarbageCollection(assocID,false)) {
831       return;
832    }
833 
834 
835    SCTPSocket* socket = getSocketForAssociationID(assocID);
836    if(socket != NULL) {
837       SCTPAssociation* association = socket->getAssociationForAssociationID(assocID,false);
838       if(association != NULL) {
839          // ====== Correct RTOMax ============================================
840          if(association->RTOMaxIsInitTimeout) {
841             SCTP_Association_Status status;
842             if(socket->getAssocStatus(assocID,status)) {
843 #ifdef PRINT_RTOMAXRESTORE
844                char str[256];
845                snprintf((char*)&str,sizeof(str),
846                            "A%04d: Setting InitTimeout %d to saved RTOMax %d",assocID,status.rtoMax,association->RTOMax);
847                std::cerr << str << std::endl;
848 #endif
849                status.rtoMax = association->RTOMax;
850                socket->setAssocStatus(assocID,status);
851             }
852             association->RTOMaxIsInitTimeout = false;
853          }
854 
855          // ====== Notify waiting main thread ===============================
856          association->CommunicationLostNotification = true;
857          association->ShutdownCompleteNotification  = true;
858          association->ShutdownCompleteCondition.broadcast();
859          association->ReadUpdateCondition.broadcast();
860 
861 
862          // ====== Generate "Communication Lost" notification ===============
863          SCTPNotification notification;
864          initNotification(notification);
865          sctp_assoc_change* sac = &notification.Content.sn_assoc_change;
866          sac->sac_type             = SCTP_ASSOC_CHANGE;
867          sac->sac_flags            = 0;
868          sac->sac_length           = sizeof(sctp_assoc_change);
869          sac->sac_state            = SCTP_COMM_LOST;
870          sac->sac_error            = 0;
871          sac->sac_outbound_streams = 0;
872          sac->sac_inbound_streams  = 0;
873          sac->sac_assoc_id         = assocID;
874          addNotification(socket,assocID,notification);
875 
876          // If association() is waiting for connection establishment,
877          // send signal abort.
878          association->HasException = true;
879          association->WriteReady   = true;
880          association->ReadReady    = true;
881          association->EstablishCondition.broadcast();
882          association->ReadyForTransmit.broadcast();
883       }
884       socket->checkAutoClose();
885    }
886 }
887 
888 
889 // ###### SCTP communication error notification callback ####################
890 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
communicationErrorNotif(unsigned int assocID,unsigned short status,void * dummy)891 void SCTPSocketMaster::communicationErrorNotif(unsigned int   assocID,
892                                                unsigned short status,
893                                                void*          dummy)
894 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
895 void SCTPSocketMaster::communicationErrorNotif(unsigned int assocID,
896                                                int          status,
897                                                void*        dummy)
898 #else
899 #error Wrong sctplib version!
900 #endif
901 {
902 #ifdef PRINT_NOTIFICATIONS
903    char str[256];
904    snprintf((char*)&str,sizeof(str),
905                "A%04d: Communication Error Notification, Status=%d",assocID,status);
906    std::cerr << str << std::endl;
907 #endif
908 
909 
910    // ====== Generate "Communication Error" notification ====================
911    SCTPSocket* socket = getSocketForAssociationID(assocID);
912    if(socket != NULL) {
913       SCTPNotification notification;
914       initNotification(notification, assocID, 0);
915       sctp_remote_error* sre = &notification.Content.sn_remote_error;
916       sre->sre_type      = SCTP_REMOTE_ERROR;
917       sre->sre_flags     = 0;
918       sre->sre_length    = sizeof(sctp_remote_error);
919       sre->sre_error     = 0;
920       sre->sre_assoc_id  = assocID;
921       addNotification(socket,assocID,notification);
922    }
923 }
924 
925 
926 // ###### SCTP restart notification callback ################################
restartNotif(unsigned int assocID,void * ulpDataPtr)927 void SCTPSocketMaster::restartNotif(unsigned int assocID, void* ulpDataPtr)
928 {
929 #ifdef PRINT_NOTIFICATIONS
930    char str[256];
931    snprintf((char*)&str,sizeof(str),
932                "A%04d: Restart Notification",assocID);
933    std::cerr << str << std::endl;
934 #endif
935 
936 
937    // ====== Generate "Restart" notification ==================================
938    SCTPSocket* socket = getSocketForAssociationID(assocID);
939    if(socket != NULL) {
940       SCTPNotification notification;
941       initNotification(notification);
942       sctp_assoc_change* sac = &notification.Content.sn_assoc_change;
943       sac->sac_type             = SCTP_ASSOC_CHANGE;
944       sac->sac_flags            = 0;
945       sac->sac_length           = sizeof(sctp_assoc_change);
946       sac->sac_state            = SCTP_RESTART;
947       sac->sac_error            = 0;
948       SCTP_Association_Status status;
949       if(sctp_getAssocStatus(assocID,&status) == 0) {
950          sac->sac_outbound_streams = status.outStreams;
951          sac->sac_inbound_streams  = status.inStreams;
952       }
953       else {
954 #ifndef DISABLE_WARNINGS
955          std::cerr << "WARNING: SCTPSocketMaster::restartNotif() - sctp_getAssocStatus() failed!" << std::endl;
956 #endif
957          sac->sac_outbound_streams = 1;
958          sac->sac_inbound_streams  = 1;
959       }
960       sac->sac_assoc_id = assocID;
961       addNotification(socket,assocID,notification);
962    }
963 }
964 
965 
966 // ###### SCTP shutdown complete notification callback ######################
shutdownReceivedNotif(unsigned int assocID,void * ulpDataPtr)967 void SCTPSocketMaster::shutdownReceivedNotif(unsigned int assocID, void* ulpDataPtr)
968 {
969 #ifdef PRINT_NOTIFICATIONS
970    char str[256];
971    snprintf((char*)&str,sizeof(str),
972                "A%04d: Shutdown Received Notification",assocID);
973    std::cerr << str << std::endl;
974 #endif
975 
976    SCTPSocket* socket = getSocketForAssociationID(assocID);
977    if(socket != NULL) {
978       SCTPAssociation* association = socket->getAssociationForAssociationID(assocID, false);
979       if(association != NULL) {
980          // ====== Generate "Shutdown Complete" notification ================
981          SCTPNotification notification;
982          initNotification(notification);
983          sctp_shutdown_event* sse = &notification.Content.sn_shutdown_event;
984          sse->sse_type            = SCTP_SHUTDOWN_EVENT;
985          sse->sse_flags           = 0;
986          sse->sse_length          = sizeof(sctp_assoc_change);
987          sse->sse_assoc_id        = assocID;
988          addNotification(socket,assocID,notification);
989       }
990    }
991 }
992 
993 
994 // ###### SCTP shutdown complete notification callback ######################
shutdownCompleteNotif(unsigned int assocID,void * ulpDataPtr)995 void SCTPSocketMaster::shutdownCompleteNotif(unsigned int assocID, void* ulpDataPtr)
996 {
997 #ifdef PRINT_NOTIFICATIONS
998    char str[256];
999    snprintf((char*)&str,sizeof(str),
1000                "A%04d: Shutdown Complete Notification",assocID);
1001    std::cerr << str << std::endl;
1002 #endif
1003 
1004    // ====== Delayed removal ================================================
1005    if(associationGarbageCollection(assocID,false)) {
1006       return;
1007    }
1008 
1009    SCTPSocket* socket = getSocketForAssociationID(assocID);
1010    if(socket != NULL) {
1011       SCTPAssociation* association = socket->getAssociationForAssociationID(assocID,false);
1012       if(association != NULL) {
1013          // ====== Notify waiting main thread ===============================
1014          association->WriteReady   = true;
1015          association->ReadReady    = true;
1016          association->HasException = true;
1017          association->ShutdownCompleteNotification = true;
1018          association->ShutdownCompleteCondition.broadcast();
1019          association->ReadyForTransmit.broadcast();
1020          association->ReadUpdateCondition.broadcast();
1021 
1022          // ====== Generate "Shutdown Complete" notification ================
1023          SCTPNotification notification;
1024          initNotification(notification);
1025          sctp_assoc_change* sac = &notification.Content.sn_assoc_change;
1026          sac->sac_type             = SCTP_ASSOC_CHANGE;
1027          sac->sac_flags            = 0;
1028          sac->sac_length           = sizeof(sctp_assoc_change);
1029          sac->sac_state            = SCTP_SHUTDOWN_COMP;
1030          sac->sac_error            = 0;
1031          sac->sac_outbound_streams = 0;
1032          sac->sac_inbound_streams  = 0;
1033          sac->sac_assoc_id         = assocID;
1034          addNotification(socket,assocID,notification);
1035       }
1036       socket->checkAutoClose();
1037    }
1038 }
1039 
1040 
1041 // ###### SCTP queue status change notification callback ######################
queueStatusChangeNotif(unsigned int assocID,int queueType,int queueIdentifier,int queueLength,void * ulpData)1042 void SCTPSocketMaster::queueStatusChangeNotif(unsigned int assocID,
1043                                               int          queueType,
1044                                               int          queueIdentifier,
1045                                               int          queueLength,
1046                                               void*        ulpData)
1047 {
1048 #ifdef PRINT_NOTIFICATIONS
1049    char str[256];
1050    snprintf((char*)&str,sizeof(str),
1051                "A%04d: Queue Status Change Notification, Qid=%d Qtype=%d Qlength=%d",
1052                assocID,queueIdentifier,queueType,queueLength);
1053    std::cerr << str << std::endl;
1054 #endif
1055 
1056    SCTPSocket* socket = getSocketForAssociationID(assocID);
1057    if(socket != NULL) {
1058       SCTPAssociation* association = socket->getAssociationForAssociationID(assocID,false);
1059       if(association != NULL) {
1060          association->ReadyForTransmit.broadcast();
1061          association->WriteReady = true;
1062          association->sendPreEstablishmentPackets();
1063       }
1064    }
1065 }
1066 
1067 
1068 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1069 // ###### SCTP asconf status change notification callback #####################
asconfStatusNotif(unsigned int assocID,unsigned int correlationID,int result,void * request,void * ulpData)1070 void SCTPSocketMaster::asconfStatusNotif(unsigned int assocID,
1071                                          unsigned int correlationID,
1072                                          int          result,
1073                                          void*        request,
1074                                          void*        ulpData)
1075 {
1076 #ifdef PRINT_NOTIFICATIONS
1077    char str[256];
1078    snprintf((char*)&str,sizeof(str),
1079                "A%04d: ASConf Status Change Notification, Cid=%d result=%d",
1080                assocID,correlationID,result);
1081    std::cerr << str << std::endl;
1082 #endif
1083 }
1084 #endif
1085 
1086 
1087 // ###### User callback #####################################################
userCallback(int fileDescriptor,short int eventMask,short int * registeredEvents,void * userData)1088 void SCTPSocketMaster::userCallback(int        fileDescriptor,
1089                                     short int  eventMask,
1090                                     short int* registeredEvents,
1091                                     void*      userData)
1092 {
1093    char str[256];
1094 #ifdef PRINT_USERCALLBACK
1095    snprintf((char*)&str,sizeof(str),
1096                "F%04d: User Callback, mask=$%x",
1097                fileDescriptor,eventMask);
1098    std::cerr << str << std::endl;
1099 #endif
1100 
1101    UserSocketNotification* usn = (UserSocketNotification*)userData;
1102    if(userData != NULL) {
1103       if(usn->FileDescriptor != BreakPipe[0]) {
1104          usn->Events |= eventMask;
1105          *registeredEvents &= ~eventMask;
1106          if(eventMask & usn->EventMask) {
1107             usn->UpdateCondition.broadcast();
1108          }
1109       }
1110       else {
1111 #ifdef PRINT_PIPE
1112          std::cout << getpid() << ": Break via break pipe received" << std::endl;
1113 #endif
1114          ssize_t received = read(BreakPipe[0],(char*)&str,sizeof(str));
1115          while(received > 0) {
1116 #ifdef PRINT_PIPE
1117            std::cout << "Break Pipe: " << received << " calls" << std::endl;
1118 #endif
1119            received = read(BreakPipe[0],(char*)&str,sizeof(str));
1120          }
1121          BreakNotification.UpdateCondition.fired();
1122       }
1123    }
1124 }
1125 
1126 
1127 // ###### Get socket for given association ID ###############################
getSocketForAssociationID(const unsigned int assocID)1128 SCTPSocket* SCTPSocketMaster::getSocketForAssociationID(const unsigned int assocID)
1129 {
1130 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1131    unsigned short instanceID = 0;
1132 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1133    int instanceID = 0;
1134 #else
1135 #error Wrong sctplib version!
1136 #endif
1137 
1138    if(sctp_getInstanceID(assocID,&instanceID) == 0) {
1139       if(instanceID != 0) {
1140          std::multimap<int, SCTPSocket*>::iterator iterator =
1141             SocketList.find((int)instanceID);
1142          if(iterator != SocketList.end()) {
1143             return(iterator->second);
1144          }
1145       }
1146 #ifdef DEBUG
1147       else {
1148         std::cerr << "WARNING: SCTPSocketMaster::getSocketForAssociationID() - "
1149                      "Instance ID for association ID #" << assocID << " is zero!" << std::endl;
1150       }
1151 #endif
1152    }
1153 #ifdef DEBUG
1154    else {
1155       std::cerr << "WARNING: SCTPSocketMaster::getSocketForAssociationID() - "
1156                    "No instance ID for association ID #" << assocID << " found!" << std::endl;
1157    }
1158 #endif
1159    return(NULL);
1160 }
1161 
1162 
1163 // ###### Clear SCTPNotification structure ##################################
initNotification(SCTPNotification & notification)1164 void SCTPSocketMaster::initNotification(SCTPNotification& notification)
1165 {
1166    notification.Content.sn_header.sn_type = SCTP_UNDEFINED;
1167    notification.ContentPosition = 0;
1168    notification.RemotePort      = 0;
1169    notification.RemoteAddresses = 0;
1170    for(unsigned int i = 0;i < SCTP_MAX_NUM_ADDRESSES;i++) {
1171       notification.RemoteAddress[i][0] = 0x00;
1172    }
1173 }
1174 
1175 
1176 // ###### Initialize SCTPNotification structure #############################
initNotification(SCTPNotification & notification,unsigned int assocID,unsigned short streamID)1177 bool SCTPSocketMaster::initNotification(SCTPNotification& notification,
1178                                         unsigned int      assocID,
1179                                         unsigned short    streamID)
1180 {
1181    notification.Content.sn_header.sn_type = SCTP_UNDEFINED;
1182    notification.ContentPosition = 0;
1183    SCTP_Association_Status status;
1184    if(sctp_getAssocStatus(assocID, &status) == 0) {
1185       notification.RemotePort      = status.destPort;
1186 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1187       notification.RemoteAddresses = std::min((unsigned short)SCTP_MAX_NUM_ADDRESSES,
1188                                               status.numberOfAddresses);
1189 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1190       notification.RemoteAddresses = std::min((unsigned short)SCTP_MAX_NUM_ADDRESSES,
1191                                               status.numberOfDestinationPaths);
1192 #else
1193 #error Wrong sctplib version!
1194 #endif
1195       for(unsigned int i = 0;i < notification.RemoteAddresses;i++) {
1196          SCTP_Path_Status pathStatus;
1197 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1198          if(sctp_getPathStatus(assocID,i,&pathStatus) != 0) {
1199 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1200          if(sctp_getPathStatus(assocID,status.destinationPathIDs[i],&pathStatus) != 0) {
1201 #else
1202 #error Wrong sctplib version!
1203 #endif
1204 
1205 #ifndef DISABLE_WARNINGS
1206             std::cerr << "WARNING: SCTPSocketMaster::initNotification() - sctp_getPathStatus() failure!"
1207                       << std::endl;
1208 #endif
1209 
1210          }
1211          else {
1212             memcpy((char*)&notification.RemoteAddress[i],
1213                    (char*)&pathStatus.destinationAddress,
1214                    sizeof(pathStatus.destinationAddress));
1215          }
1216       }
1217       return(true);
1218    }
1219 #ifndef DISABLE_WARNINGS
1220          std::cerr << "WARNING: SCTPSocketMaster::initNotification() - sctp_getAssocStatus() failure!"
1221                    << std::endl;
1222 #endif
1223    return(false);
1224 }
1225 
1226 
1227 // ###### Add SCTPNotification structure to socket's queue ##################
1228 void SCTPSocketMaster::addNotification(SCTPSocket*             socket,
1229                                        unsigned int            assocID,
1230                                        const SCTPNotification& notification)
1231 {
1232    // ====== Get notification flags =========================================
1233    SCTPAssociation* association = socket->getAssociationForAssociationID(assocID, false);
1234    if(association == NULL) {
1235       // Association not found -> already closed.
1236       return;
1237    }
1238    const unsigned int notificationFlags = association->NotificationFlags;
1239 
1240    // ====== Check, if notification has to be added =========================
1241    if((notification.Content.sn_header.sn_type == SCTP_DATA_ARRIVE)    ||
1242       ((notification.Content.sn_header.sn_type == SCTP_ASSOC_CHANGE)     && (notificationFlags & SCTP_RECVASSOCEVNT))    ||
1243       ((notification.Content.sn_header.sn_type == SCTP_PEER_ADDR_CHANGE) && (notificationFlags & SCTP_RECVPADDREVNT))    ||
1244       ((notification.Content.sn_header.sn_type == SCTP_REMOTE_ERROR)     && (notificationFlags & SCTP_RECVPEERERR))      ||
1245       ((notification.Content.sn_header.sn_type == SCTP_SEND_FAILED)      && (notificationFlags & SCTP_RECVSENDFAILEVNT)) ||
1246       ((notification.Content.sn_header.sn_type == SCTP_SHUTDOWN_EVENT)   && (notificationFlags & SCTP_RECVSHUTDOWNEVNT))) {
1247 
1248       association->UseCount++;
1249 #ifdef PRINT_ASSOC_USECOUNT
1250       std::cout << association->UseCount << ". Notification Type = " << notification.Content.sn_header.sn_type << std::endl;
1251 #endif
1252 
1253       // ====== Add notification to global or association's queue ===========
1254 #ifdef PRINT_ASSOC_USECOUNT
1255       std::cout << "AddNotification: UseCount increment for A" << association->getID() << ": "
1256                 << association->UseCount << " -> ";
1257 #endif
1258       if( (socket->Flags & SCTPSocket::SSF_GlobalQueue) &&
1259           (association->PeeledOff == false) ) {
1260          socket->GlobalQueue.addNotification(notification);
1261          socket->ReadReady = socket->hasData() || (socket->ConnectionRequests != NULL);
1262       }
1263       else {
1264          association->InQueue.addNotification(notification);
1265          association->ReadReady = association->hasData();
1266       }
1267    }
1268 
1269    else {
1270       /* The user does not want a notification, but an action has to be
1271          signallised in order to end waiting for events (e.g. interrupting
1272          SCTPSocket::interalReceive() in case of a shutdown complete)! */
1273       if(!((socket->Flags & SCTPSocket::SSF_GlobalQueue) &&
1274            (association->PeeledOff == false))) {
1275          association->InQueue.signal();
1276       }
1277    }
1278 }
1279 
1280 
1281 // ###### Add user socket notification ######################################
1282 void SCTPSocketMaster::addUserSocketNotification(UserSocketNotification* usn)
1283 {
1284    lock();
1285    usn->Events = 0;
1286    const int result = sctp_registerUserCallback(usn->FileDescriptor,userCallback,(void*)usn,usn->EventMask);
1287 
1288    if(result < 0) {
1289 #ifndef DISABLE_WARNINGS
1290       std::cerr << "ERROR: SCTPSocketMaster::addUserSocketNotification() - sctp_registerUserCallback() failed!" << std::endl;
1291 #endif
1292    }
1293 
1294    if((usn->FileDescriptor != BreakPipe[0]) && (BreakPipe[0] != -1)) {
1295       char dummy = 'T';
1296 #ifdef PRINT_PIPE
1297       std::cout << "Sending Break via break pipe..." << std::endl;
1298 #endif
1299       dummy = write(BreakPipe[1],&dummy,sizeof(dummy));
1300    }
1301 
1302    unlock();
1303 }
1304 
1305 
1306 // ###### Delete user socket notification ###################################
1307 void SCTPSocketMaster::deleteUserSocketNotification(UserSocketNotification* usn)
1308 {
1309    lock();
1310    if(sctp_unregisterUserCallback(usn->FileDescriptor) != SCTP_SUCCESS) {
1311 #ifndef DISABLE_WARNINGS
1312       std::cerr << "INTERNAL ERROR: SCTPSocketMaster::deleteUserSocketNotification() - sctp_unregisterUserCallback() failed!" << std::endl;
1313 #endif
1314    }
1315    unlock();
1316 }
1317 
1318 
1319 // ###### Lock callback #####################################################
1320 void SCTPSocketMaster::lock(void* data)
1321 {
1322    SCTPSocketMaster* task = (SCTPSocketMaster*)data;
1323    task->lock();
1324 }
1325 
1326 
1327 // ###### Unlock callback ###################################################
1328 void SCTPSocketMaster::unlock(void* data)
1329 {
1330    SCTPSocketMaster* task = (SCTPSocketMaster*)data;
1331    task->unlock();
1332 }
1333