source: roaraudio/libroar/vio_socket.c @ 1650:432469c37b16

Last change on this file since 1650:432469c37b16 was 1650:432469c37b16, checked in by phi, 15 years ago

got HTTP for non default port working, tool, Defaults based sockets striped everything behind the first colon

File size: 14.2 KB
Line 
1//vio_socket.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
37#ifdef ROAR_HAVE_BSDSOCKETS
38#define _CAN_OPERATE
39#endif
40
41int     roar_vio_open_def_socket          (struct roar_vio_calls * calls, struct roar_vio_defaults * def) {
42#ifdef _CAN_OPERATE
43 int       fh  = -1;
44 socklen_t len =  0;
45
46 if ( calls == NULL || def == NULL )
47  return -1;
48
49 if ( def->type != ROAR_VIO_DEF_TYPE_SOCKET )
50  return -1;
51
52 switch (def->d.socket.domain) {
53#ifdef ROAR_HAVE_IPV4
54  case AF_INET:
55    len = sizeof(struct sockaddr_in);
56
57    if ( roar_vio_socket_init_inet4host_def(def) == -1 )
58     return -1;
59
60    switch (def->d.socket.type) {
61     case SOCK_STREAM:
62       fh = roar_socket_new_tcp();
63      break;
64     case SOCK_DGRAM:
65       fh = roar_socket_new_udp();
66      break;
67     default:
68       return -1;
69    }
70   break;
71#endif
72#ifdef ROAR_HAVE_UNIX
73  case AF_UNIX:
74    len = sizeof(struct sockaddr_un);
75
76    switch (def->d.socket.type) {
77     case SOCK_STREAM:
78       fh = roar_socket_new_unix();
79      break;
80     case SOCK_DGRAM:
81       return -1;
82      break;
83     default:
84       return -1;
85    }
86   break;
87#endif
88#ifdef ROAR_HAVE_LIBDNET
89  case AF_DECnet:
90    len = sizeof(struct sockaddr_dn);
91
92    if ( roar_vio_socket_init_decnetnode_def(def) == -1 )
93     return -1;
94
95    switch (def->d.socket.type) {
96     case SOCK_STREAM:
97       fh = roar_socket_new_decnet_stream();
98      break;
99     default:
100       return -1;
101    }
102   break;
103#endif
104#ifdef ROAR_HAVE_IPV6
105  case AF_INET6:
106    len = sizeof(struct sockaddr_in6);
107
108    switch (def->d.socket.type) {
109     case SOCK_STREAM:
110       fh = roar_socket_new_tcp6();
111      break;
112     case SOCK_DGRAM:
113       fh = roar_socket_new_udp6();
114      break;
115     default:
116       return -1;
117    }
118   break;
119#endif
120#ifdef ROAR_HAVE_IPX
121  case AF_IPX:
122    len = sizeof(struct sockaddr_ipx);
123
124    return -1;
125   break;
126#endif
127  default:
128    return -1;
129 }
130
131 if ( fh == -1 )
132  return -1;
133
134 if ( connect(fh, &(def->d.socket.sa.sa), len) == -1 ) {
135  close(fh);
136  return -1;
137 }
138
139 if ( roar_vio_open_fh_socket(calls, fh) == -1 ) {
140  close(fh);
141  return -1;
142 }
143
144 // there is no problem if the shutdown()s fail.
145 // some socket domains don't support unidirectional connections
146 // this just free()s some kernel buffers :)
147 switch (def->o_flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
148  case O_RDONLY:
149    ROAR_SHUTDOWN(fh, SHUT_WR);
150   break;
151  case O_WRONLY:
152    ROAR_SHUTDOWN(fh, SHUT_RD);
153   break;
154 }
155
156 return 0;
157#else
158 return -1;
159#endif
160}
161
162int     roar_vio_socket_init_socket_def   (struct roar_vio_defaults * def, int domain, int type) {
163#ifdef _CAN_OPERATE
164 if ( def == NULL || domain == -1 || type == -1 )
165  return -1;
166
167 // we do not memset(def, 0, sizeof(...)) here
168 // because this is allready done in roar_vio_dstr_init_defaults()
169 // if we would be would override o_flags/o_mode and maybe others
170
171 memset(&(def->d.socket.sa), 0, sizeof(def->d.socket.sa));
172
173 def->type                     = ROAR_VIO_DEF_TYPE_SOCKET;
174 def->d.socket.domain          = domain;
175 def->d.socket.type            = type;
176 def->d.socket.sa.sa.sa_family = domain;
177
178 return 0;
179#else
180 return -1;
181#endif
182}
183
184int     roar_vio_socket_init_dstr_def     (struct roar_vio_defaults * def, char * dstr, int hint, int type,
185                                           struct roar_vio_defaults * odef) {
186#ifdef _CAN_OPERATE
187 char * host;
188#if defined(ROAR_HAVE_IPV4) || defined(ROAR_HAVE_IPV6)
189 int    port;
190#endif
191#if defined(ROAR_HAVE_IPV4)
192 int ret;
193#endif
194
195 if ( def == NULL )
196  return -1;
197
198 if ( dstr == NULL && odef == NULL )
199  return -1;
200
201 if ( dstr == NULL )
202  dstr = "";
203
204 ROAR_DBG("roar_vio_socket_init_dstr_def(def=%p, dstr='%s', hint=%i, type=%i, odef=%p) = ?", def, dstr, hint, type, odef);
205
206 if ( hint == -1 ) {
207  if ( 0 ) { // this is needed to keep the syntx ok, compiler will throw it away
208#ifdef ROAR_HAVE_IPV6
209  } else if ( strstr(dstr, "[") != NULL ) { // [ip]:service
210   hint = AF_INET6;
211#endif
212#ifdef ROAR_HAVE_LIBDNET
213  } else if ( strstr(dstr, "::") != NULL ) { // node::object
214   hint = AF_DECnet;
215#endif
216#ifdef ROAR_HAVE_IPX
217  } else if ( strstr(dstr, "(") != NULL ) { // net:mac(service)
218   hint = AF_IPX;
219#endif
220#ifdef ROAR_HAVE_UNIX
221  } else if ( strstr(dstr, "/") != NULL ) { // /path/to/sock
222   hint = AF_UNIX;
223#endif
224#ifdef ROAR_HAVE_IPV4
225  } else if ( strstr(dstr, ":") != NULL ) { // host:port
226   hint = AF_INET;
227#endif
228  }
229 }
230
231 if ( hint == -1 && odef != NULL ) { // if we still don't know what this is we try
232                                     // to use the parent objects request
233  ROAR_DBG("roar_vio_socket_init_dstr_def(*): hint=-1 && odef!=NULL");
234  if ( odef->type == ROAR_VIO_DEF_TYPE_SOCKET ) {
235   ROAR_DBG("roar_vio_socket_init_dstr_def(*): hint=-1 && odef!=NULL, using hint from odef");
236   hint = odef->d.socket.domain;
237  }
238 }
239
240 if ( hint == -1 ) /* we really have no glue what this is... */
241  return -1;
242
243#ifdef ROAR_HAVE_UNIX
244 if ( hint == AF_UNIX ) {
245  if ( *dstr != 0 && strcmp(dstr, "//") != 0 ) {
246   return roar_vio_socket_init_unix_def(def, dstr);
247  } else {
248   if ( roar_vio_socket_conv_def(odef, AF_UNIX) == -1 )
249    return -1;
250
251   return roar_vio_socket_init_unix_def(def, odef->d.socket.sa.un.sun_path);
252  }
253 }
254#endif
255
256 ROAR_DBG("roar_vio_socket_init_dstr_def(*) = ?");
257
258 if ( *dstr == 0 ) {
259  if ( roar_vio_socket_conv_def(odef, hint) == -1 )
260   return -1;
261
262  if ( odef->d.socket.type != type )
263   return -1;
264
265  if ( def != odef )
266   memcpy(def, odef, sizeof(struct roar_vio_defaults));
267
268  return 0;
269 }
270
271 for (; *dstr == '/'; dstr++);
272
273 ROAR_DBG("roar_vio_socket_init_dstr_def(*) = ?");
274
275 switch (hint) {
276#ifdef ROAR_HAVE_IPV4
277  case AF_INET:
278    host = dstr;
279    for (; *dstr != 0 && *dstr != ':'; dstr++);
280
281    if ( *dstr == ':' ) { // we have a port :)
282     *dstr++ = 0;
283     if ( (port = roar_vio_socket_get_port(dstr, AF_INET, type)) == -1 )
284      return -1;
285
286     ret = roar_vio_socket_init_inet4_def(def, host, port, type);
287
288     *(dstr-1) = ':';
289
290     return ret;
291    } else {
292     if ( roar_vio_socket_conv_def(odef, AF_INET) == -1 )
293      return -1;
294
295     return roar_vio_socket_init_inet4_def(def, host, ROAR_NET2HOST16(odef->d.socket.sa.in.sin_port), type);
296    }
297   break;
298#endif
299#ifdef ROAR_HAVE_LIBDNET
300  case AF_DECnet:
301    ROAR_DBG("roar_vio_socket_init_dstr_def(*) = ?");
302    host = dstr;
303
304    if ( type != SOCK_STREAM )
305     return -1;
306
307    if ( (dstr = strstr(dstr, "::")) == NULL ) {
308     if ( roar_vio_socket_conv_def(odef, AF_DECnet) == -1 )
309      return -1;
310
311     return -1;
312//     return roar_vio_socket_init_decnet_def(def, host, -1, dstr);
313    } else {
314     *dstr  = 0;
315      dstr += 2;
316     return roar_vio_socket_init_decnet_def(def, host, -1, dstr);
317    }
318   break;
319#endif
320#ifdef ROAR_HAVE_IPV6
321  case AF_INET6:
322    return -1;
323   break;
324#endif
325#ifdef ROAR_HAVE_IPX
326  case AF_IPX:
327    return -1;
328   break;
329#endif
330  default:
331    return -1;
332 }
333
334 return 0;
335#else
336 return -1;
337#endif
338}
339
340#ifdef _CAN_OPERATE
341int     roar_vio_socket_conv_def          (struct roar_vio_defaults * def, int domain) {
342 if ( def == NULL || domain == -1 )
343  return -1;
344
345#ifdef ROAR_HAVE_UNIX
346 if ( domain == AF_UNIX ) {
347  if ( def->type == ROAR_VIO_DEF_TYPE_SOCKET ) {
348   if ( def->d.socket.domain == AF_UNIX )
349    return 0;
350
351   return -1;
352  } else {
353   if ( def->type == ROAR_VIO_DEF_TYPE_FILE )
354    return roar_vio_socket_init_unix_def(def, def->d.file);
355
356   return -1;
357  }
358 }
359#endif
360
361 if ( def->type != ROAR_VIO_DEF_TYPE_SOCKET )
362  return -1;
363
364 if ( def->d.socket.domain == domain )
365  return 0;
366
367 // we sould add support to convert IPv4 <-> IPv6 here
368
369 return -1;
370}
371
372int     roar_vio_socket_get_port          (char * service, int domain, int type) {
373#ifdef ROAR_HAVE_GETSERVBYNAME
374 struct servent * serv  = NULL;
375#endif
376 char           * proto = NULL;
377 int              port;
378 char           * ts;
379
380 if ( service == NULL || domain == -1 || type == -1 )
381  return -1;
382
383 if ( (ts = strstr(service, "/")) != NULL )
384  *ts = 0;
385
386 if ( sscanf(service, "%i", &port) == 1 )
387  return port;
388
389 if ( ts != NULL )
390  *ts = '/';
391
392 switch (domain) {
393#ifdef ROAR_HAVE_IPV6
394  case AF_INET6:
395#endif
396#ifdef ROAR_HAVE_IPV4
397  case AF_INET:
398#endif
399#if defined(ROAR_HAVE_IPV6) || defined(ROAR_HAVE_IPV4)
400    switch (type) {
401     case SOCK_STREAM: proto = "tcp"; break;
402     case SOCK_DGRAM:  proto = "udp"; break;
403     default:
404      return -1;
405    }
406   break;
407#endif
408#ifdef ROAR_HAVE_LIBDNET
409  case AF_DECnet:
410#ifdef ROAR_HAVE_GETOBJECTBYNAME
411    return getobjectbyname(service);
412#else
413    if ( !strcmp(service, "roar") )
414     return 0;
415
416    return -1;
417#endif
418   break;
419#endif
420  default:
421    return -1;
422 }
423
424#ifdef ROAR_HAVE_GETSERVBYNAME
425 if ( ts != NULL )
426  *ts = 0;
427
428 if ( (serv = getservbyname(service, proto)) == NULL ) {
429  ROAR_ERR("roar_vio_socket_get_port(*): Unknown service: %s/%s: %s", service, proto, strerror(errno));
430
431  if ( ts != NULL )
432   *ts = '/';
433
434  return -1;
435 }
436
437 if ( ts != NULL )
438  *ts = '/';
439
440 return ROAR_NET2HOST16(serv->s_port);
441#endif
442
443 return -1;
444}
445#endif
446
447// AF_UNIX:
448int     roar_vio_socket_init_unix_def     (struct roar_vio_defaults * def, char * path) {
449#if defined(ROAR_HAVE_UNIX) && defined(_CAN_OPERATE)
450 if ( def == NULL || path == NULL )
451  return -1;
452
453 if ( roar_vio_socket_init_socket_def(def, AF_UNIX, SOCK_STREAM) == -1 )
454  return -1;
455
456 strncpy(def->d.socket.sa.un.sun_path, path, sizeof(def->d.socket.sa.un.sun_path) - 1);
457
458 return 0;
459#else
460 return -1;
461#endif
462}
463
464// AF_DECnet:
465int     roar_vio_socket_init_decnetnode_def(struct roar_vio_defaults * def) {
466#if defined(ROAR_HAVE_LIBDNET) && defined(_CAN_OPERATE)
467 char               * node;
468 char               * ed;
469 struct nodeent     * ne;
470
471 if ( def == NULL )
472  return -1;
473
474 if ( (node = def->d.socket.host) == NULL )
475  return -1;
476
477 if ( (ed = strstr(node, "/")) != NULL )
478  *ed = 0;
479
480 if ( (ne = getnodebyname(node)) == NULL ) {
481  ROAR_ERR("roar_vio_socket_init_decnetnode_def(*): Can\'t resolve node name '%s'", node);
482  if ( ed != NULL ) *ed = '/';
483  return -1;
484 }
485
486 memcpy(&(def->d.socket.sa.dn.sdn_add.a_addr), ne->n_addr, 2);
487
488 if ( ed != NULL ) *ed = '/';
489
490
491 return 0;
492#else
493 return -1;
494#endif
495}
496
497int     roar_vio_socket_init_decnet_def   (struct roar_vio_defaults * def, char * node, int object, char * objname) {
498#if defined(ROAR_HAVE_LIBDNET) && defined(_CAN_OPERATE)
499 struct sockaddr_dn * dn;
500
501 if ( def == NULL )
502  return -1;
503
504 if ( object < 1 && objname == NULL )
505  return -1;
506
507 if ( object == -1 )
508  object = roar_vio_socket_get_port(objname, AF_DECnet, SOCK_STREAM);
509
510 if ( object == -1 ) {
511  if ( objname == NULL ) {
512   return -1;
513  } else {
514   object = 0;
515  }
516 }
517
518 if ( roar_vio_socket_init_socket_def(def, AF_DECnet, SOCK_STREAM) == -1 )
519  return -1;
520
521 def->d.socket.host = node;
522 dn                 = &(def->d.socket.sa.dn);
523 dn->sdn_flags      = 0;
524 dn->sdn_objnum     = object;
525 dn->sdn_nodeaddrl  = 2;
526
527 if ( objname == NULL ) {
528  dn->sdn_objnamel   = 0;
529 } else {
530  dn->sdn_objnamel   = strlen(objname);
531  if ( dn->sdn_objnamel > DN_MAXOBJL )
532   dn->sdn_objnamel  = DN_MAXOBJL;
533
534  memcpy(&(dn->sdn_objname), objname, dn->sdn_objnamel);
535 }
536
537 return 0;
538#else
539 return -1;
540#endif
541}
542
543
544// AF_INET:
545int     roar_vio_socket_init_inet4host_def(struct roar_vio_defaults * def) {
546#if defined(ROAR_HAVE_IPV4) && defined(_CAN_OPERATE)
547 struct hostent     * he;
548 char               * ed, * pd;
549
550 if ( def == NULL )
551  return -1;
552
553 if ( def->d.socket.host == NULL )
554  return -1;
555
556 if ( (ed = strstr(def->d.socket.host, "/")) != NULL )
557  *ed = 0;
558
559 if ( (pd = strstr(def->d.socket.host, ":")) != NULL )
560  *pd = 0;
561
562 if ( (he = gethostbyname(def->d.socket.host)) == NULL ) {
563  ROAR_ERR("roar_vio_socket_init_inet4host_def(*): Can\'t resolve host name '%s'",
564                    def->d.socket.host);
565  if ( ed != NULL ) *ed = '/';
566  return -1;
567 }
568
569 if ( pd != NULL ) *pd = ':';
570
571 if ( ed != NULL ) *ed = '/';
572
573 memcpy((struct in_addr *)&def->d.socket.sa.in.sin_addr, he->h_addr, sizeof(struct in_addr));
574
575 return 0;
576#else
577 return -1;
578#endif
579}
580
581int     roar_vio_socket_init_inet4_def    (struct roar_vio_defaults * def, char * host, int port, int type) {
582#if defined(ROAR_HAVE_IPV4) && defined(_CAN_OPERATE)
583 if ( roar_vio_socket_init_socket_def(def, AF_INET, type) == -1 )
584  return -1;
585
586 def->d.socket.host             = host;
587
588 def->d.socket.sa.in.sin_port   = ROAR_HOST2NET16(port);
589
590 return 0;
591#else
592 return -1;
593#endif
594}
595
596int     roar_vio_socket_init_tcp4_def     (struct roar_vio_defaults * def, char * host, int port) {
597 return roar_vio_socket_init_inet4_def(def, host, port, SOCK_STREAM);
598}
599
600int     roar_vio_socket_init_udp4_def     (struct roar_vio_defaults * def, char * host, int port) {
601 return roar_vio_socket_init_inet4_def(def, host, port, SOCK_DGRAM);
602}
603
604
605// AF_INET6:
606int     roar_vio_socket_init_inet6host_def(struct roar_vio_defaults * def);
607int     roar_vio_socket_init_inet6_def    (struct roar_vio_defaults * def, char * host, int port, int type) {
608 return -1;
609}
610
611int     roar_vio_socket_init_tcp6_def     (struct roar_vio_defaults * def, char * host, int port) {
612 return roar_vio_socket_init_inet6_def(def, host, port, SOCK_STREAM);
613}
614
615int     roar_vio_socket_init_udp6_def     (struct roar_vio_defaults * def, char * host, int port) {
616 return roar_vio_socket_init_inet6_def(def, host, port, SOCK_DGRAM);
617}
618
619//ll
Note: See TracBrowser for help on using the repository browser.