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