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*)¶meters.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 = ¬ification.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*)¬ification.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*)¬ification.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