1/*
2 * Special wrappers for NSNetService methods with 'difficult' arguments.
3 *
4 * -addresses				[call]
5 */
6#include <sys/socket.h>
7#include <netinet/in.h>
8#include <sys/un.h>
9#include <netdb.h>
10
11
12static PyObject *
13makeipaddr(struct sockaddr *addr, int addrlen)
14{
15	char buf[NI_MAXHOST];
16	int error;
17	PyObject* v;
18
19	error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
20		NI_NUMERICHOST);
21	if (error) {
22		v = Py_BuildValue("(is)", error, gai_strerror(error));
23		PyErr_SetObject(PyExc_RuntimeError, v);
24		Py_DECREF(v);
25		return NULL;
26	}
27	return PyBytes_FromString(buf);
28}
29
30static PyObject *
31makesockaddr(struct sockaddr *addr, int addrlen)
32{
33	if (addrlen == 0) {
34		/* No address -- may be recvfrom() from known socket */
35		Py_INCREF(Py_None);
36		return Py_None;
37	}
38
39	switch (addr->sa_family) {
40
41	case AF_INET:
42	{
43		struct sockaddr_in *a;
44		PyObject *addrobj = makeipaddr(addr, sizeof(*a));
45		PyObject *ret = NULL;
46		if (addrobj) {
47			a = (struct sockaddr_in *)addr;
48			ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
49			Py_DECREF(addrobj);
50		}
51		return ret;
52	}
53
54	case AF_UNIX:
55	{
56		struct sockaddr_un *a = (struct sockaddr_un *) addr;
57		return PyBytes_FromString(a->sun_path);
58	}
59
60	case AF_INET6:
61	{
62		struct sockaddr_in6 *a;
63		PyObject *addrobj = makeipaddr(addr, sizeof(*a));
64		PyObject *ret = NULL;
65		if (addrobj) {
66			a = (struct sockaddr_in6 *)addr;
67			ret = Py_BuildValue("Oiii",
68					    addrobj,
69					    ntohs(a->sin6_port),
70					    a->sin6_flowinfo,
71					    a->sin6_scope_id);
72			Py_DECREF(addrobj);
73		}
74		return ret;
75	}
76
77	/* More cases here... */
78
79	default:
80		/* If we don't know the address family, don't raise an
81		   exception -- return it as a tuple. */
82		return Py_BuildValue("is#",
83				     addr->sa_family,
84				     addr->sa_data,
85				     sizeof(addr->sa_data));
86
87	}
88}
89
90static PyObject* call_NSNetService_addresses(
91	PyObject* method, PyObject* self, PyObject* arguments)
92{
93	PyObject* result;
94	struct objc_super super;
95	NSArray*  res;
96	int len, i;
97	NSData* item;
98
99	if  (!PyArg_ParseTuple(arguments, "")) {
100		return NULL;
101	}
102
103	PyObjC_DURING
104		PyObjC_InitSuper(&super,
105			PyObjCSelector_GetClass(method),
106			PyObjCObject_GetObject(self));
107
108
109		res = ((id(*)(struct objc_super*, SEL))objc_msgSendSuper)(&super, @selector(addresses));
110	PyObjC_HANDLER
111		PyObjCErr_FromObjC(localException);
112		res = nil;
113	PyObjC_ENDHANDLER
114
115	if (res == nil && PyErr_Occurred()) {
116		return NULL;
117	}
118
119	if (res == nil) {
120		Py_INCREF(Py_None);
121		return Py_None;
122	}
123
124	len = [res count];
125	result = PyTuple_New(len);
126	if (result == NULL) {
127		return NULL;
128	}
129
130	for (i = 0; i < len; i++) {
131
132		PyObject* v;
133
134		item = [res objectAtIndex:i];
135
136		v = makesockaddr((struct sockaddr*)[item bytes], [item length]);
137		if (v == NULL) {
138			Py_DECREF(result);
139			return NULL;
140		}
141		PyTuple_SET_ITEM(result, i, v);
142	}
143
144	return result;
145}
146
147
148static int setup_nsnetservice(PyObject* m __attribute__((__unused__)))
149{
150	Class classNSNetService = objc_lookUpClass("NSNetService");
151	if (classNSNetService == NULL) {
152		return 0;
153	}
154
155	if (PyObjC_RegisterMethodMapping(
156		classNSNetService,
157		@selector(addresses),
158		call_NSNetService_addresses,
159		PyObjCUnsupportedMethod_IMP) < 0) {
160
161		return -1;
162	}
163
164	return 0;
165}
166