ObjFW  Check-in [a65e33b00a]

Overview
Comment:Make SCTP work on Solaris
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a65e33b00a35b9562c2a64af8d8a0c69465c35828fa5523e8bb762062a22ba26
User & Date: js on 2024-10-26 11:29:26
Other Links: manifest | tags
Context
2024-10-27
11:38
OFPlugin: Allow path to be nil check-in: 5aba968988 user: js tags: trunk
2024-10-26
11:29
Make SCTP work on Solaris check-in: a65e33b00a user: js tags: trunk
2024-10-25
22:38
OFSCTPSocket: Don't require -lsctp check-in: abe832b03d user: js tags: trunk
Changes

Modified configure.ac from [7abd4315da] to [9067714a39].

1491
1492
1493
1494
1495
1496
1497




1498
1499
1500
1501
1502
1503
1504
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508







+
+
+
+







			[Whether we have netinet/tcp.h])
	])
	AC_CHECK_HEADER(netinet/sctp.h, [
		AC_DEFINE(OF_HAVE_SCTP, 1, [Whether we have SCTP])
		AC_DEFINE(OF_HAVE_NETINET_SCTP_H, 1,
			[Whether we have netinet/sctp.h])
		AC_SUBST(USE_SRCS_SCTP, '${SRCS_SCTP}')
	], [], [
		#ifdef OF_HAVE_SYS_SOCKET_H
		# include <sys/socket.h>
		#endif
	])
	AC_CHECK_HEADERS([arpa/inet.h netdb.h sys/sockio.h])
	AC_CHECK_HEADERS([net/if.h], [], [], [
		#ifdef OF_HAVE_SYS_SOCKET_H
		# include <sys/socket.h>
		#endif
	])

Modified src/OFSCTPSocket.m from [c5135980c9] to [90795d2a22].

14
15
16
17
18
19
20


21
22
23
24
25
26
27
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29







+
+







 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3.0 along with this program. If not, see
 * <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#define _XPG4_2

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_FCNTL_H
47
48
49
50
51
52
53




54
55
56
57
58
59
60
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66







+
+
+
+







#import "OFBindIPSocketFailedException.h"
#import "OFGetOptionFailedException.h"
#import "OFNotOpenException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFSetOptionFailedException.h"
#import "OFWriteFailedException.h"

#ifdef OF_SOLARIS
# define SCTP_UNORDERED MSG_UNORDERED
#endif

const OFSCTPMessageInfoKey OFSCTPStreamID = @"OFSCTPStreamID";
const OFSCTPMessageInfoKey OFSCTPPPID = @"OFSCTPPPID";
const OFSCTPMessageInfoKey OFSCTPUnordered = @"OFSCTPUnordered";

static const OFRunLoopMode connectRunLoopMode =
    @"OFSCTPSocketConnectRunLoopMode";
90
91
92
93
94
95
96



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122


123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
96
97
98
99
100
101
102
103
104
105
106
107
108



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125



126
127
128
129
130
131
132
133
134

135
136
137
138
139
140
141







+
+
+



-
-
-

















-
-
-
+
+







-








@implementation OFSCTPSocket
@dynamic delegate;

- (bool)of_createSocketForAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{
	const struct sctp_event_subscribe events = {
		.sctp_data_io_event = 1
	};
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	int flags;
#endif
#ifdef SCTP_RECVRCVINFO
	int one = 1;
#endif

	if (_socket != OFInvalidSocketHandle)
		@throw [OFAlreadyOpenException exceptionWithObject: self];

	if ((_socket = socket(
	    ((struct sockaddr *)&address->sockaddr)->sa_family,
	    SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_SCTP)) ==
	    OFInvalidSocketHandle) {
		*errNo = _OFSocketErrNo();
		return false;
	}

#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
	if ((flags = fcntl(_socket, F_GETFD, 0)) != -1)
		fcntl(_socket, F_SETFD, flags | FD_CLOEXEC);
#endif

#ifdef SCTP_RECVRCVINFO
	if (setsockopt(_socket, IPPROTO_SCTP, SCTP_RECVRCVINFO, &one,
	    sizeof(one)) != 0) {
	if (setsockopt(_socket, IPPROTO_SCTP, SCTP_EVENTS, &events,
	    sizeof(events)) != 0) {
		*errNo = _OFSocketErrNo();

		closesocket(_socket);
		_socket = OFInvalidSocketHandle;

		return false;
	}
#endif

	return true;
}

- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{
329
330
331
332
333
334
335
336
337
338



339
340
341
342
343


344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

367
368
369
370
371
372
373
333
334
335
336
337
338
339

340
341
342
343
344
345

346


347
348
349
350
351
352
353
354

355
356
357
358
359
360
361
362
363
364
365
366
367
368
369

370
371
372
373
374
375
376
377







-


+
+
+

-

-
-
+
+






-















-
+







	}

	objc_autoreleasePoolPop(pool);

	return address;
}

#ifdef SCTP_RECVRCVINFO
- (instancetype)accept
{
	const struct sctp_event_subscribe events = {
		.sctp_data_io_event = 1
	};
	OFSCTPSocket *accepted = [super accept];
	int one = 1;

	if (setsockopt(accepted->_socket, IPPROTO_SCTP, SCTP_RECVRCVINFO, &one,
	    sizeof(one)) != 0)
	if (setsockopt(accepted->_socket, IPPROTO_SCTP, SCTP_EVENTS, &events,
	    sizeof(events)) != 0)
		@throw [OFAcceptSocketFailedException
		    exceptionWithSocket: self
				  errNo: _OFSocketErrNo()];

	return accepted;
}
#endif

