diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-07-08 20:14:09 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-07-08 20:14:09 +0000 |
commit | cbffc42f299575e56d88527a48e26377f3d1f800 (patch) | |
tree | adae2c05ec4e912f606409689904fac38908fce0 /src | |
parent | 46828c1a7d02f029cf3fa1b3c6d56cf054100c98 (diff) | |
download | luasocket-cbffc42f299575e56d88527a48e26377f3d1f800.tar.gz luasocket-cbffc42f299575e56d88527a48e26377f3d1f800.tar.bz2 luasocket-cbffc42f299575e56d88527a48e26377f3d1f800.zip |
Initial revision
Diffstat (limited to 'src')
-rw-r--r-- | src/unix.c | 325 | ||||
-rw-r--r-- | src/unix.h | 69 |
2 files changed, 394 insertions, 0 deletions
diff --git a/src/unix.c b/src/unix.c new file mode 100644 index 0000000..d50d98c --- /dev/null +++ b/src/unix.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /*=========================================================================*\ | ||
2 | * Network compatibilization module | ||
3 | \*=========================================================================*/ | ||
4 | #include <string.h> | ||
5 | |||
6 | #include <lua.h> | ||
7 | #include <lauxlib.h> | ||
8 | |||
9 | #include "lscompat.h" | ||
10 | |||
11 | /*=========================================================================*\ | ||
12 | * Internal function prototypes | ||
13 | \*=========================================================================*/ | ||
14 | static cchar *try_setoption(lua_State *L, COMPAT_FD sock); | ||
15 | static cchar *try_setbooloption(lua_State *L, COMPAT_FD sock, int name); | ||
16 | |||
17 | /*=========================================================================*\ | ||
18 | * Exported functions. | ||
19 | \*=========================================================================*/ | ||
20 | void compat_open(lua_State *L) | ||
21 | { | ||
22 | /* Instals a handler to ignore sigpipe. This function is not | ||
23 | needed on the WinSock2, since it's sockets don't raise signals. */ | ||
24 | struct sigaction new; | ||
25 | memset(&new, 0, sizeof(new)); | ||
26 | new.sa_handler = SIG_IGN; | ||
27 | sigaction(SIGPIPE, &new, NULL); | ||
28 | } | ||
29 | |||
30 | COMPAT_FD compat_accept(COMPAT_FD s, struct sockaddr *addr, | ||
31 | socklen_t *len, int deadline) | ||
32 | { | ||
33 | struct timeval tv; | ||
34 | fd_set fds; | ||
35 | tv.tv_sec = deadline / 1000; | ||
36 | tv.tv_usec = (deadline % 1000) * 1000; | ||
37 | FD_ZERO(&fds); | ||
38 | FD_SET(s, &fds); | ||
39 | select(s+1, &fds, NULL, NULL, deadline >= 0 ? &tv : NULL); | ||
40 | return accept(s, addr, len); | ||
41 | } | ||
42 | |||
43 | int compat_send(COMPAT_FD c, cchar *data, size_t count, size_t *sent, | ||
44 | int deadline) | ||
45 | { | ||
46 | struct timeval tv; | ||
47 | fd_set fds; | ||
48 | ssize_t put = 0; | ||
49 | int err; | ||
50 | int ret; | ||
51 | tv.tv_sec = deadline / 1000; | ||
52 | tv.tv_usec = (deadline % 1000) * 1000; | ||
53 | FD_ZERO(&fds); | ||
54 | FD_SET(c, &fds); | ||
55 | ret = select(c+1, NULL, &fds, NULL, deadline >= 0 ? &tv : NULL); | ||
56 | if (ret > 0) { | ||
57 | put = write(c, data, count); | ||
58 | if (put <= 0) { | ||
59 | err = PRIV_CLOSED; | ||
60 | #ifdef __CYGWIN__ | ||
61 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ | ||
62 | if (sent < 0 && errno == EWOULDBLOCK) err = PRIV_DONE; | ||
63 | #endif | ||
64 | *sent = 0; | ||
65 | } else { | ||
66 | *sent = put; | ||
67 | err = PRIV_DONE; | ||
68 | } | ||
69 | return err; | ||
70 | } else { | ||
71 | *sent = 0; | ||
72 | return PRIV_TIMEOUT; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | int compat_sendto(COMPAT_FD c, cchar *data, size_t count, size_t *sent, | ||
77 | int deadline, SA *addr, socklen_t len) | ||
78 | { | ||
79 | struct timeval tv; | ||
80 | fd_set fds; | ||
81 | ssize_t put = 0; | ||
82 | int err; | ||
83 | int ret; | ||
84 | tv.tv_sec = deadline / 1000; | ||
85 | tv.tv_usec = (deadline % 1000) * 1000; | ||
86 | FD_ZERO(&fds); | ||
87 | FD_SET(c, &fds); | ||
88 | ret = select(c+1, NULL, &fds, NULL, deadline >= 0 ? &tv : NULL); | ||
89 | if (ret > 0) { | ||
90 | put = sendto(c, data, count, 0, addr, len); | ||
91 | if (put <= 0) { | ||
92 | err = PRIV_CLOSED; | ||
93 | #ifdef __CYGWIN__ | ||
94 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ | ||
95 | if (sent < 0 && errno == EWOULDBLOCK) err = PRIV_DONE; | ||
96 | #endif | ||
97 | *sent = 0; | ||
98 | } else { | ||
99 | *sent = put; | ||
100 | err = PRIV_DONE; | ||
101 | } | ||
102 | return err; | ||
103 | } else { | ||
104 | *sent = 0; | ||
105 | return PRIV_TIMEOUT; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | int compat_recv(COMPAT_FD c, uchar *data, size_t count, size_t *got, | ||
110 | int deadline) | ||
111 | { | ||
112 | struct timeval tv; | ||
113 | fd_set fds; | ||
114 | int ret; | ||
115 | ssize_t taken = 0; | ||
116 | tv.tv_sec = deadline / 1000; | ||
117 | tv.tv_usec = (deadline % 1000) * 1000; | ||
118 | FD_ZERO(&fds); | ||
119 | FD_SET(c, &fds); | ||
120 | ret = select(c+1, &fds, NULL, NULL, deadline >= 0 ? &tv : NULL); | ||
121 | if (ret > 0) { | ||
122 | taken = read(c, data, count); | ||
123 | if (taken <= 0) { | ||
124 | *got = 0; | ||
125 | return PRIV_CLOSED; | ||
126 | } else { | ||
127 | *got = taken; | ||
128 | return PRIV_DONE; | ||
129 | } | ||
130 | } else { | ||
131 | *got = 0; | ||
132 | return PRIV_TIMEOUT; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | int compat_recvfrom(COMPAT_FD c, uchar *data, size_t count, size_t *got, | ||
137 | int deadline, SA *addr, socklen_t *len) | ||
138 | { | ||
139 | struct timeval tv; | ||
140 | fd_set fds; | ||
141 | int ret; | ||
142 | ssize_t taken = 0; | ||
143 | tv.tv_sec = deadline / 1000; | ||
144 | tv.tv_usec = (deadline % 1000) * 1000; | ||
145 | FD_ZERO(&fds); | ||
146 | FD_SET(c, &fds); | ||
147 | ret = select(c+1, &fds, NULL, NULL, deadline >= 0 ? &tv : NULL); | ||
148 | if (ret > 0) { | ||
149 | taken = recvfrom(c, data, count, 0, addr, len); | ||
150 | if (taken <= 0) { | ||
151 | *got = 0; | ||
152 | return PRIV_CLOSED; | ||
153 | } else { | ||
154 | *got = taken; | ||
155 | return PRIV_DONE; | ||
156 | } | ||
157 | } else { | ||
158 | *got = 0; | ||
159 | return PRIV_TIMEOUT; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /*-------------------------------------------------------------------------*\ | ||
164 | * Returns a string describing the last host manipulation error. | ||
165 | \*-------------------------------------------------------------------------*/ | ||
166 | const char *compat_hoststrerror(void) | ||
167 | { | ||
168 | switch (h_errno) { | ||
169 | case HOST_NOT_FOUND: return "host not found"; | ||
170 | case NO_ADDRESS: return "unable to resolve host name"; | ||
171 | case NO_RECOVERY: return "name server error"; | ||
172 | case TRY_AGAIN: return "name server unavailable, try again later"; | ||
173 | default: return "unknown error"; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /*-------------------------------------------------------------------------*\ | ||
178 | * Returns a string describing the last socket manipulation error. | ||
179 | \*-------------------------------------------------------------------------*/ | ||
180 | const char *compat_socketstrerror(void) | ||
181 | { | ||
182 | switch (errno) { | ||
183 | case EACCES: return "access denied"; | ||
184 | case EMFILE: return "descriptor table is full"; | ||
185 | case ENFILE: return "too many open files"; | ||
186 | case ENOBUFS: return "insuffucient buffer space"; | ||
187 | default: return "unknown error"; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | /*-------------------------------------------------------------------------*\ | ||
192 | * Returns a string describing the last bind command error. | ||
193 | \*-------------------------------------------------------------------------*/ | ||
194 | const char *compat_bindstrerror(void) | ||
195 | { | ||
196 | switch (errno) { | ||
197 | case EBADF: return "invalid descriptor"; | ||
198 | case EINVAL: return "socket already bound"; | ||
199 | case EACCES: return "access denied"; | ||
200 | case ENOTSOCK: return "not a socket descriptor"; | ||
201 | case EADDRINUSE: return "address already in use"; | ||
202 | case EADDRNOTAVAIL: return "address unavailable"; | ||
203 | case ENOMEM: return "out of memory"; | ||
204 | default: return "unknown error"; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /*-------------------------------------------------------------------------*\ | ||
209 | * Returns a string describing the last connect error. | ||
210 | \*-------------------------------------------------------------------------*/ | ||
211 | const char *compat_connectstrerror(void) | ||
212 | { | ||
213 | switch (errno) { | ||
214 | case EBADF: return "invalid descriptor"; | ||
215 | case ENOTSOCK: return "not a socket descriptor"; | ||
216 | case EADDRNOTAVAIL: return "address not availabe"; | ||
217 | case ETIMEDOUT: return "connection timed out"; | ||
218 | case ECONNREFUSED: return "connection refused"; | ||
219 | case EACCES: return "access denied"; | ||
220 | case ENETUNREACH: return "network is unreachable"; | ||
221 | case EADDRINUSE: return "address already in use"; | ||
222 | default: return "unknown error"; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | /*-------------------------------------------------------------------------*\ | ||
227 | * Sets the SO_REUSEADDR socket option | ||
228 | * Input | ||
229 | * sock: socket descriptor | ||
230 | \*-------------------------------------------------------------------------*/ | ||
231 | void compat_setreuseaddr(COMPAT_FD sock) | ||
232 | { | ||
233 | int val = 1; | ||
234 | setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); | ||
235 | } | ||
236 | |||
237 | COMPAT_FD compat_socket(int domain, int type, int protocol) | ||
238 | { | ||
239 | COMPAT_FD sock = socket(domain, type, protocol); | ||
240 | if (sock != COMPAT_INVALIDFD) { | ||
241 | compat_setnonblocking(sock); | ||
242 | compat_setreuseaddr(sock); | ||
243 | } | ||
244 | return sock; | ||
245 | } | ||
246 | |||
247 | /*-------------------------------------------------------------------------*\ | ||
248 | * Put socket into blocking mode. | ||
249 | \*-------------------------------------------------------------------------*/ | ||
250 | void compat_setblocking(COMPAT_FD sock) | ||
251 | { | ||
252 | int flags = fcntl(sock, F_GETFL, 0); | ||
253 | flags &= (~(O_NONBLOCK)); | ||
254 | fcntl(sock, F_SETFL, flags); | ||
255 | } | ||
256 | |||
257 | /*-------------------------------------------------------------------------*\ | ||
258 | * Put socket into non-blocking mode. | ||
259 | \*-------------------------------------------------------------------------*/ | ||
260 | void compat_setnonblocking(COMPAT_FD sock) | ||
261 | { | ||
262 | int flags = fcntl(sock, F_GETFL, 0); | ||
263 | flags |= O_NONBLOCK; | ||
264 | fcntl(sock, F_SETFL, flags); | ||
265 | } | ||
266 | |||
267 | /*-------------------------------------------------------------------------*\ | ||
268 | * Tries to set extended udp socket options | ||
269 | * Input | ||
270 | * udp: udp structure | ||
271 | * oldtop: top of stack | ||
272 | * Returns | ||
273 | * NULL if successfull, error message on error | ||
274 | \*-------------------------------------------------------------------------*/ | ||
275 | cchar *compat_trysetoptions(lua_State *L, COMPAT_FD sock) | ||
276 | { | ||
277 | if (!lua_istable(L, 1)) luaL_argerror(L, 1, "invalid options table"); | ||
278 | lua_pushnil(L); | ||
279 | while (lua_next(L, 1)) { | ||
280 | cchar *err = try_setoption(L, sock); | ||
281 | lua_pop(L, 1); | ||
282 | if (err) return err; | ||
283 | } | ||
284 | return NULL; | ||
285 | } | ||
286 | |||
287 | /*=========================================================================*\ | ||
288 | * Internal functions. | ||
289 | \*=========================================================================*/ | ||
290 | static cchar *try_setbooloption(lua_State *L, COMPAT_FD sock, int name) | ||
291 | { | ||
292 | int bool, res; | ||
293 | if (!lua_isnumber(L, -1)) lua_error(L, "invalid option value"); | ||
294 | bool = (int) lua_tonumber(L, -1); | ||
295 | res = setsockopt(sock, SOL_SOCKET, name, (char *) &bool, sizeof(bool)); | ||
296 | if (res < 0) return "error setting option"; | ||
297 | else return NULL; | ||
298 | } | ||
299 | |||
300 | |||
301 | /*-------------------------------------------------------------------------*\ | ||
302 | * Set socket options from a table on top of Lua stack. | ||
303 | * Supports SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST, and SO_LINGER options. | ||
304 | * Input | ||
305 | * L: Lua state to use | ||
306 | * sock: socket descriptor | ||
307 | * Returns | ||
308 | * 1 if successful, 0 otherwise | ||
309 | \*-------------------------------------------------------------------------*/ | ||
310 | static cchar *try_setoption(lua_State *L, COMPAT_FD sock) | ||
311 | { | ||
312 | static cchar *options[] = { | ||
313 | "SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", "SO_LINGER", NULL | ||
314 | }; | ||
315 | cchar *option = lua_tostring(L, -2); | ||
316 | if (!lua_isstring(L, -2)) return "invalid option"; | ||
317 | switch (luaL_findstring(option, options)) { | ||
318 | case 0: return try_setbooloption(L, sock, SO_KEEPALIVE); | ||
319 | case 1: return try_setbooloption(L, sock, SO_DONTROUTE); | ||
320 | case 2: return try_setbooloption(L, sock, SO_BROADCAST); | ||
321 | case 3: return "SO_LINGER is deprecated"; | ||
322 | default: return "unsupported option"; | ||
323 | } | ||
324 | } | ||
325 | |||
diff --git a/src/unix.h b/src/unix.h new file mode 100644 index 0000000..e317b06 --- /dev/null +++ b/src/unix.h | |||
@@ -0,0 +1,69 @@ | |||
1 | #ifndef COMPAT_H_ | ||
2 | #define COMPAT_H_ | ||
3 | |||
4 | #include "lspriv.h" | ||
5 | |||
6 | /*=========================================================================*\ | ||
7 | * BSD include files | ||
8 | \*=========================================================================*/ | ||
9 | /* error codes */ | ||
10 | #include <errno.h> | ||
11 | /* close function */ | ||
12 | #include <unistd.h> | ||
13 | /* fnctnl function and associated constants */ | ||
14 | #include <fcntl.h> | ||
15 | /* struct timeval and CLK_TCK */ | ||
16 | #include <sys/time.h> | ||
17 | /* times function and struct tms */ | ||
18 | #include <sys/times.h> | ||
19 | /* struct sockaddr */ | ||
20 | #include <sys/types.h> | ||
21 | /* socket function */ | ||
22 | #include <sys/socket.h> | ||
23 | /* gethostbyname and gethostbyaddr functions */ | ||
24 | #include <netdb.h> | ||
25 | /* sigpipe handling */ | ||
26 | #include <signal.h> | ||
27 | |||
28 | #include <netinet/in.h> | ||
29 | #include <arpa/inet.h> | ||
30 | |||
31 | #define COMPAT_FD int | ||
32 | #define COMPAT_INVALIDFD (-1) | ||
33 | |||
34 | /* we are lazy... */ | ||
35 | typedef struct sockaddr SA; | ||
36 | |||
37 | /*=========================================================================*\ | ||
38 | * Exported functions | ||
39 | \*=========================================================================*/ | ||
40 | void compat_open(lua_State *L); | ||
41 | |||
42 | #define compat_bind bind | ||
43 | #define compat_connect connect | ||
44 | #define compat_listen listen | ||
45 | #define compat_close close | ||
46 | #define compat_select select | ||
47 | |||
48 | COMPAT_FD compat_socket(int domain, int type, int protocol); | ||
49 | COMPAT_FD compat_accept(COMPAT_FD s, SA *addr, socklen_t *len, int deadline); | ||
50 | int compat_send(COMPAT_FD c, cchar *data, size_t count, size_t *done, | ||
51 | int deadline); | ||
52 | int compat_recv(COMPAT_FD c, uchar *data, size_t count, size_t *done, | ||
53 | int deadline); | ||
54 | int compat_sendto(COMPAT_FD c, cchar *data, size_t count, size_t *done, | ||
55 | int deadline, SA *addr, socklen_t len); | ||
56 | int compat_recvfrom(COMPAT_FD c, uchar *data, size_t count, size_t *got, | ||
57 | int deadline, SA *addr, socklen_t *len); | ||
58 | void compat_setnonblocking(COMPAT_FD sock); | ||
59 | void compat_setblocking(COMPAT_FD sock); | ||
60 | void compat_setreuseaddr(COMPAT_FD sock); | ||
61 | |||
62 | const char *compat_hoststrerror(void); | ||
63 | const char *compat_socketstrerror(void); | ||
64 | const char *compat_bindstrerror(void); | ||
65 | const char *compat_connectstrerror(void); | ||
66 | |||
67 | cchar *compat_trysetoptions(lua_State *L, COMPAT_FD sock); | ||
68 | |||
69 | #endif /* COMPAT_H_ */ | ||