source: roaraudio/libroar/vio_pipe.c @ 3795:6d3ee2c1c22f

Last change on this file since 3795:6d3ee2c1c22f was 3795:6d3ee2c1c22f, checked in by phi, 14 years ago

support ROAR_VIO_CTL_GET_NAME

File size: 8.8 KB
Line 
1//vio_pipe.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38int roar_vio_open_pipe (struct roar_vio_calls * s0, struct roar_vio_calls * s1, int type, int flags) {
39#ifndef ROAR_WITHOUT_VIO_PIPE
40 struct roar_vio_pipe * self;
41 int                    rw = flags & (O_RDONLY|O_WRONLY|O_RDWR);
42
43 if ( s0 == NULL || s1 == NULL )
44  return -1;
45
46 if ( (self = roar_mm_malloc(sizeof(struct roar_vio_pipe))) == NULL )
47  return -1;
48
49 memset(self, 0, sizeof(struct roar_vio_pipe));
50
51 self->refcount = 2;
52 self->flags    = flags;
53
54 if ( type == ROAR_VIO_PIPE_TYPE_AUTO ) {
55#ifdef ROAR_TARGET_WIN32
56  type = ROAR_VIO_PIPE_TYPE_BUFFER;
57#else
58  type = ROAR_VIO_PIPE_TYPE_SOCKET;
59#endif
60 }
61
62 self->type     = type;
63
64 switch (type) {
65  case ROAR_VIO_PIPE_TYPE_BUFFER:
66    // no buffers need to be set up here,
67    // we handle the NULL pointer in the reader and writer func
68    roar_mm_free(self);
69    return -1;
70   break;
71  case ROAR_VIO_PIPE_TYPE_PIPE:
72    self->b.p[0] = self->b.p[1] = self->b.p[2] = self->b.p[3] = -1;
73
74    if ( rw == O_RDWR || rw == O_RDONLY )
75     if ( pipe(self->b.p) == -1 ) {
76      roar_mm_free(self);
77      return -1;
78     }
79    if ( rw == O_RDWR || rw == O_WRONLY )
80     if ( pipe((self->b.p) + 2) == -1 ) {
81      close(self->b.p[0]);
82      close(self->b.p[1]);
83      roar_mm_free(self);
84      return -1;
85     }
86   break;
87  case ROAR_VIO_PIPE_TYPE_SOCKET:
88    if ( socketpair(AF_UNIX, SOCK_STREAM, 0, self->b.p) == -1 ) {
89     roar_mm_free(self);
90     return -1;
91    }
92
93    if ( rw == O_RDONLY ) {
94     ROAR_SHUTDOWN(self->b.p[0], SHUT_WR);
95     ROAR_SHUTDOWN(self->b.p[1], SHUT_RD);
96    } else if ( rw == O_WRONLY ) {
97     ROAR_SHUTDOWN(self->b.p[0], SHUT_RD);
98     ROAR_SHUTDOWN(self->b.p[1], SHUT_WR);
99    }
100   break;
101  default:
102    roar_mm_free(self);
103    return -1;
104 }
105
106 roar_vio_pipe_init(s0, self, flags);
107 roar_vio_pipe_init(s1, self, flags);
108
109 self->s0 = s0;
110
111 return 0;
112#else
113 return -1;
114#endif
115}
116
117#ifndef ROAR_WITHOUT_VIO_PIPE
118int roar_vio_pipe_init (struct roar_vio_calls * s,  struct roar_vio_pipe * self, int flags) {
119 if ( s == NULL || self == NULL )
120  return -1;
121
122 memset(s, 0, sizeof(struct roar_vio_calls));
123
124 s->close    = roar_vio_pipe_close;
125 s->read     = roar_vio_pipe_read;
126 s->write    = roar_vio_pipe_write;
127 s->nonblock = roar_vio_pipe_nonblock;
128 s->sync     = roar_vio_pipe_sync;
129
130 s->inst = (void*) self;
131
132 if ( flags & O_NONBLOCK ) {
133  roar_vio_pipe_nonblock(s, ROAR_SOCKET_NONBLOCK);
134 }
135
136 return 0;
137}
138
139int     roar_vio_pipe_close   (struct roar_vio_calls * vio) {
140 struct roar_vio_pipe * self;
141 int                    idx;
142
143 if ( vio == NULL )
144  return -1;
145
146 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
147  return -1;
148
149 self->refcount--;
150
151 switch (self->type) {
152  case ROAR_VIO_PIPE_TYPE_BUFFER:
153    // this will be a bit more complex as we need to change the flags, too.
154   break;
155  case ROAR_VIO_PIPE_TYPE_PIPE:
156   switch (ROAR_VIO_PIPE_S(self, vio)) {
157    case 0:
158      close(self->b.p[0]);
159      close(self->b.p[3]);
160      self->b.p[0] = -1;
161      self->b.p[3] = -1;
162     break;
163    case 1:
164      close(self->b.p[1]);
165      close(self->b.p[2]);
166      self->b.p[1] = -1;
167      self->b.p[2] = -1;
168     break;
169   }
170   break;
171  case ROAR_VIO_PIPE_TYPE_SOCKET:
172    close(self->b.p[idx = ROAR_VIO_PIPE_S(self, vio)]);
173    self->b.p[idx] = -1;
174   break;
175 }
176
177 if ( ! self->refcount ) {
178  roar_mm_free(self);
179 }
180
181 vio->inst = NULL;
182 return 0;
183}
184
185int     roar_vio_pipe_nonblock(struct roar_vio_calls * vio, int state) {
186 struct roar_vio_pipe * self;
187
188 if ( vio == NULL )
189  return -1;
190
191 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
192  return -1;
193
194 switch (self->type) {
195  case ROAR_VIO_PIPE_TYPE_PIPE:
196    if ( roar_socket_nonblock(self->b.p[ROAR_VIO_PIPE_S(self,vio)*2], state) == -1 )
197     return -1;
198    return roar_socket_nonblock(self->b.p[(ROAR_VIO_PIPE_SR(self,vio)*2)+1], state);
199   break;
200  case ROAR_VIO_PIPE_TYPE_SOCKET:
201    return roar_socket_nonblock(self->b.p[ROAR_VIO_PIPE_S(self,vio)], state);
202   break;
203 }
204
205 return -1;
206}
207
208int     roar_vio_pipe_sync    (struct roar_vio_calls * vio) {
209 // we may add fdatasync() calls here depending on the type
210 // but in general they should not be needed on pipes.
211 return 0;
212}
213
214int     roar_vio_pipe_ctl     (struct roar_vio_calls * vio, int cmd, void * data) {
215 struct roar_vio_pipe * self;
216
217 if (vio == NULL || cmd == -1)
218  return -1;
219
220 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
221  return -1;
222
223 switch (cmd) {
224  case ROAR_VIO_CTL_GET_NAME:
225    if ( data == NULL )
226     return -1;
227
228    *(char**)data = "pipe";
229    return 0;
230   break;
231  case ROAR_VIO_CTL_GET_FH:
232  case ROAR_VIO_CTL_GET_SELECT_FH:
233    if ( self->type == ROAR_VIO_PIPE_TYPE_SOCKET ) {
234     *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)];
235     return 0;
236    } else {
237     return -1;
238    }
239   break;
240  case ROAR_VIO_CTL_GET_READ_FH:
241  case ROAR_VIO_CTL_GET_SELECT_READ_FH:
242    switch (self->type) {
243     case ROAR_VIO_PIPE_TYPE_SOCKET:
244       *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)];
245       return 0;
246      break;
247     case ROAR_VIO_PIPE_TYPE_PIPE:
248       *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)*2];
249       return 0;
250      break;
251    }
252  case ROAR_VIO_CTL_GET_WRITE_FH:
253  case ROAR_VIO_CTL_GET_SELECT_WRITE_FH:
254    switch (self->type) {
255     case ROAR_VIO_PIPE_TYPE_SOCKET:
256       *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)];
257       return 0;
258      break;
259     case ROAR_VIO_PIPE_TYPE_PIPE:
260       *(int*)data = self->b.p[(ROAR_VIO_PIPE_SR(self,vio)*2)+1];
261       return 0;
262      break;
263    }
264   break;
265 }
266
267 return -1;
268}
269
270
271ssize_t roar_vio_pipe_read    (struct roar_vio_calls * vio, void *buf, size_t count) {
272 struct roar_vio_pipe * self;
273 int                    idx;
274
275 if ( vio == NULL )
276  return -1;
277
278 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
279  return -1;
280
281 switch (self->type) {
282  case ROAR_VIO_PIPE_TYPE_BUFFER:
283    idx = ROAR_VIO_PIPE_S(self,vio);
284
285    if ( (idx == 0 ? O_WRONLY : O_RDONLY) == (self->flags & (O_RDONLY|O_WRONLY|O_RDWR)) ) {
286     raise(SIGPIPE);
287     return -1;
288    }
289
290    if ( self->b.b[idx] == NULL )
291     return 0;
292
293    if ( roar_buffer_shift_out(&(self->b.b[idx]), buf, &count) == -1 )
294     return -1;
295
296    return count;
297   break;
298  case ROAR_VIO_PIPE_TYPE_PIPE:
299    return read(self->b.p[ROAR_VIO_PIPE_S(self,vio)*2], buf, count);
300   break;
301  case ROAR_VIO_PIPE_TYPE_SOCKET:
302    return read(self->b.p[ROAR_VIO_PIPE_S(self,vio)], buf, count);
303   break;
304 }
305
306 return -1;
307}
308
309ssize_t roar_vio_pipe_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
310 struct roar_vio_pipe * self;
311 struct roar_buffer   * next;
312 void                 * data;
313 int                    idx;
314
315 if ( vio == NULL )
316  return -1;
317
318 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
319  return -1;
320
321 switch (self->type) {
322  case ROAR_VIO_PIPE_TYPE_BUFFER:
323    if ( self->refcount < 2 ) {
324     raise(SIGPIPE);
325     return -1;
326    }
327
328    idx = ROAR_VIO_PIPE_SR(self,vio);
329
330    if ( (idx == 0 ? O_WRONLY : O_RDONLY) == (self->flags & (O_RDONLY|O_WRONLY|O_RDWR)) ) {
331     raise(SIGPIPE);
332     return -1;
333    }
334
335    if ( roar_buffer_new_data(&next, count, &data) == -1 )
336     return -1;
337
338    memcpy(data, buf, count);
339
340    if ( self->b.b[idx] == NULL ) {
341     self->b.b[idx] = next;
342    } else {
343     if ( roar_buffer_add(self->b.b[idx], next) == -1 ) {
344      roar_buffer_free(next);
345      return -1;
346     }
347    }
348
349    return count;
350   break;
351  case ROAR_VIO_PIPE_TYPE_PIPE:
352    return write(self->b.p[(ROAR_VIO_PIPE_SR(self,vio)*2)+1], buf, count);
353   break;
354  case ROAR_VIO_PIPE_TYPE_SOCKET:
355    return write(self->b.p[ROAR_VIO_PIPE_S(self,vio)], buf, count);
356   break;
357 }
358
359 return -1;
360}
361#endif
362
363//ll
Note: See TracBrowser for help on using the repository browser.