ObjFW  Check-in [f8422ce7e9]

Overview
Comment:OFTCPSocket+SOCKS5.m: Use send/recv directly

This is necessary to make SOCKS5 support work with subclasses of
OFTCPSocket that override read and write, for example SSL sockets.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f8422ce7e98e59d78797514063ef67fb6ee64c650066d08dd56953d22f34ed16
User & Date: js on 2016-03-12 11:55:00
Other Links: manifest | tags
Context
2016-03-12
13:12
OFSystemInfo: Fix a stupid typo check-in: 6baf51ebda user: js tags: trunk
11:55
OFTCPSocket+SOCKS5.m: Use send/recv directly check-in: f8422ce7e9 user: js tags: trunk
2016-03-06
17:40
OFTLSSocket: Make use of properties check-in: 143c61869a user: js tags: trunk
Changes

Modified src/OFTCPSocket+SOCKS5.m from [8b7939a5bd] to [f0cdd75885].

13
14
15
16
17
18
19

20
21



22


23
24



























25
26
27
28
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
65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80


81
82
83
84

85
86
87
88
89
90
91
92
93

94
95
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
65
66

67
68
69
70
71

72

73


74
75
76
77
78
79
80
81
82


83
84
85
86







87
88
89
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







+


+
+
+

+
+


+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+





-
+

+
+
-
+
+
+


-
+
-

-
-
+








-
-
+
+
+

-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+

-
-
+
+
+
+

-
-
+











-
-
+


-
-
+
+


-
-
+








-
+


 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "OFTCPSocket+SOCKS5.h"
#import "OFDataArray.h"

#import "OFConnectionFailedException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#import "socket_helpers.h"

/* Reference for static linking */
int _OFTCPSocket_SOCKS5_reference;

static void
send_or_exception(OFTCPSocket *self, int socket, char *buffer, size_t length)
{
	if (send(socket, buffer, length, 0) != length)
		@throw [OFWriteFailedException
		    exceptionWithObject: self
			requestedLength: length
				  errNo: of_socket_errno()];
}

static void
recv_exact(OFTCPSocket *self, int socket, char *buffer, size_t length)
{
	while (length > 0) {
		ssize_t ret = recv(socket, buffer, length, 0);

		if (ret < 0)
			@throw [OFReadFailedException
			    exceptionWithObject: self
				requestedLength: length
					  errNo: of_socket_errno()];

		buffer += ret;
		length -= ret;
	}
}

@implementation OFTCPSocket (SOCKS5)
- (void)OF_SOCKS5ConnectToHost: (OFString*)host
			  port: (uint16_t)port
{
	const char request[] = { 5, 1, 0, 3 };
	char request[] = { 5, 1, 0, 3 };
	char reply[256];
	void *pool;
	OFDataArray *connectRequest;
	bool wasWriteBuffered;

	if ([host UTF8StringLength] > 255)
		@throw [OFOutOfRangeException exception];

	/* 5 1 0 -> no authentication */
	[self writeBuffer: request
	send_or_exception(self, _socket, request, 3);
		   length: 3];

	[self readIntoBuffer: reply
		 exactLength: 2];
	recv_exact(self, _socket, reply, 2);

	if (reply[0] != 5 || reply[1] != 0) {
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	wasWriteBuffered = [self isWriteBuffered];
	[self setWriteBuffered: true];
	/* CONNECT request */
	pool = objc_autoreleasePoolPush();
	connectRequest = [OFDataArray dataArray];

	/* CONNECT request */
	[self writeBuffer: request
		   length: 4];
	[self writeInt8: [host UTF8StringLength]];
	[self writeBuffer: [host UTF8String]
		   length: [host UTF8StringLength]];
	[self writeBigEndianInt16: port];
	[connectRequest addItems: request
			   count: 4];

	request[0] = [host UTF8StringLength];
	[connectRequest addItem: request];
	[connectRequest addItems: [host UTF8String]
			   count: request[0]];

	request[0] = port >> 8;
	request[1] = port & 0xFF;
	[connectRequest addItems: request
			   count: 2];

	[self flushWriteBuffer];
	[self setWriteBuffered: wasWriteBuffered];
	send_or_exception(self, _socket,
	    [connectRequest items], [connectRequest count]);

	objc_autoreleasePoolPop(pool);

	[self readIntoBuffer: reply
		 exactLength: 4];
	recv_exact(self, _socket, reply, 4);

	if (reply[0] != 5 || reply[1] != 0 || reply[2] != 0) {
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	/* Skip the rest of the reply */
	switch (reply[3]) {
	case 1: /* IPv4 */
		[self readIntoBuffer: reply
			 exactLength: 4];
		recv_exact(self, _socket, reply, 4);
		break;
	case 3: /* Domainname */
		[self readIntoBuffer: reply
			 exactLength: [self readInt8]];
		recv_exact(self, _socket, reply, 1);
		recv_exact(self, _socket, reply, reply[0]);
		break;
	case 4: /* IPv6 */
		[self readIntoBuffer: reply
			 exactLength: 16];
		recv_exact(self, _socket, reply, 16);
		break;
	default:
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	[self readBigEndianInt16];
	recv_exact(self, _socket, reply, 2);
}
@end