- (size_t)receiveIntoBuffer: (void *)buffer length: (size_t)length
{
	return [self receiveIntoBuffer: buffer length: length info: NULL];
}

- (size_t)receiveIntoBuffer: (void *)buffer
		     length: (size_t)length
		       info: (OFSCTPMessageInfo *)info
{
	ssize_t ret;
	struct iovec iov = {
		.iov_base = buffer,
		.iov_len = length
	};
	char cmsgBuffer[CMSG_SPACE(sizeof(struct sctp_rcvinfo))];
	char cmsgBuffer[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
	struct msghdr msg = {
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = cmsgBuffer,
		.msg_controllen = sizeof(cmsgBuffer)
	};
	struct cmsghdr *cmsg;
387
388
389
390
391
392
393
394
395
396



397
398

399
400

401
402

403
404
405
406
407
408
409
391
392
393
394
395
396
397



398
399
400
401

402
403

404
405

406
407
408
409
410
411
412
413







-
-
-
+
+
+

-
+

-
+

-
+







	*info = nil;

	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
		if (cmsg->cmsg_level != IPPROTO_SCTP)
			continue;

		if (cmsg->cmsg_type == SCTP_RCVINFO) {
			struct sctp_rcvinfo rcvinfo;
			memcpy(&rcvinfo, CMSG_DATA(cmsg), sizeof(rcvinfo));
		if (cmsg->cmsg_type == SCTP_SNDRCV) {
			struct sctp_sndrcvinfo sndrcv;
			memcpy(&sndrcv, CMSG_DATA(cmsg), sizeof(sndrcv));
			OFNumber *streamID = [OFNumber numberWithUnsignedShort:
			    rcvinfo.rcv_sid];
			    sndrcv.sinfo_stream];
			OFNumber *PPID = [OFNumber numberWithUnsignedLong:
			    rcvinfo.rcv_ppid];
			    OFFromBigEndian32(sndrcv.sinfo_ppid)];
			OFNumber *unordered = [OFNumber numberWithBool:
			    (rcvinfo.rcv_flags & SCTP_UNORDERED)];
			    (sndrcv.sinfo_flags & SCTP_UNORDERED)];

			*info = [OFDictionary dictionaryWithKeysAndObjects:
			    OFSCTPStreamID, streamID,
			    OFSCTPPPID, PPID,
			    OFSCTPUnordered, unordered, nil];

			break;
471
472
473
474
475
476
477
478
479


480
481
482
483



484
485
486

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504



505
506
507
508
509
510
511
475
476
477
478
479
480
481


482
483
484



485
486
487
488
489

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505



506
507
508
509
510
511
512
513
514
515







-
-
+
+

-
-
-
+
+
+


-
+















-
-
-
+
+
+







	      info: (OFSCTPMessageInfo)info
{
	ssize_t bytesWritten;
	struct iovec iov = {
		.iov_base = (void *)buffer,
		.iov_len = length
	};
	struct sctp_sndinfo sndinfo = {
		.snd_sid = (uint16_t)
	struct sctp_sndrcvinfo sndrcv = {
		.sinfo_stream = (uint16_t)
		    [[info objectForKey: OFSCTPStreamID] unsignedShortValue],
		.snd_ppid = (uint32_t)
		    [[info objectForKey: OFSCTPPPID] unsignedLongValue],
		.snd_flags = ([[info objectForKey: OFSCTPUnordered] boolValue]
		.sinfo_ppid = OFToBigEndian32((uint32_t)
		    [[info objectForKey: OFSCTPPPID] unsignedLongValue]),
		.sinfo_flags = ([[info objectForKey: OFSCTPUnordered] boolValue]
		    ? SCTP_UNORDERED : 0)
	};
	char cmsgBuffer[CMSG_SPACE(sizeof(sndinfo))];
	char cmsgBuffer[CMSG_SPACE(sizeof(sndrcv))];
	struct cmsghdr *cmsg = (struct cmsghdr *)(void *)&cmsgBuffer;
	struct msghdr msg = {
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = &cmsgBuffer,
		.msg_controllen = sizeof(cmsgBuffer)
	};

	if (_socket == OFInvalidSocketHandle)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (length > SSIZE_MAX)
		@throw [OFOutOfRangeException exception];

	cmsg->cmsg_level = IPPROTO_SCTP;
	cmsg->cmsg_type = SCTP_SNDINFO;
	cmsg->cmsg_len = CMSG_LEN(sizeof(sndinfo));
	memcpy(CMSG_DATA(cmsg), &sndinfo, sizeof(sndinfo));
	cmsg->cmsg_type = SCTP_SNDRCV;
	cmsg->cmsg_len = CMSG_LEN(sizeof(sndrcv));
	memcpy(CMSG_DATA(cmsg), &sndrcv, sizeof(sndrcv));

	if ((bytesWritten = sendmsg(_socket, &msg, 0)) < 0)
		@throw [OFWriteFailedException
		    exceptionWithObject: self
			requestedLength: length
			   bytesWritten: 0
				  errNo: _OFSocketErrNo()];