source: roaraudio/libroar/vio_pipe.c @ 3517:1a3218a3fc5b

Last change on this file since 3517:1a3218a3fc5b was 3517:1a3218a3fc5b, checked in by phi, 14 years ago

updated license headers, FSF moved office

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_FH:
225  case ROAR_VIO_CTL_GET_SELECT_FH:
226    if ( self->type == ROAR_VIO_PIPE_TYPE_SOCKET ) {
227     *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)];
228     return 0;
229    } else {
230     return -1;
231    }
232   break;
233  case ROAR_VIO_CTL_GET_READ_FH:
234  case ROAR_VIO_CTL_GET_SELECT_READ_FH:
235    switch (self->type) {
236     case ROAR_VIO_PIPE_TYPE_SOCKET:
237       *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)];
238       return 0;
239      break;
240     case ROAR_VIO_PIPE_TYPE_PIPE:
241       *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)*2];
242       return 0;
243      break;
244    }
245  case ROAR_VIO_CTL_GET_WRITE_FH:
246  case ROAR_VIO_CTL_GET_SELECT_WRITE_FH:
247    switch (self->type) {
248     case ROAR_VIO_PIPE_TYPE_SOCKET:
249       *(int*)data = self->b.p[ROAR_VIO_PIPE_S(self,vio)];
250       return 0;
251      break;
252     case ROAR_VIO_PIPE_TYPE_PIPE:
253       *(int*)data = self->b.p[(ROAR_VIO_PIPE_SR(self,vio)*2)+1];
254       return 0;
255      break;
256    }
257   break;
258 }
259
260 return -1;
261}
262
263
264ssize_t roar_vio_pipe_read    (struct roar_vio_calls * vio, void *buf, size_t count) {
265 struct roar_vio_pipe * self;
266 int                    idx;
267
268 if ( vio == NULL )
269  return -1;
270
271 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
272  return -1;
273
274 switch (self->type) {
275  case ROAR_VIO_PIPE_TYPE_BUFFER:
276    idx = ROAR_VIO_PIPE_S(self,vio);
277
278    if ( (idx == 0 ? O_WRONLY : O_RDONLY) == (self->flags & (O_RDONLY|O_WRONLY|O_RDWR)) ) {
279     raise(SIGPIPE);
280     return -1;
281    }
282
283    if ( self->b.b[idx] == NULL )
284     return 0;
285
286    if ( roar_buffer_shift_out(&(self->b.b[idx]), buf, &count) == -1 )
287     return -1;
288
289    return count;
290   break;
291  case ROAR_VIO_PIPE_TYPE_PIPE:
292    return read(self->b.p[ROAR_VIO_PIPE_S(self,vio)*2], buf, count);
293   break;
294  case ROAR_VIO_PIPE_TYPE_SOCKET:
295    return read(self->b.p[ROAR_VIO_PIPE_S(self,vio)], buf, count);
296   break;
297 }
298
299 return -1;
300}
301
302ssize_t roar_vio_pipe_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
303 struct roar_vio_pipe * self;
304 struct roar_buffer   * next;
305 void                 * data;
306 int                    idx;
307
308 if ( vio == NULL )
309  return -1;
310
311 if ( (self = (struct roar_vio_pipe *)vio->inst) == NULL )
312  return -1;
313
314 switch (self->type) {
315  case ROAR_VIO_PIPE_TYPE_BUFFER:
316    if ( self->refcount < 2 ) {
317     raise(SIGPIPE);
318     return -1;
319    }
320
321    idx = ROAR_VIO_PIPE_SR(self,vio);
322
323    if ( (idx == 0 ? O_WRONLY : O_RDONLY) == (self->flags & (O_RDONLY|O_WRONLY|O_RDWR)) ) {
324     raise(SIGPIPE);
325     return -1;
326    }
327
328    if ( roar_buffer_new(&next, count) == -1 )
329     return -1;
330
331    if ( roar_buffer_get_data(next, &data) == -1 ) {
332     roar_buffer_free(next);
333     return -1;
334    }
335
336    memcpy(data, buf, count);
337
338    if ( self->b.b[idx] == NULL ) {
339     self->b.b[idx] = next;
340    } else {
341     if ( roar_buffer_add(self->b.b[idx], next) == -1 ) {
342      roar_buffer_free(next);
343      return -1;
344     }
345    }
346
347    return count;
348   break;
349  case ROAR_VIO_PIPE_TYPE_PIPE:
350    return write(self->b.p[(ROAR_VIO_PIPE_SR(self,vio)*2)+1], buf, count);
351   break;
352  case ROAR_VIO_PIPE_TYPE_SOCKET:
353    return write(self->b.p[ROAR_VIO_PIPE_S(self,vio)], buf, count);
354   break;
355 }
356
357 return -1;
358}
359#endif
360
361//ll
Note: See TracBrowser for help on using the repository browser.