summary refs log tree commit diff stats
path: root/tests/vm/tcastint.nim
blob: 7b9ddd7d9ff5ddcd59ca60a63599d9ff8c03d52b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
discard """
  file: "tcastint.nim"
  output: "OK"
"""

type
  Dollar = distinct int
  XCoord = distinct int32
  Digit = range[-9..0]

# those are necessary for comparisons below.
proc `==`(x, y: Dollar): bool {.borrow.}
proc `==`(x, y: XCoord): bool {.borrow.}

proc dummy[T](x: T): T = x

proc test() =
  let U8 = 0b1011_0010'u8
  let I8 = 0b1011_0010'i8
  let C8 = 0b1011_0010'u8.char
  let C8_1 = 0b1011_0011'u8.char
  let U16 = 0b10100111_00101000'u16
  let I16 = 0b10100111_00101000'i16
  let U32 = 0b11010101_10011100_11011010_01010000'u32
  let I32 = 0b11010101_10011100_11011010_01010000'i32
  let U64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
  let I64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
  let U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
  let I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
  when sizeof(int) == 8:
    let UX = U64A.uint
    let IX = I64A.int
  elif sizeof(int) == 4:
    let UX = U32.uint
    let IX = I32.int
  elif sizeof(int) == 2:
    let UX = U16.uint
    let IX = I16.int
  else:
    let UX = U8.uint
    let IX = I8.int

  doAssert(cast[char](I8) == C8)
  doAssert(cast[uint8](I8) == U8)
  doAssert(cast[uint16](I16) == U16)
  doAssert(cast[uint32](I32) == U32)
  doAssert(cast[uint64](I64A) == U64A)
  doAssert(cast[uint64](I64B) == U64B)
  doAssert(cast[int8](U8) == I8)
  doAssert(cast[int16](U16) == I16)
  doAssert(cast[int32](U32) == I32)
  doAssert(cast[int64](U64A) == I64A)
  doAssert(cast[int64](U64B) == I64B)
  doAssert(cast[uint](IX) == UX)
  doAssert(cast[int](UX) == IX)

  doAssert(cast[char](I8 + 1) == C8_1)
  doAssert(cast[uint8](I8 + 1) == U8 + 1)
  doAssert(cast[uint16](I16 + 1) == U16 + 1)
  doAssert(cast[uint32](I32 + 1) == U32 + 1)
  doAssert(cast[uint64](I64A + 1) == U64A + 1)
  doAssert(cast[uint64](I64B + 1) == U64B + 1)
  doAssert(cast[int8](U8 + 1) == I8 + 1)
  doAssert(cast[int16](U16 + 1) == I16 + 1)
  doAssert(cast[int32](U32 + 1) == I32 + 1)
  doAssert(cast[int64](U64A + 1) == I64A + 1)
  doAssert(cast[int64](U64B + 1) == I64B + 1)
  doAssert(cast[uint](IX + 1) == UX + 1)
  doAssert(cast[int](UX + 1) == IX + 1)

  doAssert(cast[char](I8.dummy) == C8.dummy)
  doAssert(cast[uint8](I8.dummy) == U8.dummy)
  doAssert(cast[uint16](I16.dummy) == U16.dummy)
  doAssert(cast[uint32](I32.dummy) == U32.dummy)
  doAssert(cast[uint64](I64A.dummy) == U64A.dummy)
  doAssert(cast[uint64](I64B.dummy) == U64B.dummy)
  doAssert(cast[int8](U8.dummy) == I8.dummy)
  doAssert(cast[int16](U16.dummy) == I16.dummy)
  doAssert(cast[int32](U32.dummy) == I32.dummy)
  doAssert(cast[int64](U64A.dummy) == I64A.dummy)
  doAssert(cast[int64](U64B.dummy) == I64B.dummy)
  doAssert(cast[uint](IX.dummy) == UX.dummy)
  doAssert(cast[int](UX.dummy) == IX.dummy)


  doAssert(cast[int64](if false: U64B else: 0'u64) == (if false: I64B else: 0'i64))

  block:
    let raw = 3
    let money = Dollar(raw) # this must be a variable, is otherwise constant folded.
    doAssert(cast[int](money) == raw)
    doAssert(cast[Dollar](raw) == money)
  block:
    let raw = 150'i32
    let position = XCoord(raw) # this must be a variable, is otherwise constant folded.
    doAssert(cast[int32](position) == raw)
    doAssert(cast[XCoord](raw) == position)
  block:
    let raw = -2
    let digit = Digit(raw)
    doAssert(cast[int](digit) == raw)
    doAssert(cast[Digit](raw) == digit)

  when defined nimvm:
    doAssert(not compiles(cast[float](I64A)))
    doAssert(not compiles(cast[float32](I64A)))

    doAssert(not compiles(cast[char](I64A)))
    doAssert(not compiles(cast[uint16](I64A)))
    doAssert(not compiles(cast[uint32](I64A)))

    doAssert(not compiles(cast[uint16](I8)))
    doAssert(not compiles(cast[uint32](I8)))
    doAssert(not compiles(cast[uint64](I8)))

test()
static:
  test()

echo "OK"
const char *address = luaL_checkstring(L, 1); static char buffer[1024] = {0}; memset(buffer, '\0', 1024); snprintf(buffer, 1020, "socket.tohostname(\"%s\")", address); append_to_audit_log(L, buffer); struct hostent *hp = NULL; int err = inet_gethost(address, &hp); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, socket_hoststrerror(err)); return 2; } lua_pushstring(L, hp->h_name); inet_pushresolved(L, hp); return 2; } static int inet_global_getnameinfo(lua_State *L) { char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; int i, ret; struct addrinfo hints; struct addrinfo *resolved, *iter; const char *host = luaL_optstring(L, 1, NULL); const char *serv = luaL_optstring(L, 2, NULL); static char buffer[1024] = {0}; memset(buffer, '\0', 1024); snprintf(buffer, 1020, "socket.getnameinfo(\"%s\", \"%s\")", host, serv); append_to_audit_log(L, buffer); if (!(host || serv)) luaL_error(L, "host and serv cannot be both nil"); memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; ret = getaddrinfo(host, serv, &hints, &resolved); if (ret != 0) { lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_newtable(L); for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, hbuf, host? (socklen_t) sizeof(hbuf): 0, sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); if (host) { lua_pushnumber(L, i); lua_pushstring(L, hbuf); lua_settable(L, -3); } } freeaddrinfo(resolved); if (serv) { lua_pushstring(L, sbuf); return 2; } else { return 1; } } /*-------------------------------------------------------------------------*\ * Returns all information provided by the resolver given a host name * or ip address \*-------------------------------------------------------------------------*/ static int inet_global_toip(lua_State *L) { const char *address = luaL_checkstring(L, 1); struct hostent *hp = NULL; static char buffer[1024] = {0}; memset(buffer, '\0', 1024); snprintf(buffer, 1020, "socket.toip(\"%s\")", address); append_to_audit_log(L, buffer); int err = inet_gethost(address, &hp); if (err != IO_DONE) { lua_pushnil(L); lua_pushstring(L, socket_hoststrerror(err)); return 2; } lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); inet_pushresolved(L, hp); return 2; } int inet_optfamily(lua_State* L, int narg, const char* def) { static const char* optname[] = { "unspec", "inet", "inet6", NULL }; static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; return optvalue[luaL_checkoption(L, narg, def, optname)]; } int inet_optsocktype(lua_State* L, int narg, const char* def) { static const char* optname[] = { "stream", "dgram", NULL }; static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; return optvalue[luaL_checkoption(L, narg, def, optname)]; } static int inet_global_getaddrinfo(lua_State *L) { const char *hostname = luaL_checkstring(L, 1); struct addrinfo *iterator = NULL, *resolved = NULL; struct addrinfo hints; int i = 1, ret = 0; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; ret = getaddrinfo(hostname, NULL, &hints, &resolved); if (ret != 0) { lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_newtable(L); for (iterator = resolved; iterator; iterator = iterator->ai_next) { char hbuf[NI_MAXHOST]; ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); if (ret){ freeaddrinfo(resolved); lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_pushnumber(L, i); lua_newtable(L); switch (iterator->ai_family) { case AF_INET: lua_pushliteral(L, "family"); lua_pushliteral(L, "inet"); lua_settable(L, -3); break; case AF_INET6: lua_pushliteral(L, "family"); lua_pushliteral(L, "inet6"); lua_settable(L, -3); break; case AF_UNSPEC: lua_pushliteral(L, "family"); lua_pushliteral(L, "unspec"); lua_settable(L, -3); break; default: lua_pushliteral(L, "family"); lua_pushliteral(L, "unknown"); lua_settable(L, -3); break; } lua_pushliteral(L, "addr"); lua_pushstring(L, hbuf); lua_settable(L, -3); lua_settable(L, -3); i++; } freeaddrinfo(resolved); return 1; } /*-------------------------------------------------------------------------*\ * Gets the host name \*-------------------------------------------------------------------------*/ static int inet_global_gethostname(lua_State *L) { char name[257]; name[256] = '\0'; if (gethostname(name, 256) < 0) { lua_pushnil(L); lua_pushstring(L, socket_strerror(errno)); return 2; } else { lua_pushstring(L, name); return 1; } } /*=========================================================================*\ * Lua methods \*=========================================================================*/ /*-------------------------------------------------------------------------*\ * Retrieves socket peer name \*-------------------------------------------------------------------------*/ int inet_meth_getpeername(lua_State *L, p_socket ps, int family) { int err; struct sockaddr_storage peer; socklen_t peer_len = sizeof(peer); char name[INET6_ADDRSTRLEN]; char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { lua_pushnil(L); lua_pushstring(L, socket_strerror(errno)); return 2; } err = getnameinfo((struct sockaddr *) &peer, peer_len, name, INET6_ADDRSTRLEN, port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); if (err) { lua_pushnil(L); lua_pushstring(L, gai_strerror(err)); return 2; } lua_pushstring(L, name); lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); switch (family) { case AF_INET: lua_pushliteral(L, "inet"); break; case AF_INET6: lua_pushliteral(L, "inet6"); break; case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; default: lua_pushliteral(L, "unknown"); break; } return 3; } /*-------------------------------------------------------------------------*\ * Retrieves socket local name \*-------------------------------------------------------------------------*/ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) { int err; struct sockaddr_storage peer; socklen_t peer_len = sizeof(peer); char name[INET6_ADDRSTRLEN]; char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) { lua_pushnil(L); lua_pushstring(L, socket_strerror(errno)); return 2; } err=getnameinfo((struct sockaddr *)&peer, peer_len, name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); if (err) { lua_pushnil(L); lua_pushstring(L, gai_strerror(err)); return 2; } lua_pushstring(L, name); lua_pushstring(L, port); switch (family) { case AF_INET: lua_pushliteral(L, "inet"); break; case AF_INET6: lua_pushliteral(L, "inet6"); break; case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; default: lua_pushliteral(L, "unknown"); break; } return 3; } /*=========================================================================*\ * Internal functions \*=========================================================================*/ /*-------------------------------------------------------------------------*\ * Passes all resolver information to Lua as a table \*-------------------------------------------------------------------------*/ static void inet_pushresolved(lua_State *L, struct hostent *hp) { char **alias; struct in_addr **addr; int i, resolved; lua_newtable(L); resolved = lua_gettop(L); lua_pushstring(L, "name"); lua_pushstring(L, hp->h_name); lua_settable(L, resolved); lua_pushstring(L, "ip"); lua_pushstring(L, "alias"); i = 1; alias = hp->h_aliases; lua_newtable(L); if (alias) { while (*alias) { lua_pushnumber(L, i); lua_pushstring(L, *alias); lua_settable(L, -3); i++; alias++; } } lua_settable(L, resolved); i = 1; lua_newtable(L); addr = (struct in_addr **) hp->h_addr_list; if (addr) { while (*addr) { lua_pushnumber(L, i); lua_pushstring(L, inet_ntoa(**addr)); lua_settable(L, -3); i++; addr++; } } lua_settable(L, resolved); } /*-------------------------------------------------------------------------*\ * Tries to create a new inet socket \*-------------------------------------------------------------------------*/ const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { const char *err = socket_strerror(socket_create(ps, family, type, protocol)); if (err == NULL && family == AF_INET6) { int yes = 1; setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); } return err; } /*-------------------------------------------------------------------------*\ * "Disconnects" a DGRAM socket \*-------------------------------------------------------------------------*/ const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) { switch (family) { case AF_INET: { struct sockaddr_in sin; memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_UNSPEC; sin.sin_addr.s_addr = INADDR_ANY; return socket_strerror(socket_connect(ps, (SA *) &sin, sizeof(sin), tm)); } case AF_INET6: { struct sockaddr_in6 sin6; struct in6_addr addrany = IN6ADDR_ANY_INIT; memset((char *) &sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_UNSPEC; sin6.sin6_addr = addrany; return socket_strerror(socket_connect(ps, (SA *) &sin6, sizeof(sin6), tm)); } } return NULL; } /*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* create new socket if necessary. if there was no * bind, we need to create one for every new family * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; /* set non-blocking before connect */ socket_setnonblocking(ps); } /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success or timeout is zero, break out of loop */ if (err == NULL || timeout_iszero(tm)) { *family = current_family; break; } } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; } /*-------------------------------------------------------------------------*\ * Tries to accept a socket \*-------------------------------------------------------------------------*/ const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm) { socklen_t len; t_sockaddr_storage addr; switch (family) { case AF_INET6: len = sizeof(struct sockaddr_in6); break; case AF_INET: len = sizeof(struct sockaddr_in); break; default: len = sizeof(addr); break; } return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm)); } /*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* translate luasocket special values to C */ if (strcmp(address, "*") == 0) address = NULL; if (!serv) serv = "0"; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); if (err) { if (resolved) freeaddrinfo(resolved); return err; } /* iterate over resolved addresses until one is good */ for (iterator = resolved; iterator; iterator = iterator->ai_next) { if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; } /* try binding to local address */ err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen)); /* keep trying unless bind succeeded */ if (err == NULL) { *family = current_family; /* set to non-blocking after bind */ socket_setnonblocking(ps); break; } } /* cleanup and return error */ freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; } /*-------------------------------------------------------------------------*\ * Some systems do not provide these so that we provide our own. \*-------------------------------------------------------------------------*/ #ifdef LUASOCKET_INET_ATON int inet_aton(const char *cp, struct in_addr *inp) { unsigned int a = 0, b = 0, c = 0, d = 0; int n = 0, r; unsigned long int addr = 0; r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); if (r == 0 || n == 0) return 0; cp += n; if (*cp) return 0; if (a > 255 || b > 255 || c > 255 || d > 255) return 0; if (inp) { addr += a; addr <<= 8; addr += b; addr <<= 8; addr += c; addr <<= 8; addr += d; inp->s_addr = htonl(addr); } return 1; } #endif #ifdef LUASOCKET_INET_PTON int inet_pton(int af, const char *src, void *dst) { struct addrinfo hints, *res; int ret = 1; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = af; hints.ai_flags = AI_NUMERICHOST; if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1; if (af == AF_INET) { struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; memcpy(dst, &in->sin_addr, sizeof(in->sin_addr)); } else if (af == AF_INET6) { struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr)); } else { ret = -1; } freeaddrinfo(res); return ret; } #endif