source: roaraudio/libroar/vio_proto.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: 10.2 KB
Line 
1//vio_proto.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2010
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_proto_init_def  (struct roar_vio_defaults * def, char * dstr, int proto, struct roar_vio_defaults * odef) {
39#ifndef ROAR_WITHOUT_VIO_PROTO
40 int                        port = 0;
41 int                        ret;
42 char                     * ed;
43
44 if ( def == NULL )
45  return -1;
46
47 switch (proto) {
48  case ROAR_VIO_PROTO_P_HTTP:    port =   80; break;
49  case ROAR_VIO_PROTO_P_GOPHER:  port =   70; break;
50  case ROAR_VIO_PROTO_P_ICY:     port = 8000; break;
51  default:
52    return -1;
53 }
54
55 if ( dstr == NULL )
56  dstr = "//";
57
58 if ( roar_vio_dstr_init_defaults(def, ROAR_VIO_DEF_TYPE_SOCKET, O_RDWR, 0644) == -1 )
59  return -1;
60
61 if ( roar_vio_socket_init_tcp4_def(def, "localhost", port) == -1 )
62  return -1;
63
64 if ( !strncmp(dstr, "//", 2) )
65  dstr += 2;
66
67 if ( (ed = strstr(dstr, "/")) != NULL )
68  *ed = 0;
69
70 ROAR_DBG("roar_vio_proto_init_def(*): def->o_flags=%i", def->o_flags);
71
72 ret = roar_vio_socket_init_dstr_def(def, dstr, -1, SOCK_STREAM, def);
73
74 ROAR_DBG("roar_vio_proto_init_def(*): def->o_flags=%i", def->o_flags);
75
76 if ( ed != NULL )
77  *ed = '/';
78
79 ROAR_DBG("roar_vio_proto_init_def(*): dstr='%s'", dstr);
80
81 return ret;
82#else
83 return -1;
84#endif
85}
86
87int roar_vio_open_proto      (struct roar_vio_calls * calls, struct roar_vio_calls * dst,
88                              char * dstr, int proto, struct roar_vio_defaults * odef) {
89#ifndef ROAR_WITHOUT_VIO_PROTO
90 struct roar_vio_proto * self;
91 char * host;
92 char * tmp;
93
94 ROAR_DBG("roar_vio_open_proto(calls=%p, dst=%p, dstr='%s', proto=%i, odef=%p) = ?", calls, dst, dstr, proto, odef);
95
96 if ( calls == NULL || dst == NULL || odef == NULL )
97  return -1;
98
99 ROAR_DBG("roar_vio_open_proto(*): odef->o_flags=%i", odef->o_flags);
100 ROAR_DBG("roar_vio_open_proto(*) = ?");
101
102 if ( (self = roar_mm_malloc(sizeof(struct roar_vio_proto))) == NULL )
103  return -1;
104
105 memset(self, 0, sizeof(struct roar_vio_proto));
106
107 self->next      = dst;
108
109 calls->inst     = self;
110
111 calls->read     = roar_vio_proto_read;
112 calls->write    = roar_vio_proto_write;
113// calls->lseek    = roar_vio_proto_lseek; // TODO: this is currently not supported
114 calls->nonblock = roar_vio_proto_nonblock;
115 calls->sync     = roar_vio_proto_sync;
116 calls->ctl      = roar_vio_proto_ctl;
117 calls->close    = roar_vio_proto_close;
118
119 ROAR_DBG("roar_vio_open_proto(*) = ?");
120
121 if ( dstr != NULL ) {
122  dstr += 2;
123  host  = dstr;
124
125  if ( (tmp = strstr(dstr, "/")) == NULL )
126   return -1;
127
128  *tmp++ = 0;
129  dstr   = tmp;
130
131  if ( (tmp = strstr(dstr, "#")) != NULL )
132   *tmp = 0;
133 } else {
134  ROAR_DBG("roar_vio_open_proto(*): no dstr!, odef->type=%i", odef->type);
135  if ( odef->type == ROAR_VIO_DEF_TYPE_FILE ) {
136   dstr = odef->d.file;
137   host = "localhost";
138
139   for (; *dstr == '/'; dstr++);
140
141  } else if ( odef->type == ROAR_VIO_DEF_TYPE_SOCKET ) {
142   dstr = ""; // index document
143   host = odef->d.socket.host;
144  } else {
145   return -1;
146  }
147 }
148
149 ROAR_DBG("roar_vio_open_proto(*) = ?");
150 ROAR_DBG("roar_vio_open_proto(*): proto=%i, host='%s', file='%s'", proto, host, dstr);
151
152 switch (proto) {
153  case ROAR_VIO_PROTO_P_HTTP:
154  case ROAR_VIO_PROTO_P_ICY:
155    return roar_vio_open_proto_http(calls, dst, host, dstr);
156   break;
157  case ROAR_VIO_PROTO_P_GOPHER:
158    return roar_vio_open_proto_gopher(calls, dst, host, dstr);
159   break;
160 }
161
162 ROAR_DBG("roar_vio_open_proto(*) = -1 // no matching protocol");
163 return -1;
164#else
165 return -1;
166#endif
167}
168
169#ifndef ROAR_WITHOUT_VIO_PROTO
170ssize_t roar_vio_proto_read    (struct roar_vio_calls * vio, void *buf, size_t count) {
171 struct roar_vio_proto * self = vio->inst;
172 ssize_t ret;
173 ssize_t have = 0;
174 size_t  len;
175
176 if ( self->reader.buffer != NULL ) {
177  len = count;
178  if ( roar_buffer_shift_out(&(self->reader.buffer), buf, &len) == -1 ) {
179   // This is very bad.
180   return -1;
181  }
182
183  if ( len ) {
184   have   = len;
185   buf   += len;
186   count -= len;
187  }
188 }
189
190 if ( count == 0 )
191  return have;
192
193 ROAR_DBG("roar_vio_proto_read(*): have=%lli, count=%lli", (long long int)have, (long long int)count);
194
195 if ( (ret = roar_vio_read(self->next, buf, count)) == -1 )
196  return ret;
197
198 return have + ret;
199}
200
201ssize_t roar_vio_proto_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
202 struct roar_vio_proto * self = vio->inst;
203
204 return roar_vio_write(self->next, buf, count);
205}
206
207// TODO: this is currently not implemented as this is hard to implement with buffers:
208off_t   roar_vio_proto_lseek   (struct roar_vio_calls * vio, off_t offset, int whence);
209
210int     roar_vio_proto_nonblock(struct roar_vio_calls * vio, int state) {
211 struct roar_vio_proto * self = vio->inst;
212
213 /* we can simply use the next layer's nonblock as all we do in addtion *
214  * to call there functions are our buffers which do not block normaly  */
215
216 return roar_vio_nonblock(self->next, state);
217}
218
219int     roar_vio_proto_sync    (struct roar_vio_calls * vio) {
220 struct roar_vio_proto * self = vio->inst;
221
222 return roar_vio_sync(self->next);
223}
224
225int     roar_vio_proto_ctl     (struct roar_vio_calls * vio, int cmd, void * data) {
226 struct roar_vio_proto * self = vio->inst;
227
228 if (vio == NULL || cmd == -1)
229  return -1;
230
231 ROAR_DBG("roar_vio_proto_ctl(vio=%p, cmd=0x%.8x, data=%p) = ?", vio, cmd, data);
232
233 switch (cmd) {
234  case ROAR_VIO_CTL_GET_NAME:
235    if ( data == NULL )
236     return -1;
237
238    *(char**)data = "proto";
239    return 0;
240   break;
241  case ROAR_VIO_CTL_GET_NEXT:
242    *(struct roar_vio_calls **)data = self->next;
243    return 0;
244   break;
245  case ROAR_VIO_CTL_SET_NEXT:
246    self->next = *(struct roar_vio_calls **)data;
247    return 0;
248   break;
249 }
250
251 return roar_vio_ctl(self->next, cmd, data);
252}
253
254int     roar_vio_proto_close   (struct roar_vio_calls * vio) {
255 struct roar_vio_proto * self = vio->inst;
256
257 if ( roar_vio_close(self->next) == -1 )
258  return -1;
259
260 roar_mm_free(self);
261
262 return 0;
263}
264
265
266int roar_vio_open_proto_http   (struct roar_vio_calls * calls, struct roar_vio_calls * dst, char * host, char * file) {
267 struct roar_vio_proto * self;
268 struct roar_buffer * bufbuf;
269 void * vpbuf;
270 char * buf;
271 char * endofheader = NULL;
272 char b0[80], b1[80];
273 int  status;
274 int  len;
275
276 ROAR_DBG("roar_vio_open_proto_http(calls=%p, dst=%p, host='%s', file='%s') = ?", calls, dst, host, file);
277
278 if ( calls == NULL || dst == NULL || host == NULL || file == NULL )
279  return -1;
280
281 self         = calls->inst;
282 calls->write = NULL; // Disable write as we do not support this
283
284 if ( roar_buffer_new_data(&bufbuf, 1024, &vpbuf) == -1 )
285  return -1;
286
287 buf = vpbuf;
288
289 ROAR_DBG("roar_vio_open_proto_http(calls=%p, dst=%p, host='%s', file='%s') = ?", calls, dst, host, file);
290
291 roar_vio_printf(dst, "GET /%s HTTP/1.1\r\n", file);
292 roar_vio_printf(dst, "Host: %s\r\n", host);
293 roar_vio_printf(dst, "User-Agent: roar_vio_open_proto_http() $Revision$\r\n");
294 roar_vio_printf(dst, "Connection: close\r\n");
295 roar_vio_printf(dst, "\r\n");
296
297 ROAR_DBG("roar_vio_open_proto_http(*) = ?");
298
299 roar_vio_sync(dst);
300
301 ROAR_DBG("roar_vio_open_proto_http(*) = ?");
302
303 if ( (len = roar_vio_read(dst, buf, 1023)) < 1 ) {
304  ROAR_DBG("roar_vio_open_proto_http(*) = -1");
305  roar_buffer_free(bufbuf);
306  return -1;
307 }
308
309 buf[len] = 0;
310
311 ROAR_DBG("roar_vio_open_proto_http(*) = ?");
312
313 if ( sscanf(buf, "%79s %i %79s\n", b0, &status, b1) != 3 ) {
314  ROAR_DBG("roar_vio_open_proto_http(*) = -1");
315  roar_buffer_free(bufbuf);
316  return -1;
317 }
318
319 ROAR_DBG("roar_vio_open_proto_http(*) = ?");
320
321 if ( status != 200 ) {
322  ROAR_DBG("roar_vio_open_proto_http(*) = -1 // status=%i", status);
323  roar_buffer_free(bufbuf);
324  return -1;
325 }
326
327 ROAR_DBG("roar_vio_open_proto_http(*): status=%i", status);
328// ROAR_WARN("roar_vio_open_proto_http(*): buf='%s'", buf);
329
330 endofheader = strstr(buf, "\r\n\r\n");
331
332 ROAR_DBG("roar_vio_open_proto_http(*): endofheader=%p\n", endofheader);
333
334 while ( endofheader == NULL ) {
335  if ( (len = roar_vio_read(dst, buf, 1023)) < 1 )
336   return -1;
337
338  buf[len] = 0;
339  endofheader = strstr(buf, "\r\n\r\n");
340  ROAR_DBG("roar_vio_open_proto_http(*): endofheader=%p\n", endofheader);
341 }
342
343 ROAR_DBG("roar_vio_open_proto_http(*): endofheader=%p\n", endofheader);
344 ROAR_DBG("roar_vio_open_proto_http(*): buf=%p\n", buf);
345
346 if ( (endofheader - buf) == (len - 4) ) {
347  roar_buffer_free(bufbuf);
348  bufbuf = NULL;
349 }
350
351 if ( bufbuf != NULL ) {
352  roar_buffer_set_offset(bufbuf, endofheader - buf + 4);
353  roar_buffer_set_len(bufbuf,    len - (endofheader - buf + 4) - 1);
354 }
355 self->reader.buffer = bufbuf;
356
357/*
358 if ( !strcmp((buf+len)-4, "\r\n\r\n") )
359  return 0;
360
361 while (*buf != '\r' && *buf != '\n') {
362  if ( (len = roar_vio_read(dst, buf, 1023)) < 1 )
363   return -1;
364 }
365*/
366
367 return 0;
368}
369
370int roar_vio_open_proto_gopher (struct roar_vio_calls * calls, struct roar_vio_calls * dst, char * host, char * file) {
371 if ( calls == NULL || dst == NULL || host == NULL || file == NULL )
372  return -1;
373
374 calls->write = NULL; // Disable write as we do not support this
375
376 ROAR_DBG("roar_vio_open_proto_gopher(calls=%p, dst=%p, host='%s', file='%s') = ?", calls, dst, host, file);
377
378 if ( file[1] == '/' )
379  file += 2;
380
381 roar_vio_printf(dst, "/%s\r\n", file);
382
383 roar_vio_sync(dst); // for encryption/compression layers
384
385 return 0;
386}
387#endif
388
389//ll
Note: See TracBrowser for help on using the repository browser.