1/*
2 * Converting socketaddresses to/from Python in a way that is compatible with
3 * the socket module.
4 *
5 * This code reimplements parts of the socket module, sadly enough the socket
6 * module doesn't have enough of a public C API to do this otherwise.
7 */
8
9#include "pyobjc.h"
10
11#include <sys/socket.h>
12#include <sys/types.h>
13#include <netinet/in.h>
14#include <netdb.h>
15
16static PyObject* socket_error = NULL;
17static PyObject* socket_gaierror = NULL;
18
19static int
20setup_exceptions(void)
21{
22	PyObject* mod;
23
24	mod = PyImport_ImportModule("socket");
25	if (mod == NULL) {
26		return -1;
27	}
28
29	Py_XDECREF(socket_error);
30	socket_error = PyObject_GetAttrString(mod, "error");
31	if (socket_error == NULL) {
32		Py_DECREF(mod);
33		return -1;
34	}
35
36	Py_XDECREF(socket_gaierror);
37	socket_gaierror = PyObject_GetAttrString(mod, "gaierror");
38	if (socket_gaierror == NULL) {
39		Py_DECREF(mod);
40		return -1;
41	}
42
43	Py_DECREF(mod);
44	return 0;
45}
46
47static PyObject*
48set_gaierror(int error)
49{
50	if (error == EAI_SYSTEM) {
51		if (socket_error == NULL) {
52			if (setup_exceptions() == -1) {
53				return NULL;
54			}
55		}
56		PyErr_SetFromErrno(socket_error);
57		return NULL;
58	}
59
60	PyObject* v = Py_BuildValue("is", error, gai_strerror(error));
61	if (v != NULL) {
62		if (socket_gaierror == NULL) {
63			if (setup_exceptions() == -1) {
64				return NULL;
65			}
66		}
67		PyErr_SetObject(socket_gaierror, v);
68		Py_DECREF(v);
69		return NULL;
70	}
71	return NULL;
72}
73
74static PyObject*
75makeipaddr(struct sockaddr* addr, int addrlen)
76{
77	char buf[NI_MAXHOST];
78	int r;
79
80	r = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
81			NI_NUMERICHOST);
82	if (r) {
83		return set_gaierror(r);
84	}
85	return PyBytes_FromString(buf);
86}
87
88static int
89setipaddr(char* name, struct sockaddr* addr_ret, size_t addr_ret_size, int af)
90{
91	struct addrinfo hints, *res;
92	int error;
93	int d1, d2, d3, d4;
94	char ch;
95
96	memset((void *) addr_ret, '\0', sizeof(*addr_ret));
97	if (name[0] == '\0') {
98		int siz;
99		memset(&hints, 0, sizeof(hints));
100		hints.ai_family = af;
101		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
102		hints.ai_flags = AI_PASSIVE;
103		error = getaddrinfo(NULL, "0", &hints, &res);
104		/* We assume that those thread-unsafe getaddrinfo() versions
105		   *are* safe regarding their return value, ie. that a
106		   subsequent call to getaddrinfo() does not destroy the
107		   outcome of the first call. */
108		if (error) {
109			set_gaierror(error);
110			return -1;
111		}
112		switch (res->ai_family) {
113		case AF_INET:
114			siz = 4;
115			break;
116		case AF_INET6:
117			siz = 16;
118			break;
119		default:
120			freeaddrinfo(res);
121			PyErr_SetString(socket_error,
122				"unsupported address family");
123			return -1;
124		}
125		if (res->ai_next) {
126			freeaddrinfo(res);
127			PyErr_SetString(socket_error,
128				"wildcard resolved to multiple address");
129			return -1;
130		}
131		if (res->ai_addrlen < addr_ret_size)
132			addr_ret_size = res->ai_addrlen;
133		memcpy(addr_ret, res->ai_addr, addr_ret_size);
134		freeaddrinfo(res);
135		return siz;
136	}
137	if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
138		struct sockaddr_in *sinaddr;
139		if (af != AF_INET && af != AF_UNSPEC) {
140			PyErr_SetString(socket_error,
141				"address family mismatched");
142			return -1;
143		}
144		sinaddr = (struct sockaddr_in *)addr_ret;
145		memset((void *) sinaddr, '\0', sizeof(*sinaddr));
146		sinaddr->sin_family = AF_INET;
147		sinaddr->sin_len = sizeof(*sinaddr);
148		sinaddr->sin_addr.s_addr = INADDR_BROADCAST;
149		return sizeof(sinaddr->sin_addr);
150	}
151	if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 &&
152	    0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
153	    0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
154		struct sockaddr_in *sinaddr;
155		sinaddr = (struct sockaddr_in *)addr_ret;
156		sinaddr->sin_addr.s_addr = htonl(
157			((long) d1 << 24) | ((long) d2 << 16) |
158			((long) d3 << 8) | ((long) d4 << 0));
159		sinaddr->sin_family = AF_INET;
160		sinaddr->sin_len = sizeof(*sinaddr);
161		return 4;
162	}
163	memset(&hints, 0, sizeof(hints));
164	hints.ai_family = af;
165	error = getaddrinfo(name, NULL, &hints, &res);
166	if (error) {
167		set_gaierror(error);
168		return -1;
169	}
170	if (res->ai_addrlen < addr_ret_size)
171		addr_ret_size = res->ai_addrlen;
172	memcpy((char *) addr_ret, res->ai_addr, addr_ret_size);
173	freeaddrinfo(res);
174	switch (addr_ret->sa_family) {
175	case AF_INET:
176		return 4;
177	case AF_INET6:
178		return 16;
179	default:
180		PyErr_SetString(socket_error, "unknown address family");
181		return -1;
182	}
183}
184
185PyObject*
186PyObjC_SockAddrToPython(void* value)
187{
188	switch (((struct sockaddr*)value)->sa_family) {
189	case AF_INET:
190		{
191			struct sockaddr_in* a = (struct sockaddr_in*)value;
192			PyObject* addrobj = makeipaddr((struct sockaddr*)a, sizeof(*a));
193			if (addrobj != NULL) {
194				return Py_BuildValue("Ni", addrobj,
195						ntohs(a->sin_port));
196			}
197			return NULL;
198		}
199
200	case AF_INET6:
201		{
202			struct sockaddr_in6* a = (struct sockaddr_in6*)value;
203			PyObject* addrobj = makeipaddr((struct sockaddr*)a, sizeof(*a));
204			if (addrobj != NULL) {
205				return Py_BuildValue("Niii", addrobj,
206						ntohs(a->sin6_port),
207						a->sin6_flowinfo,
208						a->sin6_scope_id);
209			}
210			return NULL;
211		}
212
213	default:
214		PyErr_Format(PyExc_ValueError,
215			"Don't know how to convert sockaddr family %d",
216			((struct sockaddr*)value)->sa_family
217		);
218		return NULL;
219	}
220}
221
222int
223PyObjC_SockAddrFromPython(PyObject* value, void* buffer)
224{
225	if (PyTuple_Size(value) == 2) {
226		/* IPv4 address */
227		struct sockaddr_in* addr = (struct sockaddr_in*)buffer;
228		char* host;
229		int port, result;
230
231		if (!PyArg_ParseTuple(value, "eti:getsockaddrarg",
232				"idna", &host, &port)) {
233			return -1;
234		}
235		result = setipaddr(host, (struct sockaddr*)addr,
236				sizeof(*addr), AF_INET);
237		PyMem_Free(host);
238		if (result < 0) {
239			return -1;
240		}
241		addr->sin_family = AF_INET;
242		addr->sin_port = htons((short)port);
243		return 0;
244
245	} else {
246		/* Must be a IPv6 address */
247		struct sockaddr_in6* addr = (struct sockaddr_in6*)buffer;
248		char* host;
249		int port, flowinfo, scope_id, result;
250
251		flowinfo = scope_id = 0;
252		if (!PyArg_ParseTuple(value, "eti|ii",
253			"idna", &host, &port, &flowinfo, &scope_id))  {
254
255			return -1;
256		}
257		result = setipaddr(host, (struct sockaddr*)addr,
258				sizeof(*addr), AF_INET6);
259		PyMem_Free(host);
260		if (result < 0) {
261			return -1;
262		}
263		addr->sin6_family = AF_INET6;
264		addr->sin6_port = htons((short)port);
265		addr->sin6_flowinfo = flowinfo;
266		addr->sin6_scope_id = scope_id;
267		return 0;
268	}
269}
270