source: roaraudio/libroar/vio_socket.c @ 1461:c941ba8699b9

Last change on this file since 1461:c941ba8699b9 was 1461:c941ba8699b9, checked in by phi, 15 years ago

test for ROAR_HAVE_GETSERVBYNAME

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