/lib/socket.lua

http://github.com/schmurfy/lua_probe · Lua · 206 lines · 190 code · 16 blank · 0 comment · 2 complexity · 8e6740f9ce2a795f6eff2b6d613aab6e MD5 · raw file

  1. local ffi = require('ffi')
  2. local slen = string.len
  3. local server_port = 4000
  4. ffi.cdef [[
  5. typedef uint16_t in_port_t;
  6. typedef uint32_t in_addr_t;
  7. typedef uint32_t socklen_t;
  8. typedef long ssize_t;
  9. typedef unsigned long size_t;
  10. /*
  11. * Internet address (a structure for historical reasons)
  12. */
  13. struct in_addr {
  14. in_addr_t s_addr;
  15. };
  16. ]]
  17. if ffi.os == "Linux" then
  18. ffi.cdef [[
  19. typedef uint16_t sa_family_t;
  20. struct sockaddr_in {
  21. sa_family_t sin_family;
  22. in_port_t sin_port;
  23. struct in_addr sin_addr;
  24. char sin_zero[8];
  25. };
  26. struct sockaddr {
  27. sa_family_t sa_family; /* [XSI] address family */
  28. char sa_data[14]; /* [XSI] addr value (actually larger) */
  29. };
  30. ]]
  31. elseif (ffi.os == "OSX") or (ffi.os == "BSD") then
  32. ffi.cdef [[
  33. typedef uint8_t sa_family_t;
  34. struct sockaddr_in {
  35. uint8_t sin_len;
  36. sa_family_t sin_family;
  37. in_port_t sin_port;
  38. struct in_addr sin_addr;
  39. char sin_zero[8];
  40. };
  41. struct sockaddr {
  42. uint8_t sa_len; /* total length */
  43. sa_family_t sa_family; /* [XSI] address family */
  44. char sa_data[14]; /* [XSI] addr value (actually larger) */
  45. };
  46. ]]
  47. end
  48. ffi.cdef [[
  49. int socket(int domain, int type, int protocol);
  50. int bind(int socket, const struct sockaddr *address, socklen_t address_len);
  51. ssize_t sendto(int socket, const void *buffer, size_t length, int flags, const struct sockaddr_in *dest_addr, socklen_t dest_len);
  52. uint32_t htonl(uint32_t hostlong);
  53. uint16_t htons(uint16_t hostshort);
  54. unsigned int sleep(unsigned int seconds);
  55. int inet_aton(const char *cp, struct in_addr *pin);
  56. char *strerror(int errnum);
  57. ]]
  58. local AF_INET = 2;
  59. local SOCK_DGRAM = 2;
  60. local INADDR_ANY = 0
  61. -- local s = ffi.C.socket(AF_INET, SOCK_DGRAM, 0)
  62. -- if s == -1 then
  63. -- print("ERROR")
  64. -- end
  65. --
  66. -- local serv_addr = ffi.new("struct sockaddr_in")
  67. --
  68. -- serv_addr.sin_family = AF_INET;
  69. -- serv_addr.sin_addr.s_addr = ffi.C.htonl(INADDR_ANY);
  70. -- serv_addr.sin_port = ffi.C.htons(server_port);
  71. --
  72. -- local rc = ffi.C.bind(s, serv_addr, ffi.sizeof(serv_addr));
  73. -- if rc < 0 then
  74. -- print("ERROR")
  75. -- end
  76. --
  77. -- print("Listening on port ".. server_port)
  78. --
  79. -- while 1 do
  80. -- ffi.C.sleep(1);
  81. -- end
  82. local exports = {}
  83. local instance_methods = {}
  84. -- internal utility
  85. local function error_string()
  86. return ffi.string(ffi.C.strerror( ffi.errno() ))
  87. end
  88. function cerror(msg)
  89. print(msg .. ": " .. error_string() .. " (" .. ffi.errno() ..")")
  90. end
  91. -- utility
  92. ffi.cdef [[
  93. typedef uint32_t useconds_t;
  94. int usleep(useconds_t useconds);
  95. ]]
  96. function exports.sleep(n)
  97. ffi.C.usleep(n * 1000000)
  98. end
  99. ffi.cdef [[
  100. typedef long __darwin_time_t;
  101. typedef int32_t __darwin_suseconds_t;
  102. struct timeval {
  103. __darwin_time_t tv_sec; /* seconds */
  104. __darwin_suseconds_t tv_usec; /* and microseconds */
  105. };
  106. int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
  107. ]]
  108. function exports.gettime()
  109. local tv = ffi.new("struct timeval")
  110. ffi.C.gettimeofday(tv, nil);
  111. return tv.tv_sec + tv.tv_usec / 1.0e6;
  112. end
  113. -- Class
  114. function exports.new(socket_type)
  115. local state = {
  116. bound = false,
  117. socket = ffi.C.socket(AF_INET, SOCK_DGRAM, 0)
  118. }
  119. if state.socket == -1 then
  120. cerror("Unable to create socket")
  121. end
  122. return setmetatable(state, {__index = instance_methods})
  123. end
  124. function exports.udp()
  125. return exports.new("udp")
  126. end
  127. -- function instance_methods:bind(port)
  128. -- local local_addr = ffi.new("struct sockaddr_in")
  129. --
  130. -- local_addr.sin_family = AF_INET;
  131. -- local_addr.sin_addr.s_addr = ffi.C.htonl(INADDR_ANY);
  132. -- local_addr.sin_port = ffi.C.htons(port);
  133. --
  134. -- local rc = ffi.C.bind(s, local_addr, ffi.sizeof(local_addr));
  135. -- if rc < 0 then
  136. -- cerror("Unable to bind on port " .. port)
  137. -- end
  138. --
  139. -- self.bound = true
  140. -- end
  141. function instance_methods:sendto(payload, dest_addr, dest_port, payload_len)
  142. payload_len = payload_len or slen(payload) + 1
  143. local sa_dest_addr = ffi.new("struct sockaddr_in[1]")
  144. ffi.fill(sa_dest_addr, ffi.sizeof(sa_dest_addr))
  145. sa_dest_addr[0].sin_family = AF_INET
  146. sa_dest_addr[0].sin_port = ffi.C.htons(dest_port)
  147. if ffi.C.inet_aton(dest_addr, sa_dest_addr[0].sin_addr) == 0 then
  148. cerror("Unable to convert address: " .. dest_addr)
  149. end
  150. local sent = ffi.C.sendto(self.socket, payload, payload_len, 0, sa_dest_addr, ffi.sizeof(sa_dest_addr))
  151. if sent == -1 then
  152. cerror("Unable to send packet")
  153. end
  154. end
  155. return exports