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
35  *
36  */
37 
38 #include "tdsystem.h"
39 #include "tools.h"
40 #include "sctpsocket.h"
41 #include "sctpsocketmaster.h"
42 
43 
44 // #define PRINT_BIND
45 // #define PRINT_UNBIND
46 // #define PRINT_ADDIP
47 // #define PRINT_ACCEPT
48 // #define PRINT_ASSOCIATE
49 // #define PRINT_NEW_ASSOCIATIONS
50 // #define PRINT_SEND_TO_ALL
51 // #define PRINT_SHUTDOWNS
52 // #define PRINT_PRSCTP
53 // #define PRINT_NOTIFICATION_SKIP
54 // #define PRINT_DATA
55 // #define PRINT_RECVSTATUS
56 // #define PRINT_SENDSTATUS
57 // #define PRINT_SETPRIMARY
58 // #define PRINT_SENDTO
59 //
60 //
61 // #define PRINT_AUTOCLOSE_TIMEOUT
62 // #define PRINT_AUTOCLOSE_CHECK
63 //
64 //
65 // #define PRINT_RECVWAIT
66 // #define PRINT_ISSHUTDOWN
67 // #define PRINT_PATHFORINDEX
68 // #define PRINT_ASSOCSEARCH
69 // #define PRINT_ASSOC_USECOUNT
70 // #define PRINT_RTO
71 
72 
73 // #define TEST_PARTIAL_DELIVERY
74 // #define PRINT_PARTIAL_DELIVERY
75 // #define PARTIAL_DELIVERY_MAXSIZE 67
76 
77 
78 
79 // ###### Constructor #######################################################
SCTPSocket(const int family,const cardinal flags)80 SCTPSocket::SCTPSocket(const int family, const cardinal flags)
81 {
82    CorrelationID       = 0;
83    AutoCloseTimeout    = 30000000;
84    InstanceName        = 0;
85    ConnectionRequests  = NULL;
86    Flags               = flags;
87    NotificationFlags   = 0;
88    DefaultTrafficClass = 0x00;
89    ReadReady           = false;
90    WriteReady          = false;
91    HasException        = false;
92    Family              = family;
93 
94    AutoCloseRecursion  = false;
95 
96    EstablishCondition.setName("SCTPSocket::EstablishCondition");
97    ReadUpdateCondition.setName("SCTPSocket::ReadUpdateCondition");
98    WriteUpdateCondition.setName("SCTPSocket::WriteUpdateCondition");
99    ExceptUpdateCondition.setName("SCTPSocket::ExceptUpdateCondition");
100    GlobalQueue.getUpdateCondition()->setName("SCTPSocket::GlobalQueueCondition");
101 
102    EstablishCondition.addParent(&ReadUpdateCondition);
103    GlobalQueue.getUpdateCondition()->addParent(&ReadUpdateCondition);
104 }
105 
106 
107 // ###### Destructor ########################################################
~SCTPSocket()108 SCTPSocket::~SCTPSocket()
109 {
110    unbind();
111 }
112 
113 
114 // ###### Get association for association ID ################################
getAssociationForAssociationID(const unsigned int assocID,const bool activeOnly)115 SCTPAssociation* SCTPSocket::getAssociationForAssociationID(const unsigned int assocID,
116                                                             const bool activeOnly)
117 {
118    SCTPAssociation* association = NULL;
119 
120    SCTPSocketMaster::MasterInstance.lock();
121    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
122       AssociationList.find(assocID);
123    if(iterator != AssociationList.end()) {
124       if(!((iterator->second->IsShuttingDown) && (activeOnly))) {
125          association = iterator->second;
126       }
127    }
128    SCTPSocketMaster::MasterInstance.unlock();
129 
130    return(association);
131 }
132 
133 
134 // ###### Get local addresses ###############################################
135 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19)
getLocalAddresses(SocketAddress ** & addressArray)136 bool SCTPSocket::getLocalAddresses(SocketAddress**& addressArray)
137 {
138    // ====== Get local addresses ============================================
139    bool         result = true;
140    SCTPSocketMaster::MasterInstance.lock();
141    if(InstanceName > 0) {
142       addressArray = SocketAddress::newAddressList(NoOfLocalAddresses);
143       if(addressArray == NULL) {
144          for(int i = 0;i < NoOfLocalAddresses;i++) {
145             addressArray[i] = SocketAddress::createSocketAddress(0,(char*)LocalAddressList[i],LocalPort);
146             if(addressArray[i] == NULL) {
147 #ifndef DISABLE_WARNINGS
148                std::cerr << "WARNING: SCTPSocket::getLocalAddresses() - Bad address "
149                   << *(LocalAddressList[i]) << ", port " << LocalPort << "!" << std::endl;
150 #endif
151                SocketAddress::deleteAddressList(addressArray);
152                result = false;
153             }
154          }
155       }
156    }
157    SCTPSocketMaster::MasterInstance.unlock();
158    return(result);
159 }
160 #else
getLocalAddresses(SocketAddress ** & addressArray)161 bool SCTPSocket::getLocalAddresses(SocketAddress**& addressArray)
162 {
163    SCTP_Instance_Parameters parameters;
164    bool                     result = false;
165 
166    // ====== Get local addresses ============================================
167    SCTPSocketMaster::MasterInstance.lock();
168    if(getAssocDefaults(parameters)) {
169       const unsigned int localAddresses = parameters.noOfLocalAddresses;
170       addressArray = SocketAddress::newAddressList(localAddresses);
171       if(addressArray != NULL) {
172          for(unsigned int i = 0;i < localAddresses;i++) {
173             addressArray[i] = SocketAddress::createSocketAddress(0,(char*)&parameters.localAddressList[i],LocalPort);
174             if(addressArray[i] == NULL) {
175 #ifndef DISABLE_WARNINGS
176                std::cerr << "WARNING: SCTPSocket::getLocalAddresses() - Bad address "
177                     << parameters.localAddressList[i] << ", port " << LocalPort << "!" << std::endl;
178 #endif
179                SocketAddress::deleteAddressList(addressArray);
180                addressArray = NULL;
181                result       = false;
182                break;
183             }
184          }
185       }
186    }
187    SCTPSocketMaster::MasterInstance.unlock();
188 
189    return(result);
190 }
191 #endif
192 
193 
194 // ###### Get remote addresses for given association ########################
getRemoteAddresses(SocketAddress ** & addressArray,unsigned int assocID)195 bool SCTPSocket::getRemoteAddresses(SocketAddress**& addressArray,
196                                     unsigned int     assocID)
197 {
198    SCTPSocketMaster::MasterInstance.lock();
199 
200    // ====== Try to find association in association list ====================
201    SCTPAssociation* association = getAssociationForAssociationID(assocID,false);
202    if(association == NULL) {
203       // ====== Try to find association in AutoConnect list =================
204       std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
205          ConnectionlessAssociationList.find(assocID);
206       if(iterator != ConnectionlessAssociationList.end()) {
207          association = iterator->second;
208       }
209    }
210 
211    bool ok = false;
212    if(association != NULL) {
213       ok = association->getRemoteAddresses(addressArray);
214    }
215 
216    SCTPSocketMaster::MasterInstance.unlock();
217    return(ok);
218 }
219 
220 
221 // ###### Bind socket to local address(es) and port #########################
bind(const unsigned short localPort,const unsigned short noOfInStreams,const unsigned short noOfOutStreams,const SocketAddress ** localAddressList)222 int SCTPSocket::bind(const unsigned short    localPort,
223                      const unsigned short    noOfInStreams,
224                      const unsigned short    noOfOutStreams,
225                      const SocketAddress**   localAddressList)
226 {
227    if(SCTPSocketMaster::InitializationResult != 0) {
228 #ifdef PRINT_BIND
229       std::cerr << "WARNING: SCTPSocket::bind() - SCTP is not initialized!" << std::endl;
230 #endif
231       return(-EPROTONOSUPPORT);
232    }
233 
234    SCTPSocketMaster::MasterInstance.lock();
235    if(!SCTPSocketMaster::MasterInstance.running()) {
236       // Start SCTPSocketMaster thread.
237       if(SCTPSocketMaster::MasterInstance.start() == false) {
238 #ifndef DISABLE_WARNINGS
239          std::cerr << "WARNING: SCTPSocket::bind() - Unable to start master thread!" << std::endl;
240 #endif
241          SCTPSocketMaster::MasterInstance.unlock();
242          return(-EPROTONOSUPPORT);
243       }
244    }
245    SCTPSocketMaster::MasterInstance.unlock();
246 
247 #if (SCTPLIB_VERSION != SCTPLIB_1_0_0_PRE19)
248    unsigned int  NoOfLocalAddresses;
249    unsigned char LocalAddressList[SCTP_MAX_NUM_ADDRESSES][SCTP_MAX_IP_LEN];
250 #endif
251    NoOfLocalAddresses = 0;
252    while(localAddressList[NoOfLocalAddresses] != NULL) {
253       NoOfLocalAddresses++;
254    }
255 
256    SCTPSocketMaster::MasterInstance.lock();
257 
258    // ====== Initialize =====================================================
259    unbind();
260    LocalPort      = localPort;
261    NoOfInStreams  = noOfInStreams;
262    NoOfOutStreams = noOfOutStreams;
263    CorrelationID  = 0;
264 
265 
266    // ====== Initialize local addresses =====================================
267    for(unsigned int i = 0;i < std::min(NoOfLocalAddresses,(unsigned int)SCTP_MAX_NUM_ADDRESSES);i++) {
268       const InternetAddress* localAddress = dynamic_cast<const InternetAddress*>(localAddressList[i]);
269       const bool isIPv6 = (localAddress != NULL) ? localAddress->isIPv6() : false;
270       if(isIPv6 && (Family == AF_INET6)) {
271          snprintf((char*)&LocalAddressList[i],SCTP_MAX_IP_LEN, "%s",
272                   localAddressList[i]->getAddressString(
273                      SocketAddress::PF_HidePort|SocketAddress::PF_Address).getData());
274       }
275       else {
276          snprintf((char*)&LocalAddressList[i],SCTP_MAX_IP_LEN, "%s",
277                   localAddressList[i]->getAddressString(
278                      SocketAddress::PF_HidePort|SocketAddress::PF_Address|
279                      SocketAddress::PF_Legacy).getData());
280       }
281    }
282 #ifdef PRINT_BIND
283    std::cout << "Binding to {";
284    for(unsigned int i = 0;i < NoOfLocalAddresses;i++) {
285       std::cout << " " << LocalAddressList[i] << " ";
286    }
287    std::cout << "}, port " << LocalPort << "." << std::endl;
288 #endif
289    if(NoOfLocalAddresses < 1) {
290 #ifndef DISABLE_WARNINGS
291       std::cerr << "ERROR: SCTPSocket::bind() - No local addresses!" << std::endl;
292 #endif
293       SCTPSocketMaster::MasterInstance.unlock();
294       return(-EINVAL);
295    }
296 
297 
298    // ====== Register SCTP instance =========================================
299    if(LocalPort == 0) {
300       for(cardinal i = 0;i < 50000;i++) {
301          const card16 port = (card16)(16384 + SCTPSocketMaster::Random.random32() % (61000 - 16384));
302          InstanceName = sctp_registerInstance(port, NoOfInStreams, NoOfOutStreams,
303                                               NoOfLocalAddresses, LocalAddressList,
304                                               SCTPSocketMaster::Callbacks);
305          if(InstanceName > 0) {
306             LocalPort = port;
307 #ifdef PRINT_BIND
308             std::cout << "Allocated port " << LocalPort << std::endl;
309 #endif
310             break;
311          }
312       }
313    }
314    else {
315       InstanceName = sctp_registerInstance(LocalPort, NoOfInStreams, NoOfOutStreams,
316                                            NoOfLocalAddresses, LocalAddressList,
317                                            SCTPSocketMaster::Callbacks);
318       if(InstanceName <= 0) {
319          /* If the socket has been closed recently, it may not be deleted yet
320             (by garbage collector thread). Therefore, we run the garbage collector
321             now and try again ... */
322          SCTPSocketMaster::socketGarbageCollection();
323          InstanceName = sctp_registerInstance(LocalPort, NoOfInStreams, NoOfOutStreams,
324                                               NoOfLocalAddresses, LocalAddressList,
325                                               SCTPSocketMaster::Callbacks);
326       }
327    }
328    if(InstanceName <= 0) {
329 #ifdef PRINT_BIND
330       std::cerr << "ERROR: SCTPSocket::bind() - sctp_registerInstance() failed!" << std::endl;
331 #endif
332       SCTPSocketMaster::MasterInstance.unlock();
333       return(-EADDRINUSE);
334    }
335 
336 
337    // ====== Add socket to global list ======================================
338    SCTPSocketMaster::SocketList.insert(std::pair<unsigned short, SCTPSocket*>(InstanceName,this));
339 
340 
341    SCTPSocketMaster::MasterInstance.unlock();
342    return(0);
343 }
344 
345 
346 // ###### Release socket binding ############################################
unbind(bool sendAbort)347 void SCTPSocket::unbind(bool sendAbort)
348 {
349    if(InstanceName > 0) {
350       SCTPSocketMaster::MasterInstance.lock();
351 #ifdef PRINT_UNBIND
352       std::cout << "Unbinding...";
353 #endif
354 
355       // ====== Delete all associations made by sendTo() ====================
356       std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
357          ConnectionlessAssociationList.begin();
358       while(iterator != ConnectionlessAssociationList.end()) {
359          SCTPAssociation* association = iterator->second;
360          ConnectionlessAssociationList.erase(iterator);
361          if(sendAbort) {
362             association->abort();
363          }
364          delete association;
365          iterator = ConnectionlessAssociationList.begin();
366       }
367 
368       // ====== Delete associations created with associate() or accepted ====
369       iterator = AssociationList.begin();
370       while(iterator != AssociationList.end()) {
371          SCTPAssociation* association = iterator->second;
372          AssociationList.erase(iterator);
373          if(sendAbort) {
374             association->abort();
375          }
376          delete association;
377          iterator = AssociationList.begin();
378       }
379 
380       // ====== Remove incoming associations ================================
381       while(ConnectionRequests != NULL) {
382          SCTPAssociation* association   = ConnectionRequests->Association;
383          IncomingConnection* oldRequest = ConnectionRequests;
384          ConnectionRequests = oldRequest->NextConnection;
385          delete association;
386          delete oldRequest;
387       }
388 
389       // ====== Remove socket from global list ==============================
390       std::multimap<int, SCTPSocket*>::iterator socketIterator =
391          SCTPSocketMaster::SocketList.find(InstanceName);
392       if(socketIterator != SCTPSocketMaster::SocketList.end()) {
393          SCTPSocketMaster::SocketList.erase(socketIterator);
394       }
395       else {
396 #ifndef DISABLE_WARNINGS
397          std::cerr << "INTERNAL ERROR: SCTPSocket::unbind() - Erase failed for instance "
398                    << InstanceName << "!" << std::endl;
399          abort();
400 #endif
401       }
402 
403       // ====== Mark SCTP instance for unregistering ========================
404       SCTPSocketMaster::delayedDeleteSocket(InstanceName);
405 
406       SCTPSocketMaster::MasterInstance.unlock();
407 
408       GlobalQueue.flush();
409       InstanceName  = 0;
410       CorrelationID = 0;
411       Flags &= ~SSF_Listening;
412 
413 #ifdef PRINT_UNBIND
414       std::cout << "Unbind complete." << std::endl;
415 #endif
416    }
417 }
418 
419 
420 // ###### Set listen mode ###################################################
listen(const unsigned int backlog)421 void SCTPSocket::listen(const unsigned int backlog)
422 {
423    SCTPSocketMaster::MasterInstance.lock();
424    if(backlog > 0) {
425       Flags |= SSF_Listening;
426    }
427    else {
428       Flags &= ~SSF_Listening;
429    }
430    SCTPSocketMaster::MasterInstance.unlock();
431 }
432 
433 
434 // ###### Accept new association ############################################
accept(SocketAddress *** addressArray,const bool wait)435 SCTPAssociation* SCTPSocket::accept(SocketAddress*** addressArray,
436                                     const bool       wait)
437 {
438    if(addressArray != NULL) {
439       *addressArray = NULL;
440    }
441    SCTPSocketMaster::MasterInstance.lock();
442    if(!(Flags & SSF_Listening)) {
443 #ifndef DISABLE_WARNINGS
444       std::cerr << "ERROR: SCTPSocket::accept() - Socket is not in server mode, call listen() first!" << std::endl;
445 #endif
446       return(NULL);
447    }
448 
449 
450    // ====== Get new association=============================================
451    while(ConnectionRequests == NULL) {
452       SCTPSocketMaster::MasterInstance.unlock();
453 
454       if(!wait) {
455          return(NULL);
456       }
457       while(EstablishCondition.timedWait(100000) == false) {
458          checkAutoConnect();
459       }
460 
461       SCTPSocketMaster::MasterInstance.lock();
462    }
463    if(ConnectionRequests == NULL) {
464       SCTPSocketMaster::MasterInstance.unlock();
465       return(NULL);
466    }
467 
468 
469    // ====== Initialize address array =======================================
470    if(addressArray != NULL) {
471       *addressArray = SocketAddress::newAddressList(ConnectionRequests->Notification.RemoteAddresses);
472       if(*addressArray == NULL) {
473 #ifndef DISABLE_WARNINGS
474          std::cerr << "ERROR: SCTPSocket::accept() - Out of memory!" << std::endl;
475 #endif
476       }
477       else {
478          unsigned int i;
479          for(i = 0;i < ConnectionRequests->Notification.RemoteAddresses;i++) {
480             (*addressArray)[i] = SocketAddress::createSocketAddress(
481                                     0,
482                                     (char*)&ConnectionRequests->Notification.RemoteAddress[i],
483                                     ConnectionRequests->Notification.RemotePort);
484             if((*addressArray)[i] == NULL) {
485 #ifndef DISABLE_WARNINGS
486                std::cerr << "WARNING: SCTPSocket::accept() - Bad address "
487                          << ConnectionRequests->Notification.RemoteAddress[i] << ", port " << ConnectionRequests->Notification.RemotePort << "!" << std::endl;
488 #endif
489                SocketAddress::deleteAddressList(*addressArray);
490             }
491          }
492       }
493    }
494 
495 #ifdef PRINT_ACCEPT
496    std::cout << "Accepted association #" << ConnectionRequests->Association->AssociationID << " from {";
497    for(unsigned int i = 0;i < ConnectionRequests->Notification.RemoteAddresses;i++) {
498       InternetAddress address(String((char*)&ConnectionRequests->Notification.RemoteAddress[i]),ConnectionRequests->Notification.RemotePort);
499       std::cout << " " << address.getAddressString(SocketAddress::PF_Address|SocketAddress::PF_Legacy) << " ";
500    }
501    std::cout << "}." << std::endl;
502 #endif
503 
504 
505    // ====== Remove association from incoming list ==========================
506    SCTPAssociation* association   = ConnectionRequests->Association;
507    IncomingConnection* oldRequest = ConnectionRequests;
508    ConnectionRequests = oldRequest->NextConnection;
509    delete oldRequest;
510 
511    ReadReady = hasData() || (ConnectionRequests != NULL);
512 
513    SCTPSocketMaster::MasterInstance.unlock();
514    return(association);
515 }
516 
517 
518 // ###### Establish new association #########################################
associate(const unsigned short noOfOutStreams,const unsigned short maxAttempts,const unsigned short maxInitTimeout,const SocketAddress ** destinationAddressList,const bool blocking)519 SCTPAssociation* SCTPSocket::associate(const unsigned short  noOfOutStreams,
520                                        const unsigned short  maxAttempts,
521                                        const unsigned short  maxInitTimeout,
522                                        const SocketAddress** destinationAddressList,
523                                        const bool            blocking)
524 {
525    // ====== Establish new association ======================================
526    SCTPSocketMaster::MasterInstance.lock();
527    SCTP_Instance_Parameters oldParameters;
528    SCTP_Instance_Parameters newParameters;
529    if(getAssocDefaults(oldParameters)) {
530       newParameters = oldParameters;
531       newParameters.maxInitRetransmits = maxAttempts;
532       if(newParameters.maxInitRetransmits > 0) {
533          newParameters.maxInitRetransmits--;
534       }
535       if(newParameters.maxInitRetransmits <= 0) {
536          newParameters.maxInitRetransmits = 1;
537       }
538       newParameters.rtoMax = maxInitTimeout;
539       if(!setAssocDefaults(newParameters)) {
540 #ifndef DISABLE_WARNINGS
541          std::cerr << "WARNING: SCTPSocket::associate() - Unable to set new instance parameters!" << std::endl;
542 #endif
543       }
544    }
545    else {
546 #ifndef DISABLE_WARNINGS
547       std::cerr << "WARNING: SCTPSocket::associate() - Unable to get instance parameters!" << std::endl;
548 #endif
549    }
550 
551    unsigned int destinationAddresses = 0;
552    while(destinationAddressList[destinationAddresses] != NULL) {
553       destinationAddresses++;
554    }
555 
556    unsigned int  assocID = 0;
557    unsigned char addressArray[destinationAddresses][SCTP_MAX_IP_LEN];
558    if(destinationAddresses > 0) {
559       for(unsigned int i = 0;i < destinationAddresses;i++) {
560          const InternetAddress* destinationAddress = dynamic_cast<const InternetAddress*>(destinationAddressList[i]);
561          const bool isIPv6 = (destinationAddress != NULL) ? destinationAddress->isIPv6() : false;
562          if(isIPv6 && (Family == AF_INET6)) {
563             snprintf((char*)&addressArray[i], SCTP_MAX_IP_LEN, "%s",
564                      destinationAddressList[i]->getAddressString(SocketAddress::PF_HidePort|SocketAddress::PF_Address).getData());
565          }
566          else {
567             snprintf((char*)&addressArray[i], SCTP_MAX_IP_LEN, "%s",
568                      destinationAddressList[i]->getAddressString(SocketAddress::PF_HidePort|SocketAddress::PF_Address|SocketAddress::PF_Legacy).getData());
569          }
570       }
571 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19)
572       assocID = sctp_associate(InstanceName,
573                                (noOfOutStreams < 1) ? 1 : noOfOutStreams,
574                                addressArray[0],
575                                destinationAddressList[0]->getPort(),
576                                NULL);
577 #else
578       assocID = sctp_associatex(InstanceName,
579                                 (noOfOutStreams < 1) ? 1 : noOfOutStreams,
580                                 addressArray,
581                                 destinationAddresses,
582                                 SCTP_MAX_NUM_ADDRESSES,
583                                 destinationAddressList[0]->getPort(),
584                                 NULL);
585 #endif
586    }
587    else {
588 #ifndef DISABLE_WARNINGS
589       std::cerr << "ERROR: SCTPSocket::associate() - No destination addresses given?!" << std::endl;
590 #endif
591    }
592 
593    if(!setAssocDefaults(oldParameters)) {
594 #ifndef DISABLE_WARNINGS
595       std::cerr << "WARNING: SCTPSocket::associate() - Unable to restore old instance parameters!" << std::endl;
596 #endif
597    }
598 
599 #ifdef PRINT_ASSOCIATE
600    std::cout << "Association to { ";
601    for(unsigned int i = 0;i < destinationAddresses;i++) {
602       std::cout << addressArray[i];
603       if(i < (destinationAddresses - 1)) {
604          std::cout << ", ";
605       }
606    }
607    std::cout << " }, port " << destinationAddressList[0]->getPort()
608              << " => ID #" << assocID << "." << std::endl;
609 #endif
610 
611 
612    // ====== Create SCTPAssociation object ==================================
613    SCTPAssociation* association = NULL;
614    if(assocID != 0) {
615       association = new SCTPAssociation(this, assocID, NotificationFlags,
616                                         Flags & SCTPSocket::SSF_GlobalQueue);
617       if(association == NULL) {
618 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
619          sctp_abort(assocID, 0, NULL);
620 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
621          sctp_abort(assocID);
622 #else
623 #error Wrong sctplib version!
624 #endif
625          sctp_deleteAssociation(assocID);
626 #ifndef DISABLE_WARNINGS
627          std::cerr << "ERROR: SCTPSocket::associate() - Out of memory!" << std::endl;
628 #endif
629       }
630       else {
631 #ifdef PRINT_ASSOC_USECOUNT
632          std::cout << "Associate: UseCount increment for A" << association->getID() << ": "
633                    << association->UseCount << " -> ";
634 #endif
635          association->UseCount++;
636 #ifdef PRINT_ASSOC_USECOUNT
637          std::cout << association->UseCount << std::endl;
638 #endif
639          association->setTrafficClass(DefaultTrafficClass);
640 
641          association->RTOMaxIsInitTimeout = true;
642          association->RTOMax              = oldParameters.rtoMax;
643          association->InitTimeout         = maxInitTimeout;
644 
645          association->PreEstablishmentAddressList = SocketAddress::newAddressList(destinationAddresses);
646          if(association->PreEstablishmentAddressList != NULL) {
647             for(unsigned int i = 0;i < destinationAddresses;i++) {
648                association->PreEstablishmentAddressList[i] =
649                   destinationAddressList[i]->duplicate();
650             }
651          }
652 
653 #ifdef PRINT_RTO
654          std::cout << "associate() - InitTimeout=" << association->InitTimeout << " SavedMaxRTO=" << association->RTOMax << std::endl;
655 #endif
656       }
657    }
658    SCTPSocketMaster::MasterInstance.unlock();
659 
660    // ====== Wait for peer's connection up notification =====================
661    if(association != NULL) {
662       if(blocking) {
663 #ifdef PRINT_ASSOCIATE
664          std::cout << "Waiting for establishment of association #" << assocID << "..." << std::endl;
665 #endif
666          while(association->EstablishCondition.timedWait(100000) == false) {
667             checkAutoConnect();
668          }
669          if(!association->CommunicationUpNotification) {
670 #ifdef PRINT_ASSOCIATE
671             std::cout << "Association #" << assocID << " failed!" << std::endl;
672 #endif
673             delete association;
674             association = NULL;
675          }
676          else {
677             association->setTrafficClass(DefaultTrafficClass);
678          }
679       }
680    }
681 
682 #ifdef PRINT_ASSOCIATE
683    if(association != NULL) {
684       std::cout << "Association #" << assocID << " established." << std::endl;
685    }
686 #endif
687 
688    // ====== Decrement use count ============================================
689    SCTPSocketMaster::MasterInstance.lock();
690    if(association != NULL) {
691 #ifdef PRINT_ASSOC_USECOUNT
692          std::cout << "Associate: UseCount decrement for A" << association->getID() << ": "
693                    << association->UseCount << " -> ";
694 #endif
695       association->UseCount--;
696 #ifdef PRINT_ASSOC_USECOUNT
697       std::cout << association->UseCount << std::endl;
698 #endif
699    }
700    SCTPSocketMaster::MasterInstance.unlock();
701 
702    return(association);
703 }
704 
705 
706 // ###### Get error code for given association ID ###########################
getErrorCode(const unsigned int assocID)707 int SCTPSocket::getErrorCode(const unsigned int assocID)
708 {
709    SCTPAssociation* association = getAssociationForAssociationID(assocID, false);
710    if(association != NULL) {
711       if(association->ShutdownCompleteNotification) {
712          association->HasException = true;
713          return(-ECONNRESET);
714       }
715       else if(association->CommunicationLostNotification) {
716          association->HasException = true;
717          return(-ECONNABORTED);
718       }
719    }
720    return(0);
721 }
722 
723 
724 // ###### Internal receive implementation ###################################
internalReceive(SCTPNotificationQueue & queue,char * buffer,size_t & bufferSize,int & flags,unsigned int & assocID,unsigned short & streamID,unsigned int & protoID,uint16_t & ssn,uint32_t & tsn,SocketAddress ** address,const unsigned int notificationFlags)725 int SCTPSocket::internalReceive(SCTPNotificationQueue& queue,
726                                 char*                  buffer,
727                                 size_t&                bufferSize,
728                                 int&                   flags,
729                                 unsigned int&          assocID,
730                                 unsigned short&        streamID,
731                                 unsigned int&          protoID,
732                                 uint16_t&              ssn,
733                                 uint32_t&              tsn,
734                                 SocketAddress**        address,
735                                 const unsigned int     notificationFlags)
736 {
737    // ====== Check parameters ===============================================
738    if(bufferSize == 0) {
739 #ifndef DISABLE_WARNINGS
740       std::cerr << "WARNING: SCTPSocket::internalReceive() - Data buffer size is zero!" << std::endl;
741 #endif
742       return(-EINVAL);
743    }
744 
745    // ====== Get next data or notification from queue =====================
746 #ifdef PRINT_RECVWAIT
747    std::cout << "Waiting...";
748    std::cout.flush();
749 #endif
750    SCTPSocketMaster::MasterInstance.lock();
751    SCTPNotification notification;
752    bool received = queue.getNotification(notification);
753    while(received == false) {
754       int errorCode = getErrorCode(assocID);
755       SCTPSocketMaster::MasterInstance.unlock();
756 
757       // ====== No chunk available -> wait for chunk ======================
758       if(errorCode != 0) {
759          bufferSize = 0;
760          if((errorCode == -ECONNRESET) && !(queue.hasData(notificationFlags))) {
761 #ifdef PRINT_ISSHUTDOWN
762             std::cout << "Socket has been shut down -> leaving waiting loop!" << std::endl;
763 #endif
764             flags &= ~MSG_NOTIFICATION;
765             errorCode = 0;
766          }
767          return(errorCode);
768       }
769       if(flags & MSG_DONTWAIT) {
770          return(-EAGAIN);
771       }
772       while(queue.waitForChunk(100000) == false) {
773          checkAutoConnect();
774       }
775       SCTPSocketMaster::MasterInstance.lock();
776       received = queue.getNotification(notification);
777    }
778 #ifdef PRINT_RECVWAIT
779    std::cout << "Wakeup!" << std::endl;
780 #endif
781 
782 
783    // ====== Read data ======================================================
784    // If MSG_NOTIFICATION is set, notifications are received!
785    const bool receiveNotifications = (flags & MSG_NOTIFICATION);
786    bool updatedNotification = false;
787    int result               = 0;
788    if(notification.Content.sn_header.sn_type == SCTP_DATA_ARRIVE) {
789       // ====== Some test stuff for the partial delivery API ================
790 #ifdef TEST_PARTIAL_DELIVERY
791 #ifdef PRINT_PARTIAL_DELIVERY
792       std::cout << "Partial Delivery Test: " << bufferSize << " -> ";
793 #endif
794       bufferSize = MIN(bufferSize, PARTIAL_DELIVERY_MAXSIZE);
795 #ifdef PRINT_PARTIAL_DELIVERY
796       std::cout << bufferSize << std::endl;
797 #endif
798 #endif
799 
800       flags &= ~MSG_NOTIFICATION;
801       sctp_data_arrive* sda = &notification.Content.sn_data_arrive;
802       if(sda->sda_bytes_arrived > 0) {
803          assocID  = sda->sda_assoc_id;
804          streamID = sda->sda_stream;
805          protoID  = sda->sda_ppid;
806          if(sda->sda_flags & SCTP_ARRIVE_UNORDERED) {
807             flags |= MSG_UNORDERED;
808          }
809          unsigned int receivedBytes = std::min((size_t) sda->sda_bytes_arrived, (size_t) bufferSize);
810 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0)
811          unsigned int pathIndex;
812          const int ok = sctp_receivefrom(assocID, streamID,
813                                          (unsigned char*)buffer,
814                                          (unsigned int*)&receivedBytes,
815                                          &ssn,
816                                          &tsn,
817                                          &pathIndex,
818                                          (flags & MSG_PEEK) ? SCTP_MSG_PEEK : SCTP_MSG_DEFAULT);
819 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
820          const int ok = sctp_receive(assocID, streamID,
821                                      (unsigned char*)buffer,
822                                      (unsigned int*)&receivedBytes,
823                                      &ssn,
824                                      &tsn,
825                                      (flags & MSG_PEEK) ? SCTP_MSG_PEEK : SCTP_MSG_DEFAULT);
826          const int pathIndex = sctp_getPrimary(assocID);
827 #else
828 #error Wrong sctplib version!
829 #endif
830          if(ok == 0) {
831             bufferSize = receivedBytes;
832 
833 #ifdef PRINT_DATA
834             std::cout << "Received " << bufferSize << " bytes user data from association " << assocID << ", stream " << streamID << ":" << std::endl;
835             for(size_t i = 0;i < bufferSize;i++) {
836                char str[32];
837                snprintf((char*)&str,sizeof(str),"%02x ",((unsigned char*)buffer)[i]);
838                std::cout << str;
839             }
840             std::cout << std::endl;
841 #endif
842             result = (int)bufferSize;
843 
844             SCTP_PathStatus pathStatus;
845             SCTP_AssociationStatus assocStatus;
846             if(address) {
847                if(sctp_getPathStatus(assocID, pathIndex, &pathStatus) != 0) {
848                   std::cerr << "INTERNAL ERROR: SCTPSocket::internalReceiver() - sctp_getPathStatus() failed!" << std::endl;
849                }
850                else {
851                   if(sctp_getAssocStatus(assocID, &assocStatus) != 0) {
852                      std::cerr << "INTERNAL ERROR: SCTPSocket::internalReceiver() - sctp_getAssocStatus() failed!" << std::endl;
853                   }
854                   else {
855                      *address = SocketAddress::createSocketAddress(
856                                    0, (char*)&pathStatus.destinationAddress, assocStatus.destPort);
857                      if(*address == NULL) {
858                         std::cerr << "INTERNAL ERROR: SCTPSocket::internalReceiver() - Unable to create destination address object!" << std::endl;
859                      }
860 #ifdef PRINT_DATA
861                      else {
862                         std::cout << "Received via address " << *(*address) << " (path index " << pathIndex << ")." << std::endl;
863                      }
864 #endif
865                   }
866                }
867             }
868 
869             // ====== Peek mode: Restore chunk arrival information ==========
870             if(flags & MSG_PEEK) {
871                queue.updateNotification(notification);
872                updatedNotification = true;
873             }
874             else {
875                sda->sda_bytes_arrived -= receivedBytes;
876                if(sda->sda_bytes_arrived > 0) {
877                   queue.updateNotification(notification);
878                   updatedNotification = true;
879                }
880                else {
881                   flags |= MSG_EOR;
882                }
883             }
884          }
885          else {
886             // std::cerr << "WARNING: SCTPSocket::internalReceive() - sctp_receive() failed!" << std::endl;
887             result = -ECONNABORTED;
888          }
889       }
890       else {
891          bufferSize = 0;
892       }
893    }
894 
895    // ====== Handle notification ============================================
896    else {
897       switch(notification.Content.sn_header.sn_type) {
898          case SCTP_ASSOC_CHANGE:
899             assocID = notification.Content.sn_assoc_change.sac_assoc_id;
900           break;
901          case SCTP_REMOTE_ERROR:
902             assocID = notification.Content.sn_remote_error.sre_assoc_id;
903           break;
904          case SCTP_SEND_FAILED:
905             assocID = notification.Content.sn_send_failed.ssf_assoc_id;
906           break;
907          case SCTP_SHUTDOWN_EVENT:
908             assocID = notification.Content.sn_shutdown_event.sse_assoc_id;
909           break;
910          case SCTP_PEER_ADDR_CHANGE:
911             assocID = notification.Content.sn_paddr_change.spc_assoc_id;
912           break;
913 #ifndef DISABLE_WARNINGS
914          default:
915             std::cerr << "INTERNAL ERROR: Unexpected notification type #" << notification.Content.sn_header.sn_type << std::endl;
916             abort();
917           break;
918 #endif
919       }
920 
921       // ====== Copy notification ===========================================
922       if((receiveNotifications) &&
923          (((notification.Content.sn_header.sn_type == SCTP_ASSOC_CHANGE)     && (notificationFlags & SCTP_RECVASSOCEVNT)) ||
924           ((notification.Content.sn_header.sn_type == SCTP_PEER_ADDR_CHANGE) && (notificationFlags & SCTP_RECVPADDREVNT)) ||
925           ((notification.Content.sn_header.sn_type == SCTP_REMOTE_ERROR)     && (notificationFlags & SCTP_RECVPEERERR))   ||
926           ((notification.Content.sn_header.sn_type == SCTP_SEND_FAILED)      && (notificationFlags & SCTP_RECVSENDFAILEVNT)) ||
927           ((notification.Content.sn_header.sn_type == SCTP_SHUTDOWN_EVENT)   && (notificationFlags & SCTP_RECVSHUTDOWNEVNT)))) {
928          const cardinal toCopy = std::min((cardinal)notification.Content.sn_header.sn_length - notification.ContentPosition,(cardinal)bufferSize);
929          const char* from = (char*)&notification.Content;
930          memcpy(buffer,&from[notification.ContentPosition],toCopy);
931          bufferSize = toCopy;
932          notification.ContentPosition += toCopy;
933          if(notification.ContentPosition < notification.Content.sn_header.sn_length) {
934             if(flags & MSG_PEEK) {
935                notification.ContentPosition = 0;
936             }
937             queue.updateNotification(notification);
938             updatedNotification = true;
939             flags |= MSG_NOTIFICATION;
940          }
941          else {
942             if(flags & MSG_PEEK) {
943                notification.ContentPosition = 0;
944                queue.updateNotification(notification);
945                updatedNotification = true;
946             }
947             flags |= (MSG_EOR|MSG_NOTIFICATION);
948          }
949 
950 #ifdef PRINT_DATA
951          std::cout << "Received " << bufferSize << " bytes notification data from association " << assocID << ", stream " << streamID << ":" << std::endl;
952          for(size_t i = 0;i < bufferSize;i++) {
953             char str[32];
954             snprintf((char*)&str,sizeof(str),"%02x ",((unsigned char*)buffer)[i]);
955             std::cout << str;
956          }
957          std::cout << std::endl;
958 #endif
959          result = (int)bufferSize;
960       }
961       else {
962 #ifdef PRINT_NOTIFICATION_SKIP
963             std::cout << "WARNING: Skipping " << notification.Content.sn_header.sn_length << " bytes notification data (type "
964                       << notification.Content.sn_header.sn_type << ") from association " << assocID << ", stream " << streamID << ":" << std::endl;
965 #endif
966 #ifdef PRINT_DATA
967             for(size_t i = 0;i < notification.Content.sn_header.sn_length;i++) {
968                char str[32];
969                snprintf((char*)&str,sizeof(str),"%02x ",((unsigned char*)&notification.Content)[i]);
970                std::cout << str;
971             }
972             std::cout << std::endl;
973 #endif
974          result = getErrorCode(assocID);
975          if(result == 0) {
976             result = -EAGAIN;
977             flags &= ~MSG_NOTIFICATION;
978          }
979       }
980    }
981 
982 
983    // ====== Drop notification, if not updated ==============================
984    if(!updatedNotification) {
985       queue.dropNotification();
986       SCTPAssociation* association = getAssociationForAssociationID(assocID, false);
987       if(association != NULL) {
988          association->LastUsage = getMicroTime();
989          if(association->UseCount > 0) {
990 #ifdef PRINT_ASSOC_USECOUNT
991             std::cout << "Receive: UseCount decrement for A" << association->getID() << ": "
992                       << association->UseCount << " -> ";
993 #endif
994             association->UseCount--;
995 #ifdef PRINT_ASSOC_USECOUNT
996             std::cout << association->UseCount << std::endl;
997 #endif
998          }
999 #ifndef DISABLE_WARNINGS
1000          else {
1001             std::cerr << "INTERNAL ERROR: SCTPSocket::internalReceive() - Too many association usecount decrements for association ID " << assocID << "!" << std::endl;
1002             abort();
1003          }
1004 #endif
1005          association->ReadReady = (association->hasData() || (getErrorCode(association->AssociationID) < 0));
1006 #ifdef PRINT_RECVSTATUS
1007          std::cout << "Association " << association->AssociationID << ": ReadReady=" << association->ReadReady
1008                    << " ErrorCode=" << getErrorCode(association->AssociationID) << std::endl;
1009 #endif
1010       }
1011       ReadReady = hasData() || (ConnectionRequests != NULL);
1012 #ifdef PRINT_RECVSTATUS
1013       std::cout << "Instance " << InstanceName << ": ReadReady=" << ReadReady << std::endl;
1014 #endif
1015    }
1016 
1017 #ifdef TEST_PARTIAL_DELIVERY
1018 #ifdef PRINT_PARTIAL_DELIVERY
1019    std::cout << "got " << result << " bytes " << ((flags & MSG_EOR) ? "---EOR---" : "") << std::endl;
1020 #endif
1021 #endif
1022 
1023    SCTPSocketMaster::MasterInstance.unlock();
1024    return(result);
1025 }
1026 
1027 
1028 // ###### Internal send implementation ######################################
internalSend(const char * buffer,const size_t length,const int flags,const unsigned int assocID,const unsigned short streamID,const unsigned int protoID,const unsigned int timeToLive,Condition * waitCondition,const SocketAddress * pathDestinationAddress)1029 int SCTPSocket::internalSend(const char*          buffer,
1030                              const size_t         length,
1031                              const int            flags,
1032                              const unsigned int   assocID,
1033                              const unsigned short streamID,
1034                              const unsigned int   protoID,
1035                              const unsigned int   timeToLive,
1036                              Condition*           waitCondition,
1037                              const SocketAddress* pathDestinationAddress)
1038 {
1039    // ====== Check error code ===============================================
1040    const int errorCode = getErrorCode(assocID);
1041    if(errorCode != 0) {
1042       return(errorCode);
1043    }
1044 
1045    // ====== Do send ========================================================
1046    int result = 0;
1047    do {
1048       SCTPSocketMaster::MasterInstance.lock();
1049 
1050       int pathIndex = sctp_getPrimary(assocID);
1051       if((pathDestinationAddress) && (flags & MSG_ADDR_OVER)) {
1052          SCTP_PathStatus pathStatus;
1053          pathIndex = getPathIndexForAddress(assocID, pathDestinationAddress, pathStatus);
1054       }
1055 
1056 #ifdef PRINT_DATA
1057       std::cout << "Sending " << length << " bytes of data to association "
1058                 << assocID << ", stream " << streamID << ", PPID "
1059                 << protoID << ", path index " << pathIndex << ":" << std::endl;
1060       for(size_t i = 0;i < length;i++) {
1061          char str[32];
1062          snprintf((char*)&str,sizeof(str),"%02x ",((unsigned char*)buffer)[i]);
1063          std::cout << str;
1064       }
1065       std::cout << std::endl;
1066 #endif
1067 
1068 #ifdef PRINT_PRSCTP
1069       if(timeToLive != SCTP_INFINITE_LIFETIME) {
1070          std::cout << "Sending " << length << " bytes with lifetime " << timeToLive << "." << std::endl;
1071       }
1072 #endif
1073 
1074 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1075       result = sctp_send_private(
1076                   assocID, streamID,
1077                   (unsigned char*)buffer, length,
1078                   protoID,
1079                   pathIndex,
1080                   SCTP_NO_CONTEXT,
1081                   timeToLive,
1082                   ((flags & MSG_UNORDERED) ? SCTP_UNORDERED_DELIVERY : SCTP_ORDERED_DELIVERY),
1083                   ((flags & MSG_UNBUNDLED) ? SCTP_BUNDLING_DISABLED : SCTP_BUNDLING_ENABLED));
1084 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1085       result = sctp_send_private(
1086                   assocID, streamID,
1087                   (unsigned char*)buffer, length,
1088                   protoID,
1089                   pathIndex,
1090                   timeToLive,
1091                   SCTP_NO_CONTEXT,
1092                   ((flags & MSG_UNORDERED) ? SCTP_UNORDERED_DELIVERY : SCTP_ORDERED_DELIVERY),
1093                   ((flags & MSG_UNBUNDLED) ? SCTP_BUNDLING_DISABLED : SCTP_BUNDLING_ENABLED));
1094 #else
1095 #error Wrong sctplib version!
1096 #endif
1097 
1098       if((result == SCTP_QUEUE_EXCEEDED) && (!(flags & MSG_DONTWAIT))) {
1099          if(waitCondition != NULL) {
1100             SCTPSocketMaster::MasterInstance.unlock();
1101             waitCondition->timedWait(100000);
1102             SCTPSocketMaster::MasterInstance.lock();
1103          }
1104       }
1105       SCTPSocketMaster::MasterInstance.unlock();
1106    }
1107    while((!(flags & MSG_DONTWAIT)) && (result == SCTP_QUEUE_EXCEEDED));
1108 
1109    if(result == SCTP_QUEUE_EXCEEDED) {
1110       WriteReady = false;
1111    }
1112    else {
1113       WriteReady = true;
1114    }
1115 
1116 #ifdef PRINT_RECVSTATUS
1117    std::cout << "Association " << assocID << ": WriteReady=" << WriteReady << " sctp_send()=" << result << std::endl;
1118 #endif
1119    if(result == 0) {
1120       return((int)length);
1121    }
1122    if(result == SCTP_PARAMETER_PROBLEM) {
1123       return(-EINVAL);
1124    }
1125    if(result == SCTP_QUEUE_EXCEEDED) {
1126       return(-ENOBUFS);
1127    }
1128    return(-EIO);
1129 }
1130 
1131 
1132 // ###### Receive ###########################################################
receive(char * buffer,size_t & bufferSize,int & flags,unsigned int & assocID,unsigned short & streamID,unsigned int & protoID,uint16_t & ssn,uint32_t & tsn)1133 int SCTPSocket::receive(char*           buffer,
1134                         size_t&         bufferSize,
1135                         int&            flags,
1136                         unsigned int&   assocID,
1137                         unsigned short& streamID,
1138                         unsigned int&   protoID,
1139                         uint16_t&       ssn,
1140                         uint32_t&       tsn)
1141 {
1142    return(receiveFrom(buffer,bufferSize,
1143                       flags,
1144                       assocID, streamID, protoID,
1145                       ssn, tsn,
1146                       NULL));
1147 }
1148 
1149 
1150 // ###### Check, if socket has data for given flags #########################
hasData()1151 bool SCTPSocket::hasData()
1152 {
1153    bool result = false;
1154 
1155    SCTPSocketMaster::MasterInstance.lock();
1156    if(Flags & SSF_GlobalQueue) {
1157       result = GlobalQueue.hasData(NotificationFlags);
1158    }
1159    SCTPSocketMaster::MasterInstance.unlock();
1160    return(result);
1161 }
1162 
1163 
1164 // ###### Receive ###########################################################
receiveFrom(char * buffer,size_t & bufferSize,int & flags,unsigned int & assocID,unsigned short & streamID,unsigned int & protoID,uint16_t & ssn,uint32_t & tsn,SocketAddress ** address)1165 int SCTPSocket::receiveFrom(char*           buffer,
1166                             size_t&         bufferSize,
1167                             int&            flags,
1168                             unsigned int&   assocID,
1169                             unsigned short& streamID,
1170                             unsigned int&   protoID,
1171                             uint16_t&       ssn,
1172                             uint32_t&       tsn,
1173                             SocketAddress** address)
1174 {
1175    // ====== Receive ========================================================
1176    if(!(Flags & SSF_GlobalQueue)) {
1177       // std::cerr << "WARNING: SCTPSocket::receiveFrom() - No global queue!" << std::endl;
1178       return(-EBADF);
1179    }
1180    assocID = 0;
1181    const int result = internalReceive(
1182                          GlobalQueue,
1183                          buffer, bufferSize,
1184                          flags,
1185                          assocID, streamID, protoID,
1186                          ssn, tsn,
1187                          address,
1188                          NotificationFlags);
1189 
1190    // ====== Check, if association has to be closed =========================
1191    checkAutoConnect();
1192 
1193    return(result);
1194 }
1195 
1196 
1197 // ###### Find association for given destination address ####################
findAssociationForDestinationAddress(std::multimap<unsigned int,SCTPAssociation * > & list,const SocketAddress ** destinationAddressList)1198 SCTPAssociation* SCTPSocket::findAssociationForDestinationAddress(
1199                     std::multimap<unsigned int, SCTPAssociation*>& list,
1200                     const SocketAddress** destinationAddressList)
1201 {
1202    SCTP_PathStatus pathStatus;
1203    short           pathIndex;
1204 
1205    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator = list.begin();
1206    while(iterator != list.end()) {
1207       SCTP_Association_Status assocStatus;
1208       if(iterator->second->PreEstablishmentAddressList == NULL) {
1209          if(sctp_getAssocStatus(iterator->second->AssociationID, &assocStatus) == 0) {
1210             size_t i = 0;
1211             while(destinationAddressList[i] != NULL) {
1212 #ifdef PRINT_ASSOCSEARCH
1213                std::cout << "Check "
1214                          << destinationAddressList[i]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy)
1215                          << " in AssocID=" << iterator->second->AssociationID << "?" << std::endl;
1216 #endif
1217                if( (!iterator->second->IsShuttingDown) &&
1218                   (destinationAddressList[i]->getPort() == assocStatus.destPort) &&
1219                   ((pathIndex = getPathIndexForAddress(iterator->second->AssociationID, destinationAddressList[i], pathStatus)) >= 0) ) {
1220 #ifdef PRINT_ASSOCSEARCH
1221                   std::cout << "Found: index=" << pathIndex << std::endl;
1222 #endif
1223                   return(iterator->second);
1224                }
1225                i++;
1226             }
1227          }
1228       }
1229       else {
1230          size_t i = 0;
1231          size_t j = 0;
1232          while(destinationAddressList[i] != NULL) {
1233             while(iterator->second->PreEstablishmentAddressList[j] != NULL) {
1234 #ifdef PRINT_ASSOCSEARCH
1235                std::cout << "PreEstablishmentAddressList Check "
1236                          << destinationAddressList[i]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy)
1237                          << " == "
1238                          << iterator->second->PreEstablishmentAddressList[j]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy) << std::endl;
1239 #endif
1240                if(destinationAddressList[i]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy) ==
1241                   iterator->second->PreEstablishmentAddressList[j]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy)) {
1242 #ifdef PRINT_ASSOCSEARCH
1243                   std::cout << "Found" << std::endl;
1244 #endif
1245                   return(iterator->second);
1246                }
1247                j++;
1248             }
1249             i++;
1250          }
1251       }
1252       iterator++;
1253    }
1254    return(NULL);
1255 }
1256 
1257 
1258 // ###### Send ##############################################################
sendTo(const char * buffer,const size_t length,const int flags,unsigned int & assocID,const unsigned short streamID,const unsigned int protoID,const unsigned int timeToLive,const unsigned short maxAttempts,const unsigned short maxInitTimeout,const bool useDefaults,const SocketAddress ** destinationAddressList,const cardinal noOfOutgoingStreams)1259 int SCTPSocket::sendTo(const char*           buffer,
1260                        const size_t          length,
1261                        const int             flags,
1262                        unsigned int&         assocID,
1263                        const unsigned short  streamID,
1264                        const unsigned int    protoID,
1265                        const unsigned int    timeToLive,
1266                        const unsigned short  maxAttempts,
1267                        const unsigned short  maxInitTimeout,
1268                        const bool            useDefaults,
1269                        const SocketAddress** destinationAddressList,
1270                        const cardinal        noOfOutgoingStreams)
1271 {
1272    int result;
1273 
1274    SCTPSocketMaster::MasterInstance.lock();
1275 #ifdef PRINT_SENDTO
1276    std::cout << "SendTo: length=" << length << ", PPID=" << protoID << ", flags=" << flags << std::endl;
1277 #endif
1278 
1279    // ====== Send to one association ========================================
1280    if(!(flags & MSG_SEND_TO_ALL)) {
1281       // ====== Check for already created association =======================
1282       SCTPAssociation* association = NULL;
1283       if(destinationAddressList != NULL) {
1284          if(Flags & SSF_AutoConnect) {
1285 #ifdef PRINT_ASSOCSEARCH
1286             std::cout << "Assoc lookup in ConnectionlessAssociationList..." << std::endl;
1287 #endif
1288             association = findAssociationForDestinationAddress(ConnectionlessAssociationList,
1289                                                                destinationAddressList);
1290          }
1291          if(association == NULL) {
1292 #ifdef PRINT_ASSOCSEARCH
1293             std::cout << "Assoc lookup in AssociationList..." << std::endl;
1294 #endif
1295             association = findAssociationForDestinationAddress(AssociationList,
1296                                                                destinationAddressList);
1297          }
1298       }
1299       else {
1300 #ifdef PRINT_ASSOCSEARCH
1301          std::cout << "AssocIDLookup " << assocID << "... ";
1302 #endif
1303          std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1304             AssociationList.find(assocID);
1305          if(iterator != AssociationList.end()) {
1306 #ifdef PRINT_ASSOCSEARCH
1307             std::cout << "ok." << std::endl;
1308 #endif
1309             association = iterator->second;
1310          }
1311          else {
1312 #ifdef PRINT_ASSOCSEARCH
1313             std::cout << "failed!" << std::endl;
1314 #endif
1315          }
1316       }
1317       if(association != NULL) {
1318          /* Is sendTo called by ext_connect() (buffer = NULL, length = 0 and
1319             no EOF or ABORT flags): association is not zero => there
1320             already is an association. */
1321          if( ((buffer == NULL) || (length == 0)) &&
1322              (!((flags & MSG_ABORT) || (flags & MSG_EOF))) ) {
1323 #ifdef PRINT_ASSOCSEARCH
1324             std::cout << "Already connected (association " << association->AssociationID << ") -> returning!" << std::endl;
1325 #endif
1326             SCTPSocketMaster::MasterInstance.unlock();
1327             return(-EISCONN);
1328          }
1329 
1330 #ifdef PRINT_ASSOC_USECOUNT
1331          std::cout << "Send: UseCount increment for A" << association->getID() << ": "
1332                    << association->UseCount << " -> ";
1333 #endif
1334          association->UseCount++;
1335 #ifdef PRINT_ASSOC_USECOUNT
1336          std::cout << association->UseCount << std::endl;
1337 #endif
1338 
1339          if(flags & MSG_ABORT) {
1340 #ifdef PRINT_SHUTDOWNS
1341             std::cout << "Sending ABORT for association " << association->AssociationID << std::endl;
1342 #endif
1343             association->abort();
1344             SCTPSocketMaster::MasterInstance.unlock();
1345             return(0);
1346          }
1347 
1348 #ifdef PRINT_SENDTO
1349    std::cout << "SendTo: length=" << length << ", PPID=" << protoID << ", flags=" << flags
1350              << ": association=" << association->getID() << std::endl;
1351 #endif
1352       }
1353 
1354       SCTPSocketMaster::MasterInstance.unlock();
1355 
1356       // ====== Create new association ======================================
1357       if((Flags & SSF_AutoConnect) && (association == NULL) && (destinationAddressList != NULL)) {
1358 #ifdef PRINT_NEW_ASSOCIATIONS
1359          std::cout << "AutoConnect: New outgoing association to "
1360                    << destinationAddressList[0]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy)
1361                    << "..." << std::endl;
1362 #endif
1363          association = associate(noOfOutgoingStreams,
1364                                  maxAttempts, maxInitTimeout,
1365                                  destinationAddressList,
1366                                  (flags & MSG_DONTWAIT) ? false : true);
1367          if(association != NULL) {
1368 #ifdef PRINT_NEW_ASSOCIATIONS
1369             std::cout << "AutoConnect: New outgoing association to "
1370                       << destinationAddressList[0]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy)
1371                       << ", #" << association->getID() << " established!" << std::endl;
1372 #endif
1373             SCTPSocketMaster::MasterInstance.lock();
1374 #ifdef PRINT_ASSOC_USECOUNT
1375             std::cout << "AutoConnect: UseCount increment for A" << association->getID() << ": "
1376                       << association->UseCount << " -> ";
1377 #endif
1378             association->UseCount++;
1379 #ifdef PRINT_ASSOC_USECOUNT
1380             std::cout << association->UseCount << std::endl;
1381 #endif
1382             ConnectionlessAssociationList.insert(std::pair<unsigned int, SCTPAssociation*>(association->getID(),association));
1383             SCTPSocketMaster::MasterInstance.unlock();
1384          }
1385 #ifdef PRINT_NEW_ASSOCIATIONS
1386          else {
1387             std::cout << "AutoConnect: New outgoing association to "
1388                       << destinationAddressList[0]->getAddressString(InternetAddress::PF_Address|InternetAddress::PF_Legacy)
1389                       << " failed!" << std::endl;
1390          }
1391 #endif
1392       }
1393 
1394 
1395       // ====== Send data ===================================================
1396       if(association != NULL) {
1397          assocID = association->getID();
1398          if((buffer != NULL) && (length > 0)) {
1399             result = association->sendTo(buffer, length, flags,
1400                                          streamID, protoID, timeToLive, useDefaults,
1401                                          destinationAddressList ? destinationAddressList[0] : NULL);
1402          }
1403          else {
1404             result = 0;
1405          }
1406 
1407          // ====== Remove association, if SHUTDOWN flag is set ==============
1408          if((flags & MSG_EOF) || (flags & MSG_ABORT)) {
1409 #ifdef PRINT_SENDTO
1410             std::cout << "SendTo: length=" << length << ", PPID=" << protoID << ", flags=" << flags
1411                       << ", association=" << association->getID() << ": handling MSG_EOF or MSG_ABORT" << std::endl;
1412 #endif
1413             if(flags & MSG_ABORT) {
1414 #ifdef PRINT_SHUTDOWNS
1415                std::cout << "Sending ABORT..." << std::endl;
1416 #endif
1417                association->abort();
1418             }
1419             if(flags & MSG_EOF) {
1420 #ifdef PRINT_SHUTDOWNS
1421                std::cout << "Sending SHUTDOWN..." << std::endl;
1422 #endif
1423                association->shutdown();
1424             }
1425             if(Flags & SSF_AutoConnect) {
1426 #ifdef PRINT_SHUTDOWNS
1427                std::cout << "AutoConnect: Shutdown of outgoing association ";
1428                if(destinationAddressList != NULL) {
1429                   std::cout << "to " << *(destinationAddressList[0]) << "..." << std::endl;
1430                }
1431                else {
1432                   std::cout << "A" << assocID << "..." << std::endl;
1433                }
1434 #endif
1435                SCTPSocketMaster::MasterInstance.lock();
1436                std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1437                   ConnectionlessAssociationList.find(association->getID());
1438                if(iterator != ConnectionlessAssociationList.end()) {
1439                   ConnectionlessAssociationList.erase(iterator);
1440                }
1441                SCTPSocketMaster::MasterInstance.unlock();
1442                delete association;
1443                association = NULL;
1444 #ifdef PRINT_SHUTDOWNS
1445                std::cout << "AutoConnect: Shutdown of outgoing association ";
1446                if(destinationAddressList != NULL) {
1447                   std::cout << "to " << *(destinationAddressList[0]) << std::endl;
1448                }
1449                else {
1450                   std::cout << "A" << assocID << std::endl;
1451                }
1452                std::cout << " completed!" << std::endl;
1453 #endif
1454             }
1455 #ifdef PRINT_SENDTO
1456             std::cout << "SendTo: handling AutoConnect" << std::endl;
1457 #endif
1458             checkAutoConnect();
1459          }
1460       }
1461       else {
1462          result = -EIO;
1463       }
1464 
1465 
1466       SCTPSocketMaster::MasterInstance.lock();
1467       if(association != NULL) {
1468 #ifdef PRINT_SENDTO
1469          std::cout << "SendTo: length=" << length << ", PPID=" << protoID << ", flags=" << flags
1470                    << ", association=" << association->getID() << ": handling UseCount decrement;  ptr=" << (void*)association << std::endl;
1471 #endif
1472          association->LastUsage = getMicroTime();
1473          if(association->UseCount > 0) {
1474 #ifdef PRINT_ASSOC_USECOUNT
1475             std::cout << "Send: UseCount decrement for A" << association->getID() << ": "
1476                       << association->UseCount << " -> ";
1477 #endif
1478             association->UseCount--;
1479 #ifdef PRINT_ASSOC_USECOUNT
1480             std::cout << association->UseCount << std::endl;
1481 #endif
1482          }
1483 #ifndef DISABLE_WARNINGS
1484          else {
1485             std::cerr << "INTERNAL ERROR: SCTPSocket::sendTo() - Too many association usecount decrements for association ID " << assocID << "!" << std::endl;
1486             abort();
1487          }
1488 #endif
1489       }
1490       SCTPSocketMaster::MasterInstance.unlock();
1491 
1492 
1493       return(result);
1494    }
1495 
1496    // ====== Send to all ====================================================
1497    else {
1498       std::multimap<unsigned int, SCTPAssociation*>::iterator iterator = ConnectionlessAssociationList.begin();
1499       while(iterator != ConnectionlessAssociationList.end()) {
1500 #ifdef PRINT_SEND_TO_ALL
1501          std::cout << "SendToAll: AssocID=" << iterator->second->AssociationID << std::endl;
1502 #endif
1503          result = iterator->second->sendTo(buffer, length, flags,
1504                                            streamID, protoID, timeToLive, useDefaults,
1505                                            NULL);
1506          iterator++;
1507       }
1508       result = length;
1509    }
1510 
1511    SCTPSocketMaster::MasterInstance.unlock();
1512    return(result);
1513 }
1514 
1515 
1516 // ###### Peel UDP-like association off #####################################
peelOff(const SocketAddress & destinationAddress)1517 SCTPAssociation* SCTPSocket::peelOff(const SocketAddress& destinationAddress)
1518 {
1519    SCTPAssociation* association = NULL;
1520    SCTPSocketMaster::MasterInstance.lock();
1521 
1522    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1523       ConnectionlessAssociationList.begin();
1524    while(iterator != ConnectionlessAssociationList.end()) {
1525       SCTP_Association_Status status;
1526       if(sctp_getAssocStatus(iterator->second->AssociationID,&status) == 0) {
1527 #ifdef PRINT_ASSOCSEARCH
1528          std::cout << "CL "
1529                    << destinationAddress.getAddressString(InternetAddress::PF_HidePort|InternetAddress::PF_Address|InternetAddress::PF_Legacy)
1530                    << " == "
1531                    << String((const char*)&status.primaryDestinationAddress)
1532                    << "?" << std::endl;
1533 #endif
1534          if( (!iterator->second->IsShuttingDown)               &&
1535              (destinationAddress.getPort() == status.destPort) &&
1536              (destinationAddress.getAddressString(InternetAddress::PF_HidePort|InternetAddress::PF_Address|InternetAddress::PF_Legacy) == String((const char*)&status.primaryDestinationAddress)) ) {
1537             association = iterator->second;
1538             association->PeeledOff = true;
1539             ConnectionlessAssociationList.erase(iterator);
1540             break;
1541          }
1542       }
1543       iterator++;
1544    }
1545 
1546    SCTPSocketMaster::MasterInstance.unlock();
1547    return(association);
1548 }
1549 
1550 
1551 // ###### Peel UDP-like association off #####################################
peelOff(const unsigned int assocID)1552 SCTPAssociation* SCTPSocket::peelOff(const unsigned int assocID)
1553 {
1554    SCTPAssociation* association = NULL;
1555 
1556    SCTPSocketMaster::MasterInstance.lock();
1557    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1558       ConnectionlessAssociationList.find(assocID);
1559    if( (iterator != ConnectionlessAssociationList.end()) &&
1560        (!iterator->second->IsShuttingDown) ) {
1561       association = iterator->second;
1562       association->PeeledOff = true;
1563       ConnectionlessAssociationList.erase(iterator);
1564    }
1565    SCTPSocketMaster::MasterInstance.unlock();
1566 
1567    return(association);
1568 }
1569 
1570 
1571 // ###### Get instance parameters ###########################################
getAssocDefaults(SCTP_Instance_Parameters & assocDefaults)1572 bool SCTPSocket::getAssocDefaults(SCTP_Instance_Parameters& assocDefaults)
1573 {
1574    SCTPSocketMaster::MasterInstance.lock();
1575    const int ok = sctp_getAssocDefaults(InstanceName,&assocDefaults);
1576    SCTPSocketMaster::MasterInstance.unlock();
1577    return(ok == 0);
1578 }
1579 
1580 
1581 // ###### Set instance parameters ###########################################
setAssocDefaults(const SCTP_Instance_Parameters & assocDefaults)1582 bool SCTPSocket::setAssocDefaults(const SCTP_Instance_Parameters& assocDefaults)
1583 {
1584    SCTPSocketMaster::MasterInstance.lock();
1585    const int ok = sctp_setAssocDefaults(InstanceName,
1586                                         (SCTP_Instance_Parameters*)&assocDefaults);
1587    SCTPSocketMaster::MasterInstance.unlock();
1588    return(ok == 0);
1589 }
1590 
1591 
1592 // ###### Get association parameters ########################################
getAssocStatus(const unsigned int assocID,SCTP_Association_Status & associationParameters)1593 bool SCTPSocket::getAssocStatus(const unsigned int       assocID,
1594                                 SCTP_Association_Status& associationParameters)
1595 {
1596    SCTPSocketMaster::MasterInstance.lock();
1597    const int ok = sctp_getAssocStatus(assocID, &associationParameters);
1598    SCTPSocketMaster::MasterInstance.unlock();
1599    return(ok == 0);
1600 }
1601 
1602 
1603 // ###### Set association parameters ########################################
setAssocStatus(const unsigned int assocID,const SCTP_Association_Status & associationParameters)1604 bool SCTPSocket::setAssocStatus(const unsigned int             assocID,
1605                                 const SCTP_Association_Status& associationParameters)
1606 {
1607    SCTPSocketMaster::MasterInstance.lock();
1608    const int ok = sctp_setAssocStatus(assocID,
1609                                       (SCTP_Association_Status*)&associationParameters);
1610    SCTPSocketMaster::MasterInstance.unlock();
1611    return(ok == 0);
1612 }
1613 
1614 
1615 // ###### Get path index for address #########################################
getPathIndexForAddress(const unsigned int assocID,const SocketAddress * address,SCTP_PathStatus & pathParameters)1616 int SCTPSocket::getPathIndexForAddress(const unsigned int   assocID,
1617                                        const SocketAddress* address,
1618                                        SCTP_PathStatus&     pathParameters)
1619 {
1620    if(address == NULL) {
1621 #ifdef PRINT_PATHFORINDEX
1622       std::cout << "pathForIndex - primary" << std::endl;
1623 #endif
1624       return(sctp_getPrimary(assocID));
1625    }
1626 
1627 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1628    SCTP_Association_Status status;
1629    if(sctp_getAssocStatus(assocID,&status) != 0) {
1630 #ifndef DISABLE_WARNINGS
1631       std::cerr << "INTERNAL ERROR: SCTPSocket::getPathIndexForAddress() - Unable to get association status!" << std::endl;
1632 #endif
1633       return(-1);
1634    }
1635 #endif
1636 
1637    const String addressString = address->getAddressString(SocketAddress::PF_Address|SocketAddress::PF_HidePort|SocketAddress::PF_Legacy);
1638 
1639    for(unsigned int i = 0;;i++) {
1640 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1641       const int index = i;
1642 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1643       const int index = status.destinationPathIDs[i];
1644 #else
1645 #error Wrong sctplib version!
1646 #endif
1647 
1648       const int ok = sctp_getPathStatus(assocID, index, &pathParameters);
1649       if(ok != 0) {
1650          break;
1651       }
1652 #ifdef PRINT_PATHFORINDEX
1653       std::cout << "pathForIndex: " << index << ": " << addressString << " == " << pathParameters.destinationAddress << "?" << std::endl;
1654 #endif
1655       if(addressString == String((char*)&pathParameters.destinationAddress)) {
1656 #ifdef PRINT_PATHFORINDEX
1657          std::cout << "   => " << index << std::endl;
1658 #endif
1659          return(index);
1660       }
1661    }
1662 #ifdef PRINT_PATHFORINDEX
1663       std::cout << "pathForIndex - failed" << std::endl;
1664 #endif
1665    return(-1);
1666 }
1667 
1668 
1669 // ###### Get path parameters ###############################################
getPathParameters(const unsigned int assocID,const SocketAddress * address,SCTP_PathStatus & pathParameters)1670 bool SCTPSocket::getPathParameters(const unsigned int   assocID,
1671                                    const SocketAddress* address,
1672                                    SCTP_PathStatus&     pathParameters)
1673 {
1674    SCTPSocketMaster::MasterInstance.lock();
1675    const int pathIndex = getPathIndexForAddress(assocID,address,pathParameters);
1676    if(pathIndex >= 0) {
1677       sctp_getPathStatus(assocID,pathIndex,&pathParameters);
1678    }
1679    SCTPSocketMaster::MasterInstance.unlock();
1680    return(pathIndex >= 0);
1681 }
1682 
1683 
1684 // ###### Set path parameters ###############################################
setPathParameters(const unsigned int assocID,const SocketAddress * address,const SCTP_PathStatus & pathParameters)1685 bool SCTPSocket::setPathParameters(const unsigned int     assocID,
1686                                    const SocketAddress*   address,
1687                                    const SCTP_PathStatus& pathParameters)
1688 {
1689    SCTP_PathStatus oldPathParameters;
1690 
1691    SCTPSocketMaster::MasterInstance.lock();
1692    int pathIndex = getPathIndexForAddress(assocID,address,oldPathParameters);
1693    if(pathIndex >= 0) {
1694       if(pathParameters.heartbeatIntervall == (unsigned int)-1) {
1695          if(sctp_requestHeartbeat(assocID,pathIndex)) {
1696             pathIndex = -1;
1697          }
1698       }
1699       else {
1700          if(sctp_changeHeartBeat(assocID,
1701                                  pathIndex,
1702                                  (pathParameters.heartbeatIntervall > 0) ? SCTP_HEARTBEAT_ON : SCTP_HEARTBEAT_OFF,
1703                                  pathParameters.heartbeatIntervall) != 0) {
1704             pathIndex = -1;
1705          }
1706       }
1707    }
1708    SCTPSocketMaster::MasterInstance.unlock();
1709    return(pathIndex >= 0);
1710 }
1711 
1712 
1713 // ###### Get default settings ##############################################
getAssocIODefaults(const unsigned int assocID,struct AssocIODefaults & defaults)1714 bool SCTPSocket::getAssocIODefaults(const unsigned int          assocID,
1715                                     struct AssocIODefaults& defaults)
1716 {
1717    SCTPSocketMaster::MasterInstance.lock();
1718    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1719       ConnectionlessAssociationList.begin();
1720    if(iterator != ConnectionlessAssociationList.end()) {
1721       SCTPAssociation* association = iterator->second;
1722       association->getAssocIODefaults(defaults);
1723       return(true);
1724    }
1725    return(false);
1726 }
1727 
1728 
1729 // ###### Set default settings ##############################################
setAssocIODefaults(const unsigned int assocID,const struct AssocIODefaults & defaults)1730 bool SCTPSocket::setAssocIODefaults(const unsigned int                assocID,
1731                                     const struct AssocIODefaults& defaults)
1732 {
1733    SCTPSocketMaster::MasterInstance.lock();
1734    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1735       ConnectionlessAssociationList.begin();
1736    if(iterator != ConnectionlessAssociationList.end()) {
1737       SCTPAssociation* association = iterator->second;
1738       association->setAssocIODefaults(defaults);
1739       return(true);
1740    }
1741    return(false);
1742 }
1743 
1744 
1745 // ###### Set default timeouts ##############################################
setDefaultStreamTimeouts(const unsigned int assocID,const unsigned int timeout,const unsigned short start,const unsigned short end)1746 bool SCTPSocket::setDefaultStreamTimeouts(const unsigned int   assocID,
1747                                           const unsigned int   timeout,
1748                                           const unsigned short start,
1749                                           const unsigned short end)
1750 {
1751    SCTPSocketMaster::MasterInstance.lock();
1752    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1753       ConnectionlessAssociationList.begin();
1754    if(iterator != ConnectionlessAssociationList.end()) {
1755       SCTPAssociation* association = iterator->second;
1756       association->setDefaultStreamTimeouts(timeout,start,end);
1757       return(true);
1758    }
1759    return(false);
1760 }
1761 
1762 
1763 // ###### Get default timeout ###############################################
getDefaultStreamTimeout(const unsigned int assocID,const unsigned short streamID,unsigned int & timeout)1764 bool SCTPSocket::getDefaultStreamTimeout(const unsigned int   assocID,
1765                                          const unsigned short streamID,
1766                                          unsigned int&        timeout)
1767 {
1768    SCTPSocketMaster::MasterInstance.lock();
1769    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1770       ConnectionlessAssociationList.begin();
1771    if(iterator != ConnectionlessAssociationList.end()) {
1772       SCTPAssociation* association = iterator->second;
1773       association->getDefaultStreamTimeout(streamID,timeout);
1774       return(true);
1775    }
1776    return(false);
1777 }
1778 
1779 
1780 // ###### Set send buffer size ##############################################
setSendBuffer(const size_t size)1781 bool SCTPSocket::setSendBuffer(const size_t size)
1782 {
1783    bool ok = true;
1784    SCTPSocketMaster::MasterInstance.lock();
1785    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1786       ConnectionlessAssociationList.begin();
1787    if(iterator != ConnectionlessAssociationList.end()) {
1788       SCTPAssociation* association = iterator->second;
1789       if(association->setSendBuffer(size) == false) {
1790          ok = false;
1791       }
1792       iterator++;
1793    }
1794    SCTPSocketMaster::MasterInstance.unlock();
1795    return(ok);
1796 }
1797 
1798 
1799 // ###### Set receive buffer size ###########################################
setReceiveBuffer(const size_t size)1800 bool SCTPSocket::setReceiveBuffer(const size_t size)
1801 {
1802    bool ok = true;
1803    SCTPSocketMaster::MasterInstance.lock();
1804    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1805       ConnectionlessAssociationList.begin();
1806    if(iterator != ConnectionlessAssociationList.end()) {
1807       SCTPAssociation* association = iterator->second;
1808       if(association->setReceiveBuffer(size) == false) {
1809          ok = false;
1810       }
1811       iterator++;
1812    }
1813    SCTPSocketMaster::MasterInstance.unlock();
1814    return(ok);
1815 }
1816 
1817 
1818 // ###### Set traffic class #################################################
setTrafficClass(const card8 trafficClass,const int streamID)1819 bool SCTPSocket::setTrafficClass(const card8 trafficClass,
1820                                  const int   streamID)
1821 {
1822    bool ok = true;
1823    SCTPSocketMaster::MasterInstance.lock();
1824    DefaultTrafficClass = trafficClass;
1825    std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1826       ConnectionlessAssociationList.begin();
1827    if(iterator != ConnectionlessAssociationList.end()) {
1828       SCTPAssociation* association = iterator->second;
1829       if(association->setTrafficClass(trafficClass,streamID) == false) {
1830          ok = false;
1831       }
1832       iterator++;
1833    }
1834    SCTPSocketMaster::MasterInstance.unlock();
1835    return(ok);
1836 }
1837 
1838 
1839 // ###### Get primary address ###############################################
getPrimaryAddress(const unsigned int assocID)1840 SocketAddress* SCTPSocket::getPrimaryAddress(const unsigned int assocID)
1841 {
1842    SCTPSocketMaster::MasterInstance.lock();
1843 
1844    SocketAddress* address = NULL;
1845    const int index        = sctp_getPrimary(assocID);
1846    if(index >= 0) {
1847       SCTP_Path_Status pathStatus;
1848       const int result = sctp_getPathStatus(assocID,index,&pathStatus);
1849       if(result == 0) {
1850          address = SocketAddress::createSocketAddress(0,(char*)&pathStatus.destinationAddress);
1851       }
1852    }
1853 
1854    SCTPSocketMaster::MasterInstance.unlock();
1855    return(address);
1856 }
1857 
1858 
1859 // ###### Set primary address ###############################################
setPrimary(const unsigned int assocID,const SocketAddress & primary)1860 bool SCTPSocket::setPrimary(const unsigned int   assocID,
1861                             const SocketAddress& primary)
1862 {
1863    SCTP_PathStatus pathParameters;
1864    int             result = -1;
1865 
1866    SCTPSocketMaster::MasterInstance.lock();
1867    int index = getPathIndexForAddress(assocID,&primary,pathParameters);
1868    if(index >= 0) {
1869 #ifdef PRINT_SETPRIMARY
1870       std::cout << "setPrimary: Setting primary address to " << primary << std::endl;
1871 #endif
1872       result = sctp_setPrimary(assocID,index);
1873 #ifdef PRINT_SETPRIMARY
1874       if(result != 0) {
1875          std::cerr << "WARNING: sctp_setPrimary() failed, error #" << result << std::endl;
1876       }
1877 #endif
1878    }
1879    SCTPSocketMaster::MasterInstance.unlock();
1880 
1881    return(result == 0);
1882 }
1883 
1884 
1885 // ###### Set peer primary address ##########################################
setPeerPrimary(const unsigned int assocID,const SocketAddress & primary)1886 bool SCTPSocket::setPeerPrimary(const unsigned int   assocID,
1887                                 const SocketAddress& primary)
1888 {
1889    SCTPSocketMaster::MasterInstance.lock();
1890    unsigned char address[SCTP_MAX_IP_LEN];
1891    snprintf((char*)&address,sizeof(address),"%s",
1892             primary.getAddressString().getData());
1893 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1894    const int result = sctp_setRemotePrimary(assocID,address);
1895 #else
1896    const int result = -1;
1897 #endif
1898    SCTPSocketMaster::MasterInstance.unlock();
1899    return(result == 0);
1900 }
1901 
1902 
1903 // ###### Add address #######################################################
addAddress(const unsigned int assocID,const SocketAddress & addAddress)1904 bool SCTPSocket::addAddress(const unsigned int   assocID,
1905                             const SocketAddress& addAddress)
1906 {
1907    if(assocID == 0) {
1908       bool ok = true;
1909       SCTPSocketMaster::MasterInstance.lock();
1910       std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1911          ConnectionlessAssociationList.begin();
1912       if(iterator != ConnectionlessAssociationList.end()) {
1913          SCTPAssociation* association = iterator->second;
1914          if(association->addAddress(addAddress) == false) {
1915             ok = false;
1916          }
1917          iterator++;
1918       }
1919       SCTPSocketMaster::MasterInstance.unlock();
1920       return(ok);
1921    }
1922 
1923    SCTPSocketMaster::MasterInstance.lock();
1924    unsigned char address[SCTP_MAX_IP_LEN];
1925    snprintf((char*)&address,sizeof(address),"%s",
1926             addAddress.getAddressString().getData());
1927 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_0_0) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1928    std::cerr << "NOT IMPLEMENTED: sctp_addIPAddress()" << std::endl;
1929    const int result = -1;
1930 #else
1931    const int result = sctp_addIPAddress(assocID,address,&CorrelationID);
1932 #endif
1933 #ifdef PRINT_ADDIP
1934    std::cout << "AddIP: " << addAddress << " -> result=" << result << std::endl;
1935 #endif
1936    CorrelationID++;
1937    SCTPSocketMaster::MasterInstance.unlock();
1938    return(result == 0);
1939 }
1940 
1941 
1942 // ###### Delete address ####################################################
deleteAddress(const unsigned int assocID,const SocketAddress & delAddress)1943 bool SCTPSocket::deleteAddress(const unsigned int   assocID,
1944                                const SocketAddress& delAddress)
1945 {
1946    if(assocID == 0) {
1947       bool ok = true;
1948       SCTPSocketMaster::MasterInstance.lock();
1949       std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1950          ConnectionlessAssociationList.begin();
1951       if(iterator != ConnectionlessAssociationList.end()) {
1952          SCTPAssociation* association = iterator->second;
1953          if(association->deleteAddress(delAddress) == false) {
1954             ok = false;
1955          }
1956          iterator++;
1957       }
1958       SCTPSocketMaster::MasterInstance.unlock();
1959       return(ok);
1960    }
1961 
1962    SCTPSocketMaster::MasterInstance.lock();
1963    unsigned char address[SCTP_MAX_IP_LEN];
1964    snprintf((char*)&address,sizeof(address),"%s",
1965             delAddress.getAddressString().getData());
1966 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_0_0) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1967    std::cerr << "NOT IMPLEMENTED: sctp_deleteIPAddress()" << std::endl;
1968    const int result = -1;
1969 #else
1970    const int result = sctp_deleteIPAddress(assocID,address,&CorrelationID);
1971 #endif
1972 #ifdef PRINT_ADDIP
1973    std::cout << "DeleteIP: " << delAddress << " -> result=" << result << std::endl;
1974 #endif
1975    CorrelationID++;
1976    SCTPSocketMaster::MasterInstance.unlock();
1977    return(result == 0);
1978 }
1979 
1980 
1981 // ###### Check for necessity to auto-close associations ####################
checkAutoClose()1982 void SCTPSocket::checkAutoClose()
1983 {
1984    if(AutoCloseRecursion) {
1985       AutoCloseNewCheckRequired = true;
1986       return;
1987    }
1988    AutoCloseRecursion = true;
1989 
1990    do {
1991       AutoCloseNewCheckRequired = false;
1992 
1993       const card64 now = getMicroTime();
1994       std::multimap<unsigned int, SCTPAssociation*>::iterator iterator =
1995          ConnectionlessAssociationList.begin();
1996       while(iterator != ConnectionlessAssociationList.end()) {
1997          SCTPAssociation* association = iterator->second;
1998 #ifdef PRINT_AUTOCLOSE_CHECK
1999          std::cout << "AutoConnect: Check for AutoClose:" << std::endl
2000                    << "   AssocID          = " << association->getID() << std::endl
2001                    << "   UseCount         = " << association->UseCount << std::endl
2002                    << "   LastUsage        = " << now - association->LastUsage << std::endl
2003                    << "   AutoCloseTimeout = " << AutoCloseTimeout << std::endl;
2004 #endif
2005 
2006          /* ====== Association has no active users ======================= */
2007          if(association->UseCount == 0) {
2008             /* ====== Association is closed -> remove it ================= */
2009             if((association->ShutdownCompleteNotification) ||
2010                (association->CommunicationLostNotification)) {
2011 #ifdef PRINT_AUTOCLOSE_TIMEOUT
2012                const unsigned int assocID = association->getID();
2013                std::cout << "AutoConnect: Removing association #" << assocID << ": ";
2014                if(association->ShutdownCompleteNotification) {
2015                   std::cout << "shutdown complete";
2016                }
2017                else if(association->CommunicationLostNotification) {
2018                   std::cout << "communication lost";
2019                }
2020                std::cout << "..." << std::endl;
2021 #endif
2022 
2023                // Important! Removal will invalidate iterator!
2024                std::multimap<unsigned int, SCTPAssociation*>::iterator delIterator = iterator;
2025                iterator++;
2026                ConnectionlessAssociationList.erase(delIterator);
2027 
2028                delete association;
2029 #ifdef PRINT_AUTOCLOSE_TIMEOUT
2030                std::cout << "AutoConnect: AutoClose of association #" << assocID << " completed!" << std::endl;
2031 #endif
2032             }
2033 
2034             /* ====== Association still active, time to send ABORT! ====== */
2035             else if((AutoCloseTimeout > 0) &&
2036                     (now - association->LastUsage > 4 * AutoCloseTimeout)) {
2037 #ifdef PRINT_AUTOCLOSE_TIMEOUT
2038                const unsigned int assocID = association->getID();
2039                std::cout << "AutoConnect: Abort of association #" << assocID << " due to timeout" << std::endl;
2040 #endif
2041                iterator++;   // Important! shutdown() may invalidate iterator!
2042                association->abort();
2043             }
2044 
2045             /* ====== Association still active, but timeout has expired == */
2046             else if((AutoCloseTimeout > 0) &&
2047                     (now - association->LastUsage > AutoCloseTimeout) &&
2048                     (!association->IsShuttingDown)) {
2049 #ifdef PRINT_AUTOCLOSE_TIMEOUT
2050                const unsigned int assocID = association->getID();
2051                std::cout << "AutoConnect: Doing shutdown of association #" << assocID << " due to timeout" << std::endl;
2052 #endif
2053                iterator++;   // Important! shutdown() may invalidate iterator!
2054                association->shutdown();
2055             }
2056 
2057             /* ====== Association is waiting for shutdown/abort ========== */
2058             else {
2059                iterator++;
2060             }
2061          }
2062 
2063          /* ====== Association is still in use =========================== */
2064          else {
2065             // Skip this association
2066             iterator++;
2067 
2068             // The association is closed, but somebody is still using it.
2069             // We will remove it later ...
2070             if((association->ShutdownCompleteNotification) ||
2071                (association->CommunicationLostNotification)) {
2072 #ifdef PRINT_AUTOCLOSE_TIMEOUT
2073                std::cout << "AutoConnect: Association #" << association->getID() << " is disconnected but still has users!" << std::endl;
2074 #endif
2075             }
2076          }
2077       }
2078    } while(AutoCloseNewCheckRequired == true);
2079    AutoCloseRecursion = false;
2080 }
2081 
2082 
2083 // ###### AutoConnect maintenance ###########################################
checkAutoConnect()2084 void SCTPSocket::checkAutoConnect()
2085 {
2086    if(Flags & SSF_AutoConnect) {
2087       SCTPSocketMaster::MasterInstance.lock();
2088 
2089       // ====== Check, if there are new incoming associations ===============
2090       const cardinal oldFlags = Flags;
2091       Flags |= SSF_Listening;
2092       SCTPAssociation* association = accept(NULL,false);
2093       while(association != NULL) {
2094 #ifdef PRINT_NEW_ASSOCIATIONS
2095          std::cout << "AutoConnect: New incoming association #" << association->getID() << "..." << std::endl;
2096 #endif
2097          ConnectionlessAssociationList.insert(std::pair<unsigned int, SCTPAssociation*>(association->getID(),association));
2098          association = accept(NULL,false);
2099       }
2100       Flags = oldFlags;
2101 
2102       SCTPSocketMaster::MasterInstance.unlock();
2103    }
2104 }
2105