diff options
Diffstat (limited to 'src/udp.c')
-rw-r--r-- | src/udp.c | 157 |
1 files changed, 60 insertions, 97 deletions
@@ -3,6 +3,7 @@ | |||
3 | * LuaSocket toolkit | 3 | * LuaSocket toolkit |
4 | \*=========================================================================*/ | 4 | \*=========================================================================*/ |
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <stdlib.h> | ||
6 | 7 | ||
7 | #include "lua.h" | 8 | #include "lua.h" |
8 | #include "lauxlib.h" | 9 | #include "lauxlib.h" |
@@ -68,25 +69,34 @@ static luaL_Reg udp_methods[] = { | |||
68 | 69 | ||
69 | /* socket options for setoption */ | 70 | /* socket options for setoption */ |
70 | static t_opt optset[] = { | 71 | static t_opt optset[] = { |
71 | {"dontroute", opt_set_dontroute}, | 72 | {"dontroute", opt_set_dontroute}, |
72 | {"broadcast", opt_set_broadcast}, | 73 | {"broadcast", opt_set_broadcast}, |
73 | {"reuseaddr", opt_set_reuseaddr}, | 74 | {"reuseaddr", opt_set_reuseaddr}, |
74 | {"reuseport", opt_set_reuseport}, | 75 | {"reuseport", opt_set_reuseport}, |
75 | {"ip-multicast-if", opt_set_ip_multicast_if}, | 76 | {"ip-multicast-if", opt_set_ip_multicast_if}, |
76 | {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, | 77 | {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, |
77 | {"ip-multicast-loop", opt_set_ip_multicast_loop}, | 78 | {"ip-multicast-loop", opt_set_ip_multicast_loop}, |
78 | {"ip-add-membership", opt_set_ip_add_membership}, | 79 | {"ip-add-membership", opt_set_ip_add_membership}, |
79 | {"ip-drop-membership", opt_set_ip_drop_membersip}, | 80 | {"ip-drop-membership", opt_set_ip_drop_membersip}, |
80 | {"ipv6-v6only", opt_set_ip6_v6only}, | 81 | {"ipv6-unicast-hops", opt_set_ip6_unicast_hops}, |
81 | {NULL, NULL} | 82 | {"ipv6-multicast-hops", opt_set_ip6_unicast_hops}, |
83 | {"ipv6-multicast-loop", opt_set_ip6_multicast_loop}, | ||
84 | {"ipv6-add-membership", opt_set_ip6_add_membership}, | ||
85 | {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, | ||
86 | {"ipv6-v6only", opt_set_ip6_v6only}, | ||
87 | {NULL, NULL} | ||
82 | }; | 88 | }; |
83 | 89 | ||
84 | /* socket options for getoption */ | 90 | /* socket options for getoption */ |
85 | static t_opt optget[] = { | 91 | static t_opt optget[] = { |
86 | {"ip-multicast-if", opt_get_ip_multicast_if}, | 92 | {"ip-multicast-if", opt_get_ip_multicast_if}, |
87 | {"ip-multicast-loop", opt_get_ip_multicast_loop}, | 93 | {"ip-multicast-loop", opt_get_ip_multicast_loop}, |
88 | {"error", opt_get_error}, | 94 | {"error", opt_get_error}, |
89 | {NULL, NULL} | 95 | {"ipv6-unicast-hops", opt_get_ip6_unicast_hops}, |
96 | {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, | ||
97 | {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, | ||
98 | {"ipv6-v6only", opt_get_ip6_v6only}, | ||
99 | {NULL, NULL} | ||
90 | }; | 100 | }; |
91 | 101 | ||
92 | /* functions in library namespace */ | 102 | /* functions in library namespace */ |
@@ -156,39 +166,24 @@ static int meth_sendto(lua_State *L) { | |||
156 | size_t count, sent = 0; | 166 | size_t count, sent = 0; |
157 | const char *data = luaL_checklstring(L, 2, &count); | 167 | const char *data = luaL_checklstring(L, 2, &count); |
158 | const char *ip = luaL_checkstring(L, 3); | 168 | const char *ip = luaL_checkstring(L, 3); |
159 | unsigned short port = (unsigned short) luaL_checknumber(L, 4); | 169 | const char *port = luaL_checkstring(L, 4); |
160 | p_timeout tm = &udp->tm; | 170 | p_timeout tm = &udp->tm; |
161 | int err; | 171 | int err; |
162 | switch (udp->family) { | 172 | struct addrinfo aihint; |
163 | case PF_INET: { | 173 | struct addrinfo *ai; |
164 | struct sockaddr_in addr; | 174 | memset(&aihint, 0, sizeof(aihint)); |
165 | memset(&addr, 0, sizeof(addr)); | 175 | aihint.ai_family = udp->family; |
166 | if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1) | 176 | aihint.ai_socktype = SOCK_DGRAM; |
167 | luaL_argerror(L, 3, "invalid ip address"); | 177 | aihint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; |
168 | addr.sin_family = AF_INET; | 178 | if ((err = getaddrinfo(ip, port, &aihint, &ai))) { |
169 | addr.sin_port = htons(port); | ||
170 | timeout_markstart(tm); | ||
171 | err = socket_sendto(&udp->sock, data, count, &sent, | ||
172 | (SA *) &addr, sizeof(addr), tm); | ||
173 | break; | ||
174 | } | ||
175 | case PF_INET6: { | ||
176 | struct sockaddr_in6 addr; | ||
177 | memset(&addr, 0, sizeof(addr)); | ||
178 | if (inet_pton(AF_INET6, ip, &addr.sin6_addr) != 1) | ||
179 | luaL_argerror(L, 3, "invalid ip address"); | ||
180 | addr.sin6_family = AF_INET6; | ||
181 | addr.sin6_port = htons(port); | ||
182 | timeout_markstart(tm); | ||
183 | err = socket_sendto(&udp->sock, data, count, &sent, | ||
184 | (SA *) &addr, sizeof(addr), tm); | ||
185 | break; | ||
186 | } | ||
187 | default: | ||
188 | lua_pushnil(L); | 179 | lua_pushnil(L); |
189 | lua_pushfstring(L, "unknown family %d", udp->family); | 180 | lua_pushstring(L, udp_strerror(err)); |
190 | return 2; | 181 | return 2; |
191 | } | 182 | } |
183 | timeout_markstart(tm); | ||
184 | err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, | ||
185 | ai->ai_addrlen, tm); | ||
186 | freeaddrinfo(ai); | ||
192 | if (err != IO_DONE) { | 187 | if (err != IO_DONE) { |
193 | lua_pushnil(L); | 188 | lua_pushnil(L); |
194 | lua_pushstring(L, udp_strerror(err)); | 189 | lua_pushstring(L, udp_strerror(err)); |
@@ -225,71 +220,39 @@ static int meth_receive(lua_State *L) { | |||
225 | /*-------------------------------------------------------------------------*\ | 220 | /*-------------------------------------------------------------------------*\ |
226 | * Receives data and sender from a UDP socket | 221 | * Receives data and sender from a UDP socket |
227 | \*-------------------------------------------------------------------------*/ | 222 | \*-------------------------------------------------------------------------*/ |
228 | static int meth_receivefrom(lua_State *L) { | 223 | static int meth_receivefrom(lua_State *L) |
224 | { | ||
229 | p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); | 225 | p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); |
230 | char buffer[UDP_DATAGRAMSIZE]; | 226 | char buffer[UDP_DATAGRAMSIZE]; |
231 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 227 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); |
232 | int err; | 228 | int err; |
233 | p_timeout tm = &udp->tm; | 229 | p_timeout tm = &udp->tm; |
230 | struct sockaddr_storage addr; | ||
231 | socklen_t addr_len = sizeof(addr); | ||
232 | char addrstr[INET6_ADDRSTRLEN]; | ||
233 | char portstr[6]; | ||
234 | timeout_markstart(tm); | 234 | timeout_markstart(tm); |
235 | count = MIN(count, sizeof(buffer)); | 235 | count = MIN(count, sizeof(buffer)); |
236 | switch (udp->family) { | 236 | err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, |
237 | case PF_INET: { | 237 | &addr_len, tm); |
238 | struct sockaddr_in addr; | 238 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ |
239 | socklen_t addr_len = sizeof(addr); | 239 | if (err == IO_CLOSED) |
240 | err = socket_recvfrom(&udp->sock, buffer, count, &got, | 240 | err = IO_DONE; |
241 | (SA *) &addr, &addr_len, tm); | 241 | if (err != IO_DONE) { |
242 | /* Unlike TCP, recv() of zero is not closed, | 242 | lua_pushnil(L); |
243 | * but a zero-length packet. */ | 243 | lua_pushstring(L, udp_strerror(err)); |
244 | if (err == IO_CLOSED) | 244 | return 2; |
245 | err = IO_DONE; | ||
246 | if (err == IO_DONE) { | ||
247 | char addrstr[INET_ADDRSTRLEN]; | ||
248 | lua_pushlstring(L, buffer, got); | ||
249 | if (!inet_ntop(AF_INET, &addr.sin_addr, | ||
250 | addrstr, sizeof(addrstr))) { | ||
251 | lua_pushnil(L); | ||
252 | lua_pushstring(L, "invalid source address"); | ||
253 | return 2; | ||
254 | } | ||
255 | lua_pushstring(L, addrstr); | ||
256 | lua_pushnumber(L, ntohs(addr.sin_port)); | ||
257 | return 3; | ||
258 | } | ||
259 | break; | ||
260 | } | ||
261 | case PF_INET6: { | ||
262 | struct sockaddr_in6 addr; | ||
263 | socklen_t addr_len = sizeof(addr); | ||
264 | err = socket_recvfrom(&udp->sock, buffer, count, &got, | ||
265 | (SA *) &addr, &addr_len, tm); | ||
266 | /* Unlike TCP, recv() of zero is not closed, | ||
267 | * but a zero-length packet. */ | ||
268 | if (err == IO_CLOSED) | ||
269 | err = IO_DONE; | ||
270 | if (err == IO_DONE) { | ||
271 | char addrstr[INET6_ADDRSTRLEN]; | ||
272 | lua_pushlstring(L, buffer, got); | ||
273 | if (!inet_ntop(AF_INET6, &addr.sin6_addr, | ||
274 | addrstr, sizeof(addrstr))) { | ||
275 | lua_pushnil(L); | ||
276 | lua_pushstring(L, "invalid source address"); | ||
277 | return 2; | ||
278 | } | ||
279 | lua_pushstring(L, addrstr); | ||
280 | lua_pushnumber(L, ntohs(addr.sin6_port)); | ||
281 | return 3; | ||
282 | } | ||
283 | break; | ||
284 | } | 245 | } |
285 | default: | 246 | if ((err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, |
247 | INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV))) { | ||
286 | lua_pushnil(L); | 248 | lua_pushnil(L); |
287 | lua_pushfstring(L, "unknown family %d", udp->family); | 249 | lua_pushstring(L, gai_strerror(err)); |
288 | return 2; | 250 | return 2; |
289 | } | 251 | } |
290 | lua_pushnil(L); | 252 | lua_pushlstring(L, buffer, got); |
291 | lua_pushstring(L, udp_strerror(err)); | 253 | lua_pushstring(L, addrstr); |
292 | return 2; | 254 | lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); |
255 | return 3; | ||
293 | } | 256 | } |
294 | 257 | ||
295 | /*-------------------------------------------------------------------------*\ | 258 | /*-------------------------------------------------------------------------*\ |