OSDN Git Service

968e1461c8e46ea5c368c6b7953abfd8761e8303
[android-x86/external-alsa-lib.git] / src / control / control_shm.c
1 /*
2  *  Control - SHM Client
3  *  Copyright (c) 2000 by Abramo Bagnara <abramo@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 Library General Public License as
8  *   published by the Free Software Foundation; either version 2 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 Library General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Library General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 <errno.h>
28 #include <fcntl.h>
29 #include <sys/shm.h>
30 #include <sys/socket.h>
31 #include <sys/poll.h>
32 #include <sys/un.h>
33 #include <sys/uio.h>
34 #include <sys/mman.h>
35 #include <netinet/in.h>
36 #include <netdb.h>
37 #include "control_local.h"
38 #include "aserver.h"
39
40 typedef struct {
41         int socket;
42         void *ctrl;
43 } snd_ctl_shm_t;
44
45 extern int receive_fd(int socket, void *data, size_t len, int *fd);
46
47 static int snd_ctl_shm_action(snd_ctl_t *ctl)
48 {
49         snd_ctl_shm_t *shm = ctl->private;
50         int err;
51         char buf[1];
52         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
53         err = write(shm->socket, buf, 1);
54         if (err != 1)
55                 return -EBADFD;
56         err = read(shm->socket, buf, 1);
57         if (err != 1)
58                 return -EBADFD;
59         if (ctrl->cmd) {
60                 fprintf(stderr, "Server has not done the cmd\n");
61                 return -EBADFD;
62         }
63         return ctrl->result;
64 }
65
66 static int snd_ctl_shm_action_fd(snd_ctl_t *ctl, int *fd)
67 {
68         snd_ctl_shm_t *shm = ctl->private;
69         int err;
70         char buf[1];
71         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
72         err = write(shm->socket, buf, 1);
73         if (err != 1)
74                 return -EBADFD;
75         err = receive_fd(shm->socket, buf, 1, fd);
76         if (err != 1)
77                 return -EBADFD;
78         if (ctrl->cmd) {
79                 fprintf(stderr, "Server has not done the cmd\n");
80                 return -EBADFD;
81         }
82         return ctrl->result;
83 }
84
85 static int snd_ctl_shm_close(snd_ctl_t *ctl)
86 {
87         snd_ctl_shm_t *shm = ctl->private;
88         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
89         int result;
90         ctrl->cmd = SND_CTL_IOCTL_CLOSE;
91         result = snd_ctl_shm_action(ctl);
92         shmdt((void *)ctrl);
93         close(shm->socket);
94         free(shm);
95         return result;
96 }
97
98 static int snd_ctl_shm_poll_descriptor(snd_ctl_t *ctl)
99 {
100         snd_ctl_shm_t *shm = ctl->private;
101         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
102         int fd, err;
103         ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR;
104         err = snd_ctl_shm_action_fd(ctl, &fd);
105         if (err < 0)
106                 return err;
107         return fd;
108 }
109
110 static int snd_ctl_shm_hw_info(snd_ctl_t *ctl, snd_ctl_hw_info_t *info)
111 {
112         snd_ctl_shm_t *shm = ctl->private;
113         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
114         int err;
115 //      ctrl->u.hw_info = *info;
116         ctrl->cmd = SND_CTL_IOCTL_HW_INFO;
117         err = snd_ctl_shm_action(ctl);
118         if (err < 0)
119                 return err;
120         *info = ctrl->u.hw_info;
121         return err;
122 }
123
124 static int snd_ctl_shm_clist(snd_ctl_t *ctl, snd_control_list_t *list)
125 {
126         snd_ctl_shm_t *shm = ctl->private;
127         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
128         size_t maxsize = CTL_SHM_DATA_MAXLEN;
129         size_t bytes = list->controls_request * sizeof(*list->pids);
130         int err;
131         snd_control_id_t *pids = list->pids;
132         if (bytes > maxsize)
133                 return -EINVAL;
134         ctrl->u.clist = *list;
135         ctrl->cmd = SND_CTL_IOCTL_CONTROL_LIST;
136         err = snd_ctl_shm_action(ctl);
137         if (err < 0)
138                 return err;
139         *list = ctrl->u.clist;
140         list->pids = pids;
141         memcpy(pids, ctrl->data, bytes);
142         return err;
143 }
144
145 static int snd_ctl_shm_cinfo(snd_ctl_t *ctl, snd_control_info_t *info)
146 {
147         snd_ctl_shm_t *shm = ctl->private;
148         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
149         int err;
150         ctrl->u.cinfo = *info;
151         ctrl->cmd = SND_CTL_IOCTL_CONTROL_INFO;
152         err = snd_ctl_shm_action(ctl);
153         if (err < 0)
154                 return err;
155         *info = ctrl->u.cinfo;
156         return err;
157 }
158
159 static int snd_ctl_shm_cread(snd_ctl_t *ctl, snd_control_t *control)
160 {
161         snd_ctl_shm_t *shm = ctl->private;
162         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
163         int err;
164         ctrl->u.cread = *control;
165         ctrl->cmd = SND_CTL_IOCTL_CONTROL_READ;
166         err = snd_ctl_shm_action(ctl);
167         if (err < 0)
168                 return err;
169         *control = ctrl->u.cread;
170         return err;
171 }
172
173 static int snd_ctl_shm_cwrite(snd_ctl_t *ctl, snd_control_t *control)
174 {
175         snd_ctl_shm_t *shm = ctl->private;
176         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
177         int err;
178         ctrl->u.cwrite = *control;
179         ctrl->cmd = SND_CTL_IOCTL_CONTROL_WRITE;
180         err = snd_ctl_shm_action(ctl);
181         if (err < 0)
182                 return err;
183         *control = ctrl->u.cwrite;
184         return err;
185 }
186
187 static int snd_ctl_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)
188 {
189         snd_ctl_shm_t *shm = ctl->private;
190         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
191         int err;
192         ctrl->u.hwdep_info = *info;
193         ctrl->cmd = SND_CTL_IOCTL_HWDEP_INFO;
194         err = snd_ctl_shm_action(ctl);
195         if (err < 0)
196                 return err;
197         *info = ctrl->u.hwdep_info;
198         return err;
199 }
200
201 static int snd_ctl_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)
202 {
203         snd_ctl_shm_t *shm = ctl->private;
204         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
205         int err;
206         ctrl->u.pcm_info = *info;
207         ctrl->cmd = SND_CTL_IOCTL_PCM_INFO;
208         err = snd_ctl_shm_action(ctl);
209         if (err < 0)
210                 return err;
211         *info = ctrl->u.pcm_info;
212         return err;
213 }
214
215 static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
216 {
217         snd_ctl_shm_t *shm = ctl->private;
218         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
219         int err;
220         ctrl->u.pcm_prefer_subdevice = subdev;
221         ctrl->cmd = SND_CTL_IOCTL_PCM_PREFER_SUBDEVICE;
222         err = snd_ctl_shm_action(ctl);
223         if (err < 0)
224                 return err;
225         return err;
226 }
227
228 static int snd_ctl_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)
229 {
230         snd_ctl_shm_t *shm = ctl->private;
231         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
232         int err;
233         ctrl->u.rawmidi_info = *info;
234         ctrl->cmd = SND_CTL_IOCTL_RAWMIDI_INFO;
235         err = snd_ctl_shm_action(ctl);
236         if (err < 0)
237                 return err;
238         *info = ctrl->u.rawmidi_info;
239         return err;
240 }
241
242 static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
243 {
244         snd_ctl_shm_t *shm = ctl->private;
245         snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
246         int err;
247         ctrl->u.read = *event;
248         ctrl->cmd = SND_CTL_IOCTL_READ;
249         err = snd_ctl_shm_action(ctl);
250         if (err < 0)
251                 return err;
252         *event = ctrl->u.read;
253         return err;
254 }
255
256 struct snd_ctl_ops snd_ctl_shm_ops = {
257         close: snd_ctl_shm_close,
258         poll_descriptor: snd_ctl_shm_poll_descriptor,
259         hw_info: snd_ctl_shm_hw_info,
260         clist: snd_ctl_shm_clist,
261         cinfo: snd_ctl_shm_cinfo,
262         cread: snd_ctl_shm_cread,
263         cwrite: snd_ctl_shm_cwrite,
264         hwdep_info: snd_ctl_shm_hwdep_info,
265         pcm_info: snd_ctl_shm_pcm_info,
266         pcm_prefer_subdevice: snd_ctl_shm_pcm_prefer_subdevice,
267         rawmidi_info: snd_ctl_shm_rawmidi_info,
268         read: snd_ctl_shm_read,
269 };
270
271 static int make_local_socket(const char *filename)
272 {
273         size_t l = strlen(filename);
274         size_t size = offsetof(struct sockaddr_un, sun_path) + l;
275         struct sockaddr_un *addr = alloca(size);
276         int sock;
277
278         sock = socket(PF_LOCAL, SOCK_STREAM, 0);
279         if (sock < 0)
280                 return -errno;
281         
282         addr->sun_family = AF_LOCAL;
283         memcpy(addr->sun_path, filename, l);
284
285         if (connect(sock, (struct sockaddr *) addr, size) < 0)
286                 return -errno;
287         return sock;
288 }
289
290 #if 0
291 static int make_inet_socket(const char *host, int port)
292 {
293         struct sockaddr_in addr;
294         int sock;
295         struct hostent *h = gethostbyname(host);
296         if (!h)
297                 return -ENOENT;
298
299         sock = socket(PF_INET, SOCK_STREAM, 0);
300         if (sock < 0)
301                 return -errno;
302         
303         addr.sin_family = AF_INET;
304         addr.sin_port = htons(port);
305         memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
306
307         if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
308                 return -errno;
309         return sock;
310 }
311 #endif
312
313 int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname)
314 {
315         snd_ctl_t *ctl;
316         snd_ctl_shm_t *shm = NULL;
317         snd_client_open_request_t *req;
318         snd_client_open_answer_t ans;
319         size_t snamelen, reqlen;
320         int err;
321         int result;
322         int sock = -1;
323         snd_ctl_shm_ctrl_t *ctrl = NULL;
324         snamelen = strlen(sname);
325         if (snamelen > 255)
326                 return -EINVAL;
327
328         result = make_local_socket(socket);
329         if (result < 0) {
330                 ERR("server for socket %s is not running", socket);
331                 goto _err;
332         }
333         sock = result;
334
335         reqlen = sizeof(*req) + snamelen;
336         req = alloca(reqlen);
337         memcpy(req->name, sname, snamelen);
338         req->dev_type = SND_DEV_TYPE_CONTROL;
339         req->transport_type = SND_TRANSPORT_TYPE_SHM;
340         req->stream = 0;
341         req->mode = 0;
342         req->namelen = snamelen;
343         err = write(sock, req, reqlen);
344         if (err < 0) {
345                 ERR("write error");
346                 result = -errno;
347                 goto _err;
348         }
349         if ((size_t) err != reqlen) {
350                 ERR("write size error");
351                 result = -EINVAL;
352                 goto _err;
353         }
354         err = read(sock, &ans, sizeof(ans));
355         if (err < 0) {
356                 ERR("read error");
357                 result = -errno;
358                 goto _err;
359         }
360         if (err != sizeof(ans)) {
361                 ERR("read size error");
362                 result = -EINVAL;
363                 goto _err;
364         }
365         result = ans.result;
366         if (result < 0)
367                 goto _err;
368
369         ctrl = shmat(ans.cookie, 0, 0);
370         if (!ctrl) {
371                 result = -errno;
372                 goto _err;
373         }
374                 
375         ctl = calloc(1, sizeof(snd_ctl_t));
376         if (!ctl) {
377                 result = -ENOMEM;
378                 goto _err;
379         }
380         shm = calloc(1, sizeof(snd_ctl_shm_t));
381         if (!ctl) {
382                 free(ctl);
383                 result = -ENOMEM;
384                 goto _err;
385         }
386
387         shm->socket = sock;
388         shm->ctrl = ctrl;
389
390         if (name)
391                 ctl->name = strdup(name);
392         ctl->type = SND_CTL_TYPE_SHM;
393         ctl->ops = &snd_ctl_shm_ops;
394         ctl->private = shm;
395         INIT_LIST_HEAD(&ctl->hlist);
396         *handlep = ctl;
397         return 0;
398
399  _err:
400         close(sock);
401         if (ctrl)
402                 shmdt(ctrl);
403         if (shm)
404                 free(shm);
405         return result;
406 }
407
408 extern int is_local(struct hostent *hent);
409
410 int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf)
411 {
412         snd_config_iterator_t i;
413         char *server = NULL;
414         char *sname = NULL;
415         snd_config_t *sconfig;
416         char *host = NULL;
417         char *socket = NULL;
418         long port = -1;
419         int err;
420         int local;
421         struct hostent *h;
422         snd_config_foreach(i, conf) {
423                 snd_config_t *n = snd_config_entry(i);
424                 if (strcmp(n->id, "comment") == 0)
425                         continue;
426                 if (strcmp(n->id, "type") == 0)
427                         continue;
428                 if (strcmp(n->id, "server") == 0) {
429                         err = snd_config_string_get(n, &server);
430                         if (err < 0) {
431                                 ERR("Invalid type for server");
432                                 return -EINVAL;
433                         }
434                         continue;
435                 }
436                 if (strcmp(n->id, "sname") == 0) {
437                         err = snd_config_string_get(n, &sname);
438                         if (err < 0) {
439                                 ERR("Invalid type for sname");
440                                 return -EINVAL;
441                         }
442                         continue;
443                 }
444                 ERR("Unknown field: %s", n->id);
445                 return -EINVAL;
446         }
447         if (!sname) {
448                 ERR("sname is not defined");
449                 return -EINVAL;
450         }
451         if (!server) {
452                 ERR("server is not defined");
453                 return -EINVAL;
454         }
455         err = snd_config_searchv(snd_config, &sconfig, "server", server, 0);
456         if (err < 0) {
457                 ERR("Unknown server %s", server);
458                 return -EINVAL;
459         }
460         snd_config_foreach(i, conf) {
461                 snd_config_t *n = snd_config_entry(i);
462                 if (strcmp(n->id, "comment") == 0)
463                         continue;
464                 if (strcmp(n->id, "host") == 0) {
465                         err = snd_config_string_get(n, &host);
466                         if (err < 0) {
467                                 ERR("Invalid type for host");
468                                 return -EINVAL;
469                         }
470                         continue;
471                 }
472                 if (strcmp(n->id, "socket") == 0) {
473                         err = snd_config_string_get(n, &socket);
474                         if (err < 0) {
475                                 ERR("Invalid type for socket");
476                                 return -EINVAL;
477                         }
478                         continue;
479                 }
480                 if (strcmp(n->id, "port") == 0) {
481                         err = snd_config_integer_get(n, &port);
482                         if (err < 0) {
483                                 ERR("Invalid type for port");
484                                 return -EINVAL;
485                         }
486                         continue;
487                 }
488                 ERR("Unknown field: %s", n->id);
489                 return -EINVAL;
490         }
491
492         if (!host) {
493                 ERR("host is not defined");
494                 return -EINVAL;
495         }
496         if (!socket) {
497                 ERR("socket is not defined");
498                 return -EINVAL;
499         }
500         h = gethostbyname(host);
501         if (!h) {
502                 ERR("Cannot resolve %s", host);
503                 return -EINVAL;
504         }
505         local = is_local(h);
506         if (!local) {
507                 ERR("%s is not the local host", host);
508                 return -EINVAL;
509         }
510         return snd_ctl_shm_open(handlep, name, socket, sname);
511 }
512