source: roaraudio/libroar/vio_socket.c @ 1349:9582e89c7130

Last change on this file since 1349:9582e89c7130 was 1349:9582e89c7130, checked in by phi, 15 years ago

changed a lot, got gopher working :), need cleanup

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