diff options
author | Sam Roberts <vieuxtech@gmail.com> | 2012-05-10 14:14:22 -0700 |
---|---|---|
committer | Sam Roberts <vieuxtech@gmail.com> | 2012-05-10 14:14:22 -0700 |
commit | 156669c28bc62bfddbd5625c4bb4c1f8da94802b (patch) | |
tree | 074ea57dd044a9bed306464af8c9f141bdf0ca19 /src/inet.c | |
parent | 3d3e69c6e43f6431969e072e78df43b0ab73c48d (diff) | |
download | luasocket-156669c28bc62bfddbd5625c4bb4c1f8da94802b.tar.gz luasocket-156669c28bc62bfddbd5625c4bb4c1f8da94802b.tar.bz2 luasocket-156669c28bc62bfddbd5625c4bb4c1f8da94802b.zip |
socket.connect now implemented in the C core
This avoid socket.lua duplicating the iteration over the results
of getaddrinfo(). Some problems with the C implementation not
initializing sockets or the luasocket family have also been fixed,
and error reporting made more robust.
Diffstat (limited to 'src/inet.c')
-rw-r--r-- | src/inet.c | 54 |
1 files changed, 42 insertions, 12 deletions
@@ -143,6 +143,22 @@ static int inet_global_toip(lua_State *L) | |||
143 | return 2; | 143 | return 2; |
144 | } | 144 | } |
145 | 145 | ||
146 | int inet_optfamily(lua_State* L, int narg, const char* def) | ||
147 | { | ||
148 | static const char* optname[] = { "unspec", "inet", "inet6", NULL }; | ||
149 | static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 }; | ||
150 | |||
151 | return optvalue[luaL_checkoption(L, narg, def, optname)]; | ||
152 | } | ||
153 | |||
154 | int inet_optsocktype(lua_State* L, int narg, const char* def) | ||
155 | { | ||
156 | static const char* optname[] = { "stream", "dgram", NULL }; | ||
157 | static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; | ||
158 | |||
159 | return optvalue[luaL_checkoption(L, narg, def, optname)]; | ||
160 | } | ||
161 | |||
146 | static int inet_global_getaddrinfo(lua_State *L) | 162 | static int inet_global_getaddrinfo(lua_State *L) |
147 | { | 163 | { |
148 | const char *hostname = luaL_checkstring(L, 1); | 164 | const char *hostname = luaL_checkstring(L, 1); |
@@ -197,7 +213,7 @@ static int inet_global_gethostname(lua_State *L) | |||
197 | name[256] = '\0'; | 213 | name[256] = '\0'; |
198 | if (gethostname(name, 256) < 0) { | 214 | if (gethostname(name, 256) < 0) { |
199 | lua_pushnil(L); | 215 | lua_pushnil(L); |
200 | lua_pushstring(L, "gethostname failed"); | 216 | lua_pushstring(L, socket_strerror(errno)); |
201 | return 2; | 217 | return 2; |
202 | } else { | 218 | } else { |
203 | lua_pushstring(L, name); | 219 | lua_pushstring(L, name); |
@@ -222,7 +238,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family) | |||
222 | char name[INET_ADDRSTRLEN]; | 238 | char name[INET_ADDRSTRLEN]; |
223 | if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { | 239 | if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { |
224 | lua_pushnil(L); | 240 | lua_pushnil(L); |
225 | lua_pushstring(L, "getpeername failed"); | 241 | lua_pushstring(L, socket_strerror(errno)); |
226 | return 2; | 242 | return 2; |
227 | } else { | 243 | } else { |
228 | inet_ntop(family, &peer.sin_addr, name, sizeof(name)); | 244 | inet_ntop(family, &peer.sin_addr, name, sizeof(name)); |
@@ -238,7 +254,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family) | |||
238 | char name[INET6_ADDRSTRLEN]; | 254 | char name[INET6_ADDRSTRLEN]; |
239 | if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { | 255 | if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { |
240 | lua_pushnil(L); | 256 | lua_pushnil(L); |
241 | lua_pushstring(L, "getpeername failed"); | 257 | lua_pushstring(L, socket_strerror(errno)); |
242 | return 2; | 258 | return 2; |
243 | } else { | 259 | } else { |
244 | inet_ntop(family, &peer.sin6_addr, name, sizeof(name)); | 260 | inet_ntop(family, &peer.sin6_addr, name, sizeof(name)); |
@@ -251,7 +267,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family) | |||
251 | } | 267 | } |
252 | default: | 268 | default: |
253 | lua_pushnil(L); | 269 | lua_pushnil(L); |
254 | lua_pushstring(L, "unknown family"); | 270 | lua_pushfstring(L, "unknown family %d", family); |
255 | return 2; | 271 | return 2; |
256 | } | 272 | } |
257 | } | 273 | } |
@@ -268,7 +284,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) | |||
268 | char name[INET_ADDRSTRLEN]; | 284 | char name[INET_ADDRSTRLEN]; |
269 | if (getsockname(*ps, (SA *) &local, &local_len) < 0) { | 285 | if (getsockname(*ps, (SA *) &local, &local_len) < 0) { |
270 | lua_pushnil(L); | 286 | lua_pushnil(L); |
271 | lua_pushstring(L, "getsockname failed"); | 287 | lua_pushstring(L, socket_strerror(errno)); |
272 | return 2; | 288 | return 2; |
273 | } else { | 289 | } else { |
274 | inet_ntop(family, &local.sin_addr, name, sizeof(name)); | 290 | inet_ntop(family, &local.sin_addr, name, sizeof(name)); |
@@ -284,7 +300,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) | |||
284 | char name[INET6_ADDRSTRLEN]; | 300 | char name[INET6_ADDRSTRLEN]; |
285 | if (getsockname(*ps, (SA *) &local, &local_len) < 0) { | 301 | if (getsockname(*ps, (SA *) &local, &local_len) < 0) { |
286 | lua_pushnil(L); | 302 | lua_pushnil(L); |
287 | lua_pushstring(L, "getsockname failed"); | 303 | lua_pushstring(L, socket_strerror(errno)); |
288 | return 2; | 304 | return 2; |
289 | } else { | 305 | } else { |
290 | inet_ntop(family, &local.sin6_addr, name, sizeof(name)); | 306 | inet_ntop(family, &local.sin6_addr, name, sizeof(name)); |
@@ -296,7 +312,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) | |||
296 | } | 312 | } |
297 | default: | 313 | default: |
298 | lua_pushnil(L); | 314 | lua_pushnil(L); |
299 | lua_pushstring(L, "unknown family"); | 315 | lua_pushfstring(L, "unknown family %d", family); |
300 | return 2; | 316 | return 2; |
301 | } | 317 | } |
302 | } | 318 | } |
@@ -390,6 +406,7 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv, | |||
390 | { | 406 | { |
391 | struct addrinfo *iterator = NULL, *resolved = NULL; | 407 | struct addrinfo *iterator = NULL, *resolved = NULL; |
392 | const char *err = NULL; | 408 | const char *err = NULL; |
409 | t_socket sock = *ps; | ||
393 | /* translate luasocket special values to C */ | 410 | /* translate luasocket special values to C */ |
394 | if (strcmp(address, "*") == 0) address = NULL; | 411 | if (strcmp(address, "*") == 0) address = NULL; |
395 | if (!serv) serv = "0"; | 412 | if (!serv) serv = "0"; |
@@ -402,17 +419,30 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv, | |||
402 | } | 419 | } |
403 | /* iterate over resolved addresses until one is good */ | 420 | /* iterate over resolved addresses until one is good */ |
404 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | 421 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { |
422 | if(sock == SOCKET_INVALID) { | ||
423 | err = socket_strerror( socket_create(&sock, iterator->ai_family, | ||
424 | iterator->ai_socktype, iterator->ai_protocol)); | ||
425 | if(err) | ||
426 | continue; | ||
427 | } | ||
405 | /* try binding to local address */ | 428 | /* try binding to local address */ |
406 | err = socket_strerror(socket_bind(ps, | 429 | err = socket_strerror(socket_bind(&sock, |
407 | (SA *) iterator->ai_addr, | 430 | (SA *) iterator->ai_addr, |
408 | iterator->ai_addrlen)); | 431 | iterator->ai_addrlen)); |
409 | /* if faiiled, we try the next one */ | 432 | |
410 | if (err != NULL) socket_destroy(ps); | 433 | /* keep trying unless bind succeeded */ |
411 | /* if success, we abort loop */ | 434 | if (err) { |
412 | else break; | 435 | if(sock != *ps) |
436 | socket_destroy(&sock); | ||
437 | } else { | ||
438 | /* remember what we connected to, particularly the family */ | ||
439 | *bindhints = *iterator; | ||
440 | break; | ||
441 | } | ||
413 | } | 442 | } |
414 | /* cleanup and return error */ | 443 | /* cleanup and return error */ |
415 | freeaddrinfo(resolved); | 444 | freeaddrinfo(resolved); |
445 | *ps = sock; | ||
416 | return err; | 446 | return err; |
417 | } | 447 | } |
418 | 448 | ||