1 /*
2  * Copyright 1993 Network Computing Devices, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name Network Computing Devices, Inc. not be
9  * used in advertising or publicity pertaining to distribution of this
10  * software without specific, written prior permission.
11  *
12  * THIS SOFTWARE IS PROVIDED 'AS-IS'.  NETWORK COMPUTING DEVICES, INC.,
13  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
14  * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15  * PARTICULAR PURPOSE, OR NONINFRINGEMENT.  IN NO EVENT SHALL NETWORK
16  * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
17  * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
18  * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
19  * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * $NCDId: @(#)OpenSvr.c,v 1.25 1995/12/28 19:45:28 greg Exp $
23  */
24 
25 /* Portions derived from */
26 /*
27  * $XConsortium: XOpenDis.c,v 11.126 92/11/03 18:42:50 rws Exp $
28  */
29 
30 /* Copyright    Massachusetts Institute of Technology    1985, 1986	*/
31 
32 /*
33 Permission to use, copy, modify, distribute, and sell this software and its
34 documentation for any purpose is hereby granted without fee, provided that
35 the above copyright notice appear in all copies and that both that
36 copyright notice and this permission notice appear in supporting
37 documentation, and that the name of M.I.T. not be used in advertising or
38 publicity pertaining to distribution of the software without specific,
39 written prior permission.  M.I.T. makes no representations about the
40 suitability of this software for any purpose.  It is provided "as is"
41 without express or implied warranty.
42 */
43 
44 #define _OPENSVR_C_
45 
46 #include <audio/Alibint.h>
47 #include <audio/Aos.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 
51 AuErrorHandler  AuDefaultErrorHandler = (AuErrorHandler) NULL;
52 AuIOErrorHandler AuDefaultIOErrorHandler = (AuIOErrorHandler) NULL;
53 
54 static auReq _dummy_request = {
55 	0, 0, 0
56 };
57 
58 static void _AuOCOutOfMemory();
59 
60 static int xferConnectionSetup();
61 
62 /*****************************************************************************
63  *				 AuOpenServer				     *
64  *****************************************************************************/
65 
66 /*
67  * Connects to a server, creates a AuServer object and returns a pointer to
68  * the newly created AuServer back to the caller.
69  */
AuOpenServer(const char * server,int num_authproto,const char * authproto,int num_authdata,const char * authdata,char ** ret_svrmsg)70 AuServer *AuOpenServer (
71 	const char *server,
72 	int num_authproto,
73 	const char *authproto,
74 	int num_authdata,
75 	const char *authdata,
76 	char **ret_svrmsg)
77 {
78 	AuServer *aud;		/* New AuServer object being created */
79 	int i;
80 	const char *server_name;	/* pointer to server name */
81 	int endian;			/* to determine which endian. */
82 	auConnClientPrefix client;	/* client information */
83 	auConnSetupPrefix prefix;	/* prefix information */
84 	int vendorlen;			/* length of vendor string */
85 	char *setup = NULL;		/* memory allocated at startup */
86 	char *fullname = NULL;		/* expanded name of server */
87 	int iserver;			/* server number */
88 	union {
89 		auConnSetup *setup;
90 		char *failure;
91 	} u;				/* proto data returned from server */
92 	AuInt32 setuplength;		/* number of bytes in setup message */
93 	unsigned char *varData;		/* pointer to variable length data that
94 					 * follows the connection setup data */
95 
96 	int conn_auth_namelen = num_authproto;	  /* init the auth info */
97 	char *conn_auth_name = (char *) authproto;
98 	int conn_auth_datalen = num_authdata;
99 	char *conn_auth_data = (char *) authdata;
100 
101 	AuUint32 mask;
102 
103 	/*
104 	 * Initialize the return message to a known good value
105 	 */
106 	if (ret_svrmsg)
107 	    *ret_svrmsg = NULL;
108 
109 	/*
110 	 * If the server specifier string supplied as an argument to this
111 	 * routine is NULL or a pointer to NULL, read the DISPLAY variable.
112 	 */
113 	server_name = AuServerName (server);
114 	if (!server_name || !server_name[0])
115 	    return NULL;
116 
117 /*
118  * Lock against other threads trying to access global data (like the error
119  * handlers and server list).
120  */
121 	_AuLockMutex(_init_mutex);
122 
123 /*
124  * Attempt to allocate a server structure. Return NULL if allocation fails.
125  */
126 	if ((aud = (AuServer *)Aucalloc(1, sizeof(AuServer))) == NULL) {
127 		_AuUnlockMutex(_init_mutex);
128 		return(NULL);
129 	}
130 
131 /*
132  * Set the default error handlers.
133  */
134 	aud->funcs.error_handler = AuDefaultErrorHandler;
135 	aud->funcs.ioerror_handler = AuDefaultIOErrorHandler;
136 
137 
138 /*
139  * Call the Connect routine to get the network socket. If -1 is returned, the
140  * connection failed. The connect routine will set fullname to point to the
141  * expanded name.
142  */
143 
144 	if ((aud->fd = _AuConnectServer (server_name, &fullname, &iserver,
145 					 &conn_auth_name,
146 					 &conn_auth_namelen, &conn_auth_data,
147 					 &conn_auth_datalen)) < 0) {
148 		Aufree ((char *) aud);
149 		_AuUnlockMutex(_init_mutex);
150 		return(NULL);
151 	}
152 
153 	/* Initialize as much of the server structure as we can.
154 	 * Initialize pointers to NULL so that AuFreeServerStructure will
155 	 * work if we run out of memory before we finish initializing.
156 	 */
157 	aud->server_name	= fullname;
158 	aud->scratch_length	= 0L;
159 	aud->scratch_buffer	= NULL;
160 	aud->ext_procs		= (_AuExtension *)NULL;
161 	aud->ext_data		= (AuExtData *)NULL;
162 	aud->ext_number 	= 0;
163 	aud->event_vec[Au_Error] = _AuUnknownWireEvent;
164 	aud->event_vec[Au_Reply] = _AuUnknownWireEvent;
165 	aud->wire_vec[Au_Error]  = _AuUnknownNativeEvent;
166 	aud->wire_vec[Au_Reply]  = _AuUnknownNativeEvent;
167 	for (i = AuFirstEventType; i <= AuLastEventType; i++) {
168 	    aud->event_vec[i] 	= _AuWireToEvent;
169 	    aud->wire_vec[i] 	= NULL;
170 	}
171 	for (i = AuLastEventType + 1; i < 128; i++) {
172 	    aud->event_vec[i] 	= _AuUnknownWireEvent;
173 	    aud->wire_vec[i] 	= _AuUnknownNativeEvent;
174 	}
175 	aud->resource_id	= 0;
176 	aud->flags		= 0;
177 	aud->async_handlers	= NULL;
178 	aud->vendor		= NULL;
179 	aud->buffer		= NULL;
180 	aud->error_vec		= NULL;
181 
182 /*
183  * Setup other information in this server structure.
184  */
185 	aud->vnumber = AuProtocolMajorVersion;
186 	aud->resource_alloc = _AuAllocID;
187 	aud->synchandler = NULL;
188 	aud->request = 0;
189 	aud->last_request_read = 0;
190 	aud->last_req = (char *)&_dummy_request;
191 
192 	/* Set up the output buffers. */
193 	if ((aud->bufptr = aud->buffer = Aumalloc(BUFSIZE)) == NULL) {
194 	        _AuOCOutOfMemory (aud, setup);
195 		_AuUnlockMutex(_init_mutex);
196 		return(NULL);
197 	}
198 	aud->bufmax = aud->buffer + BUFSIZE;
199 
200 	/* Set up the input event queue and input event queue parameters. */
201 	aud->head = aud->tail = NULL;
202 	aud->qlen = 0;
203 
204 	/* Set up the scratch flow info */
205 	aud->scratch_flows.total = aud->scratch_flows.num_inuse = 0;
206 
207 /*
208  * The auConnClientPrefix describes the initial connection setup information
209  * and is followed by the authorization information.  Sites that are interested
210  * in security are strongly encouraged to use an authentication and
211  * authorization system such as Kerberos.
212  */
213 	endian = 1;
214 	if (*(char *) &endian)
215 	    client.byteOrder = '\154'; /* 'l' */
216 	else
217 	    client.byteOrder = '\102'; /* 'B' */
218 	client.majorVersion = AuProtocolMajorVersion;
219 	client.minorVersion = AuProtocolMinorVersion;
220 	client.nbytesAuthProto = conn_auth_namelen;
221 	client.nbytesAuthString = conn_auth_datalen;
222 	if (!_AuSendClientPrefix(aud, &client, conn_auth_name, conn_auth_data))
223 	{
224 	    _AuDisconnectServer (aud->fd);
225 	    Aufree ((char *)aud);
226 	    _AuUnlockMutex(_init_mutex);
227 	    return(NULL);
228 	}
229 	/* see if we had changed the auth info and release it */
230 	if (conn_auth_name && conn_auth_name != authproto)
231 	    Aufree(conn_auth_name);
232 	if (conn_auth_data && conn_auth_data != authdata)
233 	    Aufree(conn_auth_data);
234 /*
235  * Now see if connection was accepted...
236  */
237 	_AuRead (aud, (char *)&prefix,(AuInt32)SIZEOF(auConnSetupPrefix));
238 
239 	if (prefix.majorVersion < AuProtocolMajorVersion ||
240 	    prefix.minorVersion != AuProtocolMinorVersion)
241 	    fprintf (stderr, "audiolib: warning, client is protocol rev %d.%d \
242 server is %d.%d!\r\n",
243 		     AuProtocolMajorVersion, AuProtocolMinorVersion,
244 		     prefix.majorVersion, prefix.minorVersion);
245 
246 	setuplength = prefix.length << 2;
247 	if ( (u.setup = (auConnSetup *)
248 	      (setup =  Aumalloc ((unsigned) setuplength))) == NULL) {
249 		_AuDisconnectServer (aud->fd);
250 		Aufree ((char *)aud);
251 		_AuUnlockMutex(_init_mutex);
252 		return(NULL);
253 	}
254 	_AuRead (aud, (char *)u.setup, setuplength);
255 /*
256  * If the connection was not accepted by the server due to problems,
257  * give error message to the user....
258  */
259 	if (prefix.success != auTrue) {
260 	    int len = (int) prefix.lengthReason;
261 	    if (ret_svrmsg) {
262 		*ret_svrmsg = (char *) Aumalloc (len + 1);
263 		if (*ret_svrmsg) {
264 		    (void) strncpy (*ret_svrmsg, u.failure, len);
265 		    (*ret_svrmsg)[len] = '\0';
266 		}
267 	    } else {
268 		/* client is really out of memory, fallback to printing */
269 		fprintf (stderr,
270 			 "%s:  connection to \"%s\" refused by server\r\n%s:  ",
271 			 "audiolib", fullname, "audiolib");
272 		(void) fwrite (u.failure, sizeof(char),
273 			(int)prefix.lengthReason, stderr);
274 		(void) fwrite ("\r\n", sizeof(char), 2, stderr);
275 	    }
276 
277 	    _AuOCOutOfMemory(aud, setup);
278 	    _AuUnlockMutex(_init_mutex);
279 	    return (NULL);
280 	}
281 
282 /*
283  * We succeeded at authorization, so let us move the data into
284  * the server structure.
285  */
286 	aud->proto_major_version= prefix.majorVersion;
287 	aud->proto_minor_version= prefix.minorVersion;
288 	aud->release 		= u.setup->release;
289 	aud->resource_base	= u.setup->ridBase;
290 	aud->resource_mask	= u.setup->ridMask;
291 	aud->max_request_size	= u.setup->maxRequestSize;
292 	mask = aud->resource_mask;
293 	aud->resource_shift	= 0;
294 	while (!(mask & 1)) {
295 	    aud->resource_shift++;
296 	    mask = mask >> 1;
297 	}
298 /*
299  * now extract the vendor string...  String must be null terminated,
300  * padded to multiple of 4 bytes.
301  */
302 	aud->vendor = (char *) Aumalloc((unsigned) (u.setup->nbytesVendor + 1));
303 	if (aud->vendor == NULL) {
304 	    _AuOCOutOfMemory(aud, setup);
305 	    _AuUnlockMutex(_init_mutex);
306 	    return (NULL);
307 	}
308 
309 	varData = ((unsigned char *) u.setup) + sz_auConnSetup;
310 	vendorlen = u.setup->nbytesVendor;
311   	(void) strncpy(aud->vendor, (char *)varData, vendorlen);
312 	aud->vendor[vendorlen] = '\0';
313  	vendorlen = PAD4(vendorlen);
314 	varData += vendorlen;
315 /*
316  * Now iterate down setup information.....
317  */
318 	if (!xferConnectionSetup(u.setup, aud, varData))
319 	    return NULL;
320 
321 /*
322  * Now start talking to the server to setup all other information...
323  */
324 
325 	Aufree (setup);	/* all finished with setup information */
326 
327 /*
328  * and done mucking with the server
329  */
330 	_AuUnlockMutex(_init_mutex);
331 
332 /*
333  * and return successfully
334  */
335  	return(aud);
336 }
337 
338 
339 /* _AuOCOutOfMemory is called if malloc fails.  AuOpenServer returns NULL
340    after this returns. */
341 
342 static void
_AuOCOutOfMemory(AuServer * aud,char * setup)343 _AuOCOutOfMemory (
344                   AuServer *aud,
345                   char *setup
346                   )
347 {
348     _AuDisconnectServer (aud->fd);
349     _AuFreeServerStructure (aud);
350     if (setup) Aufree (setup);
351 }
352 
353 
354 /*
355  * AuFreeServerStructure frees all the storage associated with a AuServer.
356  * It is used by AuOpenServer if it runs out of memory, and also by
357  * AuCloseServer.   It needs to check whether all pointers are non-NULL
358  * before dereferencing them, since it may be called by AuOpenServer before
359  * the AuServer structure is fully formed. AuOpenServer must be sure to
360  * initialize all the pointers to NULL before the first possible call on
361  * this.
362  */
363 
364 #define AufreeIf(x)							       \
365 {									       \
366     if (x)								       \
367 	Aufree(x);							       \
368 }
369 
370 void
_AuFreeServerStructure(AuServer * aud)371 _AuFreeServerStructure(AuServer *aud)
372 {
373     int                 i;
374 
375     while (aud->ext_procs)
376     {
377 	_AuExtension       *ext = aud->ext_procs;
378 	aud->ext_procs = ext->next;
379 	AufreeIf(ext->name);
380 	Aufree((char *) ext);
381     }
382 
383     AufreeIf(aud->server_name);
384     AufreeIf(aud->vendor);
385 
386     AufreeIf(aud->connsetup.formats);
387     AufreeIf(aud->connsetup.element_types);
388     AufreeIf(aud->connsetup.wave_forms);
389     AufreeIf(aud->connsetup.actions);
390 
391     for (i = 0; i < aud->connsetup.num_devices; i++)
392     {
393 	AufreeIf(aud->connsetup.devices[i].common.description.data);
394 	AufreeIf(aud->connsetup.devices[i].device.children);
395     }
396     AufreeIf(aud->connsetup.devices);
397 
398     for (i = 0; i < aud->connsetup.num_buckets; i++)
399 	AufreeIf(aud->connsetup.buckets[i].common.description.data);
400     AufreeIf(aud->connsetup.buckets);
401 
402     AufreeIf(aud->buffer);
403     AufreeIf((char *) aud->error_vec);
404 
405     _AuFreeExtData(aud->ext_data);
406     AufreeIf(aud->scratch_buffer);
407 
408     _AuFreeQ(aud);
409 
410     Aufree((char *) aud);
411 }
412 
413 #define dst     aud->connsetup
414 
xferFail(AuServer * aud,auConnSetup * src)415 static int xferFail(AuServer *aud, auConnSetup *src)
416 {
417   _AuOCOutOfMemory(aud, (char *) src);
418   _AuUnlockMutex(_init_mutex);
419   return(0);
420 }
421 
422 #define xferAlloc(_dst, _type, _size)					      \
423 {									      \
424     if (_size)								      \
425 	if (!((_dst) = (_type *) Aumalloc((_size) * sizeof(_type))))	      \
426 	    return(0);;							      \
427 }
428 
429 static int
xferConnectionSetup(auConnSetup * src,AuServer * aud,unsigned char * varData)430 xferConnectionSetup(
431                     auConnSetup        *src,
432                     AuServer           *aud,
433                     unsigned char *varData
434                     )
435 {
436     int i;
437 
438     dst.min_sample_rate = src->minSampleRate;
439     dst.max_sample_rate = src->maxSampleRate;
440     dst.max_tracks = src->maxTracks;
441     dst.num_formats = src->numFormats;
442     dst.num_element_types = src->numElementTypes;
443     dst.num_wave_forms = src->numWaveForms;
444     dst.num_actions = src->numActions;
445     dst.num_devices = src->numDevices;
446     dst.num_buckets = src->numBuckets;
447 #ifdef NOTYET
448     dst.num_radios = src->numRadios;
449 #endif				/* NOTYET */
450 
451     /* transfer formats */
452     xferAlloc(dst.formats, int, dst.num_formats)
453     for (i = 0; i < dst.num_formats; i++)
454 	dst.formats[i] = varData[i];
455     varData += PAD4(dst.num_formats);
456 
457     /* transfer element types */
458     xferAlloc(dst.element_types, int, dst.num_element_types)
459     for (i = 0; i < dst.num_element_types; i++)
460 	dst.element_types[i] = varData[i];
461     varData += PAD4(dst.num_element_types);
462 
463     /* transfer wave forms */
464     xferAlloc(dst.wave_forms, int, dst.num_wave_forms)
465     for (i = 0; i < dst.num_wave_forms; i++)
466 	dst.wave_forms[i] = varData[i];
467     varData += PAD4(dst.num_wave_forms);
468 
469     /* transfer actions */
470     xferAlloc(dst.actions, int, dst.num_actions)
471     for (i = 0; i < dst.num_actions; i++)
472 	dst.actions[i] = varData[i];
473     varData += PAD4(dst.num_actions);
474 
475     /* transfer devices */
476     if (!(dst.devices = (AuDeviceAttributes *)
477 	  Aucalloc(1, sizeof(AuDeviceAttributes) * dst.num_devices)))
478 	xferFail(aud, src);
479 
480     for (i = 0; i < dst.num_devices; i++)
481     {
482 	_xferDeviceAttributes((auDeviceAttributes *) varData, dst.devices[i]);
483 	varData += sz_auDeviceAttributes;
484 
485 	if (dst.devices[i].common.description.len)
486 	{
487 	    int len = dst.devices[i].common.description.len;
488 	    char *s;
489 
490 	    xferAlloc(s, char, len + 1);
491 	    bcopy(varData, s, len);
492 	    s[len] = 0;
493 	    dst.devices[i].common.description.data = s;
494 	    varData += PAD4(len);
495 	}
496 
497 	if (dst.devices[i].device.num_children)
498 	{
499 	    int len = dst.devices[i].device.num_children * sizeof(AuDeviceID);
500 
501 	    xferAlloc(dst.devices[i].device.children, AuDeviceID, len);
502 	    bcopy(varData, dst.devices[i].device.children, len);
503 	    varData += len;
504 	}
505     }
506 
507     /* transfer buckets */
508     if (dst.num_buckets)
509 	if (!(dst.buckets = (AuBucketAttributes *)
510 	      Aucalloc(1, sizeof(AuBucketAttributes) * dst.num_buckets)))
511 	    xferFail(aud, src);
512 
513     for (i = 0; i < dst.num_buckets; i++)
514     {
515 	_xferBucketAttributes((auBucketAttributes *) varData, dst.buckets[i]);
516 	varData += sz_auBucketAttributes;
517 
518 	if (dst.buckets[i].common.description.len)
519 	{
520 	    int len = dst.buckets[i].common.description.len;
521 	    char *s;
522 
523 	    xferAlloc(s, char, len + 1);
524 	    bcopy(varData, s, len);
525 	    s[len] = 0;
526 	    dst.buckets[i].common.description.data = s;
527 	    varData += PAD4(len);
528 	}
529     }
530 
531     return 1;
532 }
533