diff options
Diffstat (limited to 'src')
| -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 | ||
