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