source: roaraudio/libroar/vio_socket.c @ 6052:d48765b2475e

Last change on this file since 6052:d48765b2475e was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

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