Example #1
0
/*
 * Arguments: sd_udata, new_sd_udata, [sock_addr_udata]
 * Returns: [new_sd_udata | false (EAGAIN)]
 */
static int
sock_accept (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    sd_t *sdp = checkudata(L, 2, SD_TYPENAME);
    struct sock_addr *from = lua_isnoneornil(L, 3) ? NULL
     : checkudata(L, 3, SA_TYPENAME);
    struct sockaddr *sap = NULL;
    socklen_t *slp = NULL;

    if (from) {
	sap = &from->u.addr;
	slp = &from->addrlen;
    }
#ifndef _WIN32
    do sd = accept(sd, sap, slp);
    while (sd == -1 && SYS_ERRNO == EINTR);
#else
    sd = accept(sd, sap, slp);
#endif
    if (sd != (sd_t) -1) {
	*sdp = sd;
	lua_settop(L, 2);
	return 1;
    }
    else if (SYS_EAGAIN(SYS_ERRNO)) {
	lua_pushboolean(L, 0);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #2
0
/*
 * Arguments: sd_udata, nonblocking (boolean)
 * Returns: [sd_udata]
 */
static int
sock_nonblocking (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    unsigned long opt = lua_toboolean(L, 2);

    lua_settop(L, 1);
    return !ioctlsocket(sd, FIONBIO, &opt) ? 1
     : sys_seterror(L, 0);
}
Example #3
0
/*
 * Arguments: sd_udata
 * Returns: string
 */
static int
sock_tostring (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);

    if (sd != (sd_t) -1)
	lua_pushfstring(L, SD_TYPENAME " (%d)", (int) sd);
    else
	lua_pushliteral(L, SD_TYPENAME " (closed)");
    return 1;
}
Example #4
0
/*
 * Arguments: sd_udata, [backlog (number)]
 * Returns: [sd_udata]
 */
static int
sock_listen (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    const int backlog = luaL_optinteger(L, 2, SOMAXCONN);

    if (!listen(sd, backlog)) {
	lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #5
0
/*
 * Arguments: sd_udata, sock_addr_udata
 * Returns: [sd_udata]
 */
static int
sock_bind (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    struct sock_addr *sap = checkudata(L, 2, SA_TYPENAME);

    if (!bind(sd, &sap->u.addr, sap->addrlen)) {
	lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #6
0
/*
 * Arguments: sd_udata
 * Returns: [sd_udata]
 */
static int
sock_shutdown (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);

    /* SHUT_RD (SD_RECEIVE) has different behavior in unix and win32 */
    if (!shutdown(sd, SHUT_WR)) {
	lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #7
0
/*
 * Arguments: sd_udata, option (string),
 *	[value_lo (number), value_hi (number)]
 * Returns: [sd_udata | value_lo (number), value_hi (number)]
 */
static int
sock_sockopt (lua_State *L)
{
    static const int opt_flags[] = {
	SO_REUSEADDR, SO_TYPE, SO_ERROR, SO_DONTROUTE,
	SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT, SO_RCVLOWAT,
	SO_BROADCAST, SO_KEEPALIVE, SO_OOBINLINE, SO_LINGER,
#define OPTNAMES_TCP	12
	TCP_NODELAY,
#define OPTNAMES_IP	13
	IP_MULTICAST_TTL, IP_MULTICAST_IF, IP_MULTICAST_LOOP
    };
    static const char *const opt_names[] = {
	"reuseaddr", "type", "error", "dontroute",
	"sndbuf", "rcvbuf", "sndlowat", "rcvlowat",
	"broadcast", "keepalive", "oobinline", "linger",
	"tcp_nodelay",
	"multicast_ttl", "multicast_if", "multicast_loop", NULL
    };
#undef OPT_START
#define OPT_START	2
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    const int optname = luaL_checkoption(L, OPT_START, NULL, opt_names);
    const int level = (optname < OPTNAMES_TCP) ? SOL_SOCKET
     : (optname < OPTNAMES_IP ? IPPROTO_TCP : IPPROTO_IP);
    const int optflag = opt_flags[optname];
    int optval[4];
    socklen_t optlen = sizeof(int);
    const int nargs = lua_gettop(L);

    if (nargs > OPT_START) {
	optval[0] = lua_tointeger(L, OPT_START + 1);
	if (nargs > OPT_START + 1) {
	    optval[1] = lua_tointeger(L, OPT_START + 2);
	    optlen *= 2;
	}
	if (!setsockopt(sd, level, optflag, (char *) &optval, optlen)) {
	    lua_settop(L, 1);
	    return 1;
	}
    }
    else if (!getsockopt(sd, level, optflag, (char *) &optval, &optlen)) {
	lua_pushinteger(L, optval[0]);
	if (optlen <= sizeof(int))
	    return 1;
	lua_pushinteger(L, optval[1]);
	return 2;
    }
    return sys_seterror(L, 0);
}
Example #8
0
/*
 * Arguments: sd_udata, binary_address (multiaddr),
 *	[binary_address_ipv4 (interface) | interface_ipv6 (number),
 *	add/drop (boolean)]
 * Returns: [sd_udata]
 */
static int
sock_membership (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    int len, af;
    const char *maddrp = sock_checkladdr(L, 2, &len, &af);
    const int optflag = !lua_isboolean(L, -1) || lua_toboolean(L, -1)
     ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
    union {
	struct ip_mreq ip;
#ifdef IPPROTO_IPV6
	struct ipv6_mreq ip6;
#endif
    } mr;
    int level, mr_len;

    memset(&mr, 0, sizeof(mr));
    if (af == AF_INET) {
	const char *ifacep = (lua_type(L, 3) == LUA_TSTRING)
	 ? sock_checkladdr(L, 3, &len, &af) : NULL;

	if (ifacep && af != AF_INET)
	    luaL_argerror(L, 3, "invalid interface");

	memcpy(&mr.ip.imr_multiaddr, maddrp, len);
	if (ifacep)
	    memcpy(&mr.ip.imr_interface, ifacep, len);

	level = IPPROTO_IP;
	mr_len = sizeof(struct ip_mreq);
    }
    else {
#ifdef IPPROTO_IPV6
	memcpy(&mr.ip6.ipv6mr_multiaddr, maddrp, len);
	mr.ip6.ipv6mr_interface = lua_tointeger(L, 3);

	level = IPPROTO_IPV6;
	mr_len = sizeof(struct ipv6_mreq);
#else
	luaL_argerror(L, 2, "invalid family");
#endif
    }

    if (!setsockopt(sd, level, optflag, (char *) &mr, mr_len)) {
	lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #9
0
/*
 * Arguments: rand_udata, [upper_bound (number)
 *	| buffer (ludata), buffer_length (number)]
 * Returns: number
 */
static int
rand_next (lua_State *L)
{
  const int is_udata = lua_isuserdata(L, 2);
  const unsigned int ub = is_udata ? 0 : lua_tointeger(L, 2);
  unsigned int num;
  unsigned char *buf = is_udata ? lua_touserdata(L, 2) : &num;
  const int len = is_udata ? luaL_checkinteger(L, 3) : (int) sizeof(num);
#ifndef _WIN32
  fd_t fd = (fd_t) lua_unboxinteger(L, 1, RAND_TYPENAME);
  int nr;

  sys_vm_leave(L);
  do nr = read(fd, (char *) buf, len);
  while (nr == -1 && sys_eintr());
  sys_vm_enter(L);

  if (nr == len) {
#else
  HCRYPTPROV prov = (HCRYPTPROV) lua_unboxpointer(L, 1, RAND_TYPENAME);
  int res;

  sys_vm_leave(L);
  res = CryptGenRandom(prov, len, buf);
  sys_vm_enter(L);

  if (res) {
#endif
    lua_pushinteger(L, is_udata ? 1
     : (ub ? num % ub : num));
    return 1;
  }
  return sys_seterror(L, 0);
}


#define RAND_METHODS \
  {"random",		sys_random}

static luaL_Reg rand_meth[] = {
  {"__call",		rand_next},
  {"__gc",		rand_close},
  {NULL, NULL}
};
Example #10
0
/*
 * Arguments: sd_udata, [membuf_udata, count (number)]
 * Returns: [string | false (EAGAIN)]
 */
static int
sock_read (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    size_t n = !lua_isnumber(L, -1) ? ~((size_t) 0)
     : (size_t) lua_tointeger(L, -1);
    const size_t len = n;  /* how much total to read */
    size_t rlen;  /* how much to read */
    int nr;  /* number of bytes actually read */
    struct sys_buffer sb;
    char buf[SYS_BUFSIZE];

    sys_buffer_write_init(L, 2, &sb, buf, sizeof(buf));
    do {
	rlen = (n <= sb.size) ? n : sb.size;
	sys_vm_leave();
#ifndef _WIN32
	do nr = read(sd, sb.ptr.w, rlen);
	while (nr == -1 && SYS_ERRNO == EINTR);
#else
	{
	    WSABUF buf = {rlen, sb.ptr.w};
	    DWORD l, flags = 0;
	    nr = !WSARecv(sd, &buf, 1, &l, &flags, NULL, NULL) ? l : -1;
	}
#endif
	sys_vm_enter();
	if (nr == -1) break;
	n -= nr;  /* still have to read `n' bytes */
    } while ((n != 0L && nr == (int) rlen)  /* until end of count or eof */
     && sys_buffer_write_next(L, &sb, buf, 0));
    if (nr <= 0 && len == n) {
	if (!nr || !SYS_EAGAIN(SYS_ERRNO)) goto err;
	lua_pushboolean(L, 0);
    } else {
	if (!sys_buffer_write_done(L, &sb, buf, nr))
	    lua_pushinteger(L, len - n);
    }
    return 1;
 err:
    return sys_seterror(L, 0);
}
Example #11
0
/*
 * Arguments: sd_udata, sock_addr_udata
 * Returns: [sd_udata | false (EINPROGRESS)]
 */
static int
sock_connect (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    struct sock_addr *sap = checkudata(L, 2, SA_TYPENAME);
    int res;

    sys_vm_leave();
    do res = connect(sd, &sap->u.addr, sap->addrlen);
    while (res == -1 && SYS_ERRNO == EINTR);
    sys_vm_enter();

    if (!res || SYS_ERRNO == EINPROGRESS || SYS_ERRNO == EALREADY
#if defined(__FreeBSD__)
     || SYS_ERRNO == EADDRINUSE
#endif
     || SYS_EAGAIN(SYS_ERRNO)) {
	if (res) lua_pushboolean(L, 0);
	else lua_settop(L, 1);
	return 1;
    }
    return sys_seterror(L, 0);
}
Example #12
0
/*
 * Arguments: sd_udata, {string | membuf_udata},
 *	[to (sock_addr_udata), options (string) ...]
 * Returns: [success/partial (boolean), count (number)]
 */
static int
sock_send (lua_State *L)
{
    static const int o_flags[] = {
	MSG_OOB, MSG_DONTROUTE,
    };
    static const char *const o_names[] = {
	"oob", "dontroute", NULL
    };
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    const struct sock_addr *to = !lua_isuserdata(L, 3) ? NULL
     : checkudata(L, 3, SA_TYPENAME);
    struct sys_buffer sb;
    int nw;  /* number of chars actually send */
    unsigned int i, flags = 0;

    if (!sys_buffer_read_init(L, 2, &sb))
	luaL_argerror(L, 2, "buffer expected");
    for (i = lua_gettop(L); i > 3; --i) {
	flags |= o_flags[luaL_checkoption(L, i, NULL, o_names)];
    }
    sys_vm_leave();
    do nw = !to ? send(sd, sb.ptr.r, sb.size, flags)
     : sendto(sd, sb.ptr.r, sb.size, flags, &to->u.addr, to->addrlen);
    while (nw == -1 && SYS_ERRNO == EINTR);
    sys_vm_enter();
    if (nw == -1) {
	if (!SYS_EAGAIN(SYS_ERRNO))
	    return sys_seterror(L, 0);
	nw = 0;
    } else {
	sys_buffer_read_next(&sb, nw);
    }
    lua_pushboolean(L, ((size_t) nw == sb.size));
    lua_pushinteger(L, nw);
    return 2;
}
Example #13
0
/*
 * Returns: [interfaces (table)]
 */
static int
sock_getifaddrs (lua_State *L)
{
  struct sock_addr *sap;
  int i, res;

#ifndef _WIN32
  struct ifaddrs *result, *rp;

  sys_vm_leave(L);
  res = getifaddrs(&result);
  sys_vm_enter(L);
#else
  INTERFACE_INFO result[8192], *rp;
  SOCKET sd = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAGS);
  DWORD n;

  sys_vm_leave(L);
  res = WSAIoctl(sd, SIO_GET_INTERFACE_LIST, NULL, 0,
   result, sizeof(result), &n, NULL, NULL);

  closesocket(sd);
  sys_vm_enter(L);
#endif

  if (res == -1)
    return sys_seterror(L, 0);

  lua_createtable(L, 8, 0);
  rp = result;
#ifndef _WIN32
  for (i = 0; rp; rp = rp->ifa_next) {
#else
  for (i = 0; n--; ++rp) {
#endif
#ifndef _WIN32
    sap = (struct sock_addr *) rp->ifa_addr;
#else
    sap = (struct sock_addr *) &rp->iiAddress;
#endif
    if (!sap || sap->u.addr.sa_family == AF_UNSPEC)
      continue;

    lua_newtable(L);
    {
      const int af = sap->u.addr.sa_family;

      if (af == AF_INET
#ifdef AF_INET6
       || af == AF_INET6
#endif
      ) {
        sock_pushaddr(L, sap);
        lua_setfield(L, -2, "addr");
      }

      {
        const char *s = NULL;

        switch (af) {
        case AF_INET: s = "INET"; break;
#ifdef AF_INET6
        case AF_INET6: s = "INET6"; break;
#endif
#ifdef AF_LOCAL
        case AF_LOCAL: s = "LOCAL"; break;
#endif
#ifdef AF_AX25
        case AF_AX25: s = "AX25"; break;
#endif
#ifdef AF_IPX
        case AF_IPX: s = "IPX"; break;
#endif
#ifdef AF_APPLETALK
        case AF_APPLETALK: s = "APPLETALK"; break;
#endif
#ifdef AF_NETROM
        case AF_NETROM: s = "NETROM"; break;
#endif
#ifdef AF_BRIDGE
        case AF_BRIDGE: s = "BRIDGE"; break;
#endif
#ifdef AF_ATMPVC
        case AF_ATMPVC: s = "ATMPVC"; break;
#endif
#ifdef AF_X25
        case AF_X25: s = "X25"; break;
#endif
#ifdef AF_ROSE
        case AF_ROSE: s = "ROSE"; break;
#endif
#ifdef AF_DECnet
        case AF_DECnet: s = "DECnet"; break;
#endif
#ifdef AF_NETBEUI
        case AF_NETBEUI: s = "NETBEUI"; break;
#endif
#ifdef AF_SECURITY
        case AF_SECURITY: s = "SECURITY"; break;
#endif
#ifdef AF_KEY
        case AF_KEY: s = "KEY"; break;
#endif
#ifdef AF_NETLINK
        case AF_NETLINK: s = "NETLINK"; break;
#endif
#ifdef AF_PACKET
        case AF_PACKET: s = "PACKET"; break;
#endif
#ifdef AF_ASH
        case AF_ASH: s = "ASH"; break;
#endif
#ifdef AF_ECONET
        case AF_ECONET: s = "ECONET"; break;
#endif
#ifdef AF_ATMSVC
        case AF_ATMSVC: s = "ATMSVC"; break;
#endif
#ifdef AF_RDS
        case AF_RDS: s = "RDS"; break;
#endif
#ifdef AF_SNA
        case AF_SNA: s = "SNA"; break;
#endif
#ifdef AF_IRDA
        case AF_IRDA: s = "IRDA"; break;
#endif
#ifdef AF_PPPOX
        case AF_PPPOX: s = "PPPOX"; break;
#endif
#ifdef AF_WANPIPE
        case AF_WANPIPE: s = "WANPIPE"; break;
#endif
#ifdef AF_LLC
        case AF_LLC: s = "LLC"; break;
#endif
#ifdef AF_CAN
        case AF_CAN: s = "CAN"; break;
#endif
#ifdef AF_TIPC
        case AF_TIPC: s = "TIPC"; break;
#endif
#ifdef AF_BLUETOOTH
        case AF_BLUETOOTH: s = "BLUETOOTH"; break;
#endif
#ifdef AF_IUCV
        case AF_IUCV: s = "IUCV"; break;
#endif
#ifdef AF_RXRPC
        case AF_RXRPC: s = "RXRPC"; break;
#endif
#ifdef AF_ISDN
        case AF_ISDN: s = "ISDN"; break;
#endif
#ifdef AF_PHONET
        case AF_PHONET: s = "PHONET"; break;
#endif
#ifdef AF_IEEE802154
        case AF_IEEE802154: s = "IEEE802154"; break;
#endif
        default: s = "UNKNOWN";
        }
        if (s) {
          lua_pushstring(L, s);
          lua_setfield(L, -2, "family");
        }
      }

#ifndef _WIN32
      sap = (struct sock_addr *) rp->ifa_netmask;
#else
      sap = (struct sock_addr *) &rp->iiNetmask;
#endif
      if (sap) {
        sock_pushaddr(L, sap);
        lua_setfield(L, -2, "netmask");
      }

#ifndef _WIN32
      sap = (struct sock_addr *) rp->ifa_broadaddr;
#else
      sap = (struct sock_addr *) &rp->iiBroadcastAddress;
#endif
      if (sap) {
        sock_pushaddr(L, sap);
        lua_setfield(L, -2, "broadaddr");
      }

      lua_createtable(L, 0, 5);
      {
#ifndef _WIN32
        const int flags = rp->ifa_flags;
#else
        const int flags = rp->iiFlags;
#endif

        lua_pushboolean(L, flags & IFF_UP);
        lua_setfield(L, -2, "up");

        lua_pushboolean(L, flags & IFF_BROADCAST);
        lua_setfield(L, -2, "broadcast");

        lua_pushboolean(L, flags & IFF_LOOPBACK);
        lua_setfield(L, -2, "loopback");

        lua_pushboolean(L, flags & IFF_POINTOPOINT);
        lua_setfield(L, -2, "pointtopoint");

        lua_pushboolean(L, flags & IFF_MULTICAST);
        lua_setfield(L, -2, "multicast");
      }
      lua_setfield(L, -2, "flags");
    }
    lua_rawseti(L, -2, ++i);
  }
#ifndef _WIN32
  freeifaddrs(result);
#endif
  return 1;
}


/*
 * Arguments: text_address (string), [ip4_tonumber (true)]
 * Returns: [binary_address (string | number)]
 */
static int
sock_inet_pton (lua_State *L)
{
  const char *src = luaL_checkstring(L, 1);
  const int to_ip4 = lua_toboolean(L, 2);
  const int af = (!to_ip4 && strchr(src, ':')) ? AF_INET6 : AF_INET;
  struct sock_addr sa;
  void *inp = sock_addr_get_inp(&sa, af);
  const int in_len = sock_addr_get_inlen(af);
#ifdef _WIN32
  union sys_rwptr src_ptr;  /* to avoid "const cast" warning */
#endif

  memset(&sa, 0, sizeof(struct sock_addr));
  if (*src == '*') goto end;

#ifndef _WIN32
  if (inet_pton(af, src, inp) == 1) {
#else
  sa.addrlen = sizeof(sa);
  src_ptr.r = src;
  if (!WSAStringToAddressA(src_ptr.w, af, NULL,
   &sa.u.addr, &sa.addrlen)) {
#endif
 end:
    if (to_ip4)
      lua_pushnumber(L, ntohl(*((unsigned long *) inp)));
    else
      lua_pushlstring(L, inp, in_len);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: binary_address (string | number)
 * Returns: [text_address (string)]
 */
static int
sock_inet_ntop (lua_State *L)
{
  const int is_ip4 = (lua_type(L, 1) == LUA_TNUMBER);
  unsigned long ip4;
  int in_len, af;
  const char *src;
  char buf[48];

  if (is_ip4) {
    const lua_Number num = lua_tonumber(L, 1);

    in_len = 4;
    af = AF_INET;
    ip4 = htonl((unsigned long) num);
    src = (const char *) &ip4;
  } else {
    src = sock_checkladdr(L, 1, &in_len, &af);
  }

#ifndef _WIN32
  if (inet_ntop(af, src, buf, sizeof(buf)) == NULL)
    goto err;
#else
  {
    struct sock_addr sa;
    void *inp = sock_addr_get_inp(&sa, af);
    const int sl = (af == AF_INET) ? sizeof(struct sockaddr_in)
     : sizeof(struct sockaddr_in6);
    DWORD buflen = sizeof(buf);

    memset(&sa, 0, sizeof(struct sock_addr));
    memcpy(inp, src, in_len);
    sa.u.addr.sa_family = (short) af;

    if (WSAAddressToStringA(&sa.u.addr, sl, NULL, buf, &buflen)
     || buflen >= sizeof(buf))
      goto err;
  }
#endif
  lua_pushstring(L, buf);
  return 1;
 err:
  return sys_seterror(L, 0);
}


/*
 * Returns: sock_addr_udata
 */
static int
sock_addr_new (lua_State *L)
{
  lua_newuserdata(L, sizeof(struct sock_addr));
  luaL_getmetatable(L, SA_TYPENAME);
  lua_setmetatable(L, -2);
  return 1;
}

/*
 * Arguments: sock_addr_udata, [port (number), binary_address (string)]
 * Returns: sock_addr_udata | port (number), binary_address (string)
 */
static int
sock_addr_inet (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);

  if (lua_gettop(L) == 1) {
    const int af = sap->u.addr.sa_family;

    if (af == AF_INET) {
      lua_pushinteger(L, ntohs(sap->u.in.sin_port));
      lua_pushlstring(L, (char *) &sap->u.in.sin_addr,
       sizeof(struct in_addr));
    } else if (af == AF_INET6) {
      lua_pushinteger(L, ntohs(sap->u.in6.sin6_port));
      lua_pushlstring(L, (char *) &sap->u.in6.sin6_addr,
       sizeof(struct in6_addr));
    } else
      return 0;
    return 2;
  } else {
    const int port = (int) lua_tointeger(L, 2);
    int in_len = SOCK_ADDR_LEN, af = AF_INET;
    const char *addr = lua_isnoneornil(L, 3) ? NULL
     : sock_checkladdr(L, 3, &in_len, &af);

    memset(sap, 0, sizeof(struct sock_addr));
    sap->u.addr.sa_family = (short) af;
    if (af == AF_INET) {
      sap->u.in.sin_port = htons((unsigned short) port);
      if (addr)
        memcpy(&sap->u.in.sin_addr, addr, in_len);
      sap->addrlen = sizeof(struct sockaddr_in);
    } else {
      sap->u.in6.sin6_port = htons((unsigned short) port);
      if (addr)
        memcpy(&sap->u.in6.sin6_addr, addr, in_len);
      sap->addrlen = sizeof(struct sockaddr_in6);
    }
    lua_settop(L, 1);
    return 1;
  };
}

/*
 * Arguments: sock_addr_udata, [path (string)]
 * Returns: sock_addr_udata | path (string)
 */
static int
sock_addr_file (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);

#ifndef _WIN32
  if (lua_gettop(L) == 1) {
    if (sap->u.addr.sa_family == AF_LOCAL) {
      lua_pushstring(L, sap->u.un.sun_path);
      return 1;
    }
  } else {
    size_t len;
    const char *path = luaL_checklstring(L, 2, &len);

    if (len < sizeof(sap->u.un.sun_path)) {
      sap->u.un.sun_family = AF_LOCAL;
      sap->addrlen = ++len;
      memcpy(sap->u.un.sun_path, path, len);

      lua_settop(L, 1);
      return 1;
    }
  };
#else
  (void) sap;
#endif
  return 0;
}

/*
 * Arguments: sock_addr_udata, sd_udata
 * Returns: [sock_addr_udata]
 */
static int
sock_addr_getsockname (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);
  sd_t sd = (sd_t) lua_unboxinteger(L, 2, SD_TYPENAME);

  sap->addrlen = SOCK_ADDR_LEN;
  if (!getsockname(sd, &sap->u.addr, &sap->addrlen)) {
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: sock_addr_udata, sd_udata
 * Returns: [sock_addr_udata]
 */
static int
sock_addr_getpeername (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);
  sd_t sd = (sd_t) lua_unboxinteger(L, 2, SD_TYPENAME);

  sap->addrlen = SOCK_ADDR_LEN;
  if (!getpeername(sd, &sap->u.addr, &sap->addrlen)) {
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: sock_addr_udata
 * Returns: string
 */
static int
sock_addr_tostring (lua_State *L)
{
  struct sock_addr *sap = checkudata(L, 1, SA_TYPENAME);

  lua_pushfstring(L, SA_TYPENAME " (%p)", sap);
  return 1;
}


#define ADDR_METHODS \
  {"getaddrinfo",	sock_getaddrinfo}, \
  {"getnameinfo",	sock_getnameinfo}, \
  {"getifaddrs",	sock_getifaddrs}, \
  {"inet_pton",		sock_inet_pton}, \
  {"inet_ntop",		sock_inet_ntop}, \
  {"addr",		sock_addr_new}

static luaL_Reg addr_meth[] = {
  {"inet",		sock_addr_inet},
  {"file",		sock_addr_file},
  {"getsockname",	sock_addr_getsockname},
  {"getpeername",	sock_addr_getpeername},
  {"__tostring",	sock_addr_tostring},
  {NULL, NULL}
};
Example #14
0
/*
 * Arguments: fd_udata, [options ...:
 *	reset (string: "reset"),
 *	baud_rate (number),
 *	character_size (string: "cs5".."cs8"),
 *	parity (string: "parno", "parodd", "pareven"),
 *	stop_bits (string: "sb1", "sb2"),
 *	flow_controls (string: "foff", "frtscts", "fxio")]
 * Returns: [fd_udata]
 */
static int
comm_init (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int narg = lua_gettop(L);
  int i;

#ifndef _WIN32
  struct termios tio;

  if (tcgetattr(fd, &tio) == -1) goto err;
#else
  DCB dcb;

  dcb.DCBlength = sizeof(DCB);
  if (!GetCommState(fd, &dcb)) goto err;
#endif

  for (i = 2; i <= narg; ++i) {
#ifndef _WIN32
    tcflag_t mask = 0, flag = 0;
#endif

    if (lua_isnumber(L, i)) {
      const int baud_rate = lua_tointeger(L, i);
#ifndef _WIN32
      switch (baud_rate) {
      case 9600: flag = B9600; break;
      case 19200: flag = B19200; break;
      case 38400: flag = B38400; break;
      case 57600: flag = B57600; break;
      case 115200: flag = B115200; break;
      }
      if (cfsetispeed(&tio, flag) == -1
       || cfsetospeed(&tio, flag) == -1)
        goto err;
#else
      dcb.BaudRate = baud_rate;
#endif
    } else {
      const char *opt = lua_tostring(L, i);
      const char *endp = opt + lua_rawlen(L, i) - 1;

      if (!opt) continue;
      switch (*opt) {
      case 'r':  /* reset */
#ifndef _WIN32
        memset(&tio, 0, sizeof(struct termios));
#else
        memset(&dcb, 0, sizeof(DCB));
#endif
        continue;
      case 'c':  /* character size */
#ifndef _WIN32
        switch (*endp) {
        case '5': flag = CS5; break;
        case '6': flag = CS6; break;
        case '7': flag = CS7; break;
        default: flag = CS8;
        }
        mask = CSIZE;
#else
        dcb.ByteSize = (char) (*endp - '0');
#endif
        break;
      case 'p':  /* parity */
#ifndef _WIN32
        switch (*endp) {
        case 'd': flag = PARODD;
        case 'n': flag |= PARENB; break;
        default: flag = 0;  /* no parity */
        }
        mask = PARENB | PARODD;
#else
        {
          int parity;
          switch (*endp) {
          case 'd': parity = ODDPARITY; break;
          case 'n': parity = EVENPARITY; break;
          default: parity = 0;  /* no parity */
          }
          dcb.Parity = (char) parity;
          dcb.fParity = (parity != 0);
        }
#endif
        break;
      case 's':  /* stop bits */
#ifndef _WIN32
        if (*endp == '2') flag = CSTOPB;  /* else: one stop bit */
        mask = CSTOPB;
#else
        dcb.StopBits = (char) (*endp == '2' ? TWOSTOPBITS
         : ONESTOPBIT);
#endif
        break;
      case 'f':  /* flow controls */
        /* off */
#ifndef _WIN32
        mask = CRTSCTS;
        tio.c_iflag &= ~(IXON | IXOFF | IXANY);
#else
        dcb.fOutX = dcb.fInX = 0;
        dcb.fRtsControl = RTS_CONTROL_DISABLE;
        dcb.fOutxCtsFlow = 0;
#endif
        switch (opt[1]) {
        case 'x':  /* XON/XOFF */
#ifndef _WIN32
          tio.c_iflag |= (IXON | IXOFF | IXANY);
#else
          dcb.fOutX = dcb.fInX = 1;
#endif
          break;
        case 'r':  /* RTS/CTS */
#ifndef _WIN32
          flag = CRTSCTS;
#else
          dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
          dcb.fOutxCtsFlow = 1;
#endif
          break;
        }
        break;
      }
    }
#ifndef _WIN32
    tio.c_cflag &= ~mask;
    tio.c_cflag |= flag;
#endif
  }
#ifndef _WIN32
  tio.c_cflag |= CLOCAL | CREAD;

  if (!tcsetattr(fd, TCSANOW, &tio)) {
#else
  if (SetCommState(fd, &dcb)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
 err:
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, [controls (string: "dtr", "dsr", "rts", "cts") ...]
 * Returns: [fd_udata]
 */
static int
comm_control (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int narg = lua_gettop(L);
  int i;

#ifndef _WIN32
  int flags;

  if (ioctl(fd, TIOCMGET, &flags) == -1) goto err;
  flags &= ~(TIOCM_DTR | TIOCM_DSR | TIOCM_RTS | TIOCM_CTS
   | TIOCM_ST | TIOCM_SR | TIOCM_CAR | TIOCM_RNG);
#else
  DCB dcb;

  dcb.DCBlength = sizeof(DCB);
  if (!GetCommState(fd, &dcb)) goto err;
  dcb.fDtrControl = dcb.fOutxDsrFlow
   = dcb.fRtsControl = dcb.fOutxCtsFlow = 0;
#endif

  for (i = 2; i <= narg; ++i) {
    const char *s = lua_tostring(L, i);

    if (!s) continue;
    switch (*s) {
    case 'd':  /* DTR/DSR */
#ifndef _WIN32
      flags |= (s[1] == 't') ? TIOCM_DTR : TIOCM_DSR;
#else
      if (s[1] == 't') dcb.fDtrControl = 1;
      else dcb.fOutxDsrFlow = 1;
#endif
      break;
    case 'r':  /* RTS */
#ifndef _WIN32
      flags |= TIOCM_RTS;
#else
      dcb.fRtsControl = 1;
#endif
      break;
    case 'c':  /* CTS */
#ifndef _WIN32
      flags |= TIOCM_CTS;
#else
      dcb.fOutxCtsFlow = 1;
#endif
      break;
    }
  }
#ifndef _WIN32
  if (!ioctl(fd, TIOCMSET, &flags)) {
#else
  if (SetCommState(fd, &dcb)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
 err:
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, [read_timeout (milliseconds)]
 * Returns: [fd_udata]
 */
static int
comm_timeout (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int rtime = lua_tointeger(L, 2);

#ifndef _WIN32
  struct termios tio;

  if (tcgetattr(fd, &tio) == -1) goto err;
  tio.c_cc[VTIME] = rtime / 100;
  tio.c_cc[VMIN] = 0;

  if (!tcsetattr(fd, TCSANOW, &tio)) {
#else
  COMMTIMEOUTS timeouts;

  memset(&timeouts, 0, sizeof(COMMTIMEOUTS));
  timeouts.ReadIntervalTimeout = rtime ? (DWORD) rtime : MAXDWORD;
  timeouts.ReadTotalTimeoutMultiplier =
   timeouts.ReadTotalTimeoutConstant = rtime;

  if (SetCommTimeouts(fd, &timeouts)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
#ifndef _WIN32
 err:
#endif
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, in_buffer_size (number), out_buffer_size (number)
 * Returns: [fd_udata]
 */
static int
comm_queues (lua_State *L)
{
#ifndef _WIN32
  if (1) {
#else
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int rqueue = lua_tointeger(L, 2);
  const int wqueue = lua_tointeger(L, 3);

  if (SetupComm(fd, rqueue, wqueue)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
#ifdef _WIN32
  return sys_seterror(L, 0);
#endif
}

/*
 * Arguments: fd_udata, [mode (string: "rw", "r", "w")]
 * Returns: [fd_udata]
 */
static int
comm_purge (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const char *mode = lua_tostring(L, 2);
  int flags;

  flags = TCIOFLUSH;
  if (mode)
    switch (mode[0]) {
    case 'w': flags = TCOFLUSH; break;
    case 'r': if (!mode[1]) flags = TCIFLUSH;
    }
#ifndef _WIN32
  if (!tcflush(fd, flags)) {
#else
  if (PurgeComm(fd, flags)) {
#endif
    lua_settop(L, 1);
    return 1;
  }
  return sys_seterror(L, 0);
}

/*
 * Arguments: fd_udata, options (string: "car", "cts", "dsr", "ring") ...
 * Returns: [boolean ...]
 */
static int
comm_wait (lua_State *L)
{
  const fd_t fd = (fd_t) lua_unboxinteger(L, 1, FD_TYPENAME);
  const int narg = lua_gettop(L);
  unsigned long status = 0;
  int flags = 0;
  int i, res;

  for (i = 2; i <= narg; ++i) {
    const char *s = lua_tostring(L, i);

    if (!s) continue;
    switch (*s) {
    case 'c':  /* CAR/CTS */
      flags |= (s[1] == 'a') ? TIOCM_CAR : TIOCM_CTS;
      break;
    case 'd':  /* DSR */
      flags |= TIOCM_DSR;
      break;
    case 'r':  /* RING */
      flags |= TIOCM_RNG;
      break;
    }
  }

  sys_vm_leave();
#ifndef _WIN32
  do {
#ifdef TIOCMIWAIT
    res = !(ioctl(fd, TIOCMIWAIT, flags) || ioctl(fd, TIOCMGET, &status));
#else
    while ((res = !ioctl(fd, TIOCMGET, &status)) && !(status & flags))
      usleep(10000);  /* 10 msec polling */
#endif
  } while (!res && sys_eintr());
#else
  res = SetCommMask(fd, flags) && WaitCommEvent(fd, &status, NULL);
#endif
  sys_vm_enter();

  if (res) {
    if (flags & TIOCM_CAR)
      lua_pushboolean(L, status & TIOCM_CAR);
    if (flags & TIOCM_CTS)
      lua_pushboolean(L, status & TIOCM_CTS);
    if (flags & TIOCM_DSR)
      lua_pushboolean(L, status & TIOCM_DSR);
    if (flags & TIOCM_RNG)
      lua_pushboolean(L, status & TIOCM_RNG);
    return narg - 1;
  }
  return sys_seterror(L, 0);
}
Example #15
0
/*
 * Arguments: sd_udata, fd_udata, [count (number)]
 * Returns: [count (number) | false (EAGAIN)]
 */
static int
sock_sendfile (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    fd_t fd = (fd_t) lua_unboxinteger(L, 2, FD_TYPENAME);
    size_t n = (size_t) lua_tointeger(L, 3);
    ssize_t res;

    sys_vm_leave();
#ifndef _WIN32
#if defined(__linux__)
    do res = sendfile(sd, fd, NULL, n ? n : ~((size_t) 0));
    while (res == -1 && SYS_ERRNO == EINTR);
#else
    {
	off_t nw, off = lseek(fd, 0, SEEK_CUR);

#if defined(__APPLE__) && defined(__MACH__)
	nw = n;
	do res = sendfile(fd, sd, off, &nw, NULL, 0);
#else
	do res = sendfile(fd, sd, off, n, NULL, &nw, 0);
#endif
	while (res == -1 && SYS_ERRNO == EINTR);
	if (res != -1) {
	    res = (size_t) nw;
	    lseek(fd, nw, SEEK_CUR);
	}
    }
#endif
    sys_vm_enter();

    if (res != -1 || SYS_EAGAIN(SYS_ERRNO)) {
	if (res == -1) {
	    lua_pushboolean(L, 0);
	    return 1;
	}
#else
    res = TransmitFileMap(sd, fd, n);
    sys_vm_enter();

    if (res != 0L) {
#endif
	lua_pushinteger(L, res);
	return 1;
    }
    return sys_seterror(L, 0);
}

/*
 * Arguments: sd_udata, {string | membuf_udata} ...
 * Returns: [success/partial (boolean), count (number)]
 */
static int
sock_write (lua_State *L)
{
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    ssize_t n = 0;  /* number of chars actually write */
    int i, nargs = lua_gettop(L);

    for (i = 2; i <= nargs; ++i) {
	struct sys_buffer sb;
	int nw;

	if (!sys_buffer_read_init(L, i, &sb))
	    continue;
	sys_vm_leave();
#ifndef _WIN32
	do nw = write(sd, sb.ptr.r, sb.size);
	while (nw == -1 && SYS_ERRNO == EINTR);
#else
	{
	    WSABUF buf = {sb.size, sb.ptr.w};
	    DWORD l;
	    nw = !WSASend(sd, &buf, 1, &l, 0, NULL, NULL) ? l : -1;
	}
#endif
	sys_vm_enter();
	if (nw == -1) {
	    if (n > 0 || SYS_EAGAIN(SYS_ERRNO)) break;
	    return sys_seterror(L, 0);
	}
	n += nw;
	sys_buffer_read_next(&sb, nw);
	if ((size_t) nw < sb.size) break;
    }
    lua_pushboolean(L, (i > nargs));
    lua_pushinteger(L, n);
    return 2;
}
Example #16
0
/*
 * Arguments: sd_udata, [count (number) | membuf_udata,
 *	from (sock_addr_udata), options (string) ...]
 * Returns: [string | count (number) | false (EAGAIN)]
 */
static int
sock_recv (lua_State *L)
{
    static const int o_flags[] = {
	MSG_OOB, MSG_PEEK,
#ifndef _WIN32
	MSG_WAITALL
#endif
    };
    static const char *const o_names[] = {
	"oob", "peek",
#ifndef _WIN32
	"waitall",
#endif
	NULL
    };
    sd_t sd = (sd_t) lua_unboxinteger(L, 1, SD_TYPENAME);
    size_t n = !lua_isnumber(L, 2) ? ~((size_t) 0)
     : (size_t) lua_tointeger(L, 2);
    struct sock_addr *from = !lua_isuserdata(L, 3) ? NULL
     : checkudata(L, 3, SA_TYPENAME);
    struct sockaddr *sap = NULL;
    socklen_t *slp = NULL;
    const size_t len = n;  /* how much total to read */
    size_t rlen;  /* how much to read */
    int nr;  /* number of bytes actually read */
    struct sys_buffer sb;
    char buf[SYS_BUFSIZE];
    unsigned int i, flags = 0;

    sys_buffer_write_init(L, 2, &sb, buf, sizeof(buf));

    for (i = lua_gettop(L); i > 3; --i) {
	flags |= o_flags[luaL_checkoption(L, i, NULL, o_names)];
    }
    if (from) {
	sap = &from->u.addr;
	slp = &from->addrlen;
    }
    do {
	rlen = (n <= sb.size) ? n : sb.size;
	sys_vm_leave();
#ifndef _WIN32
	do nr = recvfrom(sd, sb.ptr.w, rlen, flags, sap, slp);
	while (nr == -1 && SYS_ERRNO == EINTR);
#else
	nr = recvfrom(sd, sb.ptr.w, rlen, flags, sap, slp);
#endif
	sys_vm_enter();
	if (nr == -1) break;
	n -= nr;  /* still have to read `n' bytes */
    } while ((n != 0L && nr == (int) rlen)  /* until end of count or eof */
     && sys_buffer_write_next(L, &sb, buf, 0));
    if (nr <= 0 && len == n) {
	if (!nr || !SYS_EAGAIN(SYS_ERRNO)) goto err;
	lua_pushboolean(L, 0);
    } else {
	if (!sys_buffer_write_done(L, &sb, buf, nr))
	    lua_pushinteger(L, len - n);
    }
    return 1;
 err:
    return sys_seterror(L, 0);
}