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(¶meters) == SCTP_SUCCESS) {
321 parameters.sendOotbAborts = (enable == false) ? 0 : 1;
322 if(sctp_setLibraryParameters(¶meters) != 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(¶meters) == SCTP_SUCCESS) {
347 parameters.checksumAlgorithm =
348 (enable == true) ? SCTP_CHECKSUM_ALGORITHM_CRC32C : SCTP_CHECKSUM_ALGORITHM_ADLER32;
349 if(sctp_setLibraryParameters(¶meters) != 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 = ¬ification.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 = ¬ification.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 = ¬ification.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 = ¬ification.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 = ¬ification.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 = ¬ification.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 = ¬ification.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 = ¬ification.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 = ¬ification.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*)¬ification.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