Re: Lispworks and UDP sockets
Here is a quick and dirty hach which I used once
on windows. It should be easy to tweak it for linux if it doesn't work as
is.
Marc
(fli:define-c-typedef (socket (:foreign-name
"SOCKET"))
(:unsigned :int))
(fli:define-c-struct (in-addr (:foreign-name
"in_addr"))
(s-addr (:unsigned :long)))
(fli:define-c-struct (sockaddr-in (:foreign-name
"sockaddr_in"))
(sin-family
:short)
(sin-port (:unsigned
:short))
(sin-addr (:unsigned
:long))
(sin-zero (:c-array :char 8)))
(fli:define-c-typedef :udp-buffer (:c-array (:unsigned :char)
64))
(fli:define-foreign-function (socket "socket"
:source)
((af :int) (type :int) (protocol
:int))
:result-type
socket
:language
:ansi-c
:calling-convention :cdecl)
(fli:define-c-struct
(sockaddr
(:foreign-name
"sockaddr")
(:forward-reference t)))
(fli:define-foreign-function (bind "bind"
:source)
((s
socket)
(name (:pointer (:struct
sockaddr-in)))
(namelen
:int))
:result-type
:int
:language
:ansi-c
:calling-convention :cdecl)
(fli:define-foreign-function (set-sock-opt "setsockopt"
:source)
((s
socket)
(level
:int)
(optname
:int)
(optval (:pointer
:char))
(optlen
:int))
:result-type
:int
:language
:ansi-c
:calling-convention :cdecl)
(fli:define-foreign-function (send-to "sendto"
:source)
((s
socket)
(buf (:pointer
:char))
(len
:int)
(flags
:int)
(to (:pointer (:struct
sockaddr)))
(tolen
:int))
:result-type
:int
:language
:ansi-c
:calling-convention :cdecl)
(fli:define-foreign-function (recv-from "recvfrom"
:source)
((s
socket)
(buf
:pointer)
(len
:int)
(flags
:int)
(from (:pointer (:struct
sockaddr-in)))
(fromlen (:pointer
:int)))
:result-type
:int
:language
:ansi-c
:calling-convention :cdecl)
(fli:define-foreign-function (close-socket "closesocket"
:source)
((s
socket))
:result-type
:int
:language
:ansi-c
:calling-convention :cdecl)
(defconstant
AF_INET 2)
(defconstant
SOCK_DGRAM 2)
(defconstant
IPPROTO_UDP 17)
(defconstant INADDR_ANY
#x00000000)
(defvar *udp-socket* nil)
(defvar *udp-buffer*
nil)
(defun start-udp-listener ()
(unless
*udp-socket*
(setf *udp-socket* (socket AF_INET SOCK_DGRAM
IPPROTO_UDP))
(setf *udp-buffer*
(fli:allocate-foreign-object :type '(:c-array (:unsigned :char)
100)))
(fli:with-dynamic-foreign-objects
()
(let ((recv-addr
(fli:allocate-dynamic-foreign-object :type
'sockaddr-in)))
(setf
(fli:foreign-slot-value recv-addr 'sin-family)
AF_INET
(fli:foreign-slot-value recv-addr 'sin-port) #x8913
;5001
(fli:foreign-slot-value recv-addr 'sin-addr)
INADDR_ANY)
(bind *udp-socket*
recv-addr (fli:size-of 'sockaddr-in)))))
*udp-socket*)
(defun read-udp-socket ()
(when
*udp-socket*
(fli:with-dynamic-foreign-objects
()
(let* ((sender-addr
(fli:allocate-dynamic-foreign-object :type
'sockaddr-in))
(addr-size
(fli:allocate-dynamic-foreign-object
:type :int :initial-element (fli:size-of
'sockaddr-in)))
(nb-read (recv-from *udp-socket* *udp-buffer* 100 0 sender-addr
addr-size)))
(values
(loop for i from 0 below
nb-read collect (fli:foreign-aref *udp-buffer*
i))
(fli:foreign-slot-value
sender-addr 'sin-port)
(fli:foreign-slot-value sender-addr 'sin-addr))))))
(defun stop-udp-listener ()
(when
*udp-socket*
(close-socket
*udp-socket*)
(setf *udp-socket* nil)))