source: roaraudio/libroar/vio_socket.c @ 5396:e2e5f307ef8b

Last change on this file since 5396:e2e5f307ef8b was 5396:e2e5f307ef8b, checked in by phi, 12 years ago

better support for ROAR_VIOF_NONBLOCK

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