1 module osc.server;
2 
3 import std.socket;
4 import core.thread;
5 import core.sync.mutex;
6 
7 import osc.message;
8 import osc.bundle;
9 import osc.packet;
10 
11 
12 
13 /// A server receiving OSC packets.
14 ///
15 class OSCServer
16 {
17 
18 	private {
19 		Socket			_listener;
20 		OSCMessage[]	_buffer;
21 
22 		Mutex			_bufferLock;
23 		Thread			_thread;
24 
25 		bool			_running;
26 	}
27 
28 
29 
30 	/// Constructs a new server using an already created socket.
31 	///
32 	this( Socket sock )
33 	{
34 		_listener = sock;
35 		_bufferLock = new Mutex( );
36 
37 		_listener.setOption( SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"( 1 ) );
38 	}
39 
40 	/// Constructs a new server using an UDP socket for IPv4 addresses.
41 	///
42 	this( )
43 	{
44 		this( new Socket( AddressFamily.INET, SocketType.DGRAM ) );
45 	}
46 
47 
48 
49 	/// Binds the server to the given address.
50 	///
51 	void bind( Address addr )
52 	in
53 	{
54 		assert( _thread is null );
55 	}
56 	do
57 	{
58 		_listener.bind( addr );
59 		_thread = new Thread( () => _receive() ).start;
60 	}
61 
62 	/// Binds the server to the given IPv4 IP and port.
63 	///
64 	void bind( string ip, ushort port )
65 	in
66 	{
67 		assert( _thread is null );
68 	}
69 	do
70 	{
71 		_listener.bind( new InternetAddress( ip, port ) );
72 		_thread = new Thread( () => _receive() ).start;
73 	}
74 
75 	/// Binds the server to the "localhost" IP using the given local port.
76 	///
77 	void bind( ushort port )
78 	in
79 	{
80 		assert( _thread is null );
81 	}
82 	do
83 	{
84 		_listener.bind( new InternetAddress( "localhost", port ) );
85 		_thread = new Thread( () => _receive() ).start;
86 	}
87 
88 
89 
90 	/// Closes the server.
91 	///
92 	void close( )
93 	{
94 		_running = false;
95 
96 		_listener.close;
97 		_thread.join;
98 	}
99 
100 
101 
102 	/// Gets the next message received.
103 	///
104 	OSCMessage pop( )
105 	{
106 		if( _buffer.length == 0 )
107 			return null;
108 
109 		_bufferLock.lock;
110 		scope( exit ) 
111 			_bufferLock.unlock;
112 		
113 		OSCMessage msg = _buffer[ 0 ];
114 		_buffer = _buffer[ 1 .. $ ];
115 
116 		return msg;
117 		
118 	}
119 
120 	/// Checks if some messages are in the server buffer.
121 	///
122 	bool empty( )
123 	{
124 		return _buffer.length == 0;
125 	}
126 
127 
128 
129 
130 	private void _receive( ) {
131 		ubyte[16_192] buffer;
132 
133 		_running = true;
134 
135 		while( _running ) {
136 			
137 			ptrdiff_t size = _listener.receive( buffer );
138 
139 			if( size <= 0 )
140 				continue;
141 
142 			OSCMessage[] received;
143 			OSCPacket p = OSCPacket.parse( buffer[ 0 .. size ] );
144 
145 			if( cast(OSCBundle) p !is null )
146 				received = ( cast(OSCBundle) p ).messages;
147 			else
148 				received ~= cast(OSCMessage)p;
149 
150 			_bufferLock.lock;
151 			foreach( m; received )
152 				_buffer ~= m;
153 			_bufferLock.unlock;
154 		}
155 	}
156 
157 }