source: roaraudio/libroar/vio_socket.c @ 3293:f8b44412b38d

Last change on this file since 3293:f8b44412b38d was 3293:f8b44412b38d, checked in by phi, 14 years ago

support for listen sockets

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