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