source: roaraudio/libroar/vio_socket.c @ 5353:de96f27919bf

Last change on this file since 5353:de96f27919bf was 5253:a9d4cba9e8dc, checked in by phi, 12 years ago

improved situation on opening files with DSTR/old roar_vio_open_file()

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