aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2002-03-21 13:52:38 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2002-03-21 13:52:38 +0000
commite2d21b237d0457fde60c1803ee4153ef7238e0eb (patch)
tree3bc57dda7863ecf533d2ad517fb7a94c9e4760c1 /src
parent29ce2303c8dbbf06015a14dc3a9f8d7e0b814369 (diff)
downloadluasocket-e2d21b237d0457fde60c1803ee4153ef7238e0eb.tar.gz
luasocket-e2d21b237d0457fde60c1803ee4153ef7238e0eb.tar.bz2
luasocket-e2d21b237d0457fde60c1803ee4153ef7238e0eb.zip
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/inet.c352
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\*=========================================================================*/
22static int inet_lua_toip(lua_State *L);
23static int inet_lua_tohostname(lua_State *L);
24static int inet_lua_getpeername(lua_State *L);
25static int inet_lua_getsockname(lua_State *L);
26static void inet_pushresolved(lua_State *L, struct hostent *hp);
27
28#ifdef COMPAT_INETATON
29static int inet_aton(cchar *cp, struct in_addr *inp);
30#endif
31
32/*=========================================================================*\
33* Exported functions
34\*=========================================================================*/
35/*-------------------------------------------------------------------------*\
36* Initializes module
37\*-------------------------------------------------------------------------*/
38void 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\*-------------------------------------------------------------------------*/
51void 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
65void 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\*-------------------------------------------------------------------------*/
81static 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\*-------------------------------------------------------------------------*/
108static 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\*-------------------------------------------------------------------------*/
137static 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\*-------------------------------------------------------------------------*/
159static 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\*-------------------------------------------------------------------------*/
181static 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\*-------------------------------------------------------------------------*/
223cchar *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\*-------------------------------------------------------------------------*/
270cchar *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\*-------------------------------------------------------------------------*/
320cchar *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
333static 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