1 /*=========================================================================*\
2 * Internet domain functions
3 * LuaSocket toolkit
4 *
5 * RCS ID: $Id: inet.c,v 1.28 2005/10/07 04:40:59 diego Exp $
6 \*=========================================================================*/
7 #include <stdio.h>
8 #include <string.h>
9
10 #include "inet.h"
11
12 /*=========================================================================*\
13 * Internal function prototypes.
14 \*=========================================================================*/
15 static int inet_global_toip(lua_State *L);
16 static int inet_global_tohostname(lua_State *L);
17 static void inet_pushresolved(lua_State *L, struct hostent *hp);
18 static int inet_global_gethostname(lua_State *L);
19
20 /* DNS functions */
21 static luaL_Reg func[] = {
22 { "toip", inet_global_toip },
23 { "tohostname", inet_global_tohostname },
24 { "gethostname", inet_global_gethostname},
25 { NULL, NULL}
26 };
27
28 /*=========================================================================*\
29 * Exported functions
30 \*=========================================================================*/
31 /*-------------------------------------------------------------------------*\
32 * Initializes module
33 \*-------------------------------------------------------------------------*/
inet_open(lua_State * L)34 int inet_open(lua_State *L)
35 {
36 lua_pushstring(L, "dns");
37 lua_newtable(L);
38 luaL_openlib(L, NULL, func, 0);
39 lua_settable(L, -3);
40 return 0;
41 }
42
43 /*=========================================================================*\
44 * Global Lua functions
45 \*=========================================================================*/
46 /*-------------------------------------------------------------------------*\
47 * Returns all information provided by the resolver given a host name
48 * or ip address
49 \*-------------------------------------------------------------------------*/
inet_gethost(const char * address,struct hostent ** hp)50 static int inet_gethost(const char *address, struct hostent **hp) {
51 struct in_addr addr;
52 if (inet_aton(address, &addr))
53 return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
54 else
55 return socket_gethostbyname(address, hp);
56 }
57
58 /*-------------------------------------------------------------------------*\
59 * Returns all information provided by the resolver given a host name
60 * or ip address
61 \*-------------------------------------------------------------------------*/
inet_global_tohostname(lua_State * L)62 static int inet_global_tohostname(lua_State *L) {
63 const char *address = luaL_checkstring(L, 1);
64 struct hostent *hp = NULL;
65 int err = inet_gethost(address, &hp);
66 if (err != IO_DONE) {
67 lua_pushnil(L);
68 lua_pushstring(L, socket_hoststrerror(err));
69 return 2;
70 }
71 lua_pushstring(L, hp->h_name);
72 inet_pushresolved(L, hp);
73 return 2;
74 }
75
76 /*-------------------------------------------------------------------------*\
77 * Returns all information provided by the resolver given a host name
78 * or ip address
79 \*-------------------------------------------------------------------------*/
inet_global_toip(lua_State * L)80 static int inet_global_toip(lua_State *L)
81 {
82 const char *address = luaL_checkstring(L, 1);
83 struct hostent *hp = NULL;
84 int err = inet_gethost(address, &hp);
85 if (err != IO_DONE) {
86 lua_pushnil(L);
87 lua_pushstring(L, socket_hoststrerror(err));
88 return 2;
89 }
90 lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
91 inet_pushresolved(L, hp);
92 return 2;
93 }
94
95
96 /*-------------------------------------------------------------------------*\
97 * Gets the host name
98 \*-------------------------------------------------------------------------*/
inet_global_gethostname(lua_State * L)99 static int inet_global_gethostname(lua_State *L)
100 {
101 char name[257];
102 name[256] = '\0';
103 if (gethostname(name, 256) < 0) {
104 lua_pushnil(L);
105 lua_pushstring(L, "gethostname failed");
106 return 2;
107 } else {
108 lua_pushstring(L, name);
109 return 1;
110 }
111 }
112
113
114
115 /*=========================================================================*\
116 * Lua methods
117 \*=========================================================================*/
118 /*-------------------------------------------------------------------------*\
119 * Retrieves socket peer name
120 \*-------------------------------------------------------------------------*/
inet_meth_getpeername(lua_State * L,p_socket ps)121 int inet_meth_getpeername(lua_State *L, p_socket ps)
122 {
123 struct sockaddr_in peer;
124 socklen_t peer_len = sizeof(peer);
125 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
126 lua_pushnil(L);
127 lua_pushstring(L, "getpeername failed");
128 } else {
129 lua_pushstring(L, inet_ntoa(peer.sin_addr));
130 lua_pushnumber(L, ntohs(peer.sin_port));
131 }
132 return 2;
133 }
134
135 /*-------------------------------------------------------------------------*\
136 * Retrieves socket local name
137 \*-------------------------------------------------------------------------*/
inet_meth_getsockname(lua_State * L,p_socket ps)138 int inet_meth_getsockname(lua_State *L, p_socket ps)
139 {
140 struct sockaddr_in local;
141 socklen_t local_len = sizeof(local);
142 if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
143 lua_pushnil(L);
144 lua_pushstring(L, "getsockname failed");
145 } else {
146 lua_pushstring(L, inet_ntoa(local.sin_addr));
147 lua_pushnumber(L, ntohs(local.sin_port));
148 }
149 return 2;
150 }
151
152 /*=========================================================================*\
153 * Internal functions
154 \*=========================================================================*/
155 /*-------------------------------------------------------------------------*\
156 * Passes all resolver information to Lua as a table
157 \*-------------------------------------------------------------------------*/
inet_pushresolved(lua_State * L,struct hostent * hp)158 static void inet_pushresolved(lua_State *L, struct hostent *hp)
159 {
160 char **alias;
161 struct in_addr **addr;
162 int i, resolved;
163 lua_newtable(L); resolved = lua_gettop(L);
164 lua_pushstring(L, "name");
165 lua_pushstring(L, hp->h_name);
166 lua_settable(L, resolved);
167 lua_pushstring(L, "ip");
168 lua_pushstring(L, "alias");
169 i = 1;
170 alias = hp->h_aliases;
171 lua_newtable(L);
172 if (alias) {
173 while (*alias) {
174 lua_pushnumber(L, i);
175 lua_pushstring(L, *alias);
176 lua_settable(L, -3);
177 i++; alias++;
178 }
179 }
180 lua_settable(L, resolved);
181 i = 1;
182 lua_newtable(L);
183 addr = (struct in_addr **) hp->h_addr_list;
184 if (addr) {
185 while (*addr) {
186 lua_pushnumber(L, i);
187 lua_pushstring(L, inet_ntoa(**addr));
188 lua_settable(L, -3);
189 i++; addr++;
190 }
191 }
192 lua_settable(L, resolved);
193 }
194
195 /*-------------------------------------------------------------------------*\
196 * Tries to create a new inet socket
197 \*-------------------------------------------------------------------------*/
inet_trycreate(p_socket ps,int type)198 const char *inet_trycreate(p_socket ps, int type) {
199 return socket_strerror(socket_create(ps, AF_INET, type, 0));
200 }
201
202 /*-------------------------------------------------------------------------*\
203 * Tries to connect to remote address (address, port)
204 \*-------------------------------------------------------------------------*/
inet_tryconnect(p_socket ps,const char * address,unsigned short port,p_timeout tm)205 const char *inet_tryconnect(p_socket ps, const char *address,
206 unsigned short port, p_timeout tm)
207 {
208 struct sockaddr_in remote;
209 int err;
210 memset(&remote, 0, sizeof(remote));
211 remote.sin_family = AF_INET;
212 remote.sin_port = htons(port);
213 if (strcmp(address, "*")) {
214 if (!inet_aton(address, &remote.sin_addr)) {
215 struct hostent *hp = NULL;
216 struct in_addr **addr;
217 err = socket_gethostbyname(address, &hp);
218 if (err != IO_DONE) return socket_hoststrerror(err);
219 addr = (struct in_addr **) hp->h_addr_list;
220 memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
221 }
222 } else remote.sin_family = AF_UNSPEC;
223 err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm);
224 return socket_strerror(err);
225 }
226
227 /*-------------------------------------------------------------------------*\
228 * Tries to bind socket to (address, port)
229 \*-------------------------------------------------------------------------*/
inet_trybind(p_socket ps,const char * address,unsigned short port)230 const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
231 {
232 struct sockaddr_in local;
233 int err;
234 memset(&local, 0, sizeof(local));
235 /* address is either wildcard or a valid ip address */
236 local.sin_addr.s_addr = htonl(INADDR_ANY);
237 local.sin_port = htons(port);
238 local.sin_family = AF_INET;
239 if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
240 struct hostent *hp = NULL;
241 struct in_addr **addr;
242 err = socket_gethostbyname(address, &hp);
243 if (err != IO_DONE) return socket_hoststrerror(err);
244 addr = (struct in_addr **) hp->h_addr_list;
245 memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
246 }
247 err = socket_bind(ps, (SA *) &local, sizeof(local));
248 if (err != IO_DONE) socket_destroy(ps);
249 return socket_strerror(err);
250 }
251
252 /*-------------------------------------------------------------------------*\
253 * Some systems do not provide this so that we provide our own. It's not
254 * marvelously fast, but it works just fine.
255 \*-------------------------------------------------------------------------*/
256 #ifdef INET_ATON
inet_aton(const char * cp,struct in_addr * inp)257 int inet_aton(const char *cp, struct in_addr *inp)
258 {
259 unsigned int a = 0, b = 0, c = 0, d = 0;
260 int n = 0, r;
261 unsigned long int addr = 0;
262 r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
263 if (r == 0 || n == 0) return 0;
264 cp += n;
265 if (*cp) return 0;
266 if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
267 if (inp) {
268 addr += a; addr <<= 8;
269 addr += b; addr <<= 8;
270 addr += c; addr <<= 8;
271 addr += d;
272 inp->s_addr = htonl(addr);
273 }
274 return 1;
275 }
276 #endif
277
278
279