1 
2 /*
3  *  Diverse Bristol midi routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 3 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 /*#define DEBUG */
22 
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/select.h>
26 #include <signal.h>
27 #include <unistd.h>
28 
29 #include "bristol.h"
30 #include "bristolmidi.h"
31 
32 struct sockaddr address;
33 
34 extern bristolMidiMain bmidi;
35 extern int bristolMidiTCPPassive();
36 int bristolMidiTCPActive();
37 extern int bristolMidiFindDev();
38 extern int initControlPort();
39 extern int bristolFreeHandle();
40 extern int bristolFreeDevice();
41 
42 extern void checkcallbacks(bristolMidiMsg *);
43 
44 static char bristol_sockname[128];
45 
46 int
bristolMidiTCPClose(int handle)47 bristolMidiTCPClose(int handle)
48 {
49 #ifdef DEBUG
50 	printf("bristolMidiTCPClose()\n");
51 #endif
52 
53 	/*
54 	 * Check to see if the associated device has multiple handles associated
55 	 */
56 	if (bmidi.dev[bmidi.handle[handle].dev].handleCount > 1)
57 	{
58 		bmidi.dev[bmidi.handle[handle].dev].handleCount--;
59 		bristolFreeHandle(handle);
60 
61 		return(BRISTOL_MIDI_OK);
62 	}
63 
64 	close(bmidi.dev[bmidi.handle[handle].dev].fd);
65 	bmidi.dev[bmidi.handle[handle].dev].fd = -1;
66 
67 	if (bmidi.dev[bmidi.handle[handle].dev].flags & BRISTOL_ACCEPT_SOCKET)
68 		unlink(bristol_sockname);
69 
70 	bristolFreeDevice(bmidi.handle[handle].dev);
71 	bristolFreeHandle(handle);
72 
73 	return(BRISTOL_MIDI_OK);
74 }
75 
76 int
bristolMidiTCPOpen(char * host,int flags,int chan,int msgs,int (* callback)(),void * param,int dev,int handle)77 bristolMidiTCPOpen(char *host, int flags, int chan, int msgs,
78 int (*callback)(), void *param, int dev, int handle)
79 {
80 /* printf("bristolMidiTCPOpen(%s, %i, %i)\n", host, chan, dev); */
81 	/*
82 	 * See if we are active or passive.
83 	 */
84 	bmidi.dev[dev].handleCount = 1;
85 	if (flags & BRISTOL_CONN_PASSIVE)
86 	{
87 		/*
88 		 * This is the server, or in our case the engine, side of operations.
89 		 * we need to open a listening socket, and bind it to an address.
90 		 */
91 		return(bristolMidiTCPPassive(host, flags, chan, msgs, callback,
92 			param, dev, handle));
93 	} else {
94 		/*
95 		 * This is the client side, we should have a station address in "dev"
96 		 * and we connect to this address.
97 		 */
98 		return(bristolMidiTCPActive(host, flags, chan, msgs, callback,
99 			param, dev, handle));
100 	}
101 }
102 
103 int
bristolMidiTCPActive(char * host,int conntype,int chan,int msgs,int (* callback)(),void * param,int dev,int handle)104 bristolMidiTCPActive(char *host, int conntype, int chan, int msgs,
105 int (*callback)(), void *param, int dev, int handle)
106 {
107 	struct linger blinger;
108 
109 #ifdef DEBUG
110 	printf("bristolMidiTCPActive(%s, %i)\n", host, handle);
111 #endif
112 
113 	if ((conntype & BRISTOL_CONN_UNIX) ||
114 		((strncmp("unix", host, 4) == 0)
115 		&& (strlen(host) > 4)
116 		&& (host[4] == ':')))
117 		conntype = 0;
118 	else
119 		conntype = 1;
120 
121 	/*
122 	 * Otherwise try and find a device that is free.
123 	if ((dev = bristolMidiFindDev(NULL)) < 0)
124 		return(dev);
125 	 */
126 
127 	bmidi.dev[dev].flags |= BRISTOL_CONN_TCP;
128 
129 	if (chan == -1)
130 		chan = 5028;
131 
132 	if (conntype)
133 	{
134 		if ((bmidi.dev[dev].fd = initControlPort(host, chan)) < 0)
135 		{
136 			printf("connfailed\n");
137 			return(BRISTOL_MIDI_CHANNEL);
138 		}
139 		bmidi.dev[dev].flags = BRISTOL_CONN_TCP;
140 	} else {
141 		/*
142 		 * We need to open a control socket to the bristol engine. For the time
143 		 * being we will only be concerned with a unix domain socket.
144 		 */
145 		if ((bmidi.dev[dev].fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
146 		{
147 			printf("Could not get a socket\n");
148 			exit(-2);
149 		}
150 
151 #ifdef DEBUG
152 		printf("Opened the bristol control socket: %i\n", bmidi.dev[dev].fd);
153 #endif
154 
155 		address.sa_family = AF_LOCAL;
156 		if ((strlen(host) > 5) && (host[4] == ':'))
157 			snprintf(bristol_sockname, 128, "/tmp/br.%s", &host[5]);
158 		else
159 			snprintf(bristol_sockname, 128, "%s", BRISTOL_SOCKNAME);
160 
161 		snprintf(&address.sa_data[0], 14, "%s", bristol_sockname);
162 
163 		if (connect(bmidi.dev[dev].fd, &address, sizeof(struct sockaddr)) < 0)
164 		{
165 			printf("Could not connect to the bristol control socket\n");
166 			return(BRISTOL_MIDI_CHANNEL);
167 		}
168 		bmidi.dev[dev].flags = BRISTOL_CONN_TCP;
169 	}
170 
171 	printf("Connected to the bristol control socket: %i (dev=%i)\n",
172 		bmidi.dev[dev].fd, dev);
173 
174 	blinger.l_onoff = 1;
175 	blinger.l_linger = 2;
176 
177 	if (setsockopt(bmidi.dev[dev].fd, SOL_SOCKET, SO_LINGER,
178 		&blinger, sizeof(struct linger)) < 0)
179 		printf("client linger failed\n");
180 
181 	return(handle);
182 }
183 
184 /*
185  * select for data on every TCP connection. Hm, this is problematic for the
186  * monolithic process as it owns all the sockets.
187  */
188 int
bristolMidiTCPRead(bristolMidiMsg * msg)189 bristolMidiTCPRead(bristolMidiMsg *msg)
190 {
191 	int parsed, dev, offset, space, dc = 0;
192 	struct timeval timeout;
193 	fd_set read_set[BRISTOL_MIDI_DEVCOUNT << 1];
194 
195 #ifdef DEBUG
196 	printf("bristolMidiTCPRead()\n");
197 #endif
198 
199 	FD_ZERO(read_set);
200 
201 	/*
202 	 * Find ports of type TCP, see if they have buffer spaace then schedule them
203 	 * to be read.
204 	 */
205 	for (dev = 0; dev < BRISTOL_MIDI_DEVCOUNT; dev++)
206 	{
207 		/* Only want TCP data connections */
208 		if ((bmidi.dev[dev].fd > 0)
209 			&& (BRISTOL_MIDI_BUFSIZE - bmidi.dev[dev].bufcount > 0)
210 			&& ((bmidi.dev[dev].flags & BRISTOL_CONTROL_SOCKET) == 0)
211 			&& (bmidi.dev[dev].flags & BRISTOL_CONN_TCP))
212 		{
213 			FD_SET(bmidi.dev[dev].fd, read_set);
214 			dc++;
215 		}
216 	}
217 
218 	/* This is really just a poll operation */
219 	timeout.tv_sec = 0;
220 	timeout.tv_usec = 1000;
221 
222 	if (dc == 0)
223 		return(-1);
224 
225 	if (select(dev + 1, read_set, NULL, NULL, &timeout) == 0)
226 		return(0);
227 
228 	/* We have data somewhere. Get it */
229 	for (dev = 0; dev < BRISTOL_MIDI_DEVCOUNT; dev++)
230 	{
231 		if (bmidi.dev[dev].fd < 0)
232 			continue;
233 		if (FD_ISSET(bmidi.dev[dev].fd, read_set))
234 		{
235 			if ((offset = bmidi.dev[dev].bufindex + bmidi.dev[dev].bufcount)
236 				>= BRISTOL_MIDI_BUFSIZE)
237 				offset -= BRISTOL_MIDI_BUFSIZE;
238 
239 			if ((space = BRISTOL_MIDI_BUFSIZE - offset)
240 				> sizeof(bristolMidiMsg))
241 				space = sizeof(bristolMidiMsg);
242 
243 			if ((space =
244 				read(bmidi.dev[dev].fd, &bmidi.dev[dev].buffer[offset], space))
245 				< 0)
246 			{
247 				printf("no data in tcp buffer for %i (close)\n", dev);
248 				msg->command = -1;
249 				/*
250 				 * We should consider closing whatever synth was listening
251 				 * here. This would require build an EXIT message.
252 				 */
253 				return(BRISTOL_MIDI_DEV);
254 			}
255 
256 /*
257 int j;
258 printf("read");
259 for (j = 0; j < space; j++)
260 printf(" %x", bmidi.dev[dev].buffer[offset + j]);
261 printf("\n");
262 */
263 
264 			bmidi.dev[dev].bufcount+=space;
265 
266 			/*
267 			 * I really want to parse these, and then forward the messages to
268 			 * callback routines registered by the bristolMidiOpen() command.
269 			 */
270 			while ((parsed = bristolMidiRawToMsg(&bmidi.dev[dev].buffer[0],
271 				bmidi.dev[dev].bufcount, bmidi.dev[dev].bufindex, dev, msg))
272 				> 0)
273 			{
274 				/*
275 				 * Reduce count of available space.
276 				 */
277 				if ((bmidi.dev[dev].bufcount -= parsed) < 0)
278 				{
279 					/*
280 					 * We have an issue here, count has gone negative. Reset
281 					 * all buffer pointers, and just write an error for now.
282 					 */
283 					bmidi.dev[dev].bufcount = 0;
284 					bmidi.dev[dev].bufindex = 0;
285 					printf("Issue with buffer capacity going negative\n");
286 				}
287 				/*
288 				 * Wrap index as necessary.
289 				 */
290 				if ((bmidi.dev[dev].bufindex += parsed) >= BRISTOL_MIDI_BUFSIZE)
291 					bmidi.dev[dev].bufindex -= BRISTOL_MIDI_BUFSIZE;
292 
293 				/*
294 				 * We should now go through all the handles, and find out who
295 				 * has registered for these events - then forward them the event
296 				 * via the callback. For now we are just going to send it to the
297 				 * one existing callback.
298 				 */
299 				msg->params.bristol.from = dev;
300 /*				bristolMidiToGM2(msg); */
301 
302 				if (msg->params.bristol.msgLen == 0)
303 					msg->params.bristol.msgLen = parsed;
304 
305 				if (msg->command != 0x0ff)
306 				{
307 //if ((msg->command == 0xc0) || (msg->command == 0xc0))
308 //printf("tcp comm %x %i\n", msg->command, msg->params.program.p_id);
309 
310 					checkcallbacks(msg);
311 				}
312 
313 				msg->command = -1;
314 			}
315 		}
316 	}
317 
318 	return(1);
319 }
320 
321