PageRenderTime 32ms CodeModel.GetById 23ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/socket.lua

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