source: roaraudio/libroar/vio_pipe.c @ 3063:955233719a84

Last change on this file since 3063:955233719a84 was 3063:955233719a84, checked in by phi, 14 years ago

use memory functions from libroar, not libc, fixed a small memory leak

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