source: roaraudio/libroar/vio_socket.c @ 3517:1a3218a3fc5b

Last change on this file since 3517:1a3218a3fc5b was 3517:1a3218a3fc5b, checked in by phi, 14 years ago

updated license headers, FSF moved office

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