Mercurial > luasocket
comparison src/udp.c @ 0:4b915342e2a8
LuaSocket 2.0.2 + CMake build description.
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Tue, 26 Aug 2008 18:40:01 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4b915342e2a8 |
---|---|
1 /*=========================================================================*\ | |
2 * UDP object | |
3 * LuaSocket toolkit | |
4 * | |
5 * RCS ID: $Id: udp.c,v 1.29 2005/10/07 04:40:59 diego Exp $ | |
6 \*=========================================================================*/ | |
7 #include <string.h> | |
8 | |
9 #include "lua.h" | |
10 #include "lauxlib.h" | |
11 | |
12 #include "auxiliar.h" | |
13 #include "socket.h" | |
14 #include "inet.h" | |
15 #include "options.h" | |
16 #include "udp.h" | |
17 | |
18 /* min and max macros */ | |
19 #ifndef MIN | |
20 #define MIN(x, y) ((x) < (y) ? x : y) | |
21 #endif | |
22 #ifndef MAX | |
23 #define MAX(x, y) ((x) > (y) ? x : y) | |
24 #endif | |
25 | |
26 /*=========================================================================*\ | |
27 * Internal function prototypes | |
28 \*=========================================================================*/ | |
29 static int global_create(lua_State *L); | |
30 static int meth_send(lua_State *L); | |
31 static int meth_sendto(lua_State *L); | |
32 static int meth_receive(lua_State *L); | |
33 static int meth_receivefrom(lua_State *L); | |
34 static int meth_getsockname(lua_State *L); | |
35 static int meth_getpeername(lua_State *L); | |
36 static int meth_setsockname(lua_State *L); | |
37 static int meth_setpeername(lua_State *L); | |
38 static int meth_close(lua_State *L); | |
39 static int meth_setoption(lua_State *L); | |
40 static int meth_settimeout(lua_State *L); | |
41 static int meth_getfd(lua_State *L); | |
42 static int meth_setfd(lua_State *L); | |
43 static int meth_dirty(lua_State *L); | |
44 | |
45 /* udp object methods */ | |
46 static luaL_reg udp[] = { | |
47 {"__gc", meth_close}, | |
48 {"__tostring", auxiliar_tostring}, | |
49 {"close", meth_close}, | |
50 {"dirty", meth_dirty}, | |
51 {"getfd", meth_getfd}, | |
52 {"getpeername", meth_getpeername}, | |
53 {"getsockname", meth_getsockname}, | |
54 {"receive", meth_receive}, | |
55 {"receivefrom", meth_receivefrom}, | |
56 {"send", meth_send}, | |
57 {"sendto", meth_sendto}, | |
58 {"setfd", meth_setfd}, | |
59 {"setoption", meth_setoption}, | |
60 {"setpeername", meth_setpeername}, | |
61 {"setsockname", meth_setsockname}, | |
62 {"settimeout", meth_settimeout}, | |
63 {NULL, NULL} | |
64 }; | |
65 | |
66 /* socket options */ | |
67 static t_opt opt[] = { | |
68 {"dontroute", opt_dontroute}, | |
69 {"broadcast", opt_broadcast}, | |
70 {"reuseaddr", opt_reuseaddr}, | |
71 {"ip-multicast-ttl", opt_ip_multicast_ttl}, | |
72 {"ip-multicast-loop", opt_ip_multicast_loop}, | |
73 {"ip-add-membership", opt_ip_add_membership}, | |
74 {"ip-drop-membership", opt_ip_drop_membersip}, | |
75 {NULL, NULL} | |
76 }; | |
77 | |
78 /* functions in library namespace */ | |
79 static luaL_reg func[] = { | |
80 {"udp", global_create}, | |
81 {NULL, NULL} | |
82 }; | |
83 | |
84 /*-------------------------------------------------------------------------*\ | |
85 * Initializes module | |
86 \*-------------------------------------------------------------------------*/ | |
87 int udp_open(lua_State *L) | |
88 { | |
89 /* create classes */ | |
90 auxiliar_newclass(L, "udp{connected}", udp); | |
91 auxiliar_newclass(L, "udp{unconnected}", udp); | |
92 /* create class groups */ | |
93 auxiliar_add2group(L, "udp{connected}", "udp{any}"); | |
94 auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); | |
95 auxiliar_add2group(L, "udp{connected}", "select{able}"); | |
96 auxiliar_add2group(L, "udp{unconnected}", "select{able}"); | |
97 /* define library functions */ | |
98 luaL_openlib(L, NULL, func, 0); | |
99 return 0; | |
100 } | |
101 | |
102 /*=========================================================================*\ | |
103 * Lua methods | |
104 \*=========================================================================*/ | |
105 const char *udp_strerror(int err) { | |
106 /* a 'closed' error on an unconnected means the target address was not | |
107 * accepted by the transport layer */ | |
108 if (err == IO_CLOSED) return "refused"; | |
109 else return socket_strerror(err); | |
110 } | |
111 | |
112 /*-------------------------------------------------------------------------*\ | |
113 * Send data through connected udp socket | |
114 \*-------------------------------------------------------------------------*/ | |
115 static int meth_send(lua_State *L) { | |
116 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); | |
117 p_timeout tm = &udp->tm; | |
118 size_t count, sent = 0; | |
119 int err; | |
120 const char *data = luaL_checklstring(L, 2, &count); | |
121 timeout_markstart(tm); | |
122 err = socket_send(&udp->sock, data, count, &sent, tm); | |
123 if (err != IO_DONE) { | |
124 lua_pushnil(L); | |
125 lua_pushstring(L, udp_strerror(err)); | |
126 return 2; | |
127 } | |
128 lua_pushnumber(L, sent); | |
129 return 1; | |
130 } | |
131 | |
132 /*-------------------------------------------------------------------------*\ | |
133 * Send data through unconnected udp socket | |
134 \*-------------------------------------------------------------------------*/ | |
135 static int meth_sendto(lua_State *L) { | |
136 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); | |
137 size_t count, sent = 0; | |
138 const char *data = luaL_checklstring(L, 2, &count); | |
139 const char *ip = luaL_checkstring(L, 3); | |
140 unsigned short port = (unsigned short) luaL_checknumber(L, 4); | |
141 p_timeout tm = &udp->tm; | |
142 struct sockaddr_in addr; | |
143 int err; | |
144 memset(&addr, 0, sizeof(addr)); | |
145 if (!inet_aton(ip, &addr.sin_addr)) | |
146 luaL_argerror(L, 3, "invalid ip address"); | |
147 addr.sin_family = AF_INET; | |
148 addr.sin_port = htons(port); | |
149 timeout_markstart(tm); | |
150 err = socket_sendto(&udp->sock, data, count, &sent, | |
151 (SA *) &addr, sizeof(addr), tm); | |
152 if (err != IO_DONE) { | |
153 lua_pushnil(L); | |
154 lua_pushstring(L, udp_strerror(err)); | |
155 return 2; | |
156 } | |
157 lua_pushnumber(L, sent); | |
158 return 1; | |
159 } | |
160 | |
161 /*-------------------------------------------------------------------------*\ | |
162 * Receives data from a UDP socket | |
163 \*-------------------------------------------------------------------------*/ | |
164 static int meth_receive(lua_State *L) { | |
165 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
166 char buffer[UDP_DATAGRAMSIZE]; | |
167 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | |
168 int err; | |
169 p_timeout tm = &udp->tm; | |
170 count = MIN(count, sizeof(buffer)); | |
171 timeout_markstart(tm); | |
172 err = socket_recv(&udp->sock, buffer, count, &got, tm); | |
173 if (err != IO_DONE) { | |
174 lua_pushnil(L); | |
175 lua_pushstring(L, udp_strerror(err)); | |
176 return 2; | |
177 } | |
178 lua_pushlstring(L, buffer, got); | |
179 return 1; | |
180 } | |
181 | |
182 /*-------------------------------------------------------------------------*\ | |
183 * Receives data and sender from a UDP socket | |
184 \*-------------------------------------------------------------------------*/ | |
185 static int meth_receivefrom(lua_State *L) { | |
186 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); | |
187 struct sockaddr_in addr; | |
188 socklen_t addr_len = sizeof(addr); | |
189 char buffer[UDP_DATAGRAMSIZE]; | |
190 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | |
191 int err; | |
192 p_timeout tm = &udp->tm; | |
193 timeout_markstart(tm); | |
194 count = MIN(count, sizeof(buffer)); | |
195 err = socket_recvfrom(&udp->sock, buffer, count, &got, | |
196 (SA *) &addr, &addr_len, tm); | |
197 if (err == IO_DONE) { | |
198 lua_pushlstring(L, buffer, got); | |
199 lua_pushstring(L, inet_ntoa(addr.sin_addr)); | |
200 lua_pushnumber(L, ntohs(addr.sin_port)); | |
201 return 3; | |
202 } else { | |
203 lua_pushnil(L); | |
204 lua_pushstring(L, udp_strerror(err)); | |
205 return 2; | |
206 } | |
207 } | |
208 | |
209 /*-------------------------------------------------------------------------*\ | |
210 * Select support methods | |
211 \*-------------------------------------------------------------------------*/ | |
212 static int meth_getfd(lua_State *L) { | |
213 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
214 lua_pushnumber(L, (int) udp->sock); | |
215 return 1; | |
216 } | |
217 | |
218 /* this is very dangerous, but can be handy for those that are brave enough */ | |
219 static int meth_setfd(lua_State *L) { | |
220 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
221 udp->sock = (t_socket) luaL_checknumber(L, 2); | |
222 return 0; | |
223 } | |
224 | |
225 static int meth_dirty(lua_State *L) { | |
226 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
227 (void) udp; | |
228 lua_pushboolean(L, 0); | |
229 return 1; | |
230 } | |
231 | |
232 /*-------------------------------------------------------------------------*\ | |
233 * Just call inet methods | |
234 \*-------------------------------------------------------------------------*/ | |
235 static int meth_getpeername(lua_State *L) { | |
236 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); | |
237 return inet_meth_getpeername(L, &udp->sock); | |
238 } | |
239 | |
240 static int meth_getsockname(lua_State *L) { | |
241 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
242 return inet_meth_getsockname(L, &udp->sock); | |
243 } | |
244 | |
245 /*-------------------------------------------------------------------------*\ | |
246 * Just call option handler | |
247 \*-------------------------------------------------------------------------*/ | |
248 static int meth_setoption(lua_State *L) { | |
249 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
250 return opt_meth_setoption(L, opt, &udp->sock); | |
251 } | |
252 | |
253 /*-------------------------------------------------------------------------*\ | |
254 * Just call tm methods | |
255 \*-------------------------------------------------------------------------*/ | |
256 static int meth_settimeout(lua_State *L) { | |
257 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
258 return timeout_meth_settimeout(L, &udp->tm); | |
259 } | |
260 | |
261 /*-------------------------------------------------------------------------*\ | |
262 * Turns a master udp object into a client object. | |
263 \*-------------------------------------------------------------------------*/ | |
264 static int meth_setpeername(lua_State *L) { | |
265 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
266 p_timeout tm = &udp->tm; | |
267 const char *address = luaL_checkstring(L, 2); | |
268 int connecting = strcmp(address, "*"); | |
269 unsigned short port = connecting ? | |
270 (unsigned short) luaL_checknumber(L, 3) : | |
271 (unsigned short) luaL_optnumber(L, 3, 0); | |
272 const char *err = inet_tryconnect(&udp->sock, address, port, tm); | |
273 if (err) { | |
274 lua_pushnil(L); | |
275 lua_pushstring(L, err); | |
276 return 2; | |
277 } | |
278 /* change class to connected or unconnected depending on address */ | |
279 if (connecting) auxiliar_setclass(L, "udp{connected}", 1); | |
280 else auxiliar_setclass(L, "udp{unconnected}", 1); | |
281 lua_pushnumber(L, 1); | |
282 return 1; | |
283 } | |
284 | |
285 /*-------------------------------------------------------------------------*\ | |
286 * Closes socket used by object | |
287 \*-------------------------------------------------------------------------*/ | |
288 static int meth_close(lua_State *L) { | |
289 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); | |
290 socket_destroy(&udp->sock); | |
291 lua_pushnumber(L, 1); | |
292 return 1; | |
293 } | |
294 | |
295 /*-------------------------------------------------------------------------*\ | |
296 * Turns a master object into a server object | |
297 \*-------------------------------------------------------------------------*/ | |
298 static int meth_setsockname(lua_State *L) { | |
299 p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); | |
300 const char *address = luaL_checkstring(L, 2); | |
301 unsigned short port = (unsigned short) luaL_checknumber(L, 3); | |
302 const char *err = inet_trybind(&udp->sock, address, port); | |
303 if (err) { | |
304 lua_pushnil(L); | |
305 lua_pushstring(L, err); | |
306 return 2; | |
307 } | |
308 lua_pushnumber(L, 1); | |
309 return 1; | |
310 } | |
311 | |
312 /*=========================================================================*\ | |
313 * Library functions | |
314 \*=========================================================================*/ | |
315 /*-------------------------------------------------------------------------*\ | |
316 * Creates a master udp object | |
317 \*-------------------------------------------------------------------------*/ | |
318 static int global_create(lua_State *L) { | |
319 t_socket sock; | |
320 const char *err = inet_trycreate(&sock, SOCK_DGRAM); | |
321 /* try to allocate a system socket */ | |
322 if (!err) { | |
323 /* allocate tcp object */ | |
324 p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); | |
325 auxiliar_setclass(L, "udp{unconnected}", -1); | |
326 /* initialize remaining structure fields */ | |
327 socket_setnonblocking(&sock); | |
328 udp->sock = sock; | |
329 timeout_init(&udp->tm, -1, -1); | |
330 return 1; | |
331 } else { | |
332 lua_pushnil(L); | |
333 lua_pushstring(L, err); | |
334 return 2; | |
335 } | |
336 } |