root/ext/net/addr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sockaddr_print
  2. Scm_SockAddrP
  3. Scm_SockAddrName
  4. Scm_SockAddrFamily
  5. sockaddr_allocate
  6. Scm_MakeSockAddr
  7. sockaddr_un_allocate
  8. sockaddr_in_allocate
  9. sockaddr_in6_allocate
  10. Scm_Init_NetAddr

   1 /*
   2  * addr.c - socket address
   3  *
   4  *  Copyright(C) 2001-2004 by Shiro Kawai (shiro@acm.org)
   5  *
   6  *  Permission to use, copy, modify, distribute this software and
   7  *  accompanying documentation for any purpose is hereby granted,
   8  *  provided that existing copyright notices are retained in all
   9  *  copies and that this notice is included verbatim in all
  10  *  distributions.
  11  *  This software is provided as is, without express or implied
  12  *  warranty.  In no circumstances the author(s) shall be liable
  13  *  for any damages arising out of the use of this software.
  14  *
  15  *  $Id: addr.c,v 1.22 2005/10/13 08:14:13 shirok Exp $
  16  */
  17 
  18 #include "gauche/net.h"
  19 #include <string.h>
  20 
  21 static ScmObj key_path = SCM_FALSE;
  22 static ScmObj key_host = SCM_FALSE;
  23 static ScmObj key_port = SCM_FALSE;
  24 static ScmObj key_any = SCM_FALSE;
  25 static ScmObj key_broadcast = SCM_FALSE;
  26 static ScmObj key_loopback = SCM_FALSE;
  27 
  28 /*==================================================================
  29  * Generic Socket Address
  30  */
  31 
  32 static void sockaddr_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx);
  33 static ScmObj sockaddr_allocate(ScmClass *, ScmObj);
  34 
  35 ScmClass *Scm_SockAddrCPL[] = {
  36     SCM_CLASS_STATIC_PTR(Scm_SockAddrClass),
  37     SCM_CLASS_STATIC_PTR(Scm_TopClass),
  38     NULL
  39 };
  40 
  41 SCM_DEFINE_BUILTIN_CLASS(Scm_SockAddrClass, sockaddr_print,
  42                          NULL, NULL, sockaddr_allocate,
  43                          NULL);
  44 
  45 void sockaddr_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx)
  46 {
  47     Scm_Printf(port, "#<sockaddr %S %S>",
  48                Scm_SockAddrFamily(SCM_SOCKADDR(obj)),
  49                Scm_SockAddrName(SCM_SOCKADDR(obj)));
  50 }
  51 
  52 int Scm_SockAddrP(ScmObj obj)
  53 {
  54     return Scm_SubtypeP(Scm_ClassOf(obj), SCM_CLASS_SOCKADDR);
  55 }
  56 
  57 /* C interface of sockaddr-name and sockaddr-family */
  58 ScmObj Scm_SockAddrName(ScmSockAddr *addr)
  59 {
  60     return Scm_Apply(SCM_OBJ(&Scm_GenericSockAddrName),
  61                      SCM_LIST1(SCM_OBJ(addr)));
  62 }
  63 
  64 ScmObj Scm_SockAddrFamily(ScmSockAddr *addr)
  65 {
  66     return Scm_Apply(SCM_OBJ(&Scm_GenericSockAddrFamily),
  67                      SCM_LIST1(SCM_OBJ(addr)));
  68 }
  69 
  70 /* Fallback of allocation method */
  71 static ScmObj sockaddr_allocate(ScmClass *klass, ScmObj initargs)
  72 {
  73     Scm_Error("you can't directly instantiate the abstract class <sockaddr>");
  74     return SCM_UNDEFINED;       /* dummy */
  75 }
  76 
  77 /* creates sockaddr from struct sockaddr. */
  78 ScmObj Scm_MakeSockAddr(ScmClass *klass, struct sockaddr *saddr, int len)
  79 {
  80     ScmSockAddr *addr;
  81     addr = SCM_NEW2(ScmSockAddr*,
  82                     sizeof(ScmSockAddr) - sizeof(struct sockaddr) + len);
  83     if (klass == NULL) {
  84         switch (saddr->sa_family) {
  85         case AF_UNIX:
  86             klass = SCM_CLASS_SOCKADDR_UN;
  87             break;
  88         case AF_INET:
  89             klass = SCM_CLASS_SOCKADDR_IN;
  90             break;
  91 #ifdef HAVE_IPV6
  92         case AF_INET6:
  93             klass = SCM_CLASS_SOCKADDR_IN6;
  94             break;
  95 #endif
  96         default:
  97             Scm_Error("unknown address type (%d)", saddr->sa_family);
  98             break;
  99         }
 100     }
 101     SCM_SET_CLASS(addr, klass);
 102     addr->addrlen = len;
 103     memset(&addr->addr, 0, len);
 104     memcpy(&addr->addr, saddr, len);
 105     return SCM_OBJ(addr);
 106 }
 107 
 108 /*==================================================================
 109  * Unix domain socket
 110  */
 111 
 112 #define UNIX_ADDRESS_PATH_MAX  108
 113 static ScmObj sockaddr_un_allocate(ScmClass *klass, ScmObj initargs);
 114 
 115 SCM_DEFINE_BUILTIN_CLASS(Scm_SockAddrUnClass, sockaddr_print,
 116                          NULL, NULL, sockaddr_un_allocate, Scm_SockAddrCPL);
 117 
 118 static ScmObj sockaddr_un_allocate(ScmClass *klass, ScmObj initargs)
 119 {
 120     ScmObj path = Scm_GetKeyword(key_path, initargs, SCM_FALSE);
 121     ScmSockAddrUn *addr;
 122     
 123     if (!SCM_FALSEP(path) && !SCM_STRINGP(path)) {
 124         Scm_Error(":path parameter must be a string, but got %S", path);
 125     }
 126     addr = SCM_NEW(ScmSockAddrUn);
 127     SCM_SET_CLASS(addr, &Scm_SockAddrUnClass);
 128     memset(&addr->addr, 0, sizeof(struct sockaddr_un));
 129     addr->addr.sun_family = AF_UNIX;
 130     if (SCM_STRINGP(path)) {
 131         int size;
 132         const char *cpath = Scm_GetStringContent(SCM_STRING(path), &size,
 133                                                  NULL, NULL);
 134         if (size >= UNIX_ADDRESS_PATH_MAX-1) {
 135             Scm_Error("path too long: %S", path);
 136         }
 137         memcpy(addr->addr.sun_path, cpath, size);
 138         addr->addr.sun_path[size] = '\0';
 139     }
 140     addr->addrlen = sizeof(struct sockaddr_un);
 141     return SCM_OBJ(addr);
 142 }
 143 
 144 /*==================================================================
 145  * Inet domain socket
 146  */
 147 
 148 static ScmObj sockaddr_in_allocate(ScmClass *klass, ScmObj initargs);
 149 
 150 SCM_DEFINE_BUILTIN_CLASS(Scm_SockAddrInClass, sockaddr_print,
 151                          NULL, NULL, sockaddr_in_allocate, Scm_SockAddrCPL);
 152 
 153 static ScmObj sockaddr_in_allocate(ScmClass *klass, ScmObj initargs)
 154 {
 155     ScmObj host = Scm_GetKeyword(key_host, initargs, key_any);
 156     ScmObj port = Scm_GetKeyword(key_port, initargs, SCM_MAKE_INT(0));
 157     ScmSockAddrIn *addr;
 158 
 159     if (!SCM_INTP(port)) {
 160         Scm_Error(":port parameter must be a small exact integer, but got %S",
 161                   port);
 162     }
 163     addr = SCM_NEW(ScmSockAddrIn);
 164     SCM_SET_CLASS(addr, &Scm_SockAddrInClass);
 165     memset(&addr->addr, 0, sizeof(struct sockaddr_in));
 166 #ifdef HAVE_SIN_LEN
 167     addr->addr.sin_len = sizeof(struct sockaddr_in);
 168 #endif
 169     addr->addr.sin_family = AF_INET;
 170     addr->addr.sin_port = htons(SCM_INT_VALUE(port));
 171     if (SCM_STRINGP(host)) {
 172         const char *hname = Scm_GetStringConst(SCM_STRING(host));
 173         /* First, see if host is dotted number notation. */
 174         if (inet_aton(hname, &addr->addr.sin_addr) == 0) {
 175             /* Now, we need to look up the host name.
 176                Call MT-safe Scm_GetHostByName */
 177             ScmObj ap, hent = Scm_GetHostByName(hname);
 178             if (!SCM_SYS_HOSTENT_P(hent)) {
 179                 Scm_Error("unknown host: %S", host);
 180             }
 181             ap = SCM_SYS_HOSTENT(hent)->addresses;
 182             if (SCM_NULLP(ap) || !SCM_STRINGP(SCM_CAR(ap))) {
 183                 Scm_Error("host have unknown address type: %S", host);
 184             }
 185             hname = Scm_GetStringConst(SCM_STRING(SCM_CAR(ap)));
 186             if (inet_aton(hname, &addr->addr.sin_addr) == 0) {
 187                 Scm_Error("host name lookup failure: %S", host);
 188             }
 189         }
 190     } else if (host == key_any) {
 191         addr->addr.sin_addr.s_addr = htonl(INADDR_ANY);
 192     } else if (host == key_broadcast) {
 193         addr->addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
 194     } else if (host == key_loopback) {
 195         addr->addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 196     } else {
 197         Scm_Error("bad :host parameter: %S", host);
 198     }
 199     addr->addrlen = sizeof(struct sockaddr_in);
 200     return SCM_OBJ(addr);
 201 }
 202 
 203 /*==================================================================
 204  * Inet6 domain socket
 205  */
 206 
 207 #ifdef HAVE_IPV6
 208 
 209 static ScmObj sockaddr_in6_allocate(ScmClass *klass, ScmObj initargs);
 210 
 211 SCM_DEFINE_BUILTIN_CLASS(Scm_SockAddrIn6Class, sockaddr_print,
 212                          NULL, NULL, sockaddr_in6_allocate, Scm_SockAddrCPL);
 213 
 214 static ScmObj sockaddr_in6_allocate(ScmClass *klass, ScmObj initargs)
 215 {
 216     ScmObj host = Scm_GetKeyword(key_host, initargs, key_any);
 217     ScmObj port = Scm_GetKeyword(key_port, initargs, SCM_MAKE_INT(0));
 218     ScmSockAddrIn6 *addr;
 219 
 220     if (!SCM_INTP(port)) {
 221         Scm_Error(":port parameter must be a small exact integer, but got %S",
 222                   port);
 223     }
 224     addr = SCM_NEW(ScmSockAddrIn6);
 225     SCM_SET_CLASS(addr, &Scm_SockAddrIn6Class);
 226     memset(&addr->addr, 0, sizeof(struct sockaddr_in6));
 227 #ifdef HAVE_SIN6_LEN
 228     addr->addr.sin6_len = sizeof(struct sockaddr_in6);
 229 #endif
 230     addr->addr.sin6_family = AF_INET6;
 231     addr->addr.sin6_port = htons(SCM_INT_VALUE(port));
 232     if (SCM_STRINGP(host)) {
 233         const char *hname = Scm_GetStringConst(SCM_STRING(host));
 234         struct addrinfo hints, *res;
 235         int r;
 236         memset(&hints, 0, sizeof(hints));
 237         hints.ai_family = AF_INET6;
 238         hints.ai_socktype = SOCK_STREAM;
 239         r = getaddrinfo(hname, NULL, &hints, &res);
 240         if (r) Scm_Error("getaddrinfo: %s", gai_strerror(r));
 241         addr->addr.sin6_addr = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr;
 242     } else if (host == key_any) {
 243         addr->addr.sin6_addr = in6addr_any;
 244     } else if (host == key_loopback) {
 245         addr->addr.sin6_addr = in6addr_loopback;
 246     } else {
 247         Scm_Error("bad :host parameter: %S", host);
 248     }
 249     addr->addrlen = sizeof(struct sockaddr_in6);
 250     return SCM_OBJ(addr);
 251 }
 252 
 253 #endif /* HAVE_IPV6 */
 254 
 255 /*==================================================================
 256  * Initialization stuff
 257  */
 258 
 259 void Scm_Init_NetAddr(ScmModule *mod)
 260 {
 261     key_path      = SCM_MAKE_KEYWORD("path");
 262     key_host      = SCM_MAKE_KEYWORD("host");
 263     key_port      = SCM_MAKE_KEYWORD("port");
 264     key_any       = SCM_MAKE_KEYWORD("any");
 265     key_broadcast = SCM_MAKE_KEYWORD("broadcast");
 266     key_loopback  = SCM_MAKE_KEYWORD("loopback");
 267 
 268     Scm_InitStaticClass(&Scm_SockAddrClass, "<sockaddr>", mod, NULL, 0);
 269     Scm_InitStaticClass(&Scm_SockAddrUnClass, "<sockaddr-un>", mod, NULL, 0);
 270     Scm_InitStaticClass(&Scm_SockAddrInClass, "<sockaddr-in>", mod, NULL, 0);
 271 #ifdef HAVE_IPV6
 272     Scm_InitStaticClass(&Scm_SockAddrIn6Class, "<sockaddr-in6>", mod, NULL, 0);
 273 #endif /* HAVE_IPV6 */
 274 }
 275 

/* [<][>][^][v][top][bottom][index][help] */