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 | ||