diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2001-04-23 22:37:55 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2001-04-23 22:37:55 +0000 |
commit | 8c6473577da993fb95ccd705214aa9dc11e8ca82 (patch) | |
tree | 5e435e89f715c9399b6944bbc5097556907a2996 | |
parent | 561177a1dd111f05aa3edc4d0b89bf1341627027 (diff) | |
download | luasocket-8c6473577da993fb95ccd705214aa9dc11e8ca82.tar.gz luasocket-8c6473577da993fb95ccd705214aa9dc11e8ca82.tar.bz2 luasocket-8c6473577da993fb95ccd705214aa9dc11e8ca82.zip |
Added support to UDP socket options.
-rw-r--r-- | src/luasocket.c | 216 |
1 files changed, 139 insertions, 77 deletions
diff --git a/src/luasocket.c b/src/luasocket.c index 6512108..f144fce 100644 --- a/src/luasocket.c +++ b/src/luasocket.c | |||
@@ -159,7 +159,7 @@ static int global_tohostname(lua_State *L); | |||
159 | static int global_udpsocket(lua_State *L); | 159 | static int global_udpsocket(lua_State *L); |
160 | 160 | ||
161 | #ifndef LUASOCKET_NOGLOBALS | 161 | #ifndef LUASOCKET_NOGLOBALS |
162 | static int global_calltable(lua_State *L); | 162 | static int global_callfromtable(lua_State *L); |
163 | #endif | 163 | #endif |
164 | 164 | ||
165 | /* luasocket table method API functions */ | 165 | /* luasocket table method API functions */ |
@@ -219,6 +219,7 @@ static const char *udp_setpeername(p_sock sock, const char *address, | |||
219 | unsigned short port); | 219 | unsigned short port); |
220 | static const char *udp_setsockname(p_sock sock, const char *address, | 220 | static const char *udp_setsockname(p_sock sock, const char *address, |
221 | unsigned short port); | 221 | unsigned short port); |
222 | static int set_option(lua_State *L, p_sock sock); | ||
222 | static void set_reuseaddr(p_sock sock); | 223 | static void set_reuseaddr(p_sock sock); |
223 | static void set_blocking(p_sock sock); | 224 | static void set_blocking(p_sock sock); |
224 | static void set_nonblocking(p_sock sock); | 225 | static void set_nonblocking(p_sock sock); |
@@ -305,8 +306,6 @@ static int global_tcpconnect(lua_State *L) | |||
305 | 306 | ||
306 | /*-------------------------------------------------------------------------*\ | 307 | /*-------------------------------------------------------------------------*\ |
307 | * Creates a udp socket object and returns it to the Lua script. | 308 | * Creates a udp socket object and returns it to the Lua script. |
308 | * The timeout values are initialized as -1 so that the socket will block | ||
309 | * at any IO operation. | ||
310 | * Lua Returns | 309 | * Lua Returns |
311 | * On success: udp socket | 310 | * On success: udp socket |
312 | * On error: nil, followed by an error message | 311 | * On error: nil, followed by an error message |
@@ -314,8 +313,16 @@ static int global_tcpconnect(lua_State *L) | |||
314 | static int global_udpsocket(lua_State *L) | 313 | static int global_udpsocket(lua_State *L) |
315 | { | 314 | { |
316 | p_tags tags = pop_tags(L); | 315 | p_tags tags = pop_tags(L); |
316 | int top = lua_gettop(L); | ||
317 | p_sock sock = push_udptable(L, tags); | 317 | p_sock sock = push_udptable(L, tags); |
318 | if (!sock) return 2; | 318 | if (!sock) return 2; |
319 | if (top >= 1 && lua_istable(L, 1)) { | ||
320 | lua_pushnil(L); | ||
321 | while (lua_next(L, 1)) { | ||
322 | if (!set_option(L, sock)) lua_error(L, "invalid socket option"); | ||
323 | lua_pop(L, 1); | ||
324 | } | ||
325 | } | ||
319 | return 1; | 326 | return 1; |
320 | } | 327 | } |
321 | 328 | ||
@@ -483,8 +490,8 @@ static int table_tcpsend(lua_State *L) | |||
483 | for (arg = 2; arg <= top; arg++) { /* skip self table */ | 490 | for (arg = 2; arg <= top; arg++) { /* skip self table */ |
484 | int sent; | 491 | int sent; |
485 | size_t wanted; | 492 | size_t wanted; |
486 | const char *data = luaL_opt_lstr(L, arg, NULL, &wanted); | 493 | const char *data = luaL_opt_lstr(L, arg, NULL, &wanted); |
487 | if (!data || err != NET_DONE) break; | 494 | if (!data || err != NET_DONE) break; |
488 | err = send_raw(sock, data, wanted, &sent); | 495 | err = send_raw(sock, data, wanted, &sent); |
489 | total += sent; | 496 | total += sent; |
490 | } | 497 | } |
@@ -542,14 +549,14 @@ static int table_udpsendto(lua_State *L) | |||
542 | * Global function that calls corresponding table method. | 549 | * Global function that calls corresponding table method. |
543 | \*-------------------------------------------------------------------------*/ | 550 | \*-------------------------------------------------------------------------*/ |
544 | #ifndef LUASOCKET_NOGLOBALS | 551 | #ifndef LUASOCKET_NOGLOBALS |
545 | int global_calltable(lua_State *L) | 552 | int global_callfromtable(lua_State *L) |
546 | { | 553 | { |
547 | p_tags tags = pop_tags(L); | 554 | p_tags tags = pop_tags(L); |
548 | if (lua_tag(L, 1) != tags->table) lua_error(L, "invalid socket object"); | 555 | if (lua_tag(L, 1) != tags->table) lua_error(L, "invalid socket object"); |
549 | lua_gettable(L, 1); | 556 | lua_gettable(L, 1); |
550 | lua_insert(L, 1); | 557 | lua_insert(L, 1); |
551 | lua_call(L, lua_gettop(L)-1, LUA_MULTRET); | 558 | lua_call(L, lua_gettop(L)-1, LUA_MULTRET); |
552 | return lua_gettop(L); | 559 | return lua_gettop(L); |
553 | } | 560 | } |
554 | #endif | 561 | #endif |
555 | 562 | ||
@@ -571,8 +578,8 @@ int global_select(lua_State *L) | |||
571 | fd_set readfds, *prfds = NULL, writefds, *pwfds = NULL; | 578 | fd_set readfds, *prfds = NULL, writefds, *pwfds = NULL; |
572 | struct timeval tm, *ptm = NULL; | 579 | struct timeval tm, *ptm = NULL; |
573 | int ret; | 580 | int ret; |
574 | unsigned max = 0; | 581 | unsigned max = 0; |
575 | SOCKET s; | 582 | SOCKET s; |
576 | int byfds, canread, canwrite; | 583 | int byfds, canread, canwrite; |
577 | /* reset the file descriptor sets */ | 584 | /* reset the file descriptor sets */ |
578 | FD_ZERO(&readfds); FD_ZERO(&writefds); | 585 | FD_ZERO(&readfds); FD_ZERO(&writefds); |
@@ -588,25 +595,25 @@ int global_select(lua_State *L) | |||
588 | while (lua_next(L, 1)) { | 595 | while (lua_next(L, 1)) { |
589 | if (lua_tag(L, -1) == tags->table) { /* skip strange fields */ | 596 | if (lua_tag(L, -1) == tags->table) { /* skip strange fields */ |
590 | p_sock sock = get_sock(L, -1, tags, NULL); | 597 | p_sock sock = get_sock(L, -1, tags, NULL); |
591 | if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */ | 598 | if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */ |
592 | lua_pushnumber(L, sock->sock); | 599 | lua_pushnumber(L, sock->sock); |
593 | lua_pushvalue(L, -2); | 600 | lua_pushvalue(L, -2); |
594 | lua_settable(L, byfds); | 601 | lua_settable(L, byfds); |
595 | if (sock->sock > max) max = sock->sock; | 602 | if (sock->sock > max) max = sock->sock; |
596 | /* a socket can have unread data in our internal | 603 | /* a socket can have unread data in our internal |
597 | buffer. in that case, we only call select to find | 604 | buffer. in that case, we only call select to find |
598 | out which of the other sockets can be written to | 605 | out which of the other sockets can be written to |
599 | or read from immediately. */ | 606 | or read from immediately. */ |
600 | if (!bf_isempty(sock)) { | 607 | if (!bf_isempty(sock)) { |
601 | ms = 0; | 608 | ms = 0; |
602 | lua_pushnumber(L, lua_getn(L, canread) + 1); | 609 | lua_pushnumber(L, lua_getn(L, canread) + 1); |
603 | lua_pushvalue(L, -2); | 610 | lua_pushvalue(L, -2); |
604 | lua_settable(L, canread); | 611 | lua_settable(L, canread); |
605 | } else { | 612 | } else { |
606 | FD_SET(sock->sock, &readfds); | 613 | FD_SET(sock->sock, &readfds); |
607 | prfds = &readfds; | 614 | prfds = &readfds; |
608 | } | 615 | } |
609 | } | 616 | } |
610 | } | 617 | } |
611 | /* get rid of lua_next value and expose index */ | 618 | /* get rid of lua_next value and expose index */ |
612 | lua_pop(L, 1); | 619 | lua_pop(L, 1); |
@@ -618,14 +625,14 @@ int global_select(lua_State *L) | |||
618 | while (lua_next(L, 2)) { | 625 | while (lua_next(L, 2)) { |
619 | if (lua_tag(L, -1) == tags->table) { /* skip strange fields */ | 626 | if (lua_tag(L, -1) == tags->table) { /* skip strange fields */ |
620 | p_sock sock = get_sock(L, -1, tags, NULL); | 627 | p_sock sock = get_sock(L, -1, tags, NULL); |
621 | if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */ | 628 | if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */ |
622 | lua_pushnumber(L, sock->sock); | 629 | lua_pushnumber(L, sock->sock); |
623 | lua_pushvalue(L, -2); | 630 | lua_pushvalue(L, -2); |
624 | lua_settable(L, byfds); | 631 | lua_settable(L, byfds); |
625 | if (sock->sock > max) max = sock->sock; | 632 | if (sock->sock > max) max = sock->sock; |
626 | FD_SET(sock->sock, &writefds); | 633 | FD_SET(sock->sock, &writefds); |
627 | pwfds = &writefds; | 634 | pwfds = &writefds; |
628 | } | 635 | } |
629 | } | 636 | } |
630 | /* get rid of lua_next value and expose index */ | 637 | /* get rid of lua_next value and expose index */ |
631 | lua_pop(L, 1); | 638 | lua_pop(L, 1); |
@@ -1050,6 +1057,61 @@ void set_reuseaddr(p_sock sock) | |||
1050 | } | 1057 | } |
1051 | 1058 | ||
1052 | /*-------------------------------------------------------------------------*\ | 1059 | /*-------------------------------------------------------------------------*\ |
1060 | * Set socket options from a table on top of Lua stack. | ||
1061 | * Supports SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST, and SO_LINGER options. | ||
1062 | * Input | ||
1063 | * L: Lua state to use | ||
1064 | * sock: socket to set option | ||
1065 | * Returns | ||
1066 | * 1 if successful, 0 otherwise | ||
1067 | \*-------------------------------------------------------------------------*/ | ||
1068 | static int set_option(lua_State *L, p_sock sock) | ||
1069 | { | ||
1070 | static const char *const optionnames[] = { | ||
1071 | "SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", "SO_LINGER", NULL | ||
1072 | }; | ||
1073 | const char *option = lua_tostring(L, -2); | ||
1074 | int err; | ||
1075 | switch (luaL_findstring(option, optionnames)) { | ||
1076 | case 0: { | ||
1077 | int bool = (int) lua_tonumber(L, -1); | ||
1078 | err = setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE, &bool, | ||
1079 | sizeof(bool)); | ||
1080 | return err >= 0; | ||
1081 | } | ||
1082 | case 1: { | ||
1083 | int bool = (int) lua_tonumber(L, -1); | ||
1084 | err = setsockopt(sock->sock, SOL_SOCKET, SO_DONTROUTE, &bool, | ||
1085 | sizeof(bool)); | ||
1086 | return err >= 0; | ||
1087 | } | ||
1088 | case 2: { | ||
1089 | int bool = (int) lua_tonumber(L, -1); | ||
1090 | err = setsockopt(sock->sock, SOL_SOCKET, SO_BROADCAST, &bool, | ||
1091 | sizeof(bool)); | ||
1092 | return err >= 0; | ||
1093 | } | ||
1094 | case 3: { | ||
1095 | struct linger linger; | ||
1096 | if (!lua_istable(L, -1)) return 0; | ||
1097 | lua_pushstring(L, "l_onoff"); | ||
1098 | lua_gettable(L, -2); | ||
1099 | linger.l_onoff = lua_tonumber(L, -1); | ||
1100 | lua_pop(L, 1); | ||
1101 | lua_pushstring(L, "l_linger"); | ||
1102 | lua_gettable(L, -2); | ||
1103 | linger.l_linger = lua_tonumber(L, -1); | ||
1104 | lua_pop(L, 1); | ||
1105 | err = setsockopt(sock->sock, SOL_SOCKET, SO_LINGER, &linger, | ||
1106 | sizeof(linger)); | ||
1107 | return err >= 0; | ||
1108 | } | ||
1109 | default: return 0; | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | |||
1114 | /*-------------------------------------------------------------------------*\ | ||
1053 | * Tries to create a TCP socket and bind it to (address, port) | 1115 | * Tries to create a TCP socket and bind it to (address, port) |
1054 | * Input | 1116 | * Input |
1055 | * address: host name or ip address | 1117 | * address: host name or ip address |
@@ -1462,20 +1524,20 @@ static int receive_dosline(lua_State *L, p_sock sock) | |||
1462 | } | 1524 | } |
1463 | buffer = bf_receive(sock, &got); | 1525 | buffer = bf_receive(sock, &got); |
1464 | if (got <= 0) { | 1526 | if (got <= 0) { |
1465 | luaL_pushresult(&b); | 1527 | luaL_pushresult(&b); |
1466 | return NET_CLOSED; | 1528 | return NET_CLOSED; |
1467 | } | 1529 | } |
1468 | pos = 0; | 1530 | pos = 0; |
1469 | while (pos < got && buffer[pos] != '\n') { | 1531 | while (pos < got && buffer[pos] != '\n') { |
1470 | /* we ignore all \r's */ | 1532 | /* we ignore all \r's */ |
1471 | if (buffer[pos] != '\r') luaL_putchar(&b, buffer[pos]); | 1533 | if (buffer[pos] != '\r') luaL_putchar(&b, buffer[pos]); |
1472 | pos++; | 1534 | pos++; |
1473 | } | 1535 | } |
1474 | if (pos < got) { | 1536 | if (pos < got) { |
1475 | luaL_pushresult(&b); | 1537 | luaL_pushresult(&b); |
1476 | bf_skip(sock, pos+1); /* skip '\n' too */ | 1538 | bf_skip(sock, pos+1); /* skip '\n' too */ |
1477 | return NET_DONE; | 1539 | return NET_DONE; |
1478 | } else bf_skip(sock, pos); | 1540 | } else bf_skip(sock, pos); |
1479 | } | 1541 | } |
1480 | } | 1542 | } |
1481 | 1543 | ||
@@ -1501,17 +1563,17 @@ static int receive_unixline(lua_State *L, p_sock sock) | |||
1501 | } | 1563 | } |
1502 | buffer = bf_receive(sock, &got); | 1564 | buffer = bf_receive(sock, &got); |
1503 | if (got <= 0) { | 1565 | if (got <= 0) { |
1504 | luaL_pushresult(&b); | 1566 | luaL_pushresult(&b); |
1505 | return NET_CLOSED; | 1567 | return NET_CLOSED; |
1506 | } | 1568 | } |
1507 | pos = 0; | 1569 | pos = 0; |
1508 | while (pos < got && buffer[pos] != '\n') pos++; | 1570 | while (pos < got && buffer[pos] != '\n') pos++; |
1509 | luaL_addlstring(&b, buffer, pos); | 1571 | luaL_addlstring(&b, buffer, pos); |
1510 | if (pos < got) { | 1572 | if (pos < got) { |
1511 | luaL_pushresult(&b); | 1573 | luaL_pushresult(&b); |
1512 | bf_skip(sock, pos+1); /* skip '\n' too */ | 1574 | bf_skip(sock, pos+1); /* skip '\n' too */ |
1513 | return NET_DONE; | 1575 | return NET_DONE; |
1514 | } else bf_skip(sock, pos); | 1576 | } else bf_skip(sock, pos); |
1515 | } | 1577 | } |
1516 | } | 1578 | } |
1517 | 1579 | ||
@@ -1545,7 +1607,7 @@ static int receive_word(lua_State *L, p_sock sock) | |||
1545 | bf_skip(sock, pos); | 1607 | bf_skip(sock, pos); |
1546 | if (pos < got) { | 1608 | if (pos < got) { |
1547 | buffer += pos; | 1609 | buffer += pos; |
1548 | got -= pos; | 1610 | got -= pos; |
1549 | pos = 0; | 1611 | pos = 0; |
1550 | break; | 1612 | break; |
1551 | } | 1613 | } |
@@ -1620,20 +1682,20 @@ void lua_socketlibopen(lua_State *L) | |||
1620 | lua_pushcfunction(L, global_time); lua_setglobal(L, "time"); | 1682 | lua_pushcfunction(L, global_time); lua_setglobal(L, "time"); |
1621 | #endif | 1683 | #endif |
1622 | #ifndef LUASOCKET_NOGLOBALS | 1684 | #ifndef LUASOCKET_NOGLOBALS |
1623 | { | 1685 | { |
1624 | char *global[] = { | 1686 | char *global[] = { |
1625 | "accept", "close", "getpeername", | 1687 | "accept", "close", "getpeername", |
1626 | "getsockname", "receive", "send", | 1688 | "getsockname", "receive", "send", |
1627 | "receivefrom", "sendto" | 1689 | "receivefrom", "sendto" |
1628 | }; | 1690 | }; |
1629 | unsigned int i; | 1691 | unsigned int i; |
1630 | for (i = 0; i < sizeof(global)/sizeof(char *); i++) { | 1692 | for (i = 0; i < sizeof(global)/sizeof(char *); i++) { |
1631 | lua_pushstring(L, global[i]); | 1693 | lua_pushstring(L, global[i]); |
1632 | lua_pushuserdata(L, tags); | 1694 | lua_pushuserdata(L, tags); |
1633 | lua_pushcclosure(L, global_calltable, 2); | 1695 | lua_pushcclosure(L, global_callfromtable, 2); |
1634 | lua_setglobal(L, global[i]); | 1696 | lua_setglobal(L, global[i]); |
1635 | } | 1697 | } |
1636 | } | 1698 | } |
1637 | #endif | 1699 | #endif |
1638 | } | 1700 | } |
1639 | 1701 | ||