2010-09-25 13:48:08 +00:00
|
|
|
(cl:in-package #:osc)
|
|
|
|
|
|
|
|
(defun make-osc-server (&key (protocol :udp) debug-mode
|
2015-07-10 15:41:42 +00:00
|
|
|
(buffer-size *default-osc-buffer-size*)
|
|
|
|
cleanup-fun)
|
2010-09-25 13:48:08 +00:00
|
|
|
(ecase protocol
|
|
|
|
(:udp (make-instance 'osc-server-udp
|
2015-07-10 15:41:42 +00:00
|
|
|
:debug-mode debug-mode
|
|
|
|
:cleanup-fun cleanup-fun
|
|
|
|
:buffer-size buffer-size))
|
2010-09-25 13:48:08 +00:00
|
|
|
(:tcp (make-instance 'osc-server-tcp
|
2015-07-10 15:41:42 +00:00
|
|
|
:debug-mode debug-mode
|
|
|
|
:cleanup-fun cleanup-fun
|
|
|
|
:buffer-size buffer-size))))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defgeneric boot (osc-server port))
|
|
|
|
|
|
|
|
(defmethod boot :around ((server osc-server) port)
|
|
|
|
(if (device-active-p server)
|
|
|
|
(warn "~%Server ~A already running" (machine-instance)))
|
|
|
|
(set-socket (make-socket (protocol server)) server)
|
|
|
|
(socket-bind (socket server) #(0 0 0 0) port)
|
|
|
|
(call-next-method)
|
|
|
|
(format t "~%Server ~A listening on port ~A~%"
|
2015-07-10 15:41:42 +00:00
|
|
|
(machine-instance) port))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defmethod boot ((server osc-server-udp) port)
|
|
|
|
(declare (ignore port))
|
|
|
|
"UDP server sockets are used for receiving and unconnected sending."
|
|
|
|
(set-listening-thread (make-listening-thread server) server))
|
|
|
|
|
|
|
|
(defmethod boot ((server osc-server-tcp) port)
|
|
|
|
(declare (ignore port))
|
|
|
|
(set-listening-thread
|
|
|
|
(sb-thread:make-thread
|
|
|
|
(lambda ()
|
|
|
|
(unwind-protect
|
2015-07-10 15:41:42 +00:00
|
|
|
(progn (socket-listen (socket server) 10)
|
|
|
|
(loop for socket = (socket-accept (socket server))
|
|
|
|
for endpoint = (make-osc-client-endpoint-tcp
|
|
|
|
socket
|
|
|
|
(debug-mode server)
|
|
|
|
(buffer-size server)
|
|
|
|
(address-tree server)
|
|
|
|
(clients server)
|
|
|
|
(make-unregister-self-fun server))
|
|
|
|
do (register-tcp-client server endpoint)))
|
|
|
|
(osc-device-cleanup server)))
|
2010-09-25 13:48:08 +00:00
|
|
|
:name (format nil "osc-server-tcp: ~A" (name server)))
|
|
|
|
server)
|
|
|
|
server)
|
|
|
|
|
|
|
|
(defmethod osc-device-cleanup ((device osc-server-udp))
|
|
|
|
(loop for client-name being the hash-key in (clients device)
|
|
|
|
using (hash-value addr+port)
|
|
|
|
do (notify-quit device client-name)
|
|
|
|
do (unregister-udp-client device
|
2015-07-10 15:41:42 +00:00
|
|
|
(first addr+port)
|
|
|
|
(second addr+port)))
|
2010-09-25 13:48:08 +00:00
|
|
|
(call-next-method))
|
|
|
|
|
|
|
|
(defmethod osc-device-cleanup ((device osc-server-tcp))
|
|
|
|
(loop for client being the hash-value in (clients device)
|
|
|
|
do (quit client))
|
|
|
|
(call-next-method))
|
|
|
|
|
|
|
|
(defun make-clients-hash ()
|
|
|
|
(make-hash-table :test 'equal))
|
|
|
|
|
|
|
|
|
|
|
|
;;;=====================================================================
|
|
|
|
;;; UDP server functions
|
|
|
|
;;;=====================================================================
|
|
|
|
|
|
|
|
(defmethod initialize-instance :after ((server osc-server-udp) &key)
|
|
|
|
(make-server-responders server))
|
|
|
|
|
|
|
|
(defgeneric make-server-responders (server))
|
|
|
|
|
|
|
|
(defmethod make-server-responders ((server osc-server-udp))
|
|
|
|
(add-osc-responder server "/cl-osc/register"
|
|
|
|
(cmd args device address port timetag)
|
|
|
|
(let ((listening-port (car args))) ; Optional port for sending
|
2015-07-10 15:41:42 +00:00
|
|
|
; return messages to.
|
2010-09-25 13:48:08 +00:00
|
|
|
(register-udp-client device address
|
2015-07-10 15:41:42 +00:00
|
|
|
(if listening-port listening-port port))))
|
2010-09-25 13:48:08 +00:00
|
|
|
(add-osc-responder server "/cl-osc/quit"
|
|
|
|
(cmd args device address port timetag)
|
|
|
|
(unregister-udp-client device address port)))
|
|
|
|
|
|
|
|
(defun register-udp-client (server addr port)
|
|
|
|
(let ((client-name (make-addr+port-string addr port)))
|
|
|
|
(format t "Client registered: ~A~%" client-name)
|
|
|
|
(setf (gethash client-name (clients server))
|
2015-07-10 15:41:42 +00:00
|
|
|
(list addr port))
|
2010-09-25 13:48:08 +00:00
|
|
|
(post-register-hook server client-name)))
|
|
|
|
|
|
|
|
(defun unregister-udp-client (server addr port)
|
|
|
|
(let ((client-name (make-addr+port-string addr port)))
|
|
|
|
(format t "Client quit: ~A~%" client-name)
|
|
|
|
(remhash client-name (clients server))))
|
|
|
|
|
|
|
|
(defgeneric post-register-hook (server client-name)
|
|
|
|
(:method ((server osc-server-udp) client-name)
|
|
|
|
(format t "Post-register hook for client: ~A~%" client-name)
|
|
|
|
(notify-registered server client-name)))
|
|
|
|
|
|
|
|
(defun notify-registered (server client-name)
|
|
|
|
(send-to-client server client-name "/cl-osc/server/registered"))
|
|
|
|
|
|
|
|
(defun notify-quit (server client-name)
|
|
|
|
(send-to-client server client-name "/cl-osc/server/quit"))
|
|
|
|
|
|
|
|
|
|
|
|
;;;=====================================================================
|
|
|
|
;;; TCP server functions
|
|
|
|
;;;=====================================================================
|
|
|
|
|
|
|
|
(defun register-tcp-client (server transmitter)
|
2015-07-10 15:28:30 +00:00
|
|
|
"Clients are keyed on the names-string of the server-side socket,
|
|
|
|
not the peer name because the peer may close the socket after which
|
|
|
|
the peer name is no longer available. FIXME: Maybe we want to store
|
|
|
|
the peername independently of the socket's connection status?"
|
|
|
|
(let ((client-name (make-name-string transmitter)))
|
|
|
|
(when (debug-mode server)
|
|
|
|
(format t "Client registered: ~A~%" client-name))
|
|
|
|
(setf (gethash client-name (clients server)) transmitter)))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defun unregister-tcp-client (server transmitter)
|
2015-07-10 15:28:30 +00:00
|
|
|
(remhash (make-name-string transmitter)
|
|
|
|
(clients server)))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defun make-unregister-self-fun (server)
|
|
|
|
#'(lambda (client)
|
|
|
|
(unregister-tcp-client server client)))
|
|
|
|
|
|
|
|
(defun get-tcp-client (server socket-peername)
|
|
|
|
(gethash socket-peername (clients server)))
|
|
|
|
|
|
|
|
(defgeneric print-clients (server))
|
|
|
|
|
|
|
|
(defmethod print-clients ((server osc-server-udp))
|
|
|
|
(loop for addr+port being the hash-value in (clients server)
|
|
|
|
for i from 1
|
|
|
|
do (format t "~A. Connected to: ~A~%" i (make-addr+port-string
|
2015-07-10 15:41:42 +00:00
|
|
|
(first addr+port)
|
|
|
|
(second addr+port)))))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defmethod print-clients ((server osc-server-tcp))
|
|
|
|
(loop for endpoint being the hash-value in (clients server)
|
|
|
|
for i from 1
|
|
|
|
do (format t "~A. Connected to: ~A~%" i (make-addr+port-string
|
2015-07-10 15:41:42 +00:00
|
|
|
(peer-address endpoint)
|
|
|
|
(peer-port endpoint)))))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
;;;=====================================================================
|
|
|
|
;;; Server sending functions
|
|
|
|
;;;=====================================================================
|
|
|
|
|
|
|
|
(defgeneric send-to-client (server client-name &rest msg)
|
|
|
|
(:method :around ((server osc-server) client-name &rest msg)
|
2015-07-10 15:41:42 +00:00
|
|
|
(let ((client (gethash client-name (clients server))))
|
|
|
|
(if client
|
|
|
|
(apply #'call-next-method server client msg)
|
|
|
|
(warn "No client called ~A~%" client-name)))))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defmethod send-to-client ((server osc-server-udp) client-name &rest
|
2015-07-10 15:41:42 +00:00
|
|
|
msg)
|
2010-09-25 13:48:08 +00:00
|
|
|
(apply #'send-to server (first client-name) (second client-name)
|
2015-07-10 15:41:42 +00:00
|
|
|
msg))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defmethod send-to-client ((server osc-server-tcp) client &rest msg)
|
|
|
|
(apply #'send client msg))
|
|
|
|
|
|
|
|
(defgeneric send-bundle-to-client (server client-name timetag &rest
|
2015-07-10 15:41:42 +00:00
|
|
|
msg)
|
2010-09-25 13:48:08 +00:00
|
|
|
(:method :around ((server osc-server) client-name timetag &rest msg)
|
2015-07-10 15:41:42 +00:00
|
|
|
(let ((client (gethash client-name (clients server))))
|
|
|
|
(if client
|
|
|
|
(apply #'call-next-method server client timetag msg)
|
|
|
|
(warn "No client called ~A~%" client-name)))))
|
2010-09-25 13:48:08 +00:00
|
|
|
|
|
|
|
(defmethod send-bundle-to-client ((server osc-server-udp) client-name
|
2015-07-10 15:41:42 +00:00
|
|
|
timetag &rest msg)
|
2010-09-25 13:48:08 +00:00
|
|
|
(apply #'send-bundle-to server (first client-name)
|
2015-07-10 15:41:42 +00:00
|
|
|
(second client-name) timetag msg))
|