ObjFW  Diff

Differences From Artifact [0702a801d8]:

  • File src/OFDDPSocket.m — part of check-in [41535b41da] at 2022-11-01 22:18:34 on branch trunk — Implement OFDDPSocket using SOCK_RAW on macOS

    This required quite some reverse engineering, as it is all completely
    undocumented.

    Receiving worked pretty much as expected: Do a readv() and get the raw
    DDP packet including headers, then parse the headers ourselves to get
    the source and fill out an OFSocketAddress.

    But sending was tricky and required reading through kernel sources.
    writev() does not work on a raw DDP socket and always fails with
    EDESTADDRREQ, even if the destination address is provided as part of the
    raw DDP packet. Meanwhile, sendmsg() always creates a DDP packet for us,
    even in raw mode, and prepends the data with what it believes to be the
    DDP protocol type (the protocol parameter passed to socket()). After
    reading through the kernel source for some time to find a way to disable
    this behavior, I found that you can set DDP_HDRINCL in ATPROTO_NONE to
    provide your entire header to sendmsg() instead to work around this,
    making it behave like you would expect from a writev() to a raw socket.

    The only missing part now is to return a proper address a socket was
    bound to, as currently it just leaves network and node at 0 and only
    fills the port. This probably just requires some more reading of kernel
    sources. (user: js, size: 5781) [annotate] [blame] [check-ins using]

To Artifact [5573556d55]:


29
30
31
32
33
34
35










36
37
38
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
#import "OFBindDDPSocketFailedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#ifdef OF_HAVE_NETAT_APPLETALK_H
# include <netat/ddp.h>










#endif

@implementation OFDDPSocket
@dynamic delegate;

- (OFSocketAddress)bindToNetwork: (uint16_t)network
			    node: (uint8_t)node
			    port: (uint8_t)port
{
#ifdef OF_MACOS
	const int one = 1;

#endif
	OFSocketAddress address;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != OFInvalidSocketHandle)







>
>
>
>
>
>
>
>
>
>











>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#import "OFBindDDPSocketFailedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#ifdef OF_HAVE_NETAT_APPLETALK_H
# include <netat/ddp.h>
# include <sys/ioctl.h>

/* Unfortulately, there is no struct for the following in userland headers */
struct ATInterfaceConfig {
	char interfaceName[16];
	unsigned int flags;
	struct at_addr address, router;
	unsigned short netStart, netEnd;
	at_nvestr_t zoneName;
};
#endif

@implementation OFDDPSocket
@dynamic delegate;

- (OFSocketAddress)bindToNetwork: (uint16_t)network
			    node: (uint8_t)node
			    port: (uint8_t)port
{
#ifdef OF_MACOS
	const int one = 1;
	struct ATInterfaceConfig config = { { 0 } };
#endif
	OFSocketAddress address;
#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
	int flags;
#endif

	if (_socket != OFInvalidSocketHandle)
119
120
121
122
123
124
125
126


127
128
129
130
131
132
133



134
135
136
137
138
139
140
				    node: node
				    port: port
				  socket: self
				   errNo: EAFNOSUPPORT];
	}

#ifdef OF_MACOS
	if (setsockopt(_socket, ATPROTO_NONE, DDP_HDRINCL, &one,


	    sizeof(one)) != 0)
		@throw [OFBindDDPSocketFailedException
		    exceptionWithNetwork: network
				    node: node
				    port: port
				  socket: self
				   errNo: OFSocketErrNo()];



#endif

	return address;
}

#ifdef OF_MACOS
- (size_t)receiveIntoBuffer: (void *)buffer







|
>
>
|






>
>
>







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
				    node: node
				    port: port
				  socket: self
				   errNo: EAFNOSUPPORT];
	}

#ifdef OF_MACOS
	if (setsockopt(_socket, ATPROTO_NONE, DDP_HDRINCL, &one, sizeof(one)) !=
	    0 ||
	    ioctl(_socket, _IOWR('a', 2, struct ATInterfaceConfig), &config) !=
	    0)
		@throw [OFBindDDPSocketFailedException
		    exceptionWithNetwork: network
				    node: node
				    port: port
				  socket: self
				   errNo: OFSocketErrNo()];

	OFSocketAddressSetAppleTalkNetwork(&address, config.address.s_net);
	OFSocketAddressSetAppleTalkNode(&address, config.address.s_node);
#endif

	return address;
}

#ifdef OF_MACOS
- (size_t)receiveIntoBuffer: (void *)buffer