Home | History | Annotate | Download | only in control
      1 /*
      2  *  Control - SHM Client
      3  *  Copyright (c) 2000 by Abramo Bagnara <abramo (at) alsa-project.org>
      4  *
      5  *
      6  *   This library is free software; you can redistribute it and/or modify
      7  *   it under the terms of the GNU Lesser General Public License as
      8  *   published by the Free Software Foundation; either version 2.1 of
      9  *   the License, or (at your option) any later version.
     10  *
     11  *   This program is distributed in the hope that it will be useful,
     12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *   GNU Lesser General Public License for more details.
     15  *
     16  *   You should have received a copy of the GNU Lesser General Public
     17  *   License along with this library; if not, write to the Free Software
     18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     19  *
     20  */
     21 
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <stddef.h>
     25 #include <unistd.h>
     26 #include <string.h>
     27 #include <fcntl.h>
     28 #include <sys/shm.h>
     29 #include <sys/socket.h>
     30 #include <sys/poll.h>
     31 #include <sys/un.h>
     32 #include <sys/uio.h>
     33 #include <sys/mman.h>
     34 #include <netinet/in.h>
     35 #include <netdb.h>
     36 #include "aserver.h"
     37 
     38 #ifndef PIC
     39 /* entry for static linking */
     40 const char *_snd_module_control_shm = "";
     41 #endif
     42 
     43 #ifndef DOC_HIDDEN
     44 typedef struct {
     45 	int socket;
     46 	volatile snd_ctl_shm_ctrl_t *ctrl;
     47 } snd_ctl_shm_t;
     48 #endif
     49 
     50 static int snd_ctl_shm_action(snd_ctl_t *ctl)
     51 {
     52 	snd_ctl_shm_t *shm = ctl->private_data;
     53 	int err;
     54 	char buf[1];
     55 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
     56 	err = write(shm->socket, buf, 1);
     57 	if (err != 1)
     58 		return -EBADFD;
     59 	err = read(shm->socket, buf, 1);
     60 	if (err != 1)
     61 		return -EBADFD;
     62 	if (ctrl->cmd) {
     63 		SNDERR("Server has not done the cmd");
     64 		return -EBADFD;
     65 	}
     66 	return ctrl->result;
     67 }
     68 
     69 static int snd_ctl_shm_action_fd(snd_ctl_t *ctl, int *fd)
     70 {
     71 	snd_ctl_shm_t *shm = ctl->private_data;
     72 	int err;
     73 	char buf[1];
     74 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
     75 	err = write(shm->socket, buf, 1);
     76 	if (err != 1)
     77 		return -EBADFD;
     78 	err = snd_receive_fd(shm->socket, buf, 1, fd);
     79 	if (err != 1)
     80 		return -EBADFD;
     81 	if (ctrl->cmd) {
     82 		SNDERR("Server has not done the cmd");
     83 		return -EBADFD;
     84 	}
     85 	return ctrl->result;
     86 }
     87 
     88 static int snd_ctl_shm_close(snd_ctl_t *ctl)
     89 {
     90 	snd_ctl_shm_t *shm = ctl->private_data;
     91 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
     92 	int result;
     93 	ctrl->cmd = SND_CTL_IOCTL_CLOSE;
     94 	result = snd_ctl_shm_action(ctl);
     95 	shmdt((void *)ctrl);
     96 	close(shm->socket);
     97 	free(shm);
     98 	return result;
     99 }
    100 
    101 static int snd_ctl_shm_nonblock(snd_ctl_t *handle ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
    102 {
    103 	return 0;
    104 }
    105 
    106 static int snd_ctl_shm_async(snd_ctl_t *ctl, int sig, pid_t pid)
    107 {
    108 	snd_ctl_shm_t *shm = ctl->private_data;
    109 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    110 	ctrl->cmd = SND_CTL_IOCTL_ASYNC;
    111 	ctrl->u.async.sig = sig;
    112 	if (pid == 0)
    113 		pid = getpid();
    114 	ctrl->u.async.pid = pid;
    115 	return snd_ctl_shm_action(ctl);
    116 }
    117 
    118 static int snd_ctl_shm_poll_descriptor(snd_ctl_t *ctl)
    119 {
    120 	snd_ctl_shm_t *shm = ctl->private_data;
    121 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    122 	int fd, err;
    123 	ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR;
    124 	err = snd_ctl_shm_action_fd(ctl, &fd);
    125 	if (err < 0)
    126 		return err;
    127 	return fd;
    128 }
    129 
    130 static int snd_ctl_shm_subscribe_events(snd_ctl_t *ctl, int subscribe)
    131 {
    132 	snd_ctl_shm_t *shm = ctl->private_data;
    133 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    134 	ctrl->cmd = SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS;
    135 	ctrl->u.subscribe_events = subscribe;
    136 	return snd_ctl_shm_action(ctl);
    137 }
    138 
    139 static int snd_ctl_shm_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
    140 {
    141 	snd_ctl_shm_t *shm = ctl->private_data;
    142 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    143 	int err;
    144 //	ctrl->u.card_info = *info;
    145 	ctrl->cmd = SNDRV_CTL_IOCTL_CARD_INFO;
    146 	err = snd_ctl_shm_action(ctl);
    147 	if (err < 0)
    148 		return err;
    149 	*info = ctrl->u.card_info;
    150 	return err;
    151 }
    152 
    153 static int snd_ctl_shm_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list)
    154 {
    155 	snd_ctl_shm_t *shm = ctl->private_data;
    156 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    157 	size_t maxsize = CTL_SHM_DATA_MAXLEN;
    158 	size_t bytes = list->space * sizeof(*list->pids);
    159 	int err;
    160 	snd_ctl_elem_id_t *pids = list->pids;
    161 	if (bytes > maxsize)
    162 		return -EINVAL;
    163 	ctrl->u.element_list = *list;
    164 	ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_LIST;
    165 	err = snd_ctl_shm_action(ctl);
    166 	if (err < 0)
    167 		return err;
    168 	*list = ctrl->u.element_list;
    169 	list->pids = pids;
    170 	bytes = list->used * sizeof(*list->pids);
    171 	memcpy(pids, (void *)ctrl->data, bytes);
    172 	return err;
    173 }
    174 
    175 static int snd_ctl_shm_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info)
    176 {
    177 	snd_ctl_shm_t *shm = ctl->private_data;
    178 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    179 	int err;
    180 	ctrl->u.element_info = *info;
    181 	ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_INFO;
    182 	err = snd_ctl_shm_action(ctl);
    183 	if (err < 0)
    184 		return err;
    185 	*info = ctrl->u.element_info;
    186 	return err;
    187 }
    188 
    189 static int snd_ctl_shm_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
    190 {
    191 	snd_ctl_shm_t *shm = ctl->private_data;
    192 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    193 	int err;
    194 	ctrl->u.element_read = *control;
    195 	ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_READ;
    196 	err = snd_ctl_shm_action(ctl);
    197 	if (err < 0)
    198 		return err;
    199 	*control = ctrl->u.element_read;
    200 	return err;
    201 }
    202 
    203 static int snd_ctl_shm_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
    204 {
    205 	snd_ctl_shm_t *shm = ctl->private_data;
    206 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    207 	int err;
    208 	ctrl->u.element_write = *control;
    209 	ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_WRITE;
    210 	err = snd_ctl_shm_action(ctl);
    211 	if (err < 0)
    212 		return err;
    213 	*control = ctrl->u.element_write;
    214 	return err;
    215 }
    216 
    217 static int snd_ctl_shm_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)
    218 {
    219 	snd_ctl_shm_t *shm = ctl->private_data;
    220 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    221 	int err;
    222 	ctrl->u.element_lock = *id;
    223 	ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_LOCK;
    224 	err = snd_ctl_shm_action(ctl);
    225 	if (err < 0)
    226 		return err;
    227 	*id = ctrl->u.element_lock;
    228 	return err;
    229 }
    230 
    231 static int snd_ctl_shm_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id)
    232 {
    233 	snd_ctl_shm_t *shm = ctl->private_data;
    234 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    235 	int err;
    236 	ctrl->u.element_unlock = *id;
    237 	ctrl->cmd = SNDRV_CTL_IOCTL_ELEM_UNLOCK;
    238 	err = snd_ctl_shm_action(ctl);
    239 	if (err < 0)
    240 		return err;
    241 	*id = ctrl->u.element_unlock;
    242 	return err;
    243 }
    244 
    245 static int snd_ctl_shm_hwdep_next_device(snd_ctl_t *ctl, int * device)
    246 {
    247 	snd_ctl_shm_t *shm = ctl->private_data;
    248 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    249 	int err;
    250 	ctrl->u.device = *device;
    251 	ctrl->cmd = SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE;
    252 	err = snd_ctl_shm_action(ctl);
    253 	if (err < 0)
    254 		return err;
    255 	*device = ctrl->u.device;
    256 	return err;
    257 }
    258 
    259 static int snd_ctl_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)
    260 {
    261 	snd_ctl_shm_t *shm = ctl->private_data;
    262 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    263 	int err;
    264 	ctrl->u.hwdep_info = *info;
    265 	ctrl->cmd = SNDRV_CTL_IOCTL_HWDEP_INFO;
    266 	err = snd_ctl_shm_action(ctl);
    267 	if (err < 0)
    268 		return err;
    269 	*info = ctrl->u.hwdep_info;
    270 	return err;
    271 }
    272 
    273 static int snd_ctl_shm_pcm_next_device(snd_ctl_t *ctl, int * device)
    274 {
    275 	snd_ctl_shm_t *shm = ctl->private_data;
    276 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    277 	int err;
    278 	ctrl->u.device = *device;
    279 	ctrl->cmd = SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE;
    280 	err = snd_ctl_shm_action(ctl);
    281 	if (err < 0)
    282 		return err;
    283 	*device = ctrl->u.device;
    284 	return err;
    285 }
    286 
    287 static int snd_ctl_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)
    288 {
    289 	snd_ctl_shm_t *shm = ctl->private_data;
    290 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    291 	int err;
    292 	ctrl->u.pcm_info = *info;
    293 	ctrl->cmd = SNDRV_CTL_IOCTL_PCM_INFO;
    294 	err = snd_ctl_shm_action(ctl);
    295 	if (err < 0)
    296 		return err;
    297 	*info = ctrl->u.pcm_info;
    298 	return err;
    299 }
    300 
    301 static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
    302 {
    303 	snd_ctl_shm_t *shm = ctl->private_data;
    304 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    305 	int err;
    306 	ctrl->u.pcm_prefer_subdevice = subdev;
    307 	ctrl->cmd = SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE;
    308 	err = snd_ctl_shm_action(ctl);
    309 	if (err < 0)
    310 		return err;
    311 	return err;
    312 }
    313 
    314 static int snd_ctl_shm_rawmidi_next_device(snd_ctl_t *ctl, int * device)
    315 {
    316 	snd_ctl_shm_t *shm = ctl->private_data;
    317 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    318 	int err;
    319 	ctrl->u.device = *device;
    320 	ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE;
    321 	err = snd_ctl_shm_action(ctl);
    322 	if (err < 0)
    323 		return err;
    324 	*device = ctrl->u.device;
    325 	return err;
    326 }
    327 
    328 static int snd_ctl_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)
    329 {
    330 	snd_ctl_shm_t *shm = ctl->private_data;
    331 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    332 	int err;
    333 	ctrl->u.rawmidi_info = *info;
    334 	ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_INFO;
    335 	err = snd_ctl_shm_action(ctl);
    336 	if (err < 0)
    337 		return err;
    338 	*info = ctrl->u.rawmidi_info;
    339 	return err;
    340 }
    341 
    342 static int snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)
    343 {
    344 	snd_ctl_shm_t *shm = ctl->private_data;
    345 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    346 	int err;
    347 	ctrl->u.rawmidi_prefer_subdevice = subdev;
    348 	ctrl->cmd = SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE;
    349 	err = snd_ctl_shm_action(ctl);
    350 	if (err < 0)
    351 		return err;
    352 	return err;
    353 }
    354 
    355 static int snd_ctl_shm_set_power_state(snd_ctl_t *ctl, unsigned int state)
    356 {
    357 	snd_ctl_shm_t *shm = ctl->private_data;
    358 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    359 	int err;
    360 	ctrl->u.power_state = state;
    361 	ctrl->cmd = SNDRV_CTL_IOCTL_POWER;
    362 	err = snd_ctl_shm_action(ctl);
    363 	if (err < 0)
    364 		return err;
    365 	return err;
    366 }
    367 
    368 static int snd_ctl_shm_get_power_state(snd_ctl_t *ctl, unsigned int *state)
    369 {
    370 	snd_ctl_shm_t *shm = ctl->private_data;
    371 	volatile snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
    372 	int err;
    373 	ctrl->cmd = SNDRV_CTL_IOCTL_POWER_STATE;
    374 	err = snd_ctl_shm_action(ctl);
    375 	if (err < 0)
    376 		return err;
    377 	*state = ctrl->u.power_state;
    378 	return err;
    379 }
    380 
    381 static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
    382 {
    383 	snd_ctl_shm_t *shm;
    384 	volatile snd_ctl_shm_ctrl_t *ctrl;
    385 	int err;
    386 	err = snd_ctl_wait(ctl, -1);
    387 	if (err < 0)
    388 		return 0;
    389 	shm = ctl->private_data;
    390 	ctrl = shm->ctrl;
    391 	ctrl->u.read = *event;
    392 	ctrl->cmd = SND_CTL_IOCTL_READ;
    393 	err = snd_ctl_shm_action(ctl);
    394 	if (err < 0)
    395 		return err;
    396 	*event = ctrl->u.read;
    397 	return err;
    398 }
    399 
    400 static const snd_ctl_ops_t snd_ctl_shm_ops = {
    401 	.close = snd_ctl_shm_close,
    402 	.nonblock = snd_ctl_shm_nonblock,
    403 	.async = snd_ctl_shm_async,
    404 	.subscribe_events = snd_ctl_shm_subscribe_events,
    405 	.card_info = snd_ctl_shm_card_info,
    406 	.element_list = snd_ctl_shm_elem_list,
    407 	.element_info = snd_ctl_shm_elem_info,
    408 	.element_read = snd_ctl_shm_elem_read,
    409 	.element_write = snd_ctl_shm_elem_write,
    410 	.element_lock = snd_ctl_shm_elem_lock,
    411 	.element_unlock = snd_ctl_shm_elem_unlock,
    412 	.hwdep_next_device = snd_ctl_shm_hwdep_next_device,
    413 	.hwdep_info = snd_ctl_shm_hwdep_info,
    414 	.pcm_next_device = snd_ctl_shm_pcm_next_device,
    415 	.pcm_info = snd_ctl_shm_pcm_info,
    416 	.pcm_prefer_subdevice = snd_ctl_shm_pcm_prefer_subdevice,
    417 	.rawmidi_next_device = snd_ctl_shm_rawmidi_next_device,
    418 	.rawmidi_info = snd_ctl_shm_rawmidi_info,
    419 	.rawmidi_prefer_subdevice = snd_ctl_shm_rawmidi_prefer_subdevice,
    420 	.set_power_state = snd_ctl_shm_set_power_state,
    421 	.get_power_state = snd_ctl_shm_get_power_state,
    422 	.read = snd_ctl_shm_read,
    423 };
    424 
    425 static int make_local_socket(const char *filename)
    426 {
    427 	size_t l = strlen(filename);
    428 	size_t size = offsetof(struct sockaddr_un, sun_path) + l;
    429 	struct sockaddr_un *addr = alloca(size);
    430 	int sock;
    431 
    432 	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
    433 	if (sock < 0)
    434 		return -errno;
    435 
    436 	addr->sun_family = AF_LOCAL;
    437 	memcpy(addr->sun_path, filename, l);
    438 
    439 	if (connect(sock, (struct sockaddr *) addr, size) < 0)
    440 		return -errno;
    441 	return sock;
    442 }
    443 
    444 #if 0
    445 static int make_inet_socket(const char *host, int port)
    446 {
    447 	struct sockaddr_in addr;
    448 	int sock;
    449 	struct hostent *h = gethostbyname(host);
    450 	if (!h)
    451 		return -ENOENT;
    452 
    453 	sock = socket(PF_INET, SOCK_STREAM, 0);
    454 	if (sock < 0)
    455 		return -errno;
    456 
    457 	addr.sin_family = AF_INET;
    458 	addr.sin_port = htons(port);
    459 	memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
    460 
    461 	if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    462 		return -errno;
    463 	return sock;
    464 }
    465 #endif
    466 
    467 int snd_ctl_shm_open(snd_ctl_t **handlep, const char *name, const char *sockname, const char *sname, int mode)
    468 {
    469 	snd_ctl_t *ctl;
    470 	snd_ctl_shm_t *shm = NULL;
    471 	snd_client_open_request_t *req;
    472 	snd_client_open_answer_t ans;
    473 	size_t snamelen, reqlen;
    474 	int err;
    475 	int result;
    476 	int sock = -1;
    477 	snd_ctl_shm_ctrl_t *ctrl = NULL;
    478 	snamelen = strlen(sname);
    479 	if (snamelen > 255)
    480 		return -EINVAL;
    481 
    482 	result = make_local_socket(sockname);
    483 	if (result < 0) {
    484 		SNDERR("server for socket %s is not running", sockname);
    485 		goto _err;
    486 	}
    487 	sock = result;
    488 
    489 	reqlen = sizeof(*req) + snamelen;
    490 	req = alloca(reqlen);
    491 	memcpy(req->name, sname, snamelen);
    492 	req->dev_type = SND_DEV_TYPE_CONTROL;
    493 	req->transport_type = SND_TRANSPORT_TYPE_SHM;
    494 	req->stream = 0;
    495 	req->mode = mode;
    496 	req->namelen = snamelen;
    497 	err = write(sock, req, reqlen);
    498 	if (err < 0) {
    499 		SNDERR("write error");
    500 		result = -errno;
    501 		goto _err;
    502 	}
    503 	if ((size_t) err != reqlen) {
    504 		SNDERR("write size error");
    505 		result = -EINVAL;
    506 		goto _err;
    507 	}
    508 	err = read(sock, &ans, sizeof(ans));
    509 	if (err < 0) {
    510 		SNDERR("read error");
    511 		result = -errno;
    512 		goto _err;
    513 	}
    514 	if (err != sizeof(ans)) {
    515 		SNDERR("read size error");
    516 		result = -EINVAL;
    517 		goto _err;
    518 	}
    519 	result = ans.result;
    520 	if (result < 0)
    521 		goto _err;
    522 
    523 	ctrl = shmat(ans.cookie, 0, 0);
    524 	if (!ctrl) {
    525 		result = -errno;
    526 		goto _err;
    527 	}
    528 
    529 	shm = calloc(1, sizeof(snd_ctl_shm_t));
    530 	if (!shm) {
    531 		result = -ENOMEM;
    532 		goto _err;
    533 	}
    534 
    535 	shm->socket = sock;
    536 	shm->ctrl = ctrl;
    537 
    538 	err = snd_ctl_new(&ctl, SND_CTL_TYPE_SHM, name);
    539 	if (err < 0) {
    540 		result = err;
    541 		goto _err;
    542 	}
    543 	ctl->ops = &snd_ctl_shm_ops;
    544 	ctl->private_data = shm;
    545 	err = snd_ctl_shm_poll_descriptor(ctl);
    546 	if (err < 0) {
    547 		snd_ctl_close(ctl);
    548 		return err;
    549 	}
    550 	ctl->poll_fd = err;
    551 	*handlep = ctl;
    552 	return 0;
    553 
    554  _err:
    555 	close(sock);
    556 	if (ctrl)
    557 		shmdt(ctrl);
    558 	free(shm);
    559 	return result;
    560 }
    561 
    562 int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *root, snd_config_t *conf, int mode)
    563 {
    564 	snd_config_iterator_t i, next;
    565 	const char *server = NULL;
    566 	const char *ctl_name = NULL;
    567 	snd_config_t *sconfig;
    568 	const char *host = NULL;
    569 	const char *sockname = NULL;
    570 	long port = -1;
    571 	int err;
    572 	int local;
    573 	struct hostent *h;
    574 	snd_config_for_each(i, next, conf) {
    575 		snd_config_t *n = snd_config_iterator_entry(i);
    576 		const char *id;
    577 		if (snd_config_get_id(n, &id) < 0)
    578 			continue;
    579 		if (strcmp(id, "comment") == 0)
    580 			continue;
    581 		if (strcmp(id, "type") == 0)
    582 			continue;
    583 		if (strcmp(id, "server") == 0) {
    584 			err = snd_config_get_string(n, &server);
    585 			if (err < 0) {
    586 				SNDERR("Invalid type for %s", id);
    587 				return -EINVAL;
    588 			}
    589 			continue;
    590 		}
    591 		if (strcmp(id, "ctl") == 0) {
    592 			err = snd_config_get_string(n, &ctl_name);
    593 			if (err < 0) {
    594 				SNDERR("Invalid type for %s", id);
    595 				return -EINVAL;
    596 			}
    597 			continue;
    598 		}
    599 		SNDERR("Unknown field %s", id);
    600 		return -EINVAL;
    601 	}
    602 	if (!ctl_name) {
    603 		SNDERR("ctl is not defined");
    604 		return -EINVAL;
    605 	}
    606 	if (!server) {
    607 		SNDERR("server is not defined");
    608 		return -EINVAL;
    609 	}
    610 	err = snd_config_search_definition(root, "server", server, &sconfig);
    611 	if (err < 0) {
    612 		SNDERR("Unknown server %s", server);
    613 		return -EINVAL;
    614 	}
    615 	if (snd_config_get_type(sconfig) != SND_CONFIG_TYPE_COMPOUND) {
    616 		SNDERR("Invalid type for server %s definition", server);
    617 		err = -EINVAL;
    618 		goto _err;
    619 	}
    620 	snd_config_for_each(i, next, sconfig) {
    621 		snd_config_t *n = snd_config_iterator_entry(i);
    622 		const char *id;
    623 		if (snd_config_get_id(n, &id) < 0)
    624 			continue;
    625 		if (strcmp(id, "comment") == 0)
    626 			continue;
    627 		if (strcmp(id, "host") == 0) {
    628 			err = snd_config_get_string(n, &host);
    629 			if (err < 0) {
    630 				SNDERR("Invalid type for %s", id);
    631 				goto _err;
    632 			}
    633 			continue;
    634 		}
    635 		if (strcmp(id, "socket") == 0) {
    636 			err = snd_config_get_string(n, &sockname);
    637 			if (err < 0) {
    638 				SNDERR("Invalid type for %s", id);
    639 				goto _err;
    640 			}
    641 			continue;
    642 		}
    643 		if (strcmp(id, "port") == 0) {
    644 			err = snd_config_get_integer(n, &port);
    645 			if (err < 0) {
    646 				SNDERR("Invalid type for %s", id);
    647 				goto _err;
    648 			}
    649 			continue;
    650 		}
    651 		SNDERR("Unknown field %s", id);
    652 		err = -EINVAL;
    653 		goto _err;
    654 	}
    655 
    656 	if (!host) {
    657 		SNDERR("host is not defined");
    658 		goto _err;
    659 	}
    660 	if (!sockname) {
    661 		SNDERR("socket is not defined");
    662 		goto _err;
    663 	}
    664 	h = gethostbyname(host);
    665 	if (!h) {
    666 		SNDERR("Cannot resolve %s", host);
    667 		goto _err;
    668 	}
    669 	local = snd_is_local(h);
    670 	if (!local) {
    671 		SNDERR("%s is not the local host", host);
    672 		goto _err;
    673 	}
    674 	err = snd_ctl_shm_open(handlep, name, sockname, ctl_name, mode);
    675        _err:
    676 	snd_config_delete(sconfig);
    677 	return err;
    678 }
    679 SND_DLSYM_BUILD_VERSION(_snd_ctl_shm_open, SND_CONTROL_DLSYM_VERSION);
    680