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