source: roaraudio/libroar/vio_socket.c @ 1354:fb6e3f4bbcf6

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

got decnet:// working

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