aboutsummaryrefslogtreecommitdiff
path: root/src/usocket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usocket.c')
-rw-r--r--src/usocket.c347
1 files changed, 347 insertions, 0 deletions
diff --git a/src/usocket.c b/src/usocket.c
new file mode 100644
index 0000000..b4b8d5a
--- /dev/null
+++ b/src/usocket.c
@@ -0,0 +1,347 @@
1/*=========================================================================*\
2* Socket compatibilization module for Unix
3*
4* RCS ID: $Id$
5\*=========================================================================*/
6#include <lua.h>
7#include <lauxlib.h>
8#include <string.h>
9
10#include "sock.h"
11
12/*=========================================================================*\
13* Internal function prototypes
14\*=========================================================================*/
15static const char *try_setoption(lua_State *L, p_sock ps);
16static const char *try_setbooloption(lua_State *L, p_sock ps, int name);
17
18/*=========================================================================*\
19* Exported functions.
20\*=========================================================================*/
21int sock_open(lua_State *L)
22{
23 /* instals a handler to ignore sigpipe. */
24 struct sigaction new;
25 memset(&new, 0, sizeof(new));
26 new.sa_handler = SIG_IGN;
27 sigaction(SIGPIPE, &new, NULL);
28 return 1;
29}
30
31void sock_destroy(p_sock ps)
32{
33 close(*ps);
34}
35
36const char *sock_create(p_sock ps, int domain, int type, int protocol)
37{
38 t_sock sock = socket(domain, type, protocol);
39 if (sock == SOCK_INVALID) return sock_createstrerror();
40 *ps = sock;
41 sock_setnonblocking(ps);
42 sock_setreuseaddr(ps);
43 return NULL;
44}
45
46const char *sock_connect(p_sock ps, SA *addr, size_t addr_len)
47{
48 if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror();
49 else return NULL;
50}
51
52const char *sock_bind(p_sock ps, SA *addr, size_t addr_len)
53{
54 if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror();
55 else return NULL;
56}
57
58void sock_listen(p_sock ps, int backlog)
59{
60 listen(*ps, backlog);
61}
62
63void sock_accept(p_sock ps, p_sock pa, SA *addr, size_t *addr_len, int timeout)
64{
65 t_sock sock = *ps;
66 struct timeval tv;
67 fd_set fds;
68 tv.tv_sec = timeout / 1000;
69 tv.tv_usec = (timeout % 1000) * 1000;
70 FD_ZERO(&fds);
71 FD_SET(sock, &fds);
72 select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
73 *pa = accept(sock, addr, addr_len);
74}
75
76int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
77 int timeout)
78{
79 t_sock sock = *ps;
80 struct timeval tv;
81 fd_set fds;
82 ssize_t put = 0;
83 int err;
84 int ret;
85 tv.tv_sec = timeout / 1000;
86 tv.tv_usec = (timeout % 1000) * 1000;
87 FD_ZERO(&fds);
88 FD_SET(sock, &fds);
89 ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
90 if (ret > 0) {
91 put = write(sock, data, count);
92 if (put <= 0) {
93 err = IO_CLOSED;
94#ifdef __CYGWIN__
95 /* this is for CYGWIN, which is like Unix but has Win32 bugs */
96 if (errno == EWOULDBLOCK) err = IO_DONE;
97#endif
98 *sent = 0;
99 } else {
100 *sent = put;
101 err = IO_DONE;
102 }
103 return err;
104 } else {
105 *sent = 0;
106 return IO_TIMEOUT;
107 }
108}
109
110int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
111 SA *addr, size_t addr_len, int timeout)
112{
113 t_sock sock = *ps;
114 struct timeval tv;
115 fd_set fds;
116 ssize_t put = 0;
117 int err;
118 int ret;
119 tv.tv_sec = timeout / 1000;
120 tv.tv_usec = (timeout % 1000) * 1000;
121 FD_ZERO(&fds);
122 FD_SET(sock, &fds);
123 ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL);
124 if (ret > 0) {
125 put = sendto(sock, data, count, 0, addr, addr_len);
126 if (put <= 0) {
127 err = IO_CLOSED;
128#ifdef __CYGWIN__
129 /* this is for CYGWIN, which is like Unix but has Win32 bugs */
130 if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE;
131#endif
132 *sent = 0;
133 } else {
134 *sent = put;
135 err = IO_DONE;
136 }
137 return err;
138 } else {
139 *sent = 0;
140 return IO_TIMEOUT;
141 }
142}
143
144int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
145{
146 t_sock sock = *ps;
147 struct timeval tv;
148 fd_set fds;
149 int ret;
150 ssize_t taken = 0;
151 tv.tv_sec = timeout / 1000;
152 tv.tv_usec = (timeout % 1000) * 1000;
153 FD_ZERO(&fds);
154 FD_SET(sock, &fds);
155 ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
156 if (ret > 0) {
157 taken = read(sock, data, count);
158 if (taken <= 0) {
159 *got = 0;
160 return IO_CLOSED;
161 } else {
162 *got = taken;
163 return IO_DONE;
164 }
165 } else {
166 *got = 0;
167 return IO_TIMEOUT;
168 }
169}
170
171int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
172 SA *addr, size_t *addr_len, int timeout)
173{
174 t_sock sock = *ps;
175 struct timeval tv;
176 fd_set fds;
177 int ret;
178 ssize_t taken = 0;
179 tv.tv_sec = timeout / 1000;
180 tv.tv_usec = (timeout % 1000) * 1000;
181 FD_ZERO(&fds);
182 FD_SET(sock, &fds);
183 ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
184 if (ret > 0) {
185 taken = recvfrom(sock, data, count, 0, addr, addr_len);
186 if (taken <= 0) {
187 *got = 0;
188 return IO_CLOSED;
189 } else {
190 *got = taken;
191 return IO_DONE;
192 }
193 } else {
194 *got = 0;
195 return IO_TIMEOUT;
196 }
197}
198
199/*-------------------------------------------------------------------------*\
200* Returns a string describing the last host manipulation error.
201\*-------------------------------------------------------------------------*/
202const char *sock_hoststrerror(void)
203{
204 switch (h_errno) {
205 case HOST_NOT_FOUND: return "host not found";
206 case NO_ADDRESS: return "unable to resolve host name";
207 case NO_RECOVERY: return "name server error";
208 case TRY_AGAIN: return "name server unavailable, try again later";
209 default: return "unknown error";
210 }
211}
212
213/*-------------------------------------------------------------------------*\
214* Returns a string describing the last socket manipulation error.
215\*-------------------------------------------------------------------------*/
216const char *sock_createstrerror(void)
217{
218 switch (errno) {
219 case EACCES: return "access denied";
220 case EMFILE: return "descriptor table is full";
221 case ENFILE: return "too many open files";
222 case ENOBUFS: return "insuffucient buffer space";
223 default: return "unknown error";
224 }
225}
226
227/*-------------------------------------------------------------------------*\
228* Returns a string describing the last bind command error.
229\*-------------------------------------------------------------------------*/
230const char *sock_bindstrerror(void)
231{
232 switch (errno) {
233 case EBADF: return "invalid descriptor";
234 case EINVAL: return "socket already bound";
235 case EACCES: return "access denied";
236 case ENOTSOCK: return "not a socket descriptor";
237 case EADDRINUSE: return "address already in use";
238 case EADDRNOTAVAIL: return "address unavailable";
239 case ENOMEM: return "out of memory";
240 default: return "unknown error";
241 }
242}
243
244/*-------------------------------------------------------------------------*\
245* Returns a string describing the last connect error.
246\*-------------------------------------------------------------------------*/
247const char *sock_connectstrerror(void)
248{
249 switch (errno) {
250 case EBADF: return "invalid descriptor";
251 case ENOTSOCK: return "not a socket descriptor";
252 case EADDRNOTAVAIL: return "address not availabe";
253 case ETIMEDOUT: return "connection timed out";
254 case ECONNREFUSED: return "connection refused";
255 case EACCES: return "access denied";
256 case ENETUNREACH: return "network is unreachable";
257 case EADDRINUSE: return "address already in use";
258 default: return "unknown error";
259 }
260}
261
262/*-------------------------------------------------------------------------*\
263* Sets the SO_REUSEADDR socket option
264* Input
265* sock: socket descriptor
266\*-------------------------------------------------------------------------*/
267void sock_setreuseaddr(p_sock ps)
268{
269 int val = 1;
270 setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
271}
272
273/*-------------------------------------------------------------------------*\
274* Put socket into blocking mode.
275\*-------------------------------------------------------------------------*/
276void sock_setblocking(p_sock ps)
277{
278 int flags = fcntl(*ps, F_GETFL, 0);
279 flags &= (~(O_NONBLOCK));
280 fcntl(*ps, F_SETFL, flags);
281}
282
283/*-------------------------------------------------------------------------*\
284* Put socket into non-blocking mode.
285\*-------------------------------------------------------------------------*/
286void sock_setnonblocking(p_sock ps)
287{
288 int flags = fcntl(*ps, F_GETFL, 0);
289 flags |= O_NONBLOCK;
290 fcntl(*ps, F_SETFL, flags);
291}
292
293/*-------------------------------------------------------------------------*\
294* Tries to set extended udp socket options
295* Input
296* udp: udp structure
297* oldtop: top of stack
298* Returns
299* NULL if successfull, error message on error
300\*-------------------------------------------------------------------------*/
301const char *sock_trysetoptions(lua_State *L, p_sock ps)
302{
303 if (!lua_istable(L, 1)) luaL_argerror(L, 1, "invalid options table");
304 lua_pushnil(L);
305 while (lua_next(L, 1)) {
306 const char *err = try_setoption(L, ps);
307 lua_pop(L, 1);
308 if (err) return err;
309 }
310 return NULL;
311}
312
313/*-------------------------------------------------------------------------*\
314* Set socket options from a table on top of Lua stack.
315* Supports SO_KEEPALIVE, SO_DONTROUTE, and SO_BROADCAST options.
316* Input
317* sock: socket
318* Returns
319* 1 if successful, 0 otherwise
320\*-------------------------------------------------------------------------*/
321static const char *try_setoption(lua_State *L, p_sock ps)
322{
323 static const char *options[] = {
324 "SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", NULL
325 };
326 const char *option = lua_tostring(L, -2);
327 if (!lua_isstring(L, -2)) return "invalid option";
328 switch (luaL_findstring(option, options)) {
329 case 0: return try_setbooloption(L, ps, SO_KEEPALIVE);
330 case 1: return try_setbooloption(L, ps, SO_DONTROUTE);
331 case 2: return try_setbooloption(L, ps, SO_BROADCAST);
332 default: return "unsupported option";
333 }
334}
335
336/*=========================================================================*\
337* Internal functions.
338\*=========================================================================*/
339static const char *try_setbooloption(lua_State *L, p_sock ps, int name)
340{
341 int bool, res;
342 if (!lua_isnumber(L, -1)) luaL_error(L, "invalid option value");
343 bool = (int) lua_tonumber(L, -1);
344 res = setsockopt(*ps, SOL_SOCKET, name, (char *) &bool, sizeof(bool));
345 if (res < 0) return "error setting option";
346 else return NULL;
347}