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 }