diff options
| author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-03-21 13:52:38 +0000 |
|---|---|---|
| committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-03-21 13:52:38 +0000 |
| commit | e2d21b237d0457fde60c1803ee4153ef7238e0eb (patch) | |
| tree | 3bc57dda7863ecf533d2ad517fb7a94c9e4760c1 /src | |
| parent | 29ce2303c8dbbf06015a14dc3a9f8d7e0b814369 (diff) | |
| download | luasocket-e2d21b237d0457fde60c1803ee4153ef7238e0eb.tar.gz luasocket-e2d21b237d0457fde60c1803ee4153ef7238e0eb.tar.bz2 luasocket-e2d21b237d0457fde60c1803ee4153ef7238e0eb.zip | |
Initial revision
Diffstat (limited to 'src')
| -rw-r--r-- | src/inet.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/src/inet.c b/src/inet.c new file mode 100644 index 0000000..f512760 --- /dev/null +++ b/src/inet.c | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | /*=========================================================================*\ | ||
| 2 | * Internet socket methods implementation | ||
| 3 | * Global Lua fuctions: | ||
| 4 | * toip(hostname) | ||
| 5 | * tohostname(dotted-quad) | ||
| 6 | * Socket table methods: | ||
| 7 | * getpeername() | ||
| 8 | * getsockname() | ||
| 9 | \*=========================================================================*/ | ||
| 10 | #include <string.h> | ||
| 11 | |||
| 12 | #include <lua.h> | ||
| 13 | #include <lauxlib.h> | ||
| 14 | |||
| 15 | #include "lsinet.h" | ||
| 16 | #include "lssock.h" | ||
| 17 | #include "lscompat.h" | ||
| 18 | |||
| 19 | /*=========================================================================*\ | ||
| 20 | * Internal function prototypes. | ||
| 21 | \*=========================================================================*/ | ||
| 22 | static int inet_lua_toip(lua_State *L); | ||
| 23 | static int inet_lua_tohostname(lua_State *L); | ||
| 24 | static int inet_lua_getpeername(lua_State *L); | ||
| 25 | static int inet_lua_getsockname(lua_State *L); | ||
| 26 | static void inet_pushresolved(lua_State *L, struct hostent *hp); | ||
| 27 | |||
| 28 | #ifdef COMPAT_INETATON | ||
| 29 | static int inet_aton(cchar *cp, struct in_addr *inp); | ||
| 30 | #endif | ||
| 31 | |||
| 32 | /*=========================================================================*\ | ||
| 33 | * Exported functions | ||
| 34 | \*=========================================================================*/ | ||
| 35 | /*-------------------------------------------------------------------------*\ | ||
| 36 | * Initializes module | ||
| 37 | \*-------------------------------------------------------------------------*/ | ||
| 38 | void inet_open(lua_State *L) | ||
| 39 | { | ||
| 40 | lua_pushcfunction(L, inet_lua_toip); | ||
| 41 | lua_setglobal(L, "toip"); | ||
| 42 | lua_pushcfunction(L, inet_lua_tohostname); | ||
| 43 | lua_setglobal(L, "tohostname"); | ||
| 44 | priv_newglobalmethod(L, "getsockname"); | ||
| 45 | priv_newglobalmethod(L, "getpeername"); | ||
| 46 | } | ||
| 47 | |||
| 48 | /*-------------------------------------------------------------------------*\ | ||
| 49 | * Hook object methods to methods table. | ||
| 50 | \*-------------------------------------------------------------------------*/ | ||
| 51 | void inet_inherit(lua_State *L, cchar *lsclass) | ||
| 52 | { | ||
| 53 | unsigned int i; | ||
| 54 | static struct luaL_reg funcs[] = { | ||
| 55 | {"getsockname", inet_lua_getsockname}, | ||
| 56 | {"getpeername", inet_lua_getpeername}, | ||
| 57 | }; | ||
| 58 | sock_inherit(L, lsclass); | ||
| 59 | for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) { | ||
| 60 | lua_pushcfunction(L, funcs[i].func); | ||
| 61 | priv_setmethod(L, lsclass, funcs[i].name); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | void inet_construct(lua_State *L, p_inet inet) | ||
| 66 | { | ||
| 67 | sock_construct(L, (p_sock) inet); | ||
| 68 | } | ||
| 69 | |||
| 70 | /*=========================================================================*\ | ||
| 71 | * Global Lua functions | ||
| 72 | \*=========================================================================*/ | ||
| 73 | /*-------------------------------------------------------------------------*\ | ||
| 74 | * Returns the list of ip addresses associated with a host name | ||
| 75 | * Lua Input: address | ||
| 76 | * address: ip address or hostname to dns lookup | ||
| 77 | * Lua Returns | ||
| 78 | * On success: first IP address followed by a resolved table | ||
| 79 | * On error: nil, followed by an error message | ||
| 80 | \*-------------------------------------------------------------------------*/ | ||
| 81 | static int inet_lua_toip(lua_State *L) | ||
| 82 | { | ||
| 83 | cchar *address = luaL_check_string(L, 1); | ||
| 84 | struct in_addr addr; | ||
| 85 | struct hostent *hp; | ||
| 86 | if (inet_aton(address, &addr)) | ||
| 87 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); | ||
| 88 | else hp = gethostbyname(address); | ||
| 89 | if (!hp) { | ||
| 90 | lua_pushnil(L); | ||
| 91 | lua_pushstring(L, compat_hoststrerror()); | ||
| 92 | return 2; | ||
| 93 | } | ||
| 94 | addr = *((struct in_addr *) hp->h_addr); | ||
| 95 | lua_pushstring(L, inet_ntoa(addr)); | ||
| 96 | inet_pushresolved(L, hp); | ||
| 97 | return 2; | ||
| 98 | } | ||
| 99 | |||
| 100 | /*-------------------------------------------------------------------------*\ | ||
| 101 | * Returns the list of host names associated with an ip address | ||
| 102 | * Lua Input: address | ||
| 103 | * address: ip address or host name to reverse dns lookup | ||
| 104 | * Lua Returns | ||
| 105 | * On success: canonic name followed by a resolved table | ||
| 106 | * On error: nil, followed by an error message | ||
| 107 | \*-------------------------------------------------------------------------*/ | ||
| 108 | static int inet_lua_tohostname(lua_State *L) | ||
| 109 | { | ||
| 110 | cchar *address = luaL_check_string(L, 1); | ||
| 111 | struct in_addr addr; | ||
| 112 | struct hostent *hp; | ||
| 113 | if (inet_aton(address, &addr)) | ||
| 114 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); | ||
| 115 | else hp = gethostbyname(address); | ||
| 116 | if (!hp) { | ||
| 117 | lua_pushnil(L); | ||
| 118 | lua_pushstring(L, compat_hoststrerror()); | ||
| 119 | return 2; | ||
| 120 | } | ||
| 121 | lua_pushstring(L, hp->h_name); | ||
| 122 | inet_pushresolved(L, hp); | ||
| 123 | return 2; | ||
| 124 | } | ||
| 125 | |||
| 126 | /*=========================================================================*\ | ||
| 127 | * Socket table methods | ||
| 128 | \*=========================================================================*/ | ||
| 129 | /*-------------------------------------------------------------------------*\ | ||
| 130 | * Retrieves socket peer name | ||
| 131 | * Lua Input: sock | ||
| 132 | * sock: socket | ||
| 133 | * Lua Returns | ||
| 134 | * On success: ip address and port of peer | ||
| 135 | * On error: nil | ||
| 136 | \*-------------------------------------------------------------------------*/ | ||
| 137 | static int inet_lua_getpeername(lua_State *L) | ||
| 138 | { | ||
| 139 | p_sock sock = (p_sock) lua_touserdata(L, 1); | ||
| 140 | struct sockaddr_in peer; | ||
| 141 | size_t peer_len = sizeof(peer); | ||
| 142 | if (getpeername(sock->fd, (SA *) &peer, &peer_len) < 0) { | ||
| 143 | lua_pushnil(L); | ||
| 144 | return 1; | ||
| 145 | } | ||
| 146 | lua_pushstring(L, inet_ntoa(peer.sin_addr)); | ||
| 147 | lua_pushnumber(L, ntohs(peer.sin_port)); | ||
| 148 | return 2; | ||
| 149 | } | ||
| 150 | |||
| 151 | /*-------------------------------------------------------------------------*\ | ||
| 152 | * Retrieves socket local name | ||
| 153 | * Lua Input: sock | ||
| 154 | * sock: socket | ||
| 155 | * Lua Returns | ||
| 156 | * On success: local ip address and port | ||
| 157 | * On error: nil | ||
| 158 | \*-------------------------------------------------------------------------*/ | ||
| 159 | static int inet_lua_getsockname(lua_State *L) | ||
| 160 | { | ||
| 161 | p_sock sock = (p_sock) lua_touserdata(L, 1); | ||
| 162 | struct sockaddr_in local; | ||
| 163 | size_t local_len = sizeof(local); | ||
| 164 | if (getsockname(sock->fd, (SA *) &local, &local_len) < 0) { | ||
| 165 | lua_pushnil(L); | ||
| 166 | return 1; | ||
| 167 | } | ||
| 168 | lua_pushstring(L, inet_ntoa(local.sin_addr)); | ||
| 169 | lua_pushnumber(L, ntohs(local.sin_port)); | ||
| 170 | return 2; | ||
| 171 | } | ||
| 172 | |||
| 173 | /*=========================================================================*\ | ||
| 174 | * Internal functions | ||
| 175 | \*=========================================================================*/ | ||
| 176 | /*-------------------------------------------------------------------------*\ | ||
| 177 | * Passes all resolver information to Lua as a table | ||
| 178 | * Input | ||
| 179 | * hp: hostent structure returned by resolver | ||
| 180 | \*-------------------------------------------------------------------------*/ | ||
| 181 | static void inet_pushresolved(lua_State *L, struct hostent *hp) | ||
| 182 | { | ||
| 183 | char **alias; | ||
| 184 | struct in_addr **addr; | ||
| 185 | int i, resolved; | ||
| 186 | lua_newtable(L); resolved = lua_gettop(L); | ||
| 187 | lua_pushstring(L, "name"); | ||
| 188 | lua_pushstring(L, hp->h_name); | ||
| 189 | lua_settable(L, resolved); | ||
| 190 | lua_pushstring(L, "ip"); | ||
| 191 | lua_pushstring(L, "alias"); | ||
| 192 | i = 1; | ||
| 193 | alias = hp->h_aliases; | ||
| 194 | lua_newtable(L); | ||
| 195 | while (*alias) { | ||
| 196 | lua_pushnumber(L, i); | ||
| 197 | lua_pushstring(L, *alias); | ||
| 198 | lua_settable(L, -3); | ||
| 199 | i++; alias++; | ||
| 200 | } | ||
| 201 | lua_settable(L, resolved); | ||
| 202 | i = 1; | ||
| 203 | lua_newtable(L); | ||
| 204 | addr = (struct in_addr **) hp->h_addr_list; | ||
| 205 | while (*addr) { | ||
| 206 | lua_pushnumber(L, i); | ||
| 207 | lua_pushstring(L, inet_ntoa(**addr)); | ||
| 208 | lua_settable(L, -3); | ||
| 209 | i++; addr++; | ||
| 210 | } | ||
| 211 | lua_settable(L, resolved); | ||
| 212 | } | ||
| 213 | |||
| 214 | /*-------------------------------------------------------------------------*\ | ||
| 215 | * Tries to create a TCP socket and connect to remote address (address, port) | ||
| 216 | * Input | ||
| 217 | * client: socket structure to be used | ||
| 218 | * address: host name or ip address | ||
| 219 | * port: port number to bind to | ||
| 220 | * Returns | ||
| 221 | * NULL in case of success, error message otherwise | ||
| 222 | \*-------------------------------------------------------------------------*/ | ||
| 223 | cchar *inet_tryconnect(p_inet inet, cchar *address, ushort port, | ||
| 224 | int type) | ||
| 225 | { | ||
| 226 | struct sockaddr_in remote; | ||
| 227 | cchar *err = NULL; | ||
| 228 | memset(&remote, 0, sizeof(remote)); | ||
| 229 | if (strlen(address) && inet_aton(address, &remote.sin_addr)) { | ||
| 230 | remote.sin_family = AF_INET; | ||
| 231 | remote.sin_port = htons(port); | ||
| 232 | err = inet_trysocket(inet, type); | ||
| 233 | if (err) return err; | ||
| 234 | if (compat_connect(inet->fd, (SA *) &remote, sizeof(remote)) < 0) { | ||
| 235 | compat_close(inet->fd); | ||
| 236 | inet->fd = COMPAT_INVALIDFD; | ||
| 237 | return compat_connectstrerror(); | ||
| 238 | } else return NULL; | ||
| 239 | /* go ahead and try by hostname resolution */ | ||
| 240 | } else { | ||
| 241 | struct hostent *hp = gethostbyname(address); | ||
| 242 | struct in_addr **addr; | ||
| 243 | if (!hp) return compat_hoststrerror(); | ||
| 244 | addr = (struct in_addr **) hp->h_addr_list; | ||
| 245 | for (; *addr != NULL; addr++) { | ||
| 246 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); | ||
| 247 | remote.sin_family = AF_INET; | ||
| 248 | remote.sin_port = htons(port); | ||
| 249 | err = inet_trysocket(inet, type); | ||
| 250 | if (err) return err; | ||
| 251 | if (compat_connect(inet->fd, (SA *)&remote, sizeof(remote)) < 0) { | ||
| 252 | compat_close(inet->fd); | ||
| 253 | inet->fd = COMPAT_INVALIDFD; | ||
| 254 | } else return NULL; | ||
| 255 | memset(&remote, 0, sizeof(remote)); | ||
| 256 | } | ||
| 257 | return compat_connectstrerror(); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | /*-------------------------------------------------------------------------*\ | ||
| 262 | * Tries to create a TCP socket and bind it to (address, port) | ||
| 263 | * Input | ||
| 264 | * address: host name or ip address | ||
| 265 | * port: port number to bind to | ||
| 266 | * backlog: backlog to set | ||
| 267 | * Returns | ||
| 268 | * NULL in case of success, error message otherwise | ||
| 269 | \*-------------------------------------------------------------------------*/ | ||
| 270 | cchar *inet_trybind(p_inet inet, cchar *address, ushort port, | ||
| 271 | int type) | ||
| 272 | { | ||
| 273 | struct sockaddr_in local; | ||
| 274 | cchar *err = NULL; | ||
| 275 | memset(&local, 0, sizeof(local)); | ||
| 276 | /* address is either wildcard or a valid ip address */ | ||
| 277 | local.sin_addr.s_addr = htonl(INADDR_ANY); | ||
| 278 | if (!strcmp(address, "*") || | ||
| 279 | (strlen(address) && inet_aton(address, &local.sin_addr))) { | ||
| 280 | local.sin_port = htons(port); | ||
| 281 | local.sin_family = AF_INET; | ||
| 282 | err = inet_trysocket(inet, type); | ||
| 283 | if (err) return err; | ||
| 284 | compat_setreuseaddr(inet->fd); | ||
| 285 | if (compat_bind(inet->fd, (SA *) &local, sizeof(local)) < 0) { | ||
| 286 | compat_close(inet->fd); | ||
| 287 | inet->fd = COMPAT_INVALIDFD; | ||
| 288 | return compat_bindstrerror(); | ||
| 289 | } else return NULL; | ||
| 290 | /* otherwise, proceed with domain name resolution */ | ||
| 291 | } else { | ||
| 292 | struct hostent *hp = gethostbyname(address); | ||
| 293 | struct in_addr **addr; | ||
| 294 | if (!hp) return compat_hoststrerror(); | ||
| 295 | addr = (struct in_addr **) hp->h_addr_list; | ||
| 296 | for (; *addr != NULL; addr++) { | ||
| 297 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); | ||
| 298 | local.sin_port = htons(port); | ||
| 299 | local.sin_family = AF_INET; | ||
| 300 | err = inet_trysocket(inet, type); | ||
| 301 | if (err) return err; | ||
| 302 | compat_setreuseaddr(inet->fd); | ||
| 303 | if (compat_bind(inet->fd, (SA *) &local, sizeof(local)) < 0) { | ||
| 304 | compat_close(inet->fd); | ||
| 305 | inet->fd = COMPAT_INVALIDFD; | ||
| 306 | } else return NULL; | ||
| 307 | memset(&local, 0, sizeof(local)); | ||
| 308 | } | ||
| 309 | return compat_bindstrerror(); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | /*-------------------------------------------------------------------------*\ | ||
| 314 | * Tries to create a new inet socket | ||
| 315 | * Input | ||
| 316 | * udp: udp structure | ||
| 317 | * Returns | ||
| 318 | * NULL if successfull, error message on error | ||
| 319 | \*-------------------------------------------------------------------------*/ | ||
| 320 | cchar *inet_trysocket(p_inet inet, int type) | ||
| 321 | { | ||
| 322 | if (inet->fd != COMPAT_INVALIDFD) compat_close(inet->fd); | ||
| 323 | inet->fd = compat_socket(AF_INET, type, 0); | ||
| 324 | if (inet->fd == COMPAT_INVALIDFD) return compat_socketstrerror(); | ||
| 325 | else return NULL; | ||
| 326 | } | ||
| 327 | |||
| 328 | /*-------------------------------------------------------------------------*\ | ||
| 329 | * Some systems do not provide this so that we provide our own. It's not | ||
| 330 | * marvelously fast, but it works just fine. | ||
| 331 | \*-------------------------------------------------------------------------*/ | ||
| 332 | #ifdef COMPAT_INETATON | ||
| 333 | static int inet_aton(const char *cp, struct in_addr *inp) | ||
| 334 | { | ||
| 335 | unsigned int a = 0, b = 0, c = 0, d = 0; | ||
| 336 | int n = 0, r; | ||
| 337 | unsigned long int addr = 0; | ||
| 338 | r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); | ||
| 339 | if (r == 0 || n == 0) return 0; | ||
| 340 | cp += n; | ||
| 341 | if (*cp) return 0; | ||
| 342 | if (a > 255 || b > 255 || c > 255 || d > 255) return 0; | ||
| 343 | if (inp) { | ||
| 344 | addr += a; addr <<= 8; | ||
| 345 | addr += b; addr <<= 8; | ||
| 346 | addr += c; addr <<= 8; | ||
| 347 | addr += d; | ||
| 348 | inp->s_addr = htonl(addr); | ||
| 349 | } | ||
| 350 | return 1; | ||
| 351 | } | ||
| 352 | #endif | ||
