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
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, char * opts) {
42#ifdef _CAN_OPERATE
43 int       fh  = -1;
44 socklen_t len =  0;
45 int       listening  = 0;
46 int       one_client = 0;
47 int       client;
48
49 if ( calls == NULL || def == NULL )
50  return -1;
51
52 if ( opts != NULL ) {
53  if ( strstr(opts, "listen") != NULL ) {
54   listening  = 1;
55   one_client = 1;
56  }
57 }
58
59 if ( def->type != ROAR_VIO_DEF_TYPE_SOCKET )
60  return -1;
61
62 switch (def->d.socket.domain) {
63#ifdef ROAR_HAVE_IPV4
64  case AF_INET:
65    len = sizeof(struct sockaddr_in);
66
67    if ( roar_vio_socket_init_inet4host_def(def) == -1 )
68     return -1;
69
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;
81#endif
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
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    }
112   break;
113#endif
114#ifdef ROAR_HAVE_IPV6
115  case AF_INET6:
116    len = sizeof(struct sockaddr_in6);
117
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
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  }
170 }
171
172 if ( roar_vio_open_fh_socket(calls, fh) == -1 ) {
173  close(fh);
174  return -1;
175 }
176
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:
182    ROAR_SHUTDOWN(fh, SHUT_WR);
183   break;
184  case O_WRONLY:
185    ROAR_SHUTDOWN(fh, SHUT_RD);
186   break;
187 }
188
189 return 0;
190#else
191 return -1;
192#endif
193}
194
195int     roar_vio_socket_init_socket_def   (struct roar_vio_defaults * def, int domain, int type) {
196#ifdef _CAN_OPERATE
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;
212#else
213 return -1;
214#endif
215}
216
217int     roar_vio_socket_init_dstr_def     (struct roar_vio_defaults * def, char * dstr, int hint, int type,
218                                           struct roar_vio_defaults * odef) {
219#ifdef _CAN_OPERATE
220 char * host;
221#if defined(ROAR_HAVE_IPV4) || defined(ROAR_HAVE_IPV6)
222 int    port;
223#endif
224#if defined(ROAR_HAVE_IPV4)
225 int ret;
226#endif
227
228 if ( def == NULL )
229  return -1;
230
231 if ( dstr == NULL && odef == NULL )
232  return -1;
233
234 if ( dstr == NULL )
235  dstr = "";
236
237 ROAR_DBG("roar_vio_socket_init_dstr_def(def=%p, dstr='%s', hint=%i, type=%i, odef=%p) = ?", def, dstr, hint, type, odef);
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
257#ifdef ROAR_HAVE_IPV4
258  } else if ( strstr(dstr, ":") != NULL ) { // host:port
259   hint = AF_INET;
260#endif
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
266  ROAR_DBG("roar_vio_socket_init_dstr_def(*): hint=-1 && odef!=NULL");
267  if ( odef->type == ROAR_VIO_DEF_TYPE_SOCKET ) {
268   ROAR_DBG("roar_vio_socket_init_dstr_def(*): hint=-1 && odef!=NULL, using hint from odef");
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
289 ROAR_DBG("roar_vio_socket_init_dstr_def(*) = ?");
290
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
298  if ( def != odef )
299   memcpy(def, odef, sizeof(struct roar_vio_defaults));
300
301  return 0;
302 }
303
304 for (; *dstr == '/'; dstr++);
305
306 ROAR_DBG("roar_vio_socket_init_dstr_def(*) = ?");
307
308 switch (hint) {
309#ifdef ROAR_HAVE_IPV4
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
319     ret = roar_vio_socket_init_inet4_def(def, host, port, type);
320
321     *(dstr-1) = ':';
322
323     return ret;
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;
331#endif
332#ifdef ROAR_HAVE_LIBDNET
333  case AF_DECnet:
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    }
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;
368#else
369 return -1;
370#endif
371}
372
373#ifdef _CAN_OPERATE
374int     roar_vio_socket_conv_def          (struct roar_vio_defaults * def, int domain) {
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 {
386   if ( def->type == ROAR_VIO_DEF_TYPE_FILE )
387    return roar_vio_socket_init_unix_def(def, def->d.file);
388
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
400 // we sould add support to convert IPv4 <-> IPv6 here
401
402 return -1;
403}
404
405int     roar_vio_socket_get_port          (char * service, int domain, int type) {
406#ifdef ROAR_HAVE_GETSERVBYNAME
407 struct servent * serv  = NULL;
408#endif
409 char           * proto = NULL;
410 int              port;
411 char           * ts;
412
413 if ( service == NULL || domain == -1 || type == -1 )
414  return -1;
415
416 if ( (ts = strstr(service, "/")) != NULL )
417  *ts = 0;
418
419 if ( sscanf(service, "%i", &port) == 1 )
420  return port;
421
422 if ( ts != NULL )
423  *ts = '/';
424
425 switch (domain) {
426#ifdef ROAR_HAVE_IPV6
427  case AF_INET6:
428#endif
429#ifdef ROAR_HAVE_IPV4
430  case AF_INET:
431#endif
432#if defined(ROAR_HAVE_IPV6) || defined(ROAR_HAVE_IPV4)
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;
440#endif
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
457#ifdef ROAR_HAVE_GETSERVBYNAME
458 if ( ts != NULL )
459  *ts = 0;
460
461 if ( (serv = getservbyname(service, proto)) == NULL ) {
462  ROAR_ERR("roar_vio_socket_get_port(*): Unknown service: %s/%s: %s", service, proto, strerror(errno));
463
464  if ( ts != NULL )
465   *ts = '/';
466
467  return -1;
468 }
469
470 if ( ts != NULL )
471  *ts = '/';
472
473 return ROAR_NET2HOST16(serv->s_port);
474#endif
475
476 return -1;
477}
478#endif
479
480// AF_UNIX:
481int     roar_vio_socket_init_unix_def     (struct roar_vio_defaults * def, char * path) {
482#if defined(ROAR_HAVE_UNIX) && defined(_CAN_OPERATE)
483 if ( def == NULL || path == NULL )
484  return -1;
485
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;
492#else
493 return -1;
494#endif
495}
496
497// AF_DECnet:
498int     roar_vio_socket_init_decnetnode_def(struct roar_vio_defaults * def) {
499#if defined(ROAR_HAVE_LIBDNET) && defined(_CAN_OPERATE)
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;
525#else
526 return -1;
527#endif
528}
529
530int     roar_vio_socket_init_decnet_def   (struct roar_vio_defaults * def, char * node, int object, char * objname) {
531#if defined(ROAR_HAVE_LIBDNET) && defined(_CAN_OPERATE)
532 struct sockaddr_dn * dn;
533
534 if ( def == NULL )
535  return -1;
536
537 if ( object < 1 && objname == NULL )
538  return -1;
539
540 if ( object == -1 )
541  object = roar_vio_socket_get_port(objname, AF_DECnet, SOCK_STREAM);
542
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 )
552  return -1;
553
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;
571#else
572 return -1;
573#endif
574}
575
576
577// AF_INET:
578int     roar_vio_socket_init_inet4host_def(struct roar_vio_defaults * def) {
579#if defined(ROAR_HAVE_IPV4) && defined(_CAN_OPERATE)
580 struct hostent     * he;
581 char               * ed, * pd;
582
583 if ( def == NULL )
584  return -1;
585
586 if ( def->d.socket.host == NULL )
587  return -1;
588
589 if ( (ed = strstr(def->d.socket.host, "/")) != NULL )
590  *ed = 0;
591
592 if ( (pd = strstr(def->d.socket.host, ":")) != NULL )
593  *pd = 0;
594
595 if ( (he = gethostbyname(def->d.socket.host)) == NULL ) {
596  ROAR_ERR("roar_vio_socket_init_inet4host_def(*): Can\'t resolve host name '%s'",
597                    def->d.socket.host);
598  if ( ed != NULL ) *ed = '/';
599  return -1;
600 }
601
602 if ( pd != NULL ) *pd = ':';
603
604 if ( ed != NULL ) *ed = '/';
605
606 memcpy((struct in_addr *)&def->d.socket.sa.in.sin_addr, he->h_addr, sizeof(struct in_addr));
607
608 return 0;
609#else
610 return -1;
611#endif
612}
613
614int     roar_vio_socket_init_inet4_def    (struct roar_vio_defaults * def, char * host, int port, int type) {
615#if defined(ROAR_HAVE_IPV4) && defined(_CAN_OPERATE)
616 if ( roar_vio_socket_init_socket_def(def, AF_INET, type) == -1 )
617  return -1;
618
619 def->d.socket.host             = host;
620
621 def->d.socket.sa.in.sin_port   = ROAR_HOST2NET16(port);
622
623 return 0;
624#else
625 return -1;
626#endif
627}
628
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}
651
652//ll
Note: See TracBrowser for help on using the repository browser.