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
			[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}')




	])
	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
	])







>
>
>
>







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
 *
 * 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"



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

#ifdef HAVE_FCNTL_H







>
>







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
#import "OFBindIPSocketFailedException.h"
#import "OFGetOptionFailedException.h"
#import "OFNotOpenException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFSetOptionFailedException.h"
#import "OFWriteFailedException.h"





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

static const OFRunLoopMode connectRunLoopMode =
    @"OFSCTPSocketConnectRunLoopMode";







>
>
>
>







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

@implementation OFSCTPSocket
@dynamic delegate;

- (bool)of_createSocketForAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{



#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) {
		*errNo = _OFSocketErrNo();

		closesocket(_socket);
		_socket = OFInvalidSocketHandle;

		return false;
	}
#endif

	return true;
}

- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address
			    errNo: (int *)errNo
{







>
>
>



<
<
<

















<
|
|







<







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




	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


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

		closesocket(_socket);
		_socket = OFInvalidSocketHandle;

		return false;
	}


	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
	}

	objc_autoreleasePoolPop(pool);

	return address;
}

#ifdef SCTP_RECVRCVINFO
- (instancetype)accept
{



	OFSCTPSocket *accepted = [super accept];
	int one = 1;

	if (setsockopt(accepted->_socket, IPPROTO_SCTP, SCTP_RECVRCVINFO, &one,
	    sizeof(one)) != 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))];
	struct msghdr msg = {
		.msg_iov = &iov,
		.msg_iovlen = 1,
		.msg_control = cmsgBuffer,
		.msg_controllen = sizeof(cmsgBuffer)
	};
	struct cmsghdr *cmsg;







<


>
>
>

<

|
|






<















|







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;
}


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


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

	return accepted;
}


- (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_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
	*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));
			OFNumber *streamID = [OFNumber numberWithUnsignedShort:
			    rcvinfo.rcv_sid];
			OFNumber *PPID = [OFNumber numberWithUnsignedLong:
			    rcvinfo.rcv_ppid];
			OFNumber *unordered = [OFNumber numberWithBool:
			    (rcvinfo.rcv_flags & SCTP_UNORDERED)];

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

			break;







|
|
|

|

|

|







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_SNDRCV) {
			struct sctp_sndrcvinfo sndrcv;
			memcpy(&sndrcv, CMSG_DATA(cmsg), sizeof(sndrcv));
			OFNumber *streamID = [OFNumber numberWithUnsignedShort:
			    sndrcv.sinfo_stream];
			OFNumber *PPID = [OFNumber numberWithUnsignedLong:
			    OFFromBigEndian32(sndrcv.sinfo_ppid)];
			OFNumber *unordered = [OFNumber numberWithBool:
			    (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
	      info: (OFSCTPMessageInfo)info
{
	ssize_t bytesWritten;
	struct iovec iov = {
		.iov_base = (void *)buffer,
		.iov_len = length
	};
	struct sctp_sndinfo sndinfo = {
		.snd_sid = (uint16_t)
		    [[info objectForKey: OFSCTPStreamID] unsignedShortValue],
		.snd_ppid = (uint32_t)
		    [[info objectForKey: OFSCTPPPID] unsignedLongValue],
		.snd_flags = ([[info objectForKey: OFSCTPUnordered] boolValue]
		    ? SCTP_UNORDERED : 0)
	};
	char cmsgBuffer[CMSG_SPACE(sizeof(sndinfo))];
	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));

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







|
|

|
|
|


|















|
|
|







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_sndrcvinfo sndrcv = {
		.sinfo_stream = (uint16_t)
		    [[info objectForKey: OFSCTPStreamID] unsignedShortValue],
		.sinfo_ppid = OFToBigEndian32((uint32_t)
		    [[info objectForKey: OFSCTPPPID] unsignedLongValue]),
		.sinfo_flags = ([[info objectForKey: OFSCTPUnordered] boolValue]
		    ? SCTP_UNORDERED : 0)
	};
	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_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()];