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 Wrapper
35  *
36  */
37 
38 #include "tdsystem.h"
39 #include "sctpsocketwrapper.h"
40 #include "extsocketdescriptor.h"
41 #include "tdin6.h"
42 
43 #include <stdarg.h>
44 #include <sys/ioctl.h>
45 #include <poll.h>
46 
47 
48 // Random port selection for INADDR_ANY. Necessary for localhost testing!
49 #define RANDOM_PORTSELECTION
50 
51 // Print note, if no SCTP is available in kernel.
52 // #define PRINT_NOSCTP_NOTE
53 // #define PRINT_RANDOM_PORTSELECTION
54 // #define PRINT_SELECT
55 
56 
57 
58 #ifndef HAVE_KERNEL_SCTP
59 
60 
61 #include "tdmessage.h"
62 #include "internetaddress.h"
63 #include "sctpsocketmaster.h"
64 #include "sctpsocket.h"
65 #include "sctpassociation.h"
66 
67 
68 #include <sys/time.h>
69 #include <sys/uio.h>
70 #include <sys/types.h>
71 #include <sys/socket.h>
72 
73 #if (SYSTEM == OS_SOLARIS)
74 #include <sys/stat.h>
75 #include <fcntl.h>
76 #endif
77 // Set errno variable and return.
getErrnoResult(const int result)78 inline static int getErrnoResult(const int result)
79 {
80    if(result < 0) {
81       errno = -result;
82       return(-1);
83    }
84    // errno = 0;
85    return(result);
86 }
87 #define errno_return(x) return(getErrnoResult(x))
88 
89 
90 // FD_ISSET rewriting with NULL check
SAFE_FD_ISSET(int fd,fd_set * fdset)91 inline static int SAFE_FD_ISSET(int fd, fd_set* fdset)
92 {
93    if(fdset == NULL) {
94       return(0);
95    }
96    return(FD_ISSET(fd,fdset));
97 }
98 
99 
100 // FD_ZERO rewriting with NULL check
SAFE_FD_ZERO(fd_set * fdset)101 inline static void SAFE_FD_ZERO(fd_set* fdset)
102 {
103    if(fdset != NULL) {
104       FD_ZERO(fdset);
105    }
106 }
107 
108 
109 // ###### Unpack sockaddr blocks to sockaddr_storage array ##################
unpack_sockaddr(const sockaddr * addrArray,const size_t addrs,sockaddr_storage * newArray)110 static void unpack_sockaddr(const sockaddr*   addrArray,
111                             const size_t      addrs,
112                             sockaddr_storage* newArray)
113 {
114    for(size_t i = 0;i < addrs;i++) {
115       switch(addrArray->sa_family) {
116          case AF_INET:
117             memcpy((void*)&newArray[i], addrArray, sizeof(struct sockaddr_in));
118             addrArray = (sockaddr*)((long)addrArray + (long)sizeof(sockaddr_in));
119           break;
120          case AF_INET6:
121             memcpy((void*)&newArray[i], addrArray, sizeof(struct sockaddr_in6));
122             addrArray = (sockaddr*)((long)addrArray + (long)sizeof(sockaddr_in6));
123           break;
124          default:
125             std::cerr << "ERROR: unpack_sockaddr() - Unknown address type #" << addrArray->sa_family << "!" << std::endl;
126             abort();
127           break;
128       }
129    }
130 }
131 
132 
133 // ###### Pack sockaddr_storage array to sockaddr blocks ####################
pack_sockaddr_storage(const sockaddr_storage * addrArray,const size_t addrs)134 static sockaddr* pack_sockaddr_storage(const sockaddr_storage* addrArray, const size_t addrs)
135 {
136    size_t required = 0;
137    for(size_t i = 0;i < addrs;i++) {
138       switch(((sockaddr*)&addrArray[i])->sa_family) {
139          case AF_INET:
140             required += sizeof(struct sockaddr_in);
141           break;
142          case AF_INET6:
143             required += sizeof(struct sockaddr_in6);
144           break;
145          default:
146             std::cerr << "ERROR: pack_sockaddr_storage() - Unknown address type #" << ((sockaddr*)&addrArray[i])->sa_family << "!" << std::endl;
147             abort();
148           break;
149       }
150    }
151 
152    sockaddr* newArray = NULL;
153    if(required > 0) {
154       newArray = (sockaddr*)new char[required];
155       if(newArray == NULL) {
156          return(NULL);
157       }
158       sockaddr* a = newArray;
159       for(size_t i = 0;i < addrs;i++) {
160          switch(((sockaddr*)&addrArray[i])->sa_family) {
161             case AF_INET:
162                memcpy((void*)a, (void*)&addrArray[i], sizeof(struct sockaddr_in));
163                a = (sockaddr*)((long)a + (long)sizeof(sockaddr_in));
164              break;
165             case AF_INET6:
166                memcpy((void*)a, (void*)&addrArray[i], sizeof(struct sockaddr_in6));
167                a = (sockaddr*)((long)a + (long)sizeof(sockaddr_in6));
168              break;
169          }
170       }
171    }
172    return(newArray);
173 }
174 
175 
176 
177 // ###### Constructor #######################################################
ExtSocketDescriptorMaster()178 ExtSocketDescriptorMaster::ExtSocketDescriptorMaster()
179 {
180    for(unsigned int i = 0;i < MaxSockets;i++) {
181       Sockets[i].Type = ExtSocketDescriptor::ESDT_Invalid;
182    }
183    if(STDIN_FILENO < MaxSockets) {
184       Sockets[STDIN_FILENO].Type                   = ExtSocketDescriptor::ESDT_System;
185       Sockets[STDIN_FILENO].Socket.SystemSocketID  = STDIN_FILENO;
186    }
187    if(STDOUT_FILENO < MaxSockets) {
188       Sockets[STDOUT_FILENO].Type                  = ExtSocketDescriptor::ESDT_System;
189       Sockets[STDOUT_FILENO].Socket.SystemSocketID = STDOUT_FILENO;
190    }
191    if(STDERR_FILENO < MaxSockets) {
192       Sockets[STDERR_FILENO].Type                  = ExtSocketDescriptor::ESDT_System;
193       Sockets[STDERR_FILENO].Socket.SystemSocketID = STDERR_FILENO;
194    }
195 }
196 
197 
198 // ###### Destructor ########################################################
~ExtSocketDescriptorMaster()199 ExtSocketDescriptorMaster::~ExtSocketDescriptorMaster()
200 {
201    for(unsigned int i = 0;i < MaxSockets;i++) {
202       if((Sockets[i].Type != ExtSocketDescriptor::ESDT_Invalid) &&
203          (i != STDIN_FILENO)  &&
204          (i != STDOUT_FILENO) &&
205          (i != STDERR_FILENO)) {
206          ext_close(i);
207       }
208    }
209 }
210 
211 
212 // ###### Get ExtSocketDescriptor for given ID ##############################
getSocket(const int id)213 inline ExtSocketDescriptor* ExtSocketDescriptorMaster::getSocket(const int id)
214 {
215    if((id < (int)MaxSockets) && (id >= 0)) {
216       return(&Sockets[id]);
217    }
218    return(NULL);
219 }
220 
221 
222 // ###### Set ExtSocketDescriptor of given ID ###############################
setSocket(const ExtSocketDescriptor & newSocket)223 int ExtSocketDescriptorMaster::setSocket(const ExtSocketDescriptor& newSocket)
224 {
225    // This operation must be atomic!
226    SCTPSocketMaster::MasterInstance.lock();
227    for(int i = (int)(std::min((int)FD_SETSIZE, getdtablesize())) - 1;i >= 0;i--) {
228       if(Sockets[i].Type == ExtSocketDescriptor::ESDT_Invalid) {
229          Sockets[i] = newSocket;
230          SCTPSocketMaster::MasterInstance.unlock();
231          return(i);
232       }
233    }
234    SCTPSocketMaster::MasterInstance.unlock();
235    return(-EMFILE);
236 }
237 
238 
239 // ###### Get paddrinfo #####################################################
getPrimaryAddressInfo(ExtSocketDescriptor * tdSocket,unsigned int assocID,sctp_paddrinfo & paddrinfo)240 static int getPrimaryAddressInfo(ExtSocketDescriptor* tdSocket,
241                                  unsigned int         assocID,
242                                  sctp_paddrinfo&      paddrinfo)
243 {
244    int             result = -EBADF;
245    SCTP_PathStatus parameters;
246 
247    SCTPSocketMaster::MasterInstance.lock();
248 
249    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
250       if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
251          getPathParameters(NULL,parameters)) {
252          assocID = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID();
253          result = 0;
254       }
255    }
256    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
257       if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
258          getPathParameters(assocID,NULL,parameters)) {
259          result = 0;
260       }
261    }
262 
263    if(result == 0) {
264       SocketAddress* address = SocketAddress::createSocketAddress(0,
265                                   (char*)&parameters.destinationAddress);
266       if(address != NULL) {
267          if(address->getSystemAddress((sockaddr*)&paddrinfo.spinfo_address,
268                                       sizeof(paddrinfo.spinfo_address),
269                                       tdSocket->Socket.SCTPSocketDesc.Domain) > 0) {
270             paddrinfo.spinfo_state    = parameters.state;
271             paddrinfo.spinfo_cwnd     = parameters.cwnd;
272             paddrinfo.spinfo_srtt     = parameters.srtt;
273             paddrinfo.spinfo_rto      = parameters.rto;
274             paddrinfo.spinfo_mtu      = parameters.mtu;
275             paddrinfo.spinfo_assoc_id = assocID;
276          }
277          else {
278             result = -EIO;
279          }
280          delete address;
281       }
282       else {
283          result = -EIO;
284       }
285    }
286 
287    SCTPSocketMaster::MasterInstance.unlock();
288 
289    return(result);
290 }
291 
292 
293 // ###### Get association parameters ########################################
getAssocParams(ExtSocketDescriptor * tdSocket,unsigned int & assocID,SCTP_Association_Status & parameters)294 static int getAssocParams(ExtSocketDescriptor*     tdSocket,
295                           unsigned int&            assocID,
296                           SCTP_Association_Status& parameters)
297 {
298    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
299       if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
300             getAssocStatus(parameters)) {
301          assocID = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID();
302          return(0);
303       }
304    }
305    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
306       if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
307             getAssocStatus(assocID, parameters)) {
308          return(0);
309       }
310    }
311    return(-1);
312 }
313 
314 
315 // ###### Set association parameters ########################################
setAssocParams(ExtSocketDescriptor * tdSocket,const unsigned int assocID,const SCTP_Association_Status & parameters)316 static int setAssocParams(ExtSocketDescriptor*           tdSocket,
317                           const unsigned int             assocID,
318                           const SCTP_Association_Status& parameters)
319 {
320    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
321       if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
322             setAssocStatus(parameters)) {
323          return(0);
324       }
325    }
326    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
327       if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
328             setAssocStatus(assocID, parameters)) {
329          return(0);
330       }
331    }
332    return(-1);
333 }
334 
335 
336 // ###### Get path status ###################################################
getPathStatus(ExtSocketDescriptor * tdSocket,unsigned int & assocID,sockaddr * sockadr,const socklen_t socklen,SCTP_PathStatus & parameters)337 static int getPathStatus(ExtSocketDescriptor* tdSocket,
338                          unsigned int&        assocID,
339                          sockaddr*            sockadr,
340                          const socklen_t      socklen,
341                          SCTP_PathStatus&     parameters)
342 {
343    SocketAddress* address = SocketAddress::createSocketAddress(0,sockadr,socklen);
344    if(address == NULL) {
345       return(-EINVAL);
346    }
347 
348    // ====== Get path status =============================================
349    bool ok = false;
350    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
351       ok = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getPathParameters(address,parameters);
352    }
353    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
354       ok = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getPathParameters(assocID,address,parameters);
355    }
356 
357    delete address;
358    return((ok == false) ? -EIO : 0);
359 }
360 
361 
362 // ###### Set path status ###################################################
setPathStatus(ExtSocketDescriptor * tdSocket,unsigned int assocID,sockaddr * sockadr,const socklen_t socklen,const SCTP_PathStatus & newParameters)363 static int setPathStatus(ExtSocketDescriptor*    tdSocket,
364                          unsigned int            assocID,
365                          sockaddr*               sockadr,
366                          const socklen_t         socklen,
367                          const SCTP_PathStatus&  newParameters)
368 {
369    SocketAddress* address = SocketAddress::createSocketAddress(0,sockadr,socklen);
370    if(address == NULL) {
371       return(-EINVAL);
372    }
373 
374    // ====== Get path status =============================================
375    bool ok = false;
376    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
377       ok = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setPathParameters(address,newParameters);
378    }
379    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
380       ok = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setPathParameters(assocID,address,newParameters);
381    }
382 
383    delete address;
384    return((ok == false) ? -EIO : 0);
385 }
386 
387 
388 // ###### Get version #######################################################
socketAPIGetVersion()389 unsigned int socketAPIGetVersion()
390 {
391    return((SOCKETAPI_MAJOR_VERSION << 16) | SOCKETAPI_MINOR_VERSION);
392 }
393 
394 
395 // ###### socket() wrapper ##################################################
ext_socket(int domain,int type,int protocol)396 int ext_socket(int domain, int type, int protocol)
397 {
398    ExtSocketDescriptor tdSocket;
399    if(protocol == IPPROTO_SCTP) {
400       // ====== Is SCTP available? ==========================================
401       if(!sctp_isavailable()) {
402          errno_return(-ENOPROTOOPT);
403       }
404 
405       // ====== Check parameters ============================================
406       cardinal flags;
407       if(type == SOCK_STREAM) {
408          tdSocket.Socket.SCTPSocketDesc.ConnectionOriented = true;
409          flags = 0;
410       }
411       else if((type == SOCK_DGRAM) || (type == SOCK_SEQPACKET)) {
412          tdSocket.Socket.SCTPSocketDesc.ConnectionOriented = false;
413          flags = SCTPSocket::SSF_GlobalQueue|SCTPSocket::SSF_AutoConnect;
414       }
415       else {
416          errno_return(-EINVAL);
417       }
418 
419       // ====== Create SCTP socket ==========================================
420       tdSocket.Type = ExtSocketDescriptor::ESDT_SCTP;
421       tdSocket.Socket.SCTPSocketDesc.Domain             = domain;
422       tdSocket.Socket.SCTPSocketDesc.Type               = type;
423       tdSocket.Socket.SCTPSocketDesc.Flags              = 0;
424       tdSocket.Socket.SCTPSocketDesc.Linger.l_onoff     = 1;
425       tdSocket.Socket.SCTPSocketDesc.Linger.l_linger    = 10;
426       tdSocket.Socket.SCTPSocketDesc.SCTPAssociationPtr = NULL;
427       tdSocket.Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams   = 10;
428       tdSocket.Socket.SCTPSocketDesc.InitMsg.sinit_max_instreams  = 10;
429       tdSocket.Socket.SCTPSocketDesc.InitMsg.sinit_max_attempts   = 8;
430       tdSocket.Socket.SCTPSocketDesc.InitMsg.sinit_max_init_timeo = 60000;
431       tdSocket.Socket.SCTPSocketDesc.SCTPSocketPtr = new SCTPSocket(domain, flags);
432       if(tdSocket.Socket.SCTPSocketDesc.SCTPSocketPtr == NULL) {
433          errno_return(-ENOMEM);
434       }
435 
436       // Set default notifications for UDP-like socket: no notification messages
437       if(tdSocket.Socket.SCTPSocketDesc.ConnectionOriented == false) {
438          tdSocket.Socket.SCTPSocketDesc.SCTPSocketPtr->setNotificationFlags(
439             SCTP_RECVDATAIOEVNT );
440       }
441 
442       int result = ExtSocketDescriptorMaster::setSocket(tdSocket);
443       if(result < 0) {
444          delete tdSocket.Socket.SCTPSocketDesc.SCTPSocketPtr;
445          tdSocket.Socket.SCTPSocketDesc.SCTPSocketPtr = NULL;
446       }
447       errno_return(result);
448    }
449    else {
450       // ====== Create system socket ========================================
451       tdSocket.Type = ExtSocketDescriptor::ESDT_System;
452       tdSocket.Socket.SystemSocketID = socket(domain,type,protocol);
453       if(tdSocket.Socket.SystemSocketID >= 0) {
454          int result = ExtSocketDescriptorMaster::setSocket(tdSocket);
455          errno_return(result);
456       }
457       errno_return(tdSocket.Socket.SystemSocketID);
458    }
459 }
460 
461 
462 // ###### open() wrapper ####################################################
ext_open(const char * pathname,int flags,mode_t mode)463 int ext_open(const char* pathname, int flags, mode_t mode)
464 {
465    ExtSocketDescriptor tdSocket;
466    tdSocket.Type = ExtSocketDescriptor::ESDT_System;
467    tdSocket.Socket.SystemSocketID = open(pathname,flags,mode);
468    if(tdSocket.Socket.SystemSocketID >= 0) {
469       int result = ExtSocketDescriptorMaster::setSocket(tdSocket);
470       if(result < 0) {
471          close(tdSocket.Socket.SystemSocketID);
472       }
473       errno_return(result);
474    }
475    errno_return(tdSocket.Socket.SystemSocketID);
476 }
477 
478 
479 // ###### creat() wrapper ###################################################
ext_creat(const char * pathname,mode_t mode)480 int ext_creat(const char* pathname, mode_t mode)
481 {
482    ExtSocketDescriptor tdSocket;
483    tdSocket.Type = ExtSocketDescriptor::ESDT_System;
484    tdSocket.Socket.SystemSocketID = creat(pathname,mode);
485    if(tdSocket.Socket.SystemSocketID >= 0) {
486       int result = ExtSocketDescriptorMaster::setSocket(tdSocket);
487       if(result < 0) {
488          close(tdSocket.Socket.SystemSocketID);
489       }
490       errno_return(result);
491    }
492    errno_return(tdSocket.Socket.SystemSocketID);
493 }
494 
495 
496 // ###### pipe() wrapper ####################################################
ext_pipe(int fds[2])497 int ext_pipe(int fds[2])
498 {
499    ExtSocketDescriptor tdSocket1;
500    ExtSocketDescriptor tdSocket2;
501    int                 newPipe[2];
502 
503    if(pipe((int*)&newPipe) == 0) {
504       tdSocket1.Type = ExtSocketDescriptor::ESDT_System;
505       tdSocket1.Socket.SystemSocketID = newPipe[0];
506       tdSocket2.Type = ExtSocketDescriptor::ESDT_System;
507       tdSocket2.Socket.SystemSocketID = newPipe[1];
508 
509       fds[0] = ExtSocketDescriptorMaster::setSocket(tdSocket1);
510       if(fds[0] < 0) {
511          close(tdSocket1.Socket.SystemSocketID);
512          close(tdSocket2.Socket.SystemSocketID);
513          errno_return(fds[0]);
514       }
515       fds[1] = ExtSocketDescriptorMaster::setSocket(tdSocket2);
516       if(fds[1] < 0) {
517          ext_close(fds[0]);
518          close(tdSocket2.Socket.SystemSocketID);
519          errno_return(fds[1]);
520       }
521       errno_return(0);
522    }
523    return(-1);
524 }
525 
526 
527 // ###### Check whether the SCTP socket is still referenced #######
mayRemoveSocket(ExtSocketDescriptor * tdSocket)528 static bool mayRemoveSocket(ExtSocketDescriptor* tdSocket)
529 {
530    const SCTPSocket* sctpSocket = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr;
531 
532    for(unsigned int i = 1;i <= ExtSocketDescriptorMaster::MaxSockets;i++) {
533       ExtSocketDescriptor* td = ExtSocketDescriptorMaster::getSocket(i);
534       if((td != NULL) &&
535          (td != tdSocket) &&
536          (td->Type == ExtSocketDescriptor::ESDT_SCTP) &&
537          (td->Socket.SCTPSocketDesc.SCTPSocketPtr == sctpSocket)) {
538          return(false);
539       }
540    }
541    return(true);
542 }
543 
544 
545 // ###### close() wrapper ###################################################
ext_close(int sockfd)546 int ext_close(int sockfd)
547 {
548    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
549    if(tdSocket != NULL) {
550       SCTPSocketMaster::MasterInstance.lock();
551 
552       switch(tdSocket->Type) {
553          case ExtSocketDescriptor::ESDT_SCTP:
554             if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
555                if(tdSocket->Socket.SCTPSocketDesc.Linger.l_onoff == 1) {
556                   if(tdSocket->Socket.SCTPSocketDesc.Linger.l_linger > 0) {
557                      tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->shutdown();
558                   }
559                   else {
560                      tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->abort();
561                   }
562                }
563                delete tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr;
564                tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr = NULL;
565             }
566             if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
567                if(mayRemoveSocket(tdSocket)) {
568                   if(tdSocket->Socket.SCTPSocketDesc.Linger.l_onoff == 1) {
569                      if(tdSocket->Socket.SCTPSocketDesc.Linger.l_linger > 0) {
570                         tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->unbind(false);
571                      }
572                      else {
573                         tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->unbind(true);
574                      }
575                   }
576                   delete tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr;
577                }
578                else {
579                   /* ext_close() has been invoked on a peeled-off socket.
580                      The SCTPSocket object will be deleted when closing the last socket. */
581                   // std::cerr << "INFO: ext_close(" << sockfd << ") - still in use. OK!" << std::endl;
582                }
583                tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr = NULL;
584             }
585           break;
586          case ExtSocketDescriptor::ESDT_System:
587             close(tdSocket->Socket.SystemSocketID);
588             tdSocket->Socket.SystemSocketID = 0;
589           break;
590          default:
591             SCTPSocketMaster::MasterInstance.unlock();
592             errno_return(-ENXIO);
593           break;
594       }
595 
596       // Finally, invalidate socket descriptor
597       tdSocket->Type = ExtSocketDescriptor::ESDT_Invalid;
598 
599       SCTPSocketMaster::MasterInstance.unlock();
600       errno_return(0);
601    }
602    errno_return(-EBADF);
603 }
604 
605 
606 // ###### bind to any address ###############################################
bindToAny(struct ExtSocketDescriptor * tdSocket)607 static int bindToAny(struct ExtSocketDescriptor* tdSocket)
608 {
609    int result = 0;
610    if((tdSocket->Type == ExtSocketDescriptor::ESDT_SCTP)      &&
611       (tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) &&
612       (tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getID() <= 0)) {
613       InternetAddress anyAddress;
614       anyAddress.reset();
615 
616       SocketAddress* addressArray[2];
617       addressArray[0] = (SocketAddress*)&anyAddress;
618       addressArray[1] = NULL;
619 
620 #ifdef RANDOM_PORTSELECTION
621       card16 port;
622       for(cardinal i = 0;i < 50000;i++) {
623          SCTPSocketMaster::MasterInstance.lock();
624          port = (card16)(16384 + SCTPSocketMaster::Random.random32() % (61000 - 16384));
625          SCTPSocketMaster::MasterInstance.unlock();
626          addressArray[0]->setPort(port),
627 #ifdef PRINT_RANDOM_PORTSELECTION
628          std::cout << "trying " << *(addressArray[0]) << "..." << std::endl;
629 #endif
630 #endif
631 
632          result = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->bind(
633             addressArray[0]->getPort(),
634             tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_instreams,
635             tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams,
636             (const SocketAddress**)&addressArray);
637 
638 #ifdef RANDOM_PORTSELECTION
639          if(result >= 0) {
640             break;
641          }
642       }
643 #endif
644 
645    }
646    errno_return(result);
647 }
648 
649 
650 // ###### bind() wrapper ####################################################
ext_bind(int sockfd,struct sockaddr * my_addr,socklen_t addrlen)651 int ext_bind(int sockfd, struct sockaddr* my_addr, socklen_t addrlen)
652 {
653    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
654    if(tdSocket != NULL) {
655       switch(tdSocket->Type) {
656          case ExtSocketDescriptor::ESDT_SCTP:
657              return(sctp_bindx(sockfd,my_addr,1,SCTP_BINDX_ADD_ADDR));
658           break;
659          case ExtSocketDescriptor::ESDT_System:
660             return(bind(tdSocket->Socket.SystemSocketID,(sockaddr*)my_addr,addrlen));
661           break;
662          default:
663             errno_return(-ENXIO);
664           break;
665       }
666    }
667    errno_return(-EBADF);
668 }
669 
670 
671 // ###### sctp_bindx() wrapper ##############################################
sctp_bindx(int sockfd,struct sockaddr * packedAddrs,int addrcnt,int flags)672 int sctp_bindx(int              sockfd,
673                struct sockaddr* packedAddrs,
674                int              addrcnt,
675                int              flags)
676 {
677    sockaddr_storage addrs[addrcnt];
678    unpack_sockaddr(packedAddrs, addrcnt, (sockaddr_storage*)addrs);
679 
680    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
681    if(tdSocket != NULL) {
682       switch(tdSocket->Type) {
683          case ExtSocketDescriptor::ESDT_SCTP: {
684                // ====== Check parameters and descriptor ====================
685                if((addrcnt < 1) || (addrcnt > SCTP_MAX_NUM_ADDRESSES)) {
686                   errno_return(-EINVAL);
687                }
688                else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr == NULL) {
689                   errno_return(-EBADF);
690                }
691 
692                // ====== Get addresses ======================================
693                SocketAddress* addressArray[addrcnt + 1];
694                sockaddr_storage* a = addrs;
695                for(int i = 0;i < addrcnt;i++) {
696                   addressArray[i] = SocketAddress::createSocketAddress(
697                                        0,(sockaddr*)a,sizeof(sockaddr_storage));
698                   if(addressArray[i] == NULL) {
699                      for(int j = 0;j < i;j++) {
700                         delete addressArray[j];
701                      }
702                      errno_return(-ENOMEM);
703                   }
704                   a = (sockaddr_storage*)((long)a + (long)sizeof(sockaddr_storage));
705                }
706                addressArray[addrcnt] = NULL;
707 
708                // ====== Bind socket ========================================
709                int result = -EINVAL;
710                if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getID() <= 0) {
711                   if(flags == SCTP_BINDX_ADD_ADDR) {
712                      result = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->bind(
713                                  addressArray[0]->getPort(),
714                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_instreams,
715                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams,
716                                  (const SocketAddress**)&addressArray);
717                   }
718                }
719                else {
720                   if(flags == SCTP_BINDX_ADD_ADDR) {
721                      result = 0;
722                      if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
723                         for(int i = 0;i < addrcnt;i++) {
724                            const bool ok = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
725                                               addAddress(*(addressArray[i]));
726                            if(!ok) {
727                               result = -EINVAL;
728                               break;
729                            }
730                         }
731                      }
732                      else {
733                         for(int i = 0;i < addrcnt;i++) {
734                            const bool ok = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
735                                               addAddress(0,*(addressArray[i]));
736                            if(!ok) {
737                               result = -EINVAL;
738                               break;
739                            }
740                         }
741                      }
742                   }
743                   else if(flags == SCTP_BINDX_REM_ADDR) {
744                      result = 0;
745                      if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
746                         for(int i = 0;i < addrcnt;i++) {
747                            const bool ok = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
748                                               deleteAddress(*(addressArray[i]));
749                            if(!ok) {
750                               result = -EINVAL;
751                               break;
752                            }
753                         }
754                      }
755                      else {
756                         for(int i = 0;i < addrcnt;i++) {
757                            const bool ok = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
758                                               deleteAddress(0,*(addressArray[i]));
759                            if(!ok) {
760                               result = -EINVAL;
761                               break;
762                            }
763                         }
764                      }
765                   }
766                }
767 
768                // ====== Remove addresses ===================================
769                for(int i = 0;i < addrcnt;i++) {
770                   delete addressArray[i];
771                }
772                errno_return(result);
773             }
774            break;
775          case ExtSocketDescriptor::ESDT_System:
776             return(bind(tdSocket->Socket.SystemSocketID,(sockaddr*)addrs,sizeof(sockaddr_storage)));
777            break;
778          default:
779             errno_return(-ENXIO);
780           break;
781       }
782    }
783    errno_return(-EBADF);
784 }
785 
786 
787 // ###### listen() wrapper ####################################################
ext_listen(int sockfd,int backlog)788 int ext_listen(int sockfd, int backlog)
789 {
790    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
791    if(tdSocket != NULL) {
792       switch(tdSocket->Type) {
793          case ExtSocketDescriptor::ESDT_SCTP:
794             bindToAny(tdSocket);
795             if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
796                tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->listen(backlog);
797                errno_return(0);
798             }
799             errno_return(-EOPNOTSUPP);
800           break;
801          case ExtSocketDescriptor::ESDT_System:
802             return(listen(tdSocket->Socket.SystemSocketID,backlog));
803           break;
804       }
805       errno_return(-ENXIO);
806    }
807    errno_return(-EBADF);
808 }
809 
810 
811 // ###### accept() wrapper ####################################################
ext_accept(int sockfd,struct sockaddr * addr,socklen_t * addrlen)812 int ext_accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
813 {
814    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
815    if(tdSocket != NULL) {
816       switch(tdSocket->Type) {
817          case ExtSocketDescriptor::ESDT_SCTP:
818             {
819                if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
820                   SocketAddress** remoteAddressArray = NULL;
821                   SCTPAssociation* association =
822                      tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->accept(
823                         &remoteAddressArray,
824                         !(tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK));
825                   if(association != NULL) {
826                      if((remoteAddressArray != NULL)    &&
827                         (remoteAddressArray[0] != NULL) &&
828                         (addr != NULL) && (addrlen != NULL)) {
829                         *addrlen = remoteAddressArray[0]->getSystemAddress(
830                                       addr, *addrlen,
831                                       tdSocket->Socket.SCTPSocketDesc.Domain);
832                      }
833                      else {
834                         addrlen = 0;
835                      }
836 
837                      ExtSocketDescriptor newExtSocketDescriptor = *tdSocket;
838                      newExtSocketDescriptor.Socket.SCTPSocketDesc.ConnectionOriented = true;
839                      newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPSocketPtr      = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr;
840                      newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr = association;
841                      const int newFD = ExtSocketDescriptorMaster::setSocket(newExtSocketDescriptor);
842                      SocketAddress::deleteAddressList(remoteAddressArray);
843                      if(newFD < 0) {
844                         delete newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr;
845                         newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr = NULL;
846                      }
847 
848                      // New socket may not inherit flags from parent socket!
849                      newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr->setNotificationFlags(
850                         SCTP_RECVDATAIOEVNT
851                      );
852 
853                      errno_return(newFD);
854                   }
855                   else {
856                      errno_return(-EWOULDBLOCK);
857                   }
858                }
859                errno_return(-EOPNOTSUPP);
860             }
861           break;
862          case ExtSocketDescriptor::ESDT_System:
863             {
864                ExtSocketDescriptor newExtSocketDescriptor = *tdSocket;
865                newExtSocketDescriptor.Socket.SystemSocketID = accept(tdSocket->Socket.SystemSocketID,addr,addrlen);
866                if(newExtSocketDescriptor.Socket.SystemSocketID >= 0) {
867                   int result = ExtSocketDescriptorMaster::setSocket(newExtSocketDescriptor);
868                   if(result < 0) {
869                      close(newExtSocketDescriptor.Socket.SystemSocketID);
870                   }
871                   errno_return(result);
872                }
873                errno_return(newExtSocketDescriptor.Socket.SystemSocketID);
874             }
875           break;
876       }
877       errno_return(-ENXIO);
878    }
879    errno_return(-EBADF);
880 }
881 
882 
883 // ###### getsockname() wrapper #############################################
ext_getsockname(int sockfd,struct sockaddr * name,socklen_t * namelen)884 int ext_getsockname(int sockfd, struct sockaddr* name, socklen_t* namelen)
885 {
886    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
887    if(tdSocket != NULL) {
888       switch(tdSocket->Type) {
889          case ExtSocketDescriptor::ESDT_SCTP:
890             {
891                int result = -ENXIO;
892                SocketAddress** localAddressArray = NULL;
893                if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
894                   tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getLocalAddresses(localAddressArray);
895                }
896                else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
897                   tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getLocalAddresses(localAddressArray);
898                }
899                else {
900                   result = -EBADF;
901                }
902 
903                if((localAddressArray != NULL)    &&
904                   (localAddressArray[0] != NULL) &&
905                   (name != NULL) && (namelen != NULL)) {
906                   result = -ENAMETOOLONG;
907                   size_t i = 0;
908                   while(localAddressArray[i] != NULL) {
909                      if(localAddressArray[i]->getSystemAddress(
910                            name,*namelen,
911                            tdSocket->Socket.SCTPSocketDesc.Domain)) {
912                         result = 0;
913                         break;
914                      }
915                      i++;
916                   }
917                }
918 
919                SocketAddress::deleteAddressList(localAddressArray);
920                errno_return(result);
921             }
922           break;
923          case ExtSocketDescriptor::ESDT_System:
924             return(getsockname(tdSocket->Socket.SystemSocketID,name,namelen));
925           break;
926       }
927       errno_return(-ENXIO);
928    }
929    errno_return(-EBADF);
930 }
931 
932 
933 // ###### getpeername() wrapper #############################################
ext_getpeername(int sockfd,struct sockaddr * name,socklen_t * namelen)934 int ext_getpeername(int sockfd, struct sockaddr* name, socklen_t* namelen)
935 {
936    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
937    if(tdSocket != NULL) {
938       switch(tdSocket->Type) {
939          case ExtSocketDescriptor::ESDT_SCTP:
940             {
941                int result = -ENXIO;
942                SocketAddress** remoteAddressArray = NULL;
943                if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
944                   tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getRemoteAddresses(remoteAddressArray);
945                }
946                else {
947                   result = -EBADF;
948                }
949 
950                if((remoteAddressArray != NULL)    &&
951                   (remoteAddressArray[0] != NULL) &&
952                   (name != NULL) && (namelen != NULL)) {
953                   result = -ENAMETOOLONG;
954                   size_t i = 0;
955                   while(remoteAddressArray[i] != NULL) {
956                      if(remoteAddressArray[i]->getSystemAddress(
957                            name,*namelen,
958                            tdSocket->Socket.SCTPSocketDesc.Domain)) {
959                         result = 0;
960                         break;
961                      }
962                      i++;
963                   }
964                }
965 
966                SocketAddress::deleteAddressList(remoteAddressArray);
967                errno_return(result);
968             }
969           break;
970          case ExtSocketDescriptor::ESDT_System:
971             return(getpeername(tdSocket->Socket.SystemSocketID,name,namelen));
972           break;
973       }
974       errno_return(-ENXIO);
975    }
976    errno_return(-EBADF);
977 }
978 
979 
980 // ###### fcntl() wrapper ###################################################
ext_fcntl(int sockfd,int cmd,...)981 int ext_fcntl(int sockfd, int cmd, ...)
982 {
983    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
984    if(tdSocket != NULL) {
985       va_list va;
986       unsigned long int arg;
987       va_start (va, cmd);
988       arg = va_arg (va, unsigned long int);
989       va_end (va);
990       switch(tdSocket->Type) {
991          case ExtSocketDescriptor::ESDT_SCTP:
992             switch(cmd) {
993                case F_GETFL:
994                   errno_return(tdSocket->Socket.SCTPSocketDesc.Flags);
995                  break;
996                case F_SETFL:
997                    tdSocket->Socket.SCTPSocketDesc.Flags = arg;
998                    errno_return(0);
999                  break;
1000                default:
1001                   errno_return(-EOPNOTSUPP);
1002                 break;
1003             }
1004           break;
1005          case ExtSocketDescriptor::ESDT_System:
1006             return(fcntl(tdSocket->Socket.SystemSocketID,cmd,arg));
1007           break;
1008       }
1009       errno_return(-ENXIO);
1010    }
1011    errno_return(-EBADF);
1012 }
1013 
1014 
1015 // ###### ioctl() wrapper ###################################################
ext_ioctl(int sockfd,int request,const void * argp)1016 int ext_ioctl(int sockfd, int request, const void* argp)
1017 {
1018    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1019    if(tdSocket != NULL) {
1020       switch(tdSocket->Type) {
1021          case ExtSocketDescriptor::ESDT_SCTP:
1022             errno_return(-EOPNOTSUPP);
1023           break;
1024          case ExtSocketDescriptor::ESDT_System:
1025             return(ioctl(tdSocket->Socket.SystemSocketID,request,argp));
1026           break;
1027       }
1028       errno_return(-ENXIO);
1029    }
1030    errno_return(-EBADF);
1031 }
1032 
1033 
1034 // ###### Get association status ############################################
getAssocStatus(ExtSocketDescriptor * tdSocket,void * optval,socklen_t * optlen)1035 static int getAssocStatus(ExtSocketDescriptor* tdSocket,
1036                           void* optval, socklen_t* optlen)
1037 {
1038    if((*optlen < (int)sizeof(sctp_status)) || (optval == NULL)) {
1039       errno_return(-EINVAL);
1040    }
1041    sctp_status*            status  = (sctp_status*)optval;
1042    unsigned int            assocID = status->sstat_assoc_id;
1043    SCTP_Association_Status parameters;
1044 
1045    SCTPSocketMaster::MasterInstance.lock();
1046    int result = getAssocParams(tdSocket,assocID,parameters);
1047    if(result == 0) {
1048       status->sstat_state     = parameters.state;
1049       status->sstat_rwnd      = parameters.currentReceiverWindowSize;
1050       status->sstat_unackdata = parameters.noOfChunksInRetransmissionQueue;
1051       status->sstat_penddata  = parameters.noOfChunksInReceptionQueue;
1052       status->sstat_instrms   = parameters.inStreams;
1053       status->sstat_outstrms  = parameters.outStreams;
1054       status->sstat_fragmentation_point = 0;
1055       status->sstat_assoc_id            = assocID;
1056       result = getPrimaryAddressInfo(tdSocket,assocID,status->sstat_primary);
1057       *optlen = sizeof(sctp_status);
1058    }
1059    SCTPSocketMaster::MasterInstance.unlock();
1060    errno_return(result);
1061 }
1062 
1063 
1064 // ###### Get RTO info ######################################################
getRTOInfo(ExtSocketDescriptor * tdSocket,void * optval,socklen_t * optlen)1065 static int getRTOInfo(ExtSocketDescriptor* tdSocket,
1066                       void* optval, socklen_t* optlen)
1067 {
1068    if((optval == NULL) || ((size_t)*optlen < sizeof(sctp_rtoinfo))) {
1069       errno_return(-EINVAL);
1070    }
1071    sctp_rtoinfo*           rtoinfo = (sctp_rtoinfo*)optval;
1072    unsigned int            assocID = rtoinfo->srto_assoc_id;
1073    SCTP_Association_Status parameters;
1074 
1075    int result = getAssocParams(tdSocket,assocID,parameters);
1076    if(result == 0) {
1077       rtoinfo->srto_initial  = parameters.rtoInitial;
1078       rtoinfo->srto_max      = parameters.rtoMax;
1079       rtoinfo->srto_min      = parameters.rtoMin;
1080       rtoinfo->srto_assoc_id = assocID;
1081       *optlen = sizeof(sctp_rtoinfo);
1082    }
1083    errno_return(result);
1084 }
1085 
1086 
1087 // ###### Get delayed ack time ##############################################
getDelayedAckTime(ExtSocketDescriptor * tdSocket,void * optval,socklen_t * optlen)1088 static int getDelayedAckTime(ExtSocketDescriptor*     tdSocket,
1089                              void* optval, socklen_t* optlen)
1090 {
1091    if((optval == NULL) || ((size_t)*optlen < sizeof(sctp_sack_info))) {
1092       errno_return(-EINVAL);
1093    }
1094    sctp_sack_info* sackInfo  = (sctp_sack_info*)optval;
1095    unsigned int      assocID = sackInfo->sack_assoc_id;
1096 
1097    if((assocID == 0) && (tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr)) {
1098       assocID = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID();
1099    }
1100 
1101    if(assocID != 0) {
1102       SCTP_Association_Status parameters;
1103       int result = getAssocParams(tdSocket, assocID, parameters);
1104       if(result == 0) {
1105          sackInfo->sack_delay = parameters.delay;
1106          *optlen = sizeof(sctp_sack_info);
1107       }
1108       errno_return(result);
1109    }
1110    else {
1111       SCTP_Instance_Parameters parameters;
1112       if(tdSocket->Type == ExtSocketDescriptor::ESDT_SCTP) {
1113          if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr) {
1114             if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getAssocDefaults(parameters)) {
1115                sackInfo->sack_delay = parameters.delay;
1116                *optlen = sizeof(sctp_sack_info);
1117                errno_return(0);
1118             }
1119          }
1120       }
1121       else {
1122          errno_return(-ENOTSUP);
1123       }
1124    }
1125    errno_return(-EINVAL);
1126 }
1127 
1128 
1129 // ###### Get RTO info ######################################################
getAssocInfo(ExtSocketDescriptor * tdSocket,void * optval,socklen_t * optlen)1130 static int getAssocInfo(ExtSocketDescriptor* tdSocket,
1131                           void* optval, socklen_t* optlen)
1132 {
1133    if((optval == NULL) || ((size_t)*optlen < sizeof(sctp_assocparams))) {
1134       errno_return(-EINVAL);
1135    }
1136    sctp_assocparams*       assocparams = (sctp_assocparams*)optval;
1137    unsigned int            assocID     = assocparams->sasoc_assoc_id;
1138    SCTP_Association_Status parameters;
1139 
1140    int result = getAssocParams(tdSocket,assocID,parameters);
1141    if(result == 0) {
1142       assocparams->sasoc_assoc_id                 = assocID;
1143       assocparams->sasoc_asocmaxrxt               = parameters.assocMaxRetransmits;
1144 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19) || (SCTPLIB_VERSION == SCTPLIB_1_0_0)
1145       assocparams->sasoc_number_peer_destinations = parameters.numberOfAddresses;
1146 #elif (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE20) || (SCTPLIB_VERSION == SCTPLIB_1_3_0)
1147       assocparams->sasoc_number_peer_destinations = parameters.numberOfDestinationPaths;
1148 #else
1149 #error Wrong sctplib version!
1150 #endif
1151       assocparams->sasoc_peer_rwnd                = 0;
1152       assocparams->sasoc_local_rwnd               = parameters.currentReceiverWindowSize;
1153       assocparams->sasoc_cookie_life              = parameters.validCookieLife;
1154       *optlen = sizeof(sctp_assocparams);
1155    }
1156    errno_return(result);
1157 }
1158 
1159 
1160 // ###### Get address information ###########################################
getPeerAddressInfo(ExtSocketDescriptor * tdSocket,void * optval,socklen_t * optlen)1161 static int getPeerAddressInfo(ExtSocketDescriptor* tdSocket,
1162                               void* optval, socklen_t* optlen)
1163 {
1164    if((optval == NULL) || ((size_t)*optlen < sizeof(sctp_paddrinfo))) {
1165       errno_return(-EINVAL);
1166    }
1167    int              result;
1168    sctp_paddrinfo*  paddrinfo = (sctp_paddrinfo*)optval;
1169    unsigned int     assocID   = paddrinfo->spinfo_assoc_id;
1170    SCTP_PathStatus  parameters;
1171 
1172    result = getPathStatus(tdSocket,assocID,
1173                           (sockaddr*)&paddrinfo->spinfo_address,
1174                           sizeof(paddrinfo->spinfo_address),
1175                           parameters);
1176    if(result == 0) {
1177       switch(parameters.state) {
1178          case 1:
1179             paddrinfo->spinfo_state = SCTP_INACTIVE;
1180           break;
1181          default:
1182             paddrinfo->spinfo_state = SCTP_ACTIVE;
1183           break;
1184       }
1185       paddrinfo->spinfo_cwnd     = parameters.cwnd;
1186       paddrinfo->spinfo_srtt     = parameters.srtt;
1187       paddrinfo->spinfo_rto      = parameters.rto;
1188       paddrinfo->spinfo_mtu      = parameters.mtu;
1189       paddrinfo->spinfo_assoc_id = assocID;
1190       *optlen = sizeof(sctp_paddrinfo);
1191    }
1192    errno_return(result);
1193 }
1194 
1195 
1196 // ###### Configure address parameters ######################################
configurePeerAddressParams(ExtSocketDescriptor * tdSocket,void * optval,socklen_t * optlen,const bool readOnly)1197 static int configurePeerAddressParams(ExtSocketDescriptor* tdSocket,
1198                                       void*                optval,
1199                                       socklen_t*           optlen,
1200                                       const bool           readOnly)
1201 {
1202    if((optval == NULL) || ((size_t)*optlen < sizeof(sctp_paddrparams))) {
1203       errno_return(-EINVAL);
1204    }
1205    int               result;
1206    sctp_paddrparams* newParams = (sctp_paddrparams*)optval;
1207    unsigned int      assocID   = newParams->spp_assoc_id;
1208    SCTP_PathStatus   parameters;
1209 
1210    SCTPSocketMaster::MasterInstance.lock();
1211    result = getPathStatus(tdSocket,
1212                           assocID,
1213                           (sockaddr*)&newParams->spp_address,
1214                           sizeof(newParams->spp_address),
1215                           parameters);
1216    if(result == 0) {
1217       if(newParams->spp_hbinterval == 0) {
1218          newParams->spp_hbinterval = parameters.heartbeatIntervall;
1219       }
1220       newParams->spp_pathmaxrxt = 0;
1221       newParams->spp_pathmtu    = parameters.mtu;
1222       newParams->spp_sackdelay  = 0;
1223       newParams->spp_flags      = (newParams->spp_hbinterval > 0) ? SPP_HB_ENABLE : SPP_HB_DISABLE;
1224       *optlen = sizeof(sctp_paddrparams);
1225 
1226       if(!readOnly) {
1227          parameters.heartbeatIntervall = newParams->spp_hbinterval;
1228          result = setPathStatus(tdSocket,assocID,
1229                               (sockaddr*)&newParams->spp_address,
1230                               sizeof(newParams->spp_address),
1231                               parameters);
1232       }
1233    }
1234    SCTPSocketMaster::MasterInstance.unlock();
1235 
1236    errno_return(result);
1237 }
1238 
1239 
1240 // ###### getsockopt() wrapper ##############################################
ext_getsockopt(int sockfd,int level,int optname,void * optval,socklen_t * optlen)1241 int ext_getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen)
1242 {
1243    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1244    if(tdSocket != NULL) {
1245       switch(tdSocket->Type) {
1246          case ExtSocketDescriptor::ESDT_SCTP:
1247             {
1248                switch(level) {
1249 #if (SYSTEM == OS_Linux)
1250                   // ====== IPv6 ============================================
1251                   case SOL_IPV6:
1252                       switch(optname) {
1253                          case IPV6_FLOWINFO:
1254                             errno_return(0);
1255                           break;
1256                          case IPV6_FLOWINFO_SEND:
1257                             errno_return(0);
1258                           break;
1259                          default:
1260                             errno_return(-EOPNOTSUPP);
1261                           break;
1262                       }
1263                    break;
1264 
1265                   // ====== IPv4 ============================================
1266                   case SOL_IP:
1267                       switch(optname) {
1268                          case IP_TOS:
1269                             if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
1270                                errno_return(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getTrafficClass());
1271                             }
1272                             errno_return(0);
1273                           break;
1274                          case IP_RECVTOS:
1275                             errno_return(0);
1276                           break;
1277                          default:
1278                             errno_return(-EOPNOTSUPP);
1279                           break;
1280                       }
1281                    break;
1282 #endif
1283 
1284                   // ====== SCTP ============================================
1285                   case IPPROTO_SCTP:
1286                       switch(optname) {
1287                          case SCTP_PEER_ADDR_PARAMS:
1288                             return(configurePeerAddressParams(tdSocket,optval,optlen,true));
1289                           break;
1290                          case SCTP_STATUS:
1291                             return(getAssocStatus(tdSocket,optval,optlen));
1292                           break;
1293                          case SCTP_INITMSG: {
1294                                if((optval == NULL) || ((size_t)*optlen < sizeof(sctp_initmsg))) {
1295                                   errno_return(-EINVAL);
1296                                }
1297                                sctp_initmsg* initmsg = (sctp_initmsg*)optval;
1298                                *initmsg = tdSocket->Socket.SCTPSocketDesc.InitMsg;
1299                                *optlen = sizeof(sctp_initmsg);
1300                                errno_return(0);
1301                             }
1302                           break;
1303                          case SCTP_GET_PEER_ADDR_INFO:
1304                             return(getPeerAddressInfo(tdSocket,optval,optlen));
1305                           break;
1306                          case SCTP_RTOINFO:
1307                             return(getRTOInfo(tdSocket,optval,optlen));
1308                           break;
1309                          case SCTP_DELAYED_SACK:
1310                             return(getDelayedAckTime(tdSocket,optval,optlen));
1311                           break;
1312                          case SCTP_NODELAY:
1313                             errno_return(0);
1314                           break;
1315                          case SCTP_ASSOCINFO:
1316                             return(getAssocInfo(tdSocket,optval,optlen));
1317                           break;
1318                          case SCTP_AUTOCLOSE:
1319                             if((optval == NULL) || ((size_t)*optlen < sizeof(unsigned int))) {
1320                                errno_return(-EINVAL);
1321                             }
1322                             if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1323                                *((unsigned int*)optval) =
1324                                   (unsigned int)(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getAutoClose() /
1325                                                     1000000);
1326                                *optlen = sizeof(unsigned int);
1327                                errno_return(0);
1328                             }
1329                             errno_return(-EBADF);
1330                           break;
1331                          default:
1332                             errno_return(-EOPNOTSUPP);
1333                           break;
1334                       }
1335                    break;
1336 
1337                   // ====== Socket ==========================================
1338                   case SOL_SOCKET:
1339                       switch(optname) {
1340                          case SO_SNDBUF:
1341                             if((optval == NULL) || ((size_t)*optlen < sizeof(unsigned int))) {
1342                                errno_return(-EINVAL);
1343                             }
1344                             if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
1345                                *((int*)optval) = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getSendBuffer();
1346                                *optlen = sizeof(unsigned int);
1347                                errno_return((*((int*)optval) >= 0) ? 0 : -EIO);
1348                             }
1349                             errno_return(-EBADF);
1350                           break;
1351                          case SO_RCVBUF:
1352                             if((optval == NULL) || ((size_t)*optlen < sizeof(unsigned int))) {
1353                                errno_return(-EINVAL);
1354                             }
1355                             if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
1356                                *((int*)optval) = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getReceiveBuffer();
1357                                *optlen = sizeof(unsigned int);
1358                                errno_return((*((int*)optval) >= 0) ? 0 : -EIO);
1359                             }
1360                             errno_return(-EBADF);
1361                           break;
1362                          case SO_LINGER:
1363                             if((optval == NULL) || ((size_t)*optlen < sizeof(linger))) {
1364                                errno_return(-EINVAL);
1365                             }
1366                             *((linger*)optval) = tdSocket->Socket.SCTPSocketDesc.Linger;
1367                             *optlen = sizeof(linger);
1368                             errno_return(0);
1369                           break;
1370                          default:
1371                             errno_return(-EOPNOTSUPP);
1372                           break;
1373                       }
1374                    break;
1375 
1376                   // ====== Default =========================================
1377                   default:
1378                      errno_return(-EOPNOTSUPP);
1379                    break;
1380                }
1381             }
1382           break;
1383          case ExtSocketDescriptor::ESDT_System:
1384             return(getsockopt(tdSocket->Socket.SystemSocketID,level,optname,optval,optlen));
1385           break;
1386       }
1387       errno_return(-ENXIO);
1388    }
1389    errno_return(-EBADF);
1390 }
1391 
1392 
1393 // ###### Set events ########################################################
setDefaultSendParams(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1394 static int setDefaultSendParams(ExtSocketDescriptor* tdSocket,
1395                                 const void* optval, const socklen_t optlen)
1396 {
1397    if((optlen != sizeof(sctp_sndrcvinfo)) || (optval == NULL)) {
1398       errno_return(-EINVAL);
1399    }
1400 
1401    sctp_sndrcvinfo*    sndrcvinfo = (sctp_sndrcvinfo*)optval;
1402    AssocIODefaults defaults;
1403 
1404    defaults.StreamID   = sndrcvinfo->sinfo_stream;
1405    defaults.ProtoID    = sndrcvinfo->sinfo_ppid;
1406    defaults.TimeToLive = sndrcvinfo->sinfo_timetolive;
1407    defaults.Context    = sndrcvinfo->sinfo_context;
1408 
1409    bool result = false;
1410    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1411       tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setAssocIODefaults(defaults);
1412       result = true;
1413    }
1414    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1415       result = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setAssocIODefaults(sndrcvinfo->sinfo_assoc_id,defaults);
1416    }
1417 
1418    if(result == true) {
1419       errno_return(0);
1420    }
1421    errno_return(-EINVAL);
1422 }
1423 
1424 
1425 // ###### Set events ########################################################
setDefaultStreamTimeouts(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1426 static int setDefaultStreamTimeouts(ExtSocketDescriptor* tdSocket,
1427                                     const void* optval, const socklen_t optlen)
1428 {
1429    if((optlen != sizeof(sctp_setstrm_timeout)) || (optval == NULL)) {
1430       errno_return(-EINVAL);
1431    }
1432 
1433    sctp_setstrm_timeout* timeout = (sctp_setstrm_timeout*)optval;
1434 
1435    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1436       tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setDefaultStreamTimeouts(
1437          timeout->ssto_timeout,
1438          timeout->ssto_streamid_start,
1439          timeout->ssto_streamid_end);
1440       return(0);
1441    }
1442    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1443       if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setDefaultStreamTimeouts(
1444          timeout->ssto_assoc_id,
1445          timeout->ssto_timeout,
1446          timeout->ssto_streamid_start,
1447          timeout->ssto_streamid_end)) {
1448          return(0);
1449       }
1450    }
1451    errno_return(-EINVAL);
1452 }
1453 
1454 
1455 // ###### Set events ########################################################
setEvents(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1456 static int setEvents(ExtSocketDescriptor* tdSocket,
1457                      const void* optval, const socklen_t optlen)
1458 {
1459    if((optlen != sizeof(sctp_event_subscribe)) || (optval == NULL)) {
1460       errno_return(-EINVAL);
1461    }
1462 
1463    unsigned int flags           = 0;
1464    sctp_event_subscribe* events = (sctp_event_subscribe*)optval;
1465 
1466    if(events->sctp_data_io_event) {
1467       flags |= SCTP_RECVDATAIOEVNT;
1468    }
1469    if(events->sctp_association_event) {
1470       flags |= SCTP_RECVASSOCEVNT;
1471    }
1472    if(events->sctp_address_event) {
1473       flags |= SCTP_RECVPADDREVNT;
1474    }
1475    if(events->sctp_send_failure_event) {
1476       flags |= SCTP_RECVSENDFAILEVNT;
1477    }
1478    if(events->sctp_peer_error_event) {
1479       flags |= SCTP_RECVPEERERR;
1480    }
1481    if(events->sctp_shutdown_event) {
1482       flags |= SCTP_RECVSHUTDOWNEVNT;
1483    }
1484    if(events->sctp_partial_delivery_event) {
1485       flags |= SCTP_RECVPDEVNT;
1486    }
1487    if(events->sctp_adaptation_layer_event) {
1488       flags |= SCTP_RECVADAPTATIONINDICATION;
1489    }
1490 
1491    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1492       tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setNotificationFlags(flags);
1493       errno_return(0);
1494    }
1495    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1496       tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setNotificationFlags(flags);
1497       errno_return(0);
1498    }
1499    return(-EBADF);
1500 }
1501 
1502 
1503 // ###### Set RTO info ######################################################
setRTOInfo(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1504 static int setRTOInfo(ExtSocketDescriptor* tdSocket,
1505                       const void* optval, const socklen_t optlen)
1506 {
1507    if((optval == NULL) || ((size_t)optlen < sizeof(sctp_rtoinfo))) {
1508       errno_return(-EINVAL);
1509    }
1510    sctp_rtoinfo*           rtoinfo = (sctp_rtoinfo*)optval;
1511    unsigned int            assocID = rtoinfo->srto_assoc_id;
1512    SCTP_Association_Status parameters;
1513 
1514    SCTPSocketMaster::MasterInstance.lock();
1515    int result = getAssocParams(tdSocket,assocID,parameters);
1516    if(result == 0) {
1517       if(rtoinfo->srto_initial != 0) {
1518          parameters.rtoInitial = rtoinfo->srto_initial;
1519       }
1520       if(rtoinfo->srto_min != 0) {
1521          parameters.rtoMin = rtoinfo->srto_min;
1522       }
1523       if(rtoinfo->srto_max != 0) {
1524          parameters.rtoMax = rtoinfo->srto_max;
1525       }
1526       result = setAssocParams(tdSocket,assocID,parameters);
1527    }
1528    SCTPSocketMaster::MasterInstance.unlock();
1529 
1530    errno_return(result);
1531 }
1532 
1533 
1534 // ###### Set delayed ack time ##############################################
setDelayedAckTime(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1535 static int setDelayedAckTime(ExtSocketDescriptor* tdSocket,
1536                              const void*          optval,
1537                              const socklen_t      optlen)
1538 {
1539    if((optval == NULL) || (optlen < sizeof(sctp_sack_info))) {
1540       errno_return(-EINVAL);
1541    }
1542    const sctp_sack_info* sackInfo = (const sctp_sack_info*)optval;
1543    unsigned int          assocID  = sackInfo->sack_assoc_id;
1544 
1545    if((assocID == 0) && (tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr)) {
1546       assocID = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID();
1547    }
1548 
1549    if(assocID != 0) {
1550       SCTP_Association_Status parameters;
1551       int result = getAssocParams(tdSocket, assocID, parameters);
1552       if(result == 0) {
1553          parameters.delay = sackInfo->sack_delay;
1554          result = setAssocParams(tdSocket, assocID, parameters);
1555       }
1556       errno_return(result);
1557    }
1558    else {
1559       SCTP_Instance_Parameters parameters;
1560       if(tdSocket->Type == ExtSocketDescriptor::ESDT_SCTP) {
1561          if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr) {
1562             if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getAssocDefaults(parameters)) {
1563                parameters.delay = sackInfo->sack_delay;
1564                if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setAssocDefaults(parameters)) {
1565                   errno_return(0);
1566                }
1567             }
1568          }
1569       }
1570       else {
1571          errno_return(-ENOTSUP);
1572       }
1573    }
1574    errno_return(-EINVAL);
1575 }
1576 
1577 
1578 // ###### Set association info ##############################################
setAssocInfo(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1579 static int setAssocInfo(ExtSocketDescriptor* tdSocket,
1580                         const void*          optval,
1581                         const socklen_t      optlen)
1582 {
1583    if((optval == NULL) || ((size_t)optlen < sizeof(sctp_assocparams))) {
1584       errno_return(-EINVAL);
1585    }
1586    sctp_assocparams*       assocparams = (sctp_assocparams*)optval;
1587    unsigned int            assocID     = assocparams->sasoc_assoc_id;
1588    SCTP_Association_Status parameters;
1589 
1590    SCTPSocketMaster::MasterInstance.lock();
1591    int result = getAssocParams(tdSocket,assocID,parameters);
1592    if(result == 0) {
1593       parameters.assocMaxRetransmits = assocparams->sasoc_asocmaxrxt;
1594       result = setAssocParams(tdSocket,assocID,parameters);
1595    }
1596    SCTPSocketMaster::MasterInstance.unlock();
1597    errno_return(result);
1598 }
1599 
1600 
1601 // ###### Set primary address ###############################################
setPrimaryAddr(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1602 static int setPrimaryAddr(ExtSocketDescriptor* tdSocket,
1603                           const void* optval, const socklen_t optlen)
1604 {
1605    if((optval == NULL) || ((size_t)optlen < sizeof(sctp_setprim))) {
1606       errno_return(-EINVAL);
1607    }
1608    sctp_setprim* setprim = (sctp_setprim*)optval;
1609    SocketAddress* address = SocketAddress::createSocketAddress(0,
1610                                (sockaddr*)&setprim->ssp_addr,
1611                                sizeof(sockaddr_storage));
1612    if(address == NULL) {
1613       errno_return(-EINVAL);
1614    }
1615 
1616    int result = -EBADF;
1617    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1618       result = (tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
1619                    setPrimary(*address) == true) ? 0 : -EIO;
1620    }
1621    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1622       result = (tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
1623                    setPrimary(setprim->ssp_assoc_id,*address) == true) ? 0 : -EIO;
1624    }
1625 
1626    delete address;
1627    errno_return(result);
1628 }
1629 
1630 
1631 // ###### Set primary address ###############################################
setPeerPrimaryAddr(ExtSocketDescriptor * tdSocket,const void * optval,const socklen_t optlen)1632 static int setPeerPrimaryAddr(ExtSocketDescriptor* tdSocket,
1633                               const void* optval, const socklen_t optlen)
1634 {
1635    if((optval == NULL) || ((size_t)optlen < sizeof(sctp_setpeerprim))) {
1636       errno_return(-EINVAL);
1637    }
1638    sctp_setpeerprim* setpeerprim = (sctp_setpeerprim*)optval;
1639    SocketAddress* address = SocketAddress::createSocketAddress(0,
1640                                (sockaddr*)&setpeerprim->sspp_addr,
1641                                sizeof(sockaddr_storage));
1642    if(address == NULL) {
1643       errno_return(-EINVAL);
1644    }
1645 
1646    int result = -EBADF;
1647    if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1648       result = (tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->
1649                    setPrimary(*address) == true) ? 0 : -EIO;
1650    }
1651    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1652       result = (tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->
1653                    setPrimary(setpeerprim->sspp_assoc_id,*address) == true) ? 0 : -EIO;
1654    }
1655 
1656    delete address;
1657    errno_return(result);
1658 }
1659 
1660 
1661 // ###### Get address parameters ############################################
setInitMsg(SCTPSocket * sctpSocket,struct sctp_initmsg * initmsg)1662 static bool setInitMsg(SCTPSocket* sctpSocket, struct sctp_initmsg* initmsg)
1663 {
1664    SCTP_Instance_Parameters parameters;
1665    bool                     result = false;
1666 
1667    SCTPSocketMaster::MasterInstance.lock();
1668    if(sctpSocket->getAssocDefaults(parameters)) {
1669       parameters.outStreams = initmsg->sinit_num_ostreams;
1670       parameters.inStreams  = initmsg->sinit_max_instreams;
1671       if(sctpSocket->setAssocDefaults(parameters)) {
1672          result = true;
1673       }
1674    }
1675    SCTPSocketMaster::MasterInstance.unlock();
1676    return(result);
1677 }
1678 
1679 
1680 // ###### setsockopt() wrapper ##############################################
ext_setsockopt(int sockfd,int level,int optname,const void * optval,socklen_t optlen)1681 int ext_setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen)
1682 {
1683    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1684    if(tdSocket != NULL) {
1685       switch(tdSocket->Type) {
1686          case ExtSocketDescriptor::ESDT_SCTP:
1687             {
1688                switch(level) {
1689 #if (SYSTEM == OS_Linux)
1690                   // ====== IPv6 ============================================
1691                   case SOL_IPV6:
1692                       switch(optname) {
1693                          case IPV6_FLOWINFO:
1694                             errno_return(0);
1695                           break;
1696                          case IPV6_FLOWINFO_SEND:
1697                             errno_return(0);
1698                           break;
1699                          default:
1700                             errno_return(-EOPNOTSUPP);
1701                           break;
1702                       }
1703                    break;
1704 
1705                   // ====== IPv4 ============================================
1706                   case SOL_IP:
1707                       switch(optname) {
1708                          case IP_TOS:
1709                             if((optval == NULL) || (optlen < sizeof(int))) {
1710                                errno_return(-EINVAL);
1711                             }
1712                             if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1713                                errno_return((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setTrafficClass(*((int*)optval)) == true) ? 0 : -EIO);
1714                             }
1715                             else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1716                                errno_return((tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setTrafficClass(*((int*)optval)) == true) ? 0 : -EIO);
1717                             }
1718                             errno_return(-EOPNOTSUPP);
1719                           break;
1720                          case IP_RECVTOS:
1721                             errno_return(0);
1722                           break;
1723                          default:
1724                             errno_return(-EOPNOTSUPP);
1725                           break;
1726                       }
1727                    break;
1728 #endif
1729 
1730                   // ====== SCTP ============================================
1731                   case IPPROTO_SCTP:
1732                       switch(optname) {
1733                          case SCTP_INITMSG: {
1734                                if((optval == NULL) || ((size_t)optlen < sizeof(sctp_initmsg))) {
1735                                   errno_return(-EINVAL);
1736                                }
1737                                sctp_initmsg* initmsg = (sctp_initmsg*)optval;
1738                                tdSocket->Socket.SCTPSocketDesc.InitMsg = *initmsg;
1739                                if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr) {
1740                                   setInitMsg(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr,
1741                                                 initmsg);
1742                                }
1743                                errno_return(0);
1744                             }
1745                           break;
1746                          case SCTP_PEER_ADDR_PARAMS:
1747                             return(configurePeerAddressParams(tdSocket,(void*)optval,&optlen,false));
1748                           break;
1749                          case SCTP_PRIMARY_ADDR:
1750                             return(setPrimaryAddr(tdSocket,optval,optlen));
1751                           break;
1752                          case SCTP_SET_PEER_PRIMARY_ADDR:
1753                             return(setPeerPrimaryAddr(tdSocket,optval,optlen));
1754                           break;
1755                          case SCTP_RTOINFO:
1756                             return(setRTOInfo(tdSocket,optval,optlen));
1757                           break;
1758                          case SCTP_DELAYED_SACK:
1759                             return(setDelayedAckTime(tdSocket,optval,optlen));
1760                           break;
1761                          case SCTP_NODELAY:
1762                             errno_return(0);
1763                           break;
1764                          case SCTP_ASSOCINFO:
1765                             return(setAssocInfo(tdSocket,optval,optlen));
1766                           break;
1767                          case SCTP_EVENTS:
1768                             return(setEvents(tdSocket,optval,optlen));
1769                           break;
1770                          case SCTP_SET_DEFAULT_SEND_PARAM:
1771                             return(setDefaultSendParams(tdSocket,optval,optlen));
1772                           break;
1773                          case SCTP_SET_STREAM_TIMEOUTS:
1774                             return(setDefaultStreamTimeouts(tdSocket,optval,optlen));
1775                           break;
1776                          case SCTP_AUTOCLOSE:
1777                             if((optval == NULL) || ((size_t)optlen < sizeof(unsigned int))) {
1778                                errno_return(-EINVAL);
1779                             }
1780                             if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr == NULL) {
1781                                errno_return(-EBADF);
1782                             }
1783                             tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setAutoClose(
1784                                (card64)1000000 * (card64)*((unsigned int*)optval));
1785                             errno_return(0);
1786                           break;
1787                        }
1788                      break;
1789 
1790                   // ====== Socket ==========================================
1791                   case SOL_SOCKET:
1792                       switch(optname) {
1793                          case SO_SNDBUF:
1794                             if((optval == NULL) || ((size_t)optlen < sizeof(unsigned int))) {
1795                                errno_return(-EINVAL);
1796                             }
1797                             if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1798                                errno_return((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setSendBuffer(*((unsigned int*)optval)) == true) ? 0 : -EIO);
1799                             }
1800                             else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1801                                errno_return((tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setSendBuffer(*((unsigned int*)optval)) == true) ? 0 : -EIO);
1802                             }
1803                             errno_return(-EBADF);
1804                           break;
1805                          case SO_RCVBUF:
1806                             if((optval == NULL) || ((size_t)optlen < sizeof(unsigned int))) {
1807                                errno_return(-EINVAL);
1808                             }
1809                             if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
1810                                errno_return((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->setReceiveBuffer(*((unsigned int*)optval)) == true) ? 0 : -EIO);
1811                             }
1812                             else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1813                                errno_return((tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->setReceiveBuffer(*((unsigned int*)optval)) == true) ? 0 : -EIO);
1814                             }
1815                             errno_return(-EBADF);
1816                           break;
1817                          case SO_LINGER:
1818                             if((optval == NULL) || ((size_t)optlen < sizeof(linger))) {
1819                                errno_return(-EINVAL);
1820                             }
1821                             if( (((linger*)optval)->l_linger < 0) ||
1822                                 (((linger*)optval)->l_onoff < 0)  ||
1823                                 (((linger*)optval)->l_onoff > 1) ) {
1824                                errno_return(-EINVAL);
1825                             }
1826                             tdSocket->Socket.SCTPSocketDesc.Linger = *((linger*)optval);
1827                             errno_return(0);
1828                           break;
1829                          default:
1830                             errno_return(-EOPNOTSUPP);
1831                           break;
1832                       }
1833                    break;
1834 
1835                   // ====== Default =========================================
1836                   default:
1837                      errno_return(-EOPNOTSUPP);
1838                    break;
1839                }
1840             }
1841           break;
1842          case ExtSocketDescriptor::ESDT_System:
1843             return(setsockopt(tdSocket->Socket.SystemSocketID,level,optname,optval,optlen));
1844           break;
1845       }
1846       errno_return(-ENXIO);
1847    }
1848    errno_return(-EBADF);
1849 }
1850 
1851 
1852 // ###### shutdown() wrapper ################################################
ext_shutdown(int sockfd,int how)1853 int ext_shutdown(int sockfd, int how)
1854 {
1855    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1856    if(tdSocket != NULL) {
1857       switch(tdSocket->Type) {
1858          case ExtSocketDescriptor::ESDT_SCTP:
1859             if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
1860                tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->shutdown();
1861                errno_return(0);
1862             }
1863             errno_return(-EOPNOTSUPP);
1864           break;
1865          case ExtSocketDescriptor::ESDT_System:
1866             return(shutdown(tdSocket->Socket.SystemSocketID, how));
1867           break;
1868       }
1869       errno_return(-ENXIO);
1870    }
1871    errno_return(-EBADF);
1872 }
1873 
1874 
1875 // ###### connect() wrapper #################################################
ext_connect(int sockfd,const struct sockaddr * serv_addr,socklen_t addrlen)1876 int ext_connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen)
1877 {
1878    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1879    if(tdSocket != NULL) {
1880       if(tdSocket->Type == ExtSocketDescriptor::ESDT_SCTP) {
1881          struct sockaddr_storage addressArray[1];
1882          memcpy((char*)&addressArray[0], serv_addr, std::min(sizeof(sockaddr_storage), (size_t)addrlen));
1883          return(ext_connectx(sockfd, (const sockaddr*)&addressArray, 1, NULL));
1884       }
1885       else {
1886          return(connect(tdSocket->Socket.SystemSocketID, serv_addr, addrlen));
1887       }
1888    }
1889    errno_return(-EBADF);
1890 }
1891 
1892 
1893 // ###### connectx() wrapper ################################################
ext_connectx(int sockfd,const struct sockaddr * packedAddrs,int addrcnt,sctp_assoc_t * id)1894 int ext_connectx(int                    sockfd,
1895                  const struct sockaddr* packedAddrs,
1896                  int                    addrcnt,
1897                  sctp_assoc_t*          id)
1898 {
1899    unsigned int     dummy;
1900    sockaddr_storage addrs[addrcnt];
1901    unpack_sockaddr(packedAddrs, addrcnt, addrs);
1902 
1903    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1904    if(tdSocket != NULL) {
1905       switch(tdSocket->Type) {
1906          case ExtSocketDescriptor::ESDT_SCTP:
1907             {
1908 #if (SCTPLIB_VERSION == SCTPLIB_1_0_0_PRE19)
1909                if(addrcnt != 1) {
1910 #ifndef DISABLE_WARNINGS
1911                   std::cerr << "ERROR: connectx() with more than one address requires sctplib 1.0.0 or better!" << std::endl;
1912 #endif
1913                   errno_return(-EOPNOTSUPP);
1914                }
1915 #endif
1916                if(id == NULL) {
1917                   id = &dummy;
1918                }
1919                *id = 0;
1920 
1921                bindToAny(tdSocket);
1922                if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
1923                   const SocketAddress* addressArray[addrcnt + 1];
1924                   for(int i = 0;i < addrcnt;i++) {
1925                      addressArray[i] = SocketAddress::createSocketAddress(
1926                                           0, (sockaddr*)&addrs[i], sizeof(sockaddr_storage));
1927                      if(addressArray[i] == NULL) {
1928                         for(int j = i - 1;j > 0;j--) {
1929                            delete addressArray[j];
1930                         }
1931                         errno_return(-EINVAL);
1932                      }
1933                   }
1934                   addressArray[addrcnt] = NULL;
1935 
1936                   if(tdSocket->Socket.SCTPSocketDesc.ConnectionOriented) {
1937                      tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr =
1938                         tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->associate(
1939                            tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams,
1940                            tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_attempts,
1941                            tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_init_timeo,
1942                            (const SocketAddress**)&addressArray,
1943                            !(tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK));
1944                      for(int i = 0;i < addrcnt;i++) {
1945                         delete addressArray[i];
1946                         addressArray[i] = NULL;
1947                      }
1948                      if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr == NULL) {
1949                         errno_return(-EIO);
1950                      }
1951                      else if(tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK) {
1952                         errno_return(-EINPROGRESS);
1953                      }
1954                      if(id) {
1955                         *id = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID();
1956                      }
1957                   }
1958                   else {
1959                      int result = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->sendTo(
1960                                      NULL, 0,
1961                                      (tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK) ? MSG_DONTWAIT : 0,
1962                                      *id, 0x0000, 0x00000000, SCTP_INFINITE_LIFETIME,
1963                                      tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_attempts,
1964                                      tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_init_timeo,
1965                                      true,
1966                                      (const SocketAddress**)&addressArray,
1967                                      tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams);
1968                      for(int i = 0;i < addrcnt;i++) {
1969                         delete addressArray[i];
1970                         addressArray[i] = NULL;
1971                      }
1972                      if(result > 0) {
1973                         errno_return(result);
1974                      }
1975                      else if((result == 0) && (tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK)) {
1976                         errno_return(-EINPROGRESS);
1977                      }
1978                      errno_return(result);
1979                   }
1980                   errno_return(0);
1981                }
1982                errno_return(-EBADF);
1983             }
1984           break;
1985          case ExtSocketDescriptor::ESDT_System:
1986             errno_return(-EOPNOTSUPP);
1987           break;
1988       }
1989       errno_return(-ENXIO);
1990    }
1991    errno_return(-EBADF);
1992 }
1993 
1994 
1995 // ###### recv() wrapper ####################################################
ext_recv(int sockfd,void * buf,size_t len,int flags)1996 ssize_t ext_recv(int sockfd, void* buf, size_t len, int flags)
1997 {
1998    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
1999    if(tdSocket != NULL) {
2000       switch(tdSocket->Type) {
2001          case ExtSocketDescriptor::ESDT_SCTP:
2002             {
2003                socklen_t fromlen = 0;
2004                return(ext_recvfrom(sockfd,buf,len,flags,NULL,&fromlen));
2005             }
2006           break;
2007          case ExtSocketDescriptor::ESDT_System:
2008             return(recv(tdSocket->Socket.SystemSocketID,buf,len,flags));
2009           break;
2010       }
2011       errno_return(-ENXIO);
2012    }
2013    errno_return(-EBADF);
2014 }
2015 
2016 
2017 // ###### recvfrom() wrapper ################################################
ext_recvfrom(int sockfd,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)2018 ssize_t ext_recvfrom(int sockfd, void* buf, size_t len, int flags,
2019                 struct sockaddr* from, socklen_t* fromlen)
2020 {
2021    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
2022    if(tdSocket != NULL) {
2023       switch(tdSocket->Type) {
2024          case ExtSocketDescriptor::ESDT_SCTP:
2025             {
2026                struct iovec  iov = { (char*)buf, len };
2027                char          cbuf[1024];
2028                struct msghdr msg = {
2029 #if (SYSTEM == OS_Darwin)
2030                   (char*)from,
2031 #else
2032                   from,
2033 #endif
2034                   (fromlen != NULL) ? *fromlen : 0,
2035                   &iov, 1,
2036                   cbuf, sizeof(cbuf),
2037                   flags
2038                };
2039                int cc = ext_recvmsg2(sockfd,&msg,flags,0);
2040                if(fromlen != NULL) {
2041                   *fromlen = msg.msg_namelen;
2042                }
2043                return(cc);
2044             }
2045           break;
2046          case ExtSocketDescriptor::ESDT_System:
2047             const int result = recvfrom(tdSocket->Socket.SystemSocketID,buf,len,flags,from,fromlen);
2048             return(result);
2049           break;
2050       }
2051       errno_return(-ENXIO);
2052    }
2053    errno_return(-EBADF);
2054 }
2055 
2056 
2057 // ###### recvmsg() wrapper #################################################
ext_recvmsg_singlebuffer(int sockfd,struct msghdr * msg,int flags,const int receiveNotifications)2058 static int ext_recvmsg_singlebuffer(int sockfd, struct msghdr* msg, int flags,
2059                                     const int receiveNotifications)
2060 {
2061    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
2062    if(tdSocket != NULL) {
2063       unsigned int   assocID           = 0;
2064       unsigned short streamID          = 0;
2065       unsigned int   protoID           = 0;
2066       uint16_t       ssn               = 0;
2067       uint32_t       tsn               = 0;
2068       unsigned int   notificationFlags = 0;
2069       SocketAddress* remoteAddress     = NULL;
2070       int result = -EOPNOTSUPP;
2071       switch(tdSocket->Type) {
2072          case ExtSocketDescriptor::ESDT_SCTP:
2073                if((msg == NULL) || (msg->msg_iov == NULL)) {
2074                   errno_return(-EINVAL);
2075                }
2076                msg->msg_flags |= flags;
2077 #ifndef NON_RECVMSG_NOTIFICATIONS
2078                if(receiveNotifications) {
2079                   msg->msg_flags |= MSG_NOTIFICATION;
2080                }
2081                else {
2082                   msg->msg_flags &= ~MSG_NOTIFICATION;
2083                }
2084 #else
2085                msg->msg_flags |= MSG_NOTIFICATION;
2086 #endif
2087                if(tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK) {
2088                   msg->msg_flags |= MSG_DONTWAIT;
2089                }
2090                if((tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) && (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented)) {
2091                   const size_t oldSize = msg->msg_iov->iov_len;
2092                   do {
2093                      msg->msg_iov->iov_len = oldSize;
2094                      result = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->receive(
2095                                  (char*)msg->msg_iov->iov_base,
2096                                  msg->msg_iov->iov_len,
2097                                  msg->msg_flags,
2098                                  streamID, protoID,
2099                                  ssn, tsn);
2100                   } while((result == -EAGAIN) && !(msg->msg_flags & MSG_DONTWAIT));
2101                   notificationFlags = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getNotificationFlags();
2102                   assocID = tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID();
2103                }
2104                else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
2105                   const size_t oldSize = msg->msg_iov->iov_len;
2106                   do {
2107                      if(remoteAddress != NULL) {
2108                         delete remoteAddress;
2109                         remoteAddress = NULL;
2110                      }
2111                      msg->msg_iov->iov_len = oldSize;
2112                      result = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->receiveFrom(
2113                                  (char*)msg->msg_iov->iov_base,
2114                                  msg->msg_iov->iov_len,
2115                                  msg->msg_flags,
2116                                  assocID, streamID, protoID,
2117                                  ssn, tsn,
2118                                  &remoteAddress);
2119                   } while((result == -EAGAIN) && !(msg->msg_flags & MSG_DONTWAIT));
2120                   notificationFlags = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getNotificationFlags();
2121                }
2122                else {
2123                   result = -EBADF;
2124                }
2125 
2126                // ====== Set result to length in case of success ============
2127                if(result >= 0) {
2128                   result = msg->msg_iov->iov_len;
2129                }
2130            break;
2131          case ExtSocketDescriptor::ESDT_System: {
2132                const int result = recvmsg(tdSocket->Socket.SystemSocketID,msg,flags);
2133                return(result);
2134             }
2135            break;
2136          default:
2137             errno_return(-ENXIO);
2138           break;
2139       }
2140 
2141       if(result >= 0) {
2142          if((msg->msg_name != NULL) &&
2143             (remoteAddress != NULL)) {
2144             msg->msg_namelen = remoteAddress->getSystemAddress(
2145                                   (sockaddr*)msg->msg_name,
2146                                   (socklen_t)msg->msg_namelen,
2147                                   tdSocket->Socket.SCTPSocketDesc.Domain);
2148          }
2149          else {
2150             msg->msg_namelen = 0;
2151          }
2152          if((notificationFlags & SCTP_RECVDATAIOEVNT) &&
2153             (msg->msg_control != NULL) &&
2154             (msg->msg_controllen >= (socklen_t)CSpace(sizeof(sctp_sndrcvinfo)))) {
2155             cmsghdr* cmsg = (cmsghdr*)msg->msg_control;
2156             cmsg->cmsg_len   = CSpace(sizeof(sctp_sndrcvinfo));
2157             cmsg->cmsg_level = IPPROTO_SCTP;
2158             cmsg->cmsg_type  = SCTP_SNDRCV;
2159             sctp_sndrcvinfo* info = (sctp_sndrcvinfo*)((long)cmsg + (long)sizeof(cmsghdr));
2160             info->sinfo_stream     = streamID;
2161             info->sinfo_ssn        = ssn;
2162             info->sinfo_tsn        = tsn;
2163             info->sinfo_flags      = flags;
2164             info->sinfo_ppid       = protoID;
2165             info->sinfo_timetolive = 0;
2166             info->sinfo_context    = 0;
2167             info->sinfo_cumtsn     = 0;
2168             info->sinfo_assoc_id   = assocID;
2169             msg->msg_controllen = CSpace(sizeof(sctp_sndrcvinfo));
2170          }
2171          else {
2172             msg->msg_control    = NULL;
2173             msg->msg_controllen = 0;
2174          }
2175       }
2176       else {
2177          msg->msg_namelen    = 0;
2178          msg->msg_name       = NULL;
2179          msg->msg_controllen = 0;
2180          msg->msg_control    = NULL;
2181       }
2182 
2183       if(remoteAddress != NULL) {
2184          delete remoteAddress;
2185       }
2186       errno_return(result);
2187    }
2188    errno_return(-EBADF);
2189 }
2190 
2191 
2192 // ###### recvmsg() wrapper #################################################
ext_recvmsg2(int sockfd,struct msghdr * msg,int flags,const int receiveNotifications)2193 int ext_recvmsg2(int sockfd, struct msghdr* msg, int flags,
2194                  const int receiveNotifications)
2195 {
2196    struct iovec* iov   = msg->msg_iov;
2197    const size_t  count = msg->msg_iovlen;
2198    int result = 0;
2199    for(unsigned int i = 0;i < count;i++) {
2200       msg->msg_iov    = (iovec*)((long)iov + ((long)i * (long)sizeof(iovec)));
2201       msg->msg_iovlen = 1;
2202       const int subresult = ext_recvmsg_singlebuffer(sockfd,msg,flags,receiveNotifications);
2203       if(subresult > 0) {
2204          result += subresult;
2205       }
2206       if((result == 0) && (subresult <= 0)) {
2207          result = subresult;
2208          break;
2209       }
2210       if((subresult < (int)msg->msg_iov->iov_len) && (msg->msg_flags & MSG_EOR)) {
2211          break;
2212       }
2213    }
2214    msg->msg_iov    = iov;
2215    msg->msg_iovlen = count;
2216    return(result);
2217 }
2218 
2219 
2220 // ###### recvmsg() wrapper #################################################
ext_recvmsg(int sockfd,struct msghdr * msg,int flags)2221 ssize_t ext_recvmsg(int sockfd, struct msghdr* msg, int flags)
2222 {
2223    return(ext_recvmsg2(sockfd,msg,flags,1));
2224 }
2225 
2226 
2227 // ###### send() wrapper ####################################################
ext_send(int sockfd,const void * msg,size_t len,int flags)2228 ssize_t ext_send(int sockfd, const void* msg, size_t len, int flags)
2229 {
2230    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
2231    if(tdSocket != NULL) {
2232       switch(tdSocket->Type) {
2233          case ExtSocketDescriptor::ESDT_SCTP:
2234             return(ext_sendto(sockfd,msg,len,flags,NULL,0));
2235           break;
2236          case ExtSocketDescriptor::ESDT_System:
2237             return(send(tdSocket->Socket.SystemSocketID,msg,len,flags));
2238           break;
2239       }
2240       errno_return(-ENXIO);
2241    }
2242    errno_return(-EBADF);
2243 }
2244 
2245 
2246 // ###### sendto() wrapper ####################################################
ext_sendto(int sockfd,const void * buf,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)2247 ssize_t ext_sendto(int sockfd, const void* buf, size_t len, int flags,
2248                const struct sockaddr* to, socklen_t tolen)
2249 {
2250    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
2251    if(tdSocket != NULL) {
2252       switch(tdSocket->Type) {
2253          case ExtSocketDescriptor::ESDT_SCTP:
2254             {
2255                struct iovec  iov = { (char*)buf, len };
2256                struct msghdr msg = {
2257 #if (SYSTEM == OS_Darwin)
2258                   (char*)to,
2259 #else
2260                   (void*)to,
2261 #endif
2262                   tolen,
2263                   &iov, 1,
2264                   NULL, 0,
2265                   flags
2266                };
2267                return(ext_sendmsg(sockfd,&msg,flags));
2268             }
2269           break;
2270          case ExtSocketDescriptor::ESDT_System:
2271             return(sendto(tdSocket->Socket.SystemSocketID,buf,len,flags,to,tolen));
2272           break;
2273       }
2274       errno_return(-ENXIO);
2275    }
2276    errno_return(-EBADF);
2277 }
2278 
2279 
2280 // ###### sendmsg() wrapper #################################################
ext_sendmsg_singlebuffer(int sockfd,const struct msghdr * msg,int flags)2281 static int ext_sendmsg_singlebuffer(int sockfd, const struct msghdr* msg, int flags)
2282 {
2283    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
2284    if(tdSocket != NULL) {
2285       switch(tdSocket->Type) {
2286          case ExtSocketDescriptor::ESDT_SCTP:
2287             {
2288                if(msg == NULL) {
2289                   return(-EINVAL);
2290                }
2291                bindToAny(tdSocket);
2292                bool             useDefaults = true;
2293                sctp_sndrcvinfo* info        = NULL;
2294                for(const cmsghdr* cmsg = CFirstHeader(msg);
2295                   cmsg != NULL;
2296                   cmsg = CNextHeader(msg,cmsg)) {
2297                   if(cmsg->cmsg_level == IPPROTO_SCTP) {
2298                      if(cmsg->cmsg_type == SCTP_SNDRCV) {
2299                         if(cmsg->cmsg_len >= (socklen_t)sizeof(sctp_sndrcvinfo)) {
2300                            info        = (sctp_sndrcvinfo*)CData(cmsg);
2301                            useDefaults = false;
2302                         }
2303                         else {
2304                            errno_return(-EINVAL);
2305                         }
2306                      }
2307                      else if(cmsg->cmsg_type == SCTP_INIT) {
2308                         const sctp_initmsg* initmsg = (sctp_initmsg*)CData(cmsg);
2309                         tdSocket->Socket.SCTPSocketDesc.InitMsg = *initmsg;
2310                         if((tdSocket->Socket.SCTPSocketDesc.ConnectionOriented) && (msg->msg_name != NULL)) {
2311                            if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
2312                               errno_return(-EBUSY);
2313                            }
2314                            const SocketAddress* addressArray[2];
2315                            addressArray[0] = SocketAddress::createSocketAddress(
2316                                                 0, (sockaddr*)msg->msg_name, msg->msg_namelen);
2317                            addressArray[1] = NULL;
2318                            if(addressArray[0] != NULL) {
2319                               tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr =
2320                                  tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->associate(
2321                                     initmsg->sinit_num_ostreams,
2322                                     initmsg->sinit_max_attempts,
2323                                     initmsg->sinit_max_init_timeo,
2324                                     (const SocketAddress**)&addressArray,
2325                                     !(tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK));
2326                               delete addressArray[0];
2327                               addressArray[0] = NULL;
2328                               if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr == NULL) {
2329                                  errno_return(-ENOTCONN);
2330                               }
2331                            }
2332                            else {
2333                               errno_return(-EADDRNOTAVAIL);
2334                            }
2335                         }
2336                      }
2337                   }
2338                }
2339 
2340                flags |= msg->msg_flags;
2341                if(info != NULL) {
2342                   flags |= info->sinfo_flags;
2343                }
2344                if(tdSocket->Socket.SCTPSocketDesc.Flags & O_NONBLOCK) {
2345                   flags |= MSG_DONTWAIT;
2346                }
2347                if(msg->msg_name != NULL) {
2348                   int result = -EBADF;
2349                   const SocketAddress* destinationAddressList[SCTP_MAX_NUM_ADDRESSES + 1];
2350                   if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
2351                      if(!(flags & MSG_MULTIADDRS)) {
2352                         destinationAddressList[0] = SocketAddress::createSocketAddress(
2353                                                        0, (sockaddr*)msg->msg_name, msg->msg_namelen);
2354                         destinationAddressList[1] = NULL;
2355                      }
2356                      else {
2357                         sockaddr* sa = (sockaddr*)msg->msg_name;
2358                         size_t    i;
2359                         for(i = 0;i < (size_t)msg->msg_namelen;i++) {
2360                            destinationAddressList[i] = SocketAddress::createSocketAddress(
2361                                                           0, sa, sizeof(sockaddr_storage));
2362                            if(destinationAddressList[i] == NULL) {
2363                               errno_return(-EINVAL);
2364                            }
2365                            // std::cout << "#" << i << ": " << *(destinationAddressList[i]) << std::endl;
2366                            switch(sa->sa_family) {
2367                               case AF_INET:
2368                                  sa = (sockaddr*)((long)sa + sizeof(sockaddr_in));
2369                                break;
2370                               case AF_INET6:
2371                                  sa = (sockaddr*)((long)sa + sizeof(sockaddr_in6));
2372                                break;
2373                               default:
2374                                  errno_return(-EINVAL);
2375                                break;
2376                            }
2377                         }
2378                         destinationAddressList[i++] = NULL;
2379                      }
2380                      unsigned int idZero = 0;
2381                      result = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->sendTo(
2382                                  (char*)msg->msg_iov->iov_base,
2383                                  msg->msg_iov->iov_len,
2384                                  flags,
2385                                  (info != NULL) ? info->sinfo_assoc_id : idZero,
2386                                  (info != NULL) ? info->sinfo_stream   : 0x0000,
2387                                  (info != NULL) ? info->sinfo_ppid     : 0x00000000,
2388                                  ((info != NULL) && (info->sinfo_flags & MSG_PR_SCTP_TTL)) ? info->sinfo_timetolive : SCTP_INFINITE_LIFETIME,
2389                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_attempts,
2390                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_init_timeo,
2391                                  useDefaults,
2392                                  (const SocketAddress**)&destinationAddressList,
2393                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams);
2394                      for(size_t i = 0;i  < SCTP_MAX_NUM_ADDRESSES;i++) {
2395                         if(destinationAddressList[i] != NULL) {
2396                            delete destinationAddressList[i];
2397                            destinationAddressList[i] = NULL;
2398                         }
2399                         else {
2400                            break;
2401                         }
2402                      }
2403                   }
2404                   errno_return(result);
2405                }
2406                else {
2407                   if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
2408                      errno_return(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->send(
2409                                   (char*)msg->msg_iov->iov_base,
2410                                   msg->msg_iov->iov_len,
2411                                   flags,
2412                                   (info != NULL) ? info->sinfo_stream : 0x0000,
2413                                   (info != NULL) ? info->sinfo_ppid   : 0x0000000,
2414                                   ((info != NULL) && (info->sinfo_flags & MSG_PR_SCTP_TTL)) ? info->sinfo_timetolive : SCTP_INFINITE_LIFETIME,
2415                                   useDefaults));
2416                   }
2417                   else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
2418                      unsigned int idZero = 0;
2419                      errno_return(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->sendTo(
2420                                  (char*)msg->msg_iov->iov_base,
2421                                  msg->msg_iov->iov_len,
2422                                  flags,
2423                                  (info != NULL) ? info->sinfo_assoc_id   : idZero,
2424                                  (info != NULL) ? info->sinfo_stream     : 0x0000,
2425                                  (info != NULL) ? info->sinfo_ppid       : 0x00000000,
2426                                  ((info != NULL) && (info->sinfo_flags & MSG_PR_SCTP_TTL)) ? info->sinfo_timetolive : SCTP_INFINITE_LIFETIME,
2427                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_attempts,
2428                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_max_init_timeo,
2429                                  useDefaults,
2430                                  NULL,
2431                                  tdSocket->Socket.SCTPSocketDesc.InitMsg.sinit_num_ostreams));
2432                   }
2433                   errno_return(-EBADF);
2434                }
2435                errno_return(0);
2436             }
2437           break;
2438          case ExtSocketDescriptor::ESDT_System:
2439             return(sendmsg(tdSocket->Socket.SystemSocketID,msg,flags));
2440           break;
2441       }
2442       errno_return(-ENXIO);
2443    }
2444    errno_return(-EBADF);
2445 }
2446 
2447 
2448 // ###### sendmsg() wrapper #################################################
ext_sendmsg(int sockfd,const struct msghdr * msg,int flags)2449 ssize_t ext_sendmsg(int sockfd, const struct msghdr* msg, int flags)
2450 {
2451    struct iovec* iov    = msg->msg_iov;
2452    const size_t  count  = msg->msg_iovlen;
2453 
2454    if(count > 1) {
2455       size_t required = 0;
2456       for(unsigned int i = 0;i < count;i++) {
2457          const iovec* subvec = (iovec*)((long)iov + ((long)i * (long)sizeof(iovec)));
2458          required += subvec->iov_len;
2459       }
2460 
2461       char* buffer = new char[required];
2462       if(buffer == NULL) {
2463          return(-ENOMEM);
2464       }
2465       unsigned int j = 0;
2466       for(unsigned int i = 0;i < count;i++) {
2467          const iovec* subvec = (iovec*)((long)iov + ((long)i * (long)sizeof(iovec)));
2468          const char*  base   = (char*)subvec->iov_base;
2469          for(unsigned int k = 0;k < subvec->iov_len;k++) {
2470             buffer[j++] = base[k];
2471          }
2472       }
2473 
2474       iovec newvec;
2475       newvec.iov_len  = required;
2476       newvec.iov_base = buffer;
2477 
2478       msghdr newmsg;
2479       newmsg.msg_control    = msg->msg_control;
2480       newmsg.msg_controllen = msg->msg_controllen;
2481       newmsg.msg_name       = msg->msg_name;
2482       newmsg.msg_namelen    = msg->msg_namelen;
2483       newmsg.msg_iov        = &newvec;
2484       newmsg.msg_iovlen     = 1;
2485       newmsg.msg_flags      = msg->msg_flags;
2486       const int result = ext_sendmsg_singlebuffer(sockfd,&newmsg,flags);
2487 
2488       delete [] buffer;
2489       return(result);
2490    }
2491    else {
2492       return(ext_sendmsg_singlebuffer(sockfd,msg,flags));
2493    }
2494 }
2495 
2496 
2497 // ###### read() wrapper ####################################################
ext_read(int fd,void * buf,size_t count)2498 ssize_t ext_read(int fd, void* buf, size_t count)
2499 {
2500    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(fd);
2501    if(tdSocket != NULL) {
2502       if(tdSocket->Type == ExtSocketDescriptor::ESDT_System) {
2503          return(read(tdSocket->Socket.SystemSocketID,buf,count));
2504       }
2505       else {
2506          return(ext_recv(fd,buf,count,0));
2507       }
2508    }
2509    errno_return(-EBADF);
2510 }
2511 
2512 
2513 // ###### write() wrapper ####################################################
ext_write(int fd,const void * buf,size_t count)2514 ssize_t ext_write(int fd, const void* buf, size_t count)
2515 {
2516    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(fd);
2517    if(tdSocket != NULL) {
2518       if(tdSocket->Type == ExtSocketDescriptor::ESDT_System) {
2519          return(write(tdSocket->Socket.SystemSocketID,buf,count));
2520       }
2521       else {
2522          return(ext_send(fd,buf,count,0));
2523       }
2524    }
2525    errno_return(-EBADF);
2526 }
2527 
2528 
2529 // Internal structure for ext_select().
2530 struct SelectData
2531 {
2532    cardinal   Conditions;
2533    int        ConditionFD[FD_SETSIZE];
2534    cardinal   ConditionType[FD_SETSIZE];
2535    Condition* ConditionArray[FD_SETSIZE];
2536    Condition* ParentConditionArray[FD_SETSIZE];
2537    Condition  GlobalCondition;
2538    Condition  ReadCondition;
2539    Condition  WriteCondition;
2540    Condition  ExceptCondition;
2541    cardinal   UserCallbacks;
2542    int        UserCallbackFD[FD_SETSIZE];
2543    SCTPSocketMaster::UserSocketNotification* UserNotification[FD_SETSIZE];
2544 };
2545 
2546 
2547 // ###### Add file descriptor to SelectData structure #######################
collectSCTP_FDs(SelectData & selectData,const int fd,struct ExtSocketDescriptor * tdSocket,const UpdateConditionType type,Condition & condition)2548 static int collectSCTP_FDs(SelectData&                 selectData,
2549                            const int                   fd,
2550                            struct ExtSocketDescriptor* tdSocket,
2551                            const UpdateConditionType   type,
2552                            Condition&                  condition)
2553 {
2554    selectData.UserCallbackFD[selectData.UserCallbacks] = fd;
2555    if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
2556       selectData.ConditionArray[selectData.Conditions] =
2557          tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getUpdateCondition(type);
2558 
2559 #ifdef PRINT_SELECT
2560       if(selectData.ConditionArray[selectData.Conditions]->peekFired()) {
2561          std::cout << "collectSCTP_FDs: condition already fired" << std::endl;
2562       }
2563 #endif
2564 
2565       selectData.ParentConditionArray[selectData.Conditions] = &condition;
2566       selectData.ConditionArray[selectData.Conditions]->addParent(selectData.ParentConditionArray[selectData.Conditions]);
2567       selectData.ConditionFD[selectData.Conditions]   = fd;
2568       selectData.ConditionType[selectData.Conditions] = type;
2569       selectData.Conditions++;
2570       return(0);
2571    }
2572    else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
2573       selectData.ConditionArray[selectData.Conditions] =
2574          tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getUpdateCondition(type);
2575       if((type == UCT_Write) &&
2576          (tdSocket->Socket.SCTPSocketDesc.ConnectionOriented == false)) {
2577          selectData.ConditionArray[selectData.Conditions]->signal();
2578 #ifdef PRINT_SELECT
2579          std::cout << "collectSCTP_FDs: UDP-like sockets are always writable" << std::endl;
2580 #endif
2581       }
2582 
2583 #ifdef PRINT_SELECT
2584       if(selectData.ConditionArray[selectData.Conditions]->peekFired()) {
2585          std::cout << "collectSCTP_FDs: condition already fired" << std::endl;
2586       }
2587 #endif
2588 
2589       selectData.ParentConditionArray[selectData.Conditions] = &condition;
2590       selectData.ConditionArray[selectData.Conditions]->addParent(selectData.ParentConditionArray[selectData.Conditions]);
2591       selectData.ConditionFD[selectData.Conditions]   = fd;
2592       selectData.ConditionType[selectData.Conditions] = type;
2593       selectData.Conditions++;
2594       return(0);
2595    }
2596    else {
2597       return(-EBADF);
2598    }
2599 }
2600 
2601 
2602 // ###### Add file descriptor to SelectData structure #######################
collectFDs(SelectData & selectData,const int fd,const short int eventMask)2603 static int collectFDs(SelectData&     selectData,
2604                       const int       fd,
2605                       const short int eventMask)
2606 {
2607    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(fd);
2608    if(tdSocket != NULL) {
2609       if(tdSocket->Type == ExtSocketDescriptor::ESDT_Invalid) {
2610 #ifndef DISABLE_WARNINGS
2611          std::cerr << "WARNING: Invalid socket FD given for collectFDs(): " << fd << "!" << std::endl;
2612 #endif
2613       }
2614       else if(tdSocket->Type == ExtSocketDescriptor::ESDT_System) {
2615 #ifdef PRINT_SELECT
2616          char str[32];
2617          snprintf((char*)&str,sizeof(str),"$%04x",eventMask);
2618          std::cout << "select(" << getpid() << "): adding FD " << tdSocket->Socket.SystemSocketID
2619                    << " (" << fd << ") with mask " << str << std::endl;
2620 #endif
2621          selectData.UserCallbackFD[selectData.UserCallbacks] = fd;
2622          selectData.UserNotification[selectData.UserCallbacks] = new SCTPSocketMaster::UserSocketNotification;
2623          if(selectData.UserNotification[selectData.UserCallbacks] != NULL) {
2624             selectData.UserNotification[selectData.UserCallbacks]->FileDescriptor = tdSocket->Socket.SystemSocketID;
2625             selectData.UserNotification[selectData.UserCallbacks]->EventMask      = eventMask;
2626 #ifdef PRINT_SELECT
2627             std::cout << "select(" << getpid() << "): registering user callback for socket "
2628                       << tdSocket->Socket.SystemSocketID << "..." << std::endl;
2629 #endif
2630             if(eventMask & POLLIN) {
2631                selectData.UserNotification[selectData.UserCallbacks]->UpdateCondition.addParent(&selectData.ReadCondition);
2632             }
2633             if(eventMask & POLLOUT) {
2634                selectData.UserNotification[selectData.UserCallbacks]->UpdateCondition.addParent(&selectData.WriteCondition);
2635             }
2636             if(eventMask & POLLERR) {
2637                selectData.UserNotification[selectData.UserCallbacks]->UpdateCondition.addParent(&selectData.ExceptCondition);
2638             }
2639             SCTPSocketMaster::MasterInstance.addUserSocketNotification(selectData.UserNotification[selectData.UserCallbacks]);
2640 
2641             selectData.UserCallbacks++;
2642             return(0);
2643          }
2644       }
2645       else {
2646          int result = 0;
2647          if(eventMask & POLLIN) {
2648 #ifdef PRINT_SELECT
2649             std::cout << "select(" << getpid() << "): adding FD " << fd << " for read" << std::endl;
2650 #endif
2651             result = collectSCTP_FDs(selectData,fd,tdSocket,UCT_Read,selectData.ReadCondition);
2652          }
2653          if(eventMask & POLLOUT) {
2654 #ifdef PRINT_SELECT
2655             std::cout << "select(" << getpid() << "): adding FD " << fd << " for write" << std::endl;
2656 #endif
2657             result = collectSCTP_FDs(selectData,fd,tdSocket,UCT_Write,selectData.WriteCondition);
2658          }
2659          if(eventMask & POLLERR) {
2660 #ifdef PRINT_SELECT
2661             std::cout << "select(" << getpid() << "): adding FD " << fd << " for except" << std::endl;
2662 #endif
2663             result = collectSCTP_FDs(selectData,fd,tdSocket,UCT_Except,selectData.ExceptCondition);
2664          }
2665          errno_return(result);
2666       }
2667    }
2668    errno_return(-EBADF);
2669 }
2670 
2671 
2672 // ###### select() wrapper ##################################################
select_wrapper(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)2673 static int select_wrapper(int             n,
2674                           fd_set*         readfds,
2675                           fd_set*         writefds,
2676                           fd_set*         exceptfds,
2677                           struct timeval* timeout)
2678 {
2679    bool   fakeUDPWrite = false;
2680    fd_set r;
2681    fd_set w;
2682    fd_set e;
2683    FD_ZERO(&r);
2684    FD_ZERO(&w);
2685    FD_ZERO(&e);
2686    int maxFD = 0;
2687    int reverseMapping[ExtSocketDescriptorMaster::MaxSockets];
2688    for(unsigned int i = 0;i < std::min((const unsigned int)n,(const unsigned int)FD_SETSIZE);i++) {
2689       if(SAFE_FD_ISSET(i,readfds) || SAFE_FD_ISSET(i,writefds) || SAFE_FD_ISSET(i,exceptfds)) {
2690          ExtSocketDescriptor* socket = ExtSocketDescriptorMaster::getSocket(i);
2691          if(socket != NULL) {
2692             if(socket->Type == ExtSocketDescriptor::ESDT_System) {
2693                const int fd = socket->Socket.SystemSocketID;
2694                maxFD = std::max(maxFD,fd);
2695 
2696                if(SAFE_FD_ISSET(i,readfds)) {
2697                   FD_SET(fd,&r);
2698                }
2699                if(SAFE_FD_ISSET(i,writefds)) {
2700                   FD_SET(fd,&w);
2701                }
2702                if(SAFE_FD_ISSET(i,exceptfds)) {
2703                   FD_SET(fd,&e);
2704                }
2705 #ifdef PRINT_SELECT
2706                std::cout << "select(" << getpid() << "): added FD " << fd << " (" << i << ")" << std::endl;
2707 #endif
2708                reverseMapping[fd] = i;
2709             }
2710             else if((socket->Type == ExtSocketDescriptor::ESDT_SCTP) &&
2711                     (socket->Socket.SCTPSocketDesc.ConnectionOriented == false)) {
2712 #ifdef PRINT_SELECT
2713                std::cout << "select(" << getpid() << "): added FD " << i << " - Unbound UDP-like SCTP socket" << std::endl;
2714 #endif
2715                fakeUDPWrite = true;
2716             }
2717             else {
2718 #ifndef DISABLE_WARNINGS
2719                std::cerr << "WARNING: select_wrapper() - Bad FD " << i << "!" << std::endl;
2720 #endif
2721             }
2722          }
2723       }
2724    }
2725 
2726 #ifdef PRINT_SELECT
2727    std::cout << "select..." << std::endl;
2728 #endif
2729    int result;
2730    if(!fakeUDPWrite) {
2731       result = select(maxFD + 1,&r,&w,&e,timeout);
2732    }
2733    else {
2734       struct timeval mytimeout;
2735       mytimeout.tv_sec  = 0;
2736       mytimeout.tv_usec = 0;
2737       result = select(maxFD + 1,&r,&w,&e,&mytimeout);
2738    }
2739 #ifdef PRINT_SELECT
2740    std::cout << "select result " << result << std::endl;
2741 #endif
2742 
2743    if(result >= 0) {
2744       SAFE_FD_ZERO(readfds);
2745       SAFE_FD_ZERO(exceptfds);
2746       if(!fakeUDPWrite) {
2747          SAFE_FD_ZERO(writefds);
2748       }
2749       else {
2750          for(unsigned int i = 0;i < FD_SETSIZE;i++) {
2751             if(SAFE_FD_ISSET(i,writefds)) {
2752                ExtSocketDescriptor* socket = ExtSocketDescriptorMaster::getSocket(i);
2753                if((socket != NULL) &&
2754                   (socket->Type == ExtSocketDescriptor::ESDT_SCTP) &&
2755                   (socket->Socket.SCTPSocketDesc.ConnectionOriented == false)) {
2756 #ifdef PRINT_SELECT
2757                   std::cout << "select(" << getpid() << "): write for FD " << i
2758                             << " (Unbound UDP-like SCTP socket)" << std::endl;
2759 #endif
2760                   FD_SET(i,writefds);
2761                   result++;
2762                }
2763                else {
2764                   FD_CLR(i,writefds);
2765                }
2766             }
2767          }
2768       }
2769       for(int i = 0;i <= maxFD;i++) {
2770          if(SAFE_FD_ISSET(i,&r)) {
2771 #ifdef PRINT_SELECT
2772             std::cout << "select(" << getpid() << "): read for FD " << reverseMapping[i] << std::endl;
2773 #endif
2774             FD_SET(reverseMapping[i],readfds);
2775          }
2776          if(SAFE_FD_ISSET(i,&w)) {
2777 #ifdef PRINT_SELECT
2778             std::cout << "select(" << getpid() << "): write for FD " << reverseMapping[i] << std::endl;
2779 #endif
2780             FD_SET(reverseMapping[i],writefds);
2781          }
2782          if(SAFE_FD_ISSET(i,&e)) {
2783 #ifdef PRINT_SELECT
2784             std::cout << "select(" << getpid() << "): except for FD " << reverseMapping[i] << std::endl;
2785 #endif
2786             FD_SET(reverseMapping[i],exceptfds);
2787          }
2788       }
2789    }
2790 
2791    return(result);
2792 }
2793 
2794 
2795 // ###### ext_select() implementation #######################################
ext_select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)2796 int ext_select(int             n,
2797                fd_set*         readfds,
2798                fd_set*         writefds,
2799                fd_set*         exceptfds,
2800                struct timeval* timeout)
2801 {
2802    if(!SCTPSocketMaster::MasterInstance.running()) {
2803       // SCTP is not available -> Use select() wrapper for conversion
2804       // of FDs to system FDs and back.
2805       return(select_wrapper(n,readfds,writefds,exceptfds,timeout));
2806    }
2807 
2808    SCTPSocketMaster::MasterInstance.lock();
2809 
2810    SelectData selectData;
2811    selectData.Conditions    = 0;
2812    selectData.UserCallbacks = 0;
2813    selectData.GlobalCondition.setName("ext_select::GlobalCondition");
2814    selectData.ReadCondition.setName("ext_select::ReadCondition");
2815    selectData.WriteCondition.setName("ext_select::WriteCondition");
2816    selectData.ExceptCondition.setName("ext_select::ExceptCondition");
2817    selectData.ReadCondition.addParent(&selectData.GlobalCondition);
2818    selectData.WriteCondition.addParent(&selectData.GlobalCondition);
2819    selectData.ExceptCondition.addParent(&selectData.GlobalCondition);
2820 
2821    int result = 0;
2822    for(int i = 0;i < std::min((const int)n,(const int)FD_SETSIZE);i++) {
2823       short int eventMask = 0;
2824       if(SAFE_FD_ISSET(i,readfds)) {
2825          eventMask |= POLLIN|POLLPRI;
2826       }
2827       if(SAFE_FD_ISSET(i,writefds)) {
2828          eventMask |= POLLOUT;
2829       }
2830       if(SAFE_FD_ISSET(i,exceptfds)) {
2831          eventMask |= POLLERR;
2832       }
2833       if(eventMask) {
2834          result = collectFDs(selectData,i,eventMask);
2835          if(result != 0) {
2836             break;
2837          }
2838       }
2839    }
2840 
2841    if(result == 0) {
2842       SCTPSocketMaster::MasterInstance.unlock();
2843       if((selectData.Conditions > 0) || (selectData.UserCallbacks > 0)) {
2844 #ifdef PRINT_SELECT
2845          std::cout << "select(" << getpid() << "): waiting..." << std::endl;
2846 #endif
2847 
2848          if(timeout != NULL) {
2849             const card64 delay = ((card64)timeout->tv_sec * (card64)1000000) +
2850                                     (card64)timeout->tv_usec;
2851             selectData.GlobalCondition.timedWait(delay);
2852          }
2853          else {
2854             selectData.GlobalCondition.wait();
2855          }
2856 
2857 #ifdef PRINT_SELECT
2858          std::cout << "select(" << getpid() << "): wake-up" << std::endl;
2859 #endif
2860       }
2861       else {
2862          result = select(0, NULL, NULL, NULL,timeout);
2863       }
2864 
2865       SCTPSocketMaster::MasterInstance.lock();
2866    }
2867 
2868    if(readfds != NULL) {
2869       for(cardinal i = 0;i < selectData.Conditions;i++) {
2870          FD_CLR(selectData.ConditionFD[i],readfds);
2871       }
2872    }
2873    if(writefds != NULL) {
2874       for(cardinal i = 0;i < selectData.Conditions;i++) {
2875          FD_CLR(selectData.ConditionFD[i],writefds);
2876       }
2877    }
2878    if(exceptfds != NULL) {
2879       for(cardinal i = 0;i < selectData.Conditions;i++) {
2880          FD_CLR(selectData.ConditionFD[i],exceptfds);
2881       }
2882    }
2883 
2884    int changes = 0;
2885    for(cardinal i = 0;i < selectData.Conditions;i++) {
2886       if(selectData.ConditionArray[i]->fired()) {
2887          changes++;
2888          switch(selectData.ConditionType[i]) {
2889             case UCT_Read:
2890                if(readfds != NULL) {
2891 #ifdef PRINT_SELECT
2892                   std::cout << "select(" << getpid() << "): got read for FD " << selectData.ConditionFD[i] << "." << std::endl;
2893 #endif
2894                   FD_SET(selectData.ConditionFD[i],readfds);
2895                }
2896              break;
2897             case UCT_Write:
2898                if(writefds != NULL) {
2899 #ifdef PRINT_SELECT
2900                   std::cout << "select(" << getpid() << "): got write for FD " << selectData.ConditionFD[i] << "." << std::endl;
2901 #endif
2902                   FD_SET(selectData.ConditionFD[i],writefds);
2903                }
2904              break;
2905             case UCT_Except:
2906                if(exceptfds != NULL) {
2907 #ifdef PRINT_SELECT
2908                   std::cout << "select(" << getpid() << "): got except for FD " << selectData.ConditionFD[i] << "." << std::endl;
2909 #endif
2910                   FD_SET(selectData.ConditionFD[i],exceptfds);
2911                }
2912              break;
2913          }
2914 
2915       }
2916       selectData.ConditionArray[i]->removeParent(selectData.ParentConditionArray[i]);
2917    }
2918    if(readfds != NULL) {
2919       for(cardinal i = 0;i < selectData.UserCallbacks;i++) {
2920          FD_CLR(selectData.UserCallbackFD[i],readfds);
2921       }
2922    }
2923    if(writefds != NULL) {
2924       for(cardinal i = 0;i < selectData.UserCallbacks;i++) {
2925          FD_CLR(selectData.UserCallbackFD[i],writefds);
2926       }
2927    }
2928    if(exceptfds != NULL) {
2929       for(cardinal i = 0;i < selectData.UserCallbacks;i++) {
2930          FD_CLR(selectData.UserCallbackFD[i],exceptfds);
2931       }
2932    }
2933    for(cardinal i = 0;i < selectData.UserCallbacks;i++) {
2934       SCTPSocketMaster::MasterInstance.deleteUserSocketNotification(selectData.UserNotification[i]);
2935 
2936       if(selectData.UserNotification[i]->Events) {
2937 #ifdef PRINT_SELECT
2938          char str[32];
2939          snprintf((char*)&str,sizeof(str),"$%04x",selectData.UserNotification[i]->Events);
2940          std::cout << "select(" << getpid() << "): events " << str << " for FD " << selectData.UserNotification[i]->FileDescriptor << " ("
2941                  << selectData.UserCallbackFD[i] << ")" << std::endl;
2942 #endif
2943       }
2944 
2945       bool changed = false;
2946       if((readfds != NULL) && (selectData.UserNotification[i]->Events & (POLLIN|POLLPRI))) {
2947 #ifdef PRINT_SELECT
2948          std::cout << "select(" << getpid() << "): got read for FD " << selectData.UserNotification[i]->FileDescriptor << " ("
2949                    << selectData.UserCallbackFD[i] << ")" << std::endl;
2950 #endif
2951          FD_SET(selectData.UserCallbackFD[i],readfds);
2952          changed = true;
2953       }
2954       if((writefds != NULL) && (selectData.UserNotification[i]->Events & POLLOUT)) {
2955 #ifdef PRINT_SELECT
2956          std::cout << "select(" << getpid() << "): got write for FD " << selectData.UserNotification[i]->FileDescriptor << " ("
2957                    << selectData.UserCallbackFD[i] << ")" << std::endl;
2958 #endif
2959          FD_SET(selectData.UserCallbackFD[i],writefds);
2960          changed = true;
2961       }
2962       if((exceptfds != NULL) && (selectData.UserNotification[i]->Events & (~(POLLIN|POLLPRI|POLLOUT)))) {
2963 #ifdef PRINT_SELECT
2964          std::cout << "select(" << getpid() << "): got except for FD " << selectData.UserNotification[i]->FileDescriptor << " ("
2965                    << selectData.UserCallbackFD[i] << ")" << std::endl;
2966 #endif
2967          FD_SET(selectData.UserCallbackFD[i],exceptfds);
2968          changed = true;
2969       }
2970       if(changed) {
2971          changes++;
2972       }
2973 
2974       delete selectData.UserNotification[i];
2975    }
2976 
2977    SCTPSocketMaster::MasterInstance.unlock();
2978 
2979    errno_return((result < 0) ? result : changes);
2980 }
2981 
2982 
2983 // ###### An implementation of poll(), based on ext_select() ################
ext_poll(struct pollfd * fdlist,long unsigned int count,int time)2984 int ext_poll(struct pollfd* fdlist, long unsigned int count, int time)
2985 {
2986    // ====== Prepare timeout setting ========================================
2987    timeval  timeout;
2988    timeval* to;
2989    if(time < 0)
2990       to = NULL;
2991    else {
2992       to = &timeout;
2993       timeout.tv_sec  = time / 1000;
2994       timeout.tv_usec = (time % 1000) * 1000;
2995    }
2996 
2997    // ====== Prepare FD settings ============================================
2998    int    fdcount = 0;
2999    int    n       = 0;
3000    fd_set readfdset;
3001    fd_set writefdset;
3002    fd_set exceptfdset;
3003    FD_ZERO(&readfdset);
3004    FD_ZERO(&writefdset);
3005    FD_ZERO(&exceptfdset);
3006    for(unsigned int i = 0; i < count; i++) {
3007       if((fdlist[i].fd >= 0) && (fdlist[i].fd < (const int)FD_SETSIZE)) {
3008          if(fdlist[i].events & POLLIN) {
3009             FD_SET(fdlist[i].fd,&readfdset);
3010          }
3011          if(fdlist[i].events & POLLOUT) {
3012             FD_SET(fdlist[i].fd,&writefdset);
3013          }
3014          FD_SET(fdlist[i].fd,&exceptfdset);
3015          n = std::max(n, fdlist[i].fd);
3016          fdcount++;
3017       }
3018       else {
3019          fdlist[i].revents = POLLNVAL;
3020       }
3021    }
3022    if(fdcount == 0) {
3023       return(0);
3024    }
3025    for(unsigned int i = 0;i < count;i++) {
3026       fdlist[i].revents = 0;
3027    }
3028 
3029    // ====== Do ext_select() ================================================
3030    int result = ext_select(n + 1,&readfdset,&writefdset,&exceptfdset,to);
3031    if(result < 0) {
3032       return(result);
3033    }
3034 
3035    // ====== Set result flags ===============================================
3036    result = 0;
3037    for(unsigned int i = 0;i < count;i++) {
3038       if((fdlist[i].fd >= 0) && (fdlist[i].fd < (const int)FD_SETSIZE)) {
3039          fdlist[i].revents = 0;
3040          if(SAFE_FD_ISSET(fdlist[i].fd,&readfdset) && (fdlist[i].events & POLLIN)) {
3041             fdlist[i].revents |= POLLIN;
3042          }
3043          if(SAFE_FD_ISSET(fdlist[i].fd,&writefdset) && (fdlist[i].events & POLLOUT)) {
3044             fdlist[i].revents |= POLLOUT;
3045          }
3046          if(SAFE_FD_ISSET(fdlist[i].fd,&exceptfdset)) {
3047             fdlist[i].revents |= POLLERR;
3048          }
3049          if(fdlist[i].revents != 0) {
3050             result++;
3051          }
3052       }
3053    }
3054    return(result);
3055 }
3056 
3057 
3058 // ###### Check, if SCTP is available #######################################
sctp_isavailable()3059 int sctp_isavailable()
3060 {
3061    return(SCTPSocketMaster::InitializationResult == 0);
3062 }
3063 
3064 
3065 // ###### Peel association off ##############################################
sctp_peeloff(int sockfd,sctp_assoc_t id)3066 int sctp_peeloff(int              sockfd,
3067                  sctp_assoc_t     id)
3068 {
3069    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
3070    if(tdSocket != NULL) {
3071       switch(tdSocket->Type) {
3072          case ExtSocketDescriptor::ESDT_SCTP:
3073             {
3074                SCTPAssociation* association = NULL;
3075                if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
3076                   if(tdSocket->Socket.SCTPSocketDesc.Type != SOCK_STREAM) {
3077                      association = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->peelOff(id);
3078                   }
3079                }
3080 
3081                if(association != NULL) {
3082                   ExtSocketDescriptor newExtSocketDescriptor = *tdSocket;
3083                   newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPSocketPtr      = tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr;
3084                   newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr = association;
3085                   newExtSocketDescriptor.Socket.SCTPSocketDesc.ConnectionOriented = true;
3086                   const int newFD = ExtSocketDescriptorMaster::setSocket(newExtSocketDescriptor);
3087                   if(newFD < 0) {
3088                      delete newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr;
3089                      newExtSocketDescriptor.Socket.SCTPSocketDesc.SCTPAssociationPtr = NULL;
3090                   }
3091                   errno_return(newFD);
3092                }
3093                errno_return(-EINVAL);
3094             }
3095          default:
3096             errno_return(-EOPNOTSUPP);
3097            break;
3098       }
3099    }
3100    return(-EBADF);
3101 }
3102 
3103 
3104 // ###### sctp_getpaddrs() implementation ###################################
sctp_getlpaddrs(int sockfd,sctp_assoc_t id,struct sockaddr ** packedAddrs,const bool peerAddresses)3105 int sctp_getlpaddrs(int               sockfd,
3106                     sctp_assoc_t      id,
3107                     struct sockaddr** packedAddrs,
3108                     const bool        peerAddresses)
3109 {
3110    sockaddr_storage* addrs = NULL;
3111 
3112    *packedAddrs = NULL;
3113    ExtSocketDescriptor* tdSocket = ExtSocketDescriptorMaster::getSocket(sockfd);
3114    if(tdSocket != NULL) {
3115       switch(tdSocket->Type) {
3116          case ExtSocketDescriptor::ESDT_SCTP:
3117             {
3118                int result = -ENXIO;
3119                SocketAddress** addressArray = NULL;
3120 
3121                // ====== Get local or peer addresses ========================
3122                if(peerAddresses) {
3123                   if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
3124                      if((id != 0) && (tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getID() != id)) {
3125                         result = -EINVAL;
3126                      }
3127                      else {
3128                         tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getRemoteAddresses(addressArray);
3129                      }
3130                   }
3131                   else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
3132                      tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getRemoteAddresses(addressArray,id);
3133                   }
3134                   else {
3135                      result = -EBADF;
3136                   }
3137                }
3138                else {
3139                   if(tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr != NULL) {
3140                      tdSocket->Socket.SCTPSocketDesc.SCTPAssociationPtr->getLocalAddresses(addressArray);
3141                   }
3142                   else if(tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr != NULL) {
3143                      tdSocket->Socket.SCTPSocketDesc.SCTPSocketPtr->getLocalAddresses(addressArray);
3144                   }
3145                   else {
3146                      result = -EBADF;
3147                   }
3148                }
3149 
3150                // ====== Copy addresses into sockaddr_storage array =========
3151                if(addressArray != NULL) {
3152                   cardinal count = 0;
3153                   while(addressArray[count] != NULL) {
3154                      count++;
3155                   }
3156                   if(count > 0) {
3157                      result = (int)count;
3158                      addrs = new sockaddr_storage[count];
3159                      if(addrs != NULL) {
3160                         sockaddr* ptr = (sockaddr*)addrs;
3161                         for(cardinal i = 0;i < count;i++) {
3162                            int family = addressArray[i]->getFamily();
3163                            if(family == AF_INET6) {
3164                               if(addressArray[i]->getSystemAddress(
3165                                     ptr,
3166                                     sizeof(sockaddr_storage),
3167                                     AF_INET) > 0) {
3168                                  family = AF_INET;
3169                               }
3170                            }
3171                            if(addressArray[i]->getSystemAddress(
3172                                  ptr,
3173                                  sizeof(sockaddr_storage),
3174                                  family) <= 0) {
3175                               result = -ENAMETOOLONG;
3176                               delete addrs;
3177                               addrs = NULL;
3178                               break;
3179                            }
3180                            ptr = (sockaddr*)((long)ptr + (long)sizeof(sockaddr_storage));
3181                         }
3182                      }
3183                      else {
3184                         result = -ENOMEM;
3185                      }
3186                   }
3187                }
3188 
3189                SocketAddress::deleteAddressList(addressArray);
3190                if(addrs) {
3191                   *packedAddrs = pack_sockaddr_storage(addrs, result);
3192                   delete [] addrs;
3193                }
3194                errno_return(result);
3195             }
3196           break;
3197          case ExtSocketDescriptor::ESDT_System:
3198             errno_return(-EOPNOTSUPP);
3199           break;
3200       }
3201       errno_return(-ENXIO);
3202    }
3203    errno_return(-EBADF);
3204 }
3205 
3206 
3207 // ###### sctp_getpaddrs() implementation ###################################
sctp_getpaddrs(int sockfd,sctp_assoc_t id,struct sockaddr ** addrs)3208 int sctp_getpaddrs(int sockfd, sctp_assoc_t id, struct sockaddr** addrs)
3209 {
3210    return(sctp_getlpaddrs(sockfd,id,addrs,true));
3211 }
3212 
3213 
3214 // ###### sctp_freepaddrs() #################################################
sctp_freepaddrs(struct sockaddr * addrs)3215 void sctp_freepaddrs(struct sockaddr* addrs)
3216 {
3217    delete [] addrs;
3218 }
3219 
3220 
3221 // ###### sctp_getladdrs() implementation ###################################
sctp_getladdrs(int sockfd,sctp_assoc_t id,struct sockaddr ** addrs)3222 int sctp_getladdrs(int sockfd, sctp_assoc_t id, struct sockaddr** addrs)
3223 {
3224    return(sctp_getlpaddrs(sockfd,id,addrs,false));
3225 }
3226 
3227 
3228 // ###### sctp_freeladdrs() #################################################
sctp_freeladdrs(struct sockaddr * addrs)3229 void sctp_freeladdrs(struct sockaddr* addrs)
3230 {
3231    delete [] addrs;
3232 }
3233 
3234 
3235 // ###### sctp_opt_info() implementation ####################################
sctp_opt_info(int sd,sctp_assoc_t assocID,int opt,void * arg,socklen_t * size)3236 int sctp_opt_info(int sd, sctp_assoc_t assocID,
3237                   int opt, void* arg, socklen_t* size)
3238 {
3239    if((opt == SCTP_RTOINFO)            ||
3240       (opt == SCTP_ASSOCINFO)          ||
3241       (opt == SCTP_STATUS)             ||
3242       (opt == SCTP_GET_PEER_ADDR_INFO)) {
3243          *(sctp_assoc_t *)arg = assocID;
3244          return(ext_getsockopt(sd,IPPROTO_SCTP,opt,arg,size));
3245     }
3246     else if((opt == SCTP_PRIMARY_ADDR)          ||
3247             (opt == SCTP_SET_PEER_PRIMARY_ADDR) ||
3248             (opt == SCTP_SET_STREAM_TIMEOUTS)   ||
3249             (opt == SCTP_PEER_ADDR_PARAMS)) {
3250        return(ext_setsockopt(sd,IPPROTO_SCTP,opt,arg,*size));
3251     }
3252     else {
3253        errno_return(-EOPNOTSUPP);
3254     }
3255 }
3256 
3257 
3258 // ###### sctp_sendmsg() implementation #####################################
sctp_sendmsg(int s,const void * data,size_t len,const struct sockaddr * to,socklen_t tolen,uint32_t ppid,uint32_t flags,uint16_t stream_no,uint32_t timetolive,uint32_t context)3259 ssize_t sctp_sendmsg(int                    s,
3260                      const void*            data,
3261                      size_t                 len,
3262                      const struct sockaddr* to,
3263                      socklen_t              tolen,
3264                      uint32_t               ppid,
3265                      uint32_t               flags,
3266                      uint16_t               stream_no,
3267                      uint32_t               timetolive,
3268                      uint32_t               context)
3269 {
3270    sctp_sndrcvinfo* sri;
3271    struct iovec     iov = { (char*)data, len };
3272    struct cmsghdr*  cmsg;
3273    size_t           cmsglen = CSpace(sizeof(struct sctp_sndrcvinfo));
3274    char             cbuf[CSpace(sizeof(struct sctp_sndrcvinfo))];
3275    struct msghdr msg = {
3276 #ifdef __APPLE__
3277       (char*)to,
3278 #else
3279       (struct sockaddr*)to,
3280 #endif
3281       tolen,
3282       &iov, 1,
3283       cbuf,
3284 #ifdef __FreeBSD__
3285       (socklen_t)cmsglen,
3286 #else
3287       cmsglen,
3288 #endif
3289       (int)flags
3290    };
3291 
3292    cmsg = (struct cmsghdr*)CFirstHeader(&msg);
3293    cmsg->cmsg_len   = CLength(sizeof(struct sctp_sndrcvinfo));
3294    cmsg->cmsg_level = IPPROTO_SCTP;
3295    cmsg->cmsg_type  = SCTP_SNDRCV;
3296 
3297    sri = (struct sctp_sndrcvinfo*)CData(cmsg);
3298    sri->sinfo_assoc_id   = 0;
3299    sri->sinfo_stream     = stream_no;
3300    sri->sinfo_ppid       = ppid;
3301    sri->sinfo_flags      = flags;
3302    sri->sinfo_ssn        = 0;
3303    sri->sinfo_tsn        = 0;
3304    sri->sinfo_context    = 0;
3305    sri->sinfo_cumtsn     = 0;
3306    sri->sinfo_timetolive = timetolive;
3307 
3308    return(ext_sendmsg(s, &msg, 0));
3309 }
3310 
3311 
3312 // ###### sctp_send() implementation ########################################
sctp_send(int s,const void * data,size_t len,const struct sctp_sndrcvinfo * sinfo,int flags)3313 ssize_t sctp_send(int                           s,
3314                   const void*                   data,
3315                   size_t                        len,
3316                   const struct sctp_sndrcvinfo* sinfo,
3317                   int                           flags)
3318 {
3319    sctp_sndrcvinfo* sri;
3320    struct iovec     iov = { (char*)data, len };
3321    struct cmsghdr*  cmsg;
3322    size_t           cmsglen = CSpace(sizeof(struct sctp_sndrcvinfo));
3323    char             cbuf[CSpace(sizeof(struct sctp_sndrcvinfo))];
3324    struct msghdr msg = {
3325       NULL, 0,
3326       &iov, 1,
3327       cbuf,
3328 #ifdef __FreeBSD__
3329       (socklen_t)cmsglen,
3330 #else
3331       cmsglen,
3332 #endif
3333       flags
3334    };
3335 
3336    cmsg = (struct cmsghdr*)CFirstHeader(&msg);
3337    cmsg->cmsg_len   = CLength(sizeof(struct sctp_sndrcvinfo));
3338    cmsg->cmsg_level = IPPROTO_SCTP;
3339    cmsg->cmsg_type  = SCTP_SNDRCV;
3340 
3341    sri = (struct sctp_sndrcvinfo*)CData(cmsg);
3342    memcpy(sri, sinfo, sizeof(struct sctp_sndrcvinfo));
3343 
3344    return(ext_sendmsg(s, &msg, 0));
3345 }
3346 
3347 
3348 // ###### sctp_sendmsg() implementation #####################################
sctp_sendx(int sd,const void * data,size_t len,const struct sockaddr * addrs,int addrcnt,const struct sctp_sndrcvinfo * sinfo,int flags)3349 ssize_t sctp_sendx(int                           sd,
3350                    const void*                   data,
3351                    size_t                        len,
3352                    const struct sockaddr*        addrs,
3353                    int                           addrcnt,
3354                    const struct sctp_sndrcvinfo* sinfo,
3355                    int                           flags)
3356 {
3357    sctp_sndrcvinfo* sri;
3358    struct iovec     iov = { (char*)data, len };
3359    struct cmsghdr*  cmsg;
3360    size_t           cmsglen = CSpace(sizeof(struct sctp_sndrcvinfo));
3361    char             cbuf[CSpace(sizeof(struct sctp_sndrcvinfo))];
3362    struct msghdr msg = {
3363 #ifdef __APPLE__
3364       (char*)addrs,
3365 #else
3366       (struct sockaddr*)addrs,
3367 #endif
3368       (socklen_t)addrcnt,
3369       &iov, 1,
3370       cbuf,
3371 #ifdef __FreeBSD__
3372       (socklen_t)cmsglen,
3373 #else
3374       cmsglen,
3375 #endif
3376       flags | MSG_MULTIADDRS,
3377    };
3378 
3379    cmsg = (struct cmsghdr*)CFirstHeader(&msg);
3380    cmsg->cmsg_len   = CLength(sizeof(struct sctp_sndrcvinfo));
3381    cmsg->cmsg_level = IPPROTO_SCTP;
3382    cmsg->cmsg_type  = SCTP_SNDRCV;
3383 
3384    sri = (struct sctp_sndrcvinfo*)CData(cmsg);
3385    if(sinfo != NULL) {
3386       memcpy(sri, sinfo, sizeof(struct sctp_sndrcvinfo));
3387    }
3388    else {
3389       memset(sri, 0, sizeof(struct sctp_sndrcvinfo));
3390    }
3391    sri->sinfo_flags |= MSG_MULTIADDRS;
3392 
3393    return(ext_sendmsg(sd, &msg, 0));
3394 }
3395 
3396 
3397 // ###### sctp_recvmsg() implementation #####################################
sctp_recvmsg(int s,void * data,size_t len,struct sockaddr * from,socklen_t * fromlen,struct sctp_sndrcvinfo * sinfo,int * msg_flags)3398 ssize_t sctp_recvmsg(int                     s,
3399                      void*                   data,
3400                      size_t                  len,
3401                      struct sockaddr*        from,
3402                      socklen_t*              fromlen,
3403                      struct sctp_sndrcvinfo* sinfo,
3404                      int*                    msg_flags)
3405 {
3406    struct iovec    iov = { (char*)data, len };
3407    struct cmsghdr* cmsg;
3408    size_t          cmsglen = CSpace(sizeof(struct sctp_sndrcvinfo));
3409    char            cbuf[CSpace(sizeof(struct sctp_sndrcvinfo))];
3410    struct msghdr msg = {
3411 #ifdef __APPLE__
3412       (char*)from,
3413 #else
3414       from,
3415 #endif
3416       (fromlen != NULL) ? *fromlen : 0,
3417       &iov, 1,
3418       cbuf,
3419 #ifdef __FreeBSD__
3420       (socklen_t)cmsglen,
3421 #else
3422       cmsglen,
3423 #endif
3424       (msg_flags != NULL) ? *msg_flags : 0
3425    };
3426    int cc;
3427 
3428    cc = ext_recvmsg(s, &msg, 0);
3429 
3430    if((cc > 0) && (msg.msg_control != NULL) && (msg.msg_controllen > 0)) {
3431       cmsg = (struct cmsghdr*)CFirstHeader(&msg);
3432       if((sinfo != NULL) &&
3433          (cmsg != NULL)  &&
3434          (cmsg->cmsg_len   == CLength(sizeof(struct sctp_sndrcvinfo))) &&
3435          (cmsg->cmsg_level == IPPROTO_SCTP)                             &&
3436          (cmsg->cmsg_type  == SCTP_SNDRCV)) {
3437          *sinfo = *((struct sctp_sndrcvinfo*)CData(cmsg));
3438       }
3439    }
3440    if(msg_flags != NULL) {
3441       *msg_flags = msg.msg_flags;
3442    }
3443    if(fromlen != NULL) {
3444       *fromlen = msg.msg_namelen;
3445    }
3446    return(cc);
3447 }
3448 
3449 
3450 #else
3451 
3452 
3453 // ###### Check, if SCTP is available #######################################
sctp_isavailable()3454 int sctp_isavailable()
3455 {
3456    int result = socket(AF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);
3457    if(result != -1) {
3458       close(result);
3459       errno_return(1);
3460    }
3461    else {
3462 #ifdef PRINT_NOSCTP_NOTE
3463       std::cerr << "SCTP is unsupported on this host!" << std::endl;
3464 #endif
3465       errno_return(0);
3466    }
3467 }
3468 
3469 
3470 #endif
3471 
3472 
3473 // ###### Change OOTB handling ##############################################
sctp_enableOOTBHandling(const unsigned int enable)3474 int sctp_enableOOTBHandling(const unsigned int enable)
3475 {
3476    if(SCTPSocketMaster::enableOOTBHandling(enable != 0) == false) {
3477       return(-EIO);
3478    }
3479    return(0);
3480 }
3481 
3482 
3483 // ###### Change CRC32 usage ################################################
sctp_enableCRC32(const unsigned int enable)3484 int sctp_enableCRC32(const unsigned int enable)
3485 {
3486    if(SCTPSocketMaster::enableCRC32(enable != 0) == false) {
3487       return(-EIO);
3488    }
3489    return(0);
3490 }
3491