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