root/ext/net/net.c

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

DEFINITIONS

This source file includes following definitions.
  1. socket_finalize
  2. socket_print
  3. make_socket
  4. Scm_MakeSocket
  5. Scm_SocketShutdown
  6. Scm_SocketClose
  7. Scm_SocketInputPort
  8. Scm_SocketOutputPort
  9. Scm_SocketBind
  10. Scm_SocketListen
  11. Scm_SocketAccept
  12. Scm_SocketConnect
  13. Scm_SocketGetSockName
  14. Scm_SocketGetPeerName
  15. Scm_SocketSend
  16. Scm_SocketSendTo
  17. Scm_SocketRecv
  18. Scm_SocketRecvFrom
  19. Scm_SocketSetOpt
  20. Scm_SocketGetOpt
  21. inet_aton
  22. Scm_Init_libnet

   1 /*
   2  * net.c - network interface
   3  *
   4  *   Copyright (c) 2000-2004 Shiro Kawai, All rights reserved.
   5  * 
   6  *   Redistribution and use in source and binary forms, with or without
   7  *   modification, are permitted provided that the following conditions
   8  *   are met:
   9  * 
  10  *   1. Redistributions of source code must retain the above copyright
  11  *      notice, this list of conditions and the following disclaimer.
  12  *
  13  *   2. Redistributions in binary form must reproduce the above copyright
  14  *      notice, this list of conditions and the following disclaimer in the
  15  *      documentation and/or other materials provided with the distribution.
  16  *
  17  *   3. Neither the name of the authors nor the names of its contributors
  18  *      may be used to endorse or promote products derived from this
  19  *      software without specific prior written permission.
  20  *
  21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  *
  33  *  $Id: net.c,v 1.41 2005/10/13 08:14:13 shirok Exp $
  34  */
  35 
  36 #include "gauche/net.h"
  37 #include <unistd.h>
  38 #include <fcntl.h>
  39 #include <gauche/extend.h>
  40 
  41 /*==================================================================
  42  * Socket
  43  */
  44 
  45 static void socket_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx);
  46 
  47 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_SocketClass, socket_print);
  48 
  49 static void socket_finalize(ScmObj obj, void *data)
  50 {
  51     ScmSocket *sock = (ScmSocket*)obj;
  52     /* NB: at this point, sock->inPort and sock->outPort may already
  53        be GC-ed and finalized, so we don't flush them here. */
  54     if (!(SOCKET_CLOSED(sock->fd))) {
  55         closeSocket(sock->fd);
  56         sock->fd = INVALID_SOCKET;
  57         sock->status = SCM_SOCKET_STATUS_CLOSED;
  58     }
  59 }
  60 
  61 static void socket_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx)
  62 {
  63     ScmSocket *sock = SCM_SOCKET(obj);
  64     Scm_Printf(port, "#<socket");
  65     switch (sock->status) {
  66     case SCM_SOCKET_STATUS_NONE:
  67         break;
  68     case SCM_SOCKET_STATUS_BOUND:
  69         Scm_Printf(port, " (bound %S)", Scm_SockAddrName(sock->address));
  70         break;
  71     case SCM_SOCKET_STATUS_LISTENING:
  72         Scm_Printf(port, " (listen %S)", Scm_SockAddrName(sock->address));
  73         break;
  74     case SCM_SOCKET_STATUS_CONNECTED:
  75         Scm_Printf(port, " (connect %S)", Scm_SockAddrName(sock->address));
  76         break;
  77     case SCM_SOCKET_STATUS_SHUTDOWN:
  78         Scm_Printf(port, " (shutdown)");
  79         break;
  80     case SCM_SOCKET_STATUS_CLOSED:
  81         Scm_Printf(port, " (closed)");
  82         break;
  83     default:
  84         Scm_Printf(port, " (unknown status)");
  85         break;
  86     }
  87     Scm_Printf(port, ">");
  88 }
  89 
  90 ScmSocket *make_socket(Socket fd, int type)
  91 {
  92     ScmSocket *s = SCM_NEW(ScmSocket);
  93     SCM_SET_CLASS(s, SCM_CLASS_SOCKET);
  94     s->fd = fd;
  95     s->status = SCM_SOCKET_STATUS_NONE;
  96     s->inPort = s->outPort = NULL;
  97     s->address = NULL;
  98     s->name = NULL;
  99     s->type = type;
 100     Scm_RegisterFinalizer(SCM_OBJ(s), socket_finalize, NULL);
 101     return s;
 102 }
 103 
 104 ScmObj Scm_MakeSocket(int domain, int type, int protocol)
 105 {
 106     int sock; 
 107     SCM_SYSCALL(sock, socket(domain, type, protocol));
 108     if (SOCKET_INVALID(sock)) Scm_SysError("couldn't create socket");
 109     return SCM_OBJ(make_socket(sock, type));
 110 }
 111 
 112 ScmObj Scm_SocketShutdown(ScmSocket *s, int how)
 113 {
 114     int r;
 115     if (s->status != SCM_SOCKET_STATUS_CONNECTED) {
 116         return SCM_FALSE;
 117     }
 118     SCM_SYSCALL(r, shutdown(s->fd, how));
 119     if (r < 0) {
 120         Scm_SysError("socket shutdown failed for %S", SCM_OBJ(s));
 121     }
 122     s->status = SCM_SOCKET_STATUS_SHUTDOWN;
 123     return SCM_TRUE;
 124 }
 125 
 126 ScmObj Scm_SocketClose(ScmSocket *s)
 127 {
 128     if (s->status == SCM_SOCKET_STATUS_CLOSED) {
 129         return SCM_FALSE;
 130     }
 131     /* We don't shutdown the connection; forked process may have
 132        reference to the same socket. */
 133     if (s->inPort)  Scm_ClosePort(s->inPort);  /* ignore errors */
 134     if (s->outPort) Scm_ClosePort(s->outPort); /* ignore errors */
 135     closeSocket(s->fd);
 136     s->fd = INVALID_SOCKET;
 137     s->status = SCM_SOCKET_STATUS_CLOSED;
 138     return SCM_TRUE;
 139 }
 140 
 141 ScmObj Scm_SocketInputPort(ScmSocket *sock, int buffering)
 142 {
 143     if (sock->inPort == NULL) {
 144         ScmObj sockname;
 145         int infd;
 146         if (sock->type != SOCK_DGRAM &&
 147             sock->status < SCM_SOCKET_STATUS_CONNECTED) {
 148             Scm_Error("attempt to obtain an input port from unconnected socket: %S",
 149                       SCM_OBJ(sock));
 150         }
 151 #ifndef __MINGW32__
 152         infd = sock->fd;
 153 #else  /*__MINGW32__*/
 154         infd = _open_osfhandle(sock->fd, O_RDONLY);
 155 #endif /*__MINGW32__*/
 156         /* NB: I keep the socket itself in the port name, in order to avoid
 157            the socket from GCed prematurely if application doesn't keep
 158            pointer to the socket. */
 159         sockname = SCM_LIST2(SCM_MAKE_STR("socket input"), SCM_OBJ(sock));
 160         sock->inPort = SCM_PORT(Scm_MakePortWithFd(sockname, SCM_PORT_INPUT,
 161                                                    infd, buffering,
 162                                                    FALSE));
 163     }
 164     return SCM_OBJ(sock->inPort);
 165 }
 166 
 167 ScmObj Scm_SocketOutputPort(ScmSocket *sock, int buffering)
 168 {
 169     if (sock->outPort == NULL) {
 170         ScmObj sockname;
 171         int outfd;
 172         if (sock->type != SOCK_DGRAM &&
 173             sock->status < SCM_SOCKET_STATUS_CONNECTED) {
 174             Scm_Error("attempt to obtain an output port from an unconnected socket: %S",
 175                       SCM_OBJ(sock));
 176         }
 177 #ifndef __MINGW32__
 178         outfd = sock->fd;
 179 #else  /*__MINGW32__*/
 180         outfd = _open_osfhandle(sock->fd, 0);
 181 #endif /*__MINGW32__*/
 182 
 183         /* NB: I keep the socket itself in the port name, in order to avoid
 184            the socket from GCed prematurely if application doesn't keep
 185            pointer to the socket. */
 186         sockname = SCM_LIST2(SCM_MAKE_STR("socket output"), SCM_OBJ(sock));
 187         sock->outPort = SCM_PORT(Scm_MakePortWithFd(sockname, SCM_PORT_OUTPUT,
 188                                                     outfd, buffering, FALSE));
 189     }
 190     return SCM_OBJ(sock->outPort);
 191 }
 192 
 193 /*==================================================================
 194  * Low-level library
 195  */
 196 
 197 ScmObj Scm_SocketBind(ScmSocket *sock, ScmSockAddr *addr)
 198 {
 199     ScmSockAddr *naddr;
 200     int r;
 201     
 202     if (SOCKET_CLOSED(sock->fd)) {
 203         Scm_Error("attempt to bind a closed socket: %S", sock);
 204     }
 205     SCM_SYSCALL(r, bind(sock->fd, &addr->addr, addr->addrlen));
 206     if (r < 0) {
 207         Scm_SysError("bind failed to %S", addr);
 208     }
 209     /* The system may assign different address than <addr>, especially when
 210        <addr> contains some 'wild card' (e.g. port=0).  We call getsockname
 211        to obtain the exact address.   Patch provided by ODA Hideo */
 212     naddr = SCM_SOCKADDR(Scm_MakeSockAddr(SCM_CLASS_OF(addr),
 213                                           &addr->addr, addr->addrlen));
 214     SCM_SYSCALL(r, getsockname(sock->fd, &naddr->addr, &naddr->addrlen));
 215     if (r < 0) {
 216         Scm_SysError("getsockname failed to %S", addr);
 217     }
 218     sock->address = naddr;
 219     sock->status = SCM_SOCKET_STATUS_BOUND;
 220     return SCM_OBJ(sock);
 221 }
 222 
 223 ScmObj Scm_SocketListen(ScmSocket *sock, int backlog)
 224 {
 225     int r;
 226     if (SOCKET_CLOSED(sock->fd)) {
 227         Scm_Error("attempt to listen a closed socket: %S", sock);
 228     }
 229     SCM_SYSCALL(r, listen(sock->fd, backlog));
 230     if (r < 0) {
 231         Scm_SysError("listen(2) failed");
 232     }
 233     sock->status = SCM_SOCKET_STATUS_LISTENING;
 234     return SCM_OBJ(sock);
 235 }
 236 
 237 ScmObj Scm_SocketAccept(ScmSocket *sock)
 238 {
 239     const char addrbuf[SCM_SOCKADDR_MAXLEN];
 240     int newfd;
 241     socklen_t addrlen = SCM_SOCKADDR_MAXLEN;
 242     ScmSocket *newsock;
 243     ScmClass *addrClass = Scm_ClassOf(SCM_OBJ(sock->address));
 244     
 245     if (SOCKET_CLOSED(sock->fd)) {
 246         Scm_Error("attempt to accept a closed socket: %S", sock);
 247     }
 248     SCM_SYSCALL(newfd, accept(sock->fd, (struct sockaddr *)addrbuf, &addrlen));
 249     if (SOCKET_INVALID(newfd)) {
 250         if (errno == EAGAIN) {
 251             return SCM_FALSE;
 252         } else {
 253             Scm_SysError("accept(2) failed");
 254         }
 255     }
 256     newsock = make_socket(newfd, sock->type);
 257     newsock->address =
 258         SCM_SOCKADDR(Scm_MakeSockAddr(addrClass,
 259                                       (struct sockaddr *)addrbuf,
 260                                       addrlen));
 261     newsock->status = SCM_SOCKET_STATUS_CONNECTED;
 262     return SCM_OBJ(newsock);
 263 }
 264 
 265 ScmObj Scm_SocketConnect(ScmSocket *sock, ScmSockAddr *addr)
 266 {
 267     int r;
 268     if (SOCKET_CLOSED(sock->fd)) {
 269         Scm_Error("attempt to connect a closed socket: %S", sock);
 270     }
 271     SCM_SYSCALL(r, connect(sock->fd, &addr->addr, addr->addrlen));
 272     if (r < 0) {
 273         Scm_SysError("connect failed to %S", addr);
 274     }
 275     sock->address = addr;
 276     sock->status = SCM_SOCKET_STATUS_CONNECTED;
 277     return SCM_OBJ(sock);
 278 }
 279 
 280 ScmObj Scm_SocketGetSockName(ScmSocket *sock)
 281 {
 282     const char addrbuf[SCM_SOCKADDR_MAXLEN];
 283     int r;
 284     socklen_t addrlen = SCM_SOCKADDR_MAXLEN;
 285 
 286     if (SOCKET_CLOSED(sock->fd)) {
 287         Scm_Error("attempt to get the name of a closed socket: %S", sock);
 288     }
 289     SCM_SYSCALL(r, getsockname(sock->fd, (struct sockaddr *)addrbuf, &addrlen));
 290     if (r < 0) {
 291         Scm_SysError("getsockname(2) failed");
 292     }
 293     return SCM_OBJ(Scm_MakeSockAddr(NULL, (struct sockaddr *)addrbuf, addrlen));
 294 }
 295 
 296 ScmObj Scm_SocketGetPeerName(ScmSocket *sock)
 297 {
 298     const char addrbuf[SCM_SOCKADDR_MAXLEN];
 299     int r;
 300     socklen_t addrlen = SCM_SOCKADDR_MAXLEN;
 301 
 302     if (SOCKET_CLOSED(sock->fd)) {
 303         Scm_Error("attempt to get the name of a closed socket: %S", sock);
 304     }
 305     SCM_SYSCALL(r, getpeername(sock->fd, (struct sockaddr *)addrbuf, &addrlen));
 306     if (r < 0) {
 307         Scm_SysError("getpeername(2) failed");
 308     }
 309     return SCM_OBJ(Scm_MakeSockAddr(NULL, (struct sockaddr *)addrbuf, addrlen));
 310 }
 311 
 312 ScmObj Scm_SocketSend(ScmSocket *sock, ScmString *msg, int flags)
 313 {
 314     int r; u_int size;
 315     const char *cmsg;
 316     if (SOCKET_CLOSED(sock->fd)) {
 317         Scm_Error("attempt to send to a closed socket: %S", sock);
 318     }
 319     cmsg = Scm_GetStringContent(msg, &size, NULL, NULL);
 320     SCM_SYSCALL(r, send(sock->fd, cmsg, size, flags));
 321     if (r < 0) {
 322         Scm_SysError("send(2) failed");
 323     }
 324     return SCM_MAKE_INT(r);
 325 }
 326 
 327 ScmObj Scm_SocketSendTo(ScmSocket *sock, ScmString *msg, ScmSockAddr *to,
 328                         int flags)
 329 {
 330     int r; u_int size;
 331     const char *cmsg;
 332     if (SOCKET_CLOSED(sock->fd)) {
 333         Scm_Error("attempt to send to a closed socket: %S", sock);
 334     }
 335     cmsg = Scm_GetStringContent(msg, &size, NULL, NULL);
 336     SCM_SYSCALL(r, sendto(sock->fd, cmsg, size, flags,
 337                           &SCM_SOCKADDR(to)->addr, SCM_SOCKADDR(to)->addrlen));
 338     if (r < 0) {
 339         Scm_SysError("sendto(2) failed");
 340     }
 341     return SCM_MAKE_INT(r);
 342 }
 343 
 344 ScmObj Scm_SocketRecv(ScmSocket *sock, int bytes, int flags)
 345 {
 346     int r;
 347     char *buf;
 348     if (SOCKET_CLOSED(sock->fd)) {
 349         Scm_Error("attempt to recv from a closed socket: %S", sock);
 350     }
 351     buf = SCM_NEW_ATOMIC2(char*, bytes);
 352     SCM_SYSCALL(r, recv(sock->fd, buf, bytes, flags));
 353     if (r < 0) {
 354         Scm_SysError("recv(2) failed");
 355     }
 356     return Scm_MakeString(buf, r, r, SCM_MAKSTR_INCOMPLETE);
 357 }
 358 
 359 ScmObj Scm_SocketRecvFrom(ScmSocket *sock, int bytes, int flags)
 360 {
 361     int r;
 362     char *buf;
 363     struct sockaddr from;
 364     socklen_t fromlen = sizeof(from);
 365     if (SOCKET_CLOSED(sock->fd)) {
 366         Scm_Error("attempt to recv from a closed socket: %S", sock);
 367     }
 368     buf = SCM_NEW_ATOMIC2(char*, bytes);
 369     SCM_SYSCALL(r, recvfrom(sock->fd, buf, bytes, flags, &from, &fromlen));
 370     if (r < 0) {
 371         Scm_SysError("recvfrom(2) failed");
 372     }
 373     return Scm_Values2(Scm_MakeString(buf, r, r, SCM_MAKSTR_INCOMPLETE),
 374                        Scm_MakeSockAddr(NULL, &from, fromlen));
 375 }
 376 
 377 /* Low-level setsockopt() and getsockopt() interface. */
 378 /* for getsockopt(), we need to know the size of the result.
 379    if rtype > 0, it is used as the size of result buffer and
 380    a string value is returned.  if rtype == 0, the result value
 381    assumed to be an integer. */
 382 
 383 ScmObj Scm_SocketSetOpt(ScmSocket *s, int level, int option, ScmObj value)
 384 {
 385     int r = 0;
 386     if (SOCKET_CLOSED(s->fd)) {
 387         Scm_Error("attempt to set a socket option of a closed socket: %S", s);
 388     }
 389     if (SCM_STRINGP(value)) {
 390         u_int size;
 391         const char *cvalue = Scm_GetStringContent(SCM_STRING(value), &size,
 392                                                   NULL, NULL);
 393         SCM_SYSCALL(r, setsockopt(s->fd, level, option, cvalue, size));
 394     } else if (SCM_INTP(value) || SCM_BIGNUMP(value)) {
 395         int v = Scm_GetInteger(value);
 396         SCM_SYSCALL(r, setsockopt(s->fd, level, option, &v, sizeof(int)));
 397     } else {
 398         Scm_Error("socket option must be a string or an integer: %S", value);
 399     }
 400     if (r < 0) Scm_SysError("setsockopt failed");
 401     return SCM_TRUE;
 402 }
 403 
 404 ScmObj Scm_SocketGetOpt(ScmSocket *s, int level, int option, int rsize)
 405 {
 406     int r = 0;
 407     socklen_t rrsize = rsize;
 408     if (SOCKET_CLOSED(s->fd)) {
 409         Scm_Error("attempt to get a socket option of a closed socket: %S", s);
 410     }
 411     if (rsize > 0) {
 412         char *buf = SCM_NEW_ATOMIC2(char *, rrsize);
 413         SCM_SYSCALL(r, getsockopt(s->fd, level, option, buf, &rrsize));
 414         if (r < 0) Scm_SysError("getsockopt failed");
 415         return Scm_MakeString(buf, rrsize, rrsize, SCM_MAKSTR_INCOMPLETE);
 416     } else {
 417         int val;
 418         rrsize = sizeof(int);
 419         SCM_SYSCALL(r, getsockopt(s->fd, level, option, &val, &rrsize));
 420         if (r < 0) Scm_SysError("getsockopt failed");
 421         return Scm_MakeInteger(val);
 422     }
 423 }
 424 
 425 /*==================================================================
 426  * Windows/MinGW compatibility layer
 427  */
 428 #ifdef __MINGW32__
 429 
 430 /* 
 431  * I should use WSAStringToAddress, but just for the time being...
 432  */
 433 int inet_aton(const char *cp, struct in_addr *inp)
 434 {
 435     unsigned long r = inet_addr(cp);
 436     if (r == (unsigned long)-1) {
 437         return 0;
 438     } else {
 439         inp->s_addr = r;
 440         return 1;
 441     }
 442 }
 443 
 444 /* winsock requires some obscure initialization */
 445 static WSADATA wsaData;
 446 
 447 #endif /*__MINGW32__*/
 448                           
 449 /*==================================================================
 450  * Initialization
 451  */
 452 
 453 extern void Scm_Init_NetAddr(ScmModule *mod);
 454 extern void Scm_Init_NetDB(ScmModule *mod);
 455 extern void Scm_Init_netlib(ScmModule *mod);
 456 extern void Scm_Init_netaux(void);
 457 
 458 void Scm_Init_libnet(void)
 459 {
 460     ScmModule *mod;
 461 
 462     SCM_INIT_EXTENSION(net);
 463     mod = SCM_FIND_MODULE("gauche.net", SCM_FIND_MODULE_CREATE);
 464 #ifdef __MINGW32__
 465     /* NB: I'm supposed to call WSACleanup when application shuts down,
 466        or resource leak would happen, according to the Windows document.
 467        It's just ridiculous---why can't OS itself clean up the dead process?
 468        Anyway, to behave politically correctly, I need a generic callback
 469        mechanism for Gauche core to call cleanup routines in Scm_Exit.
 470        For now, let us behave like a wild kid.
 471     */
 472     {
 473         int opt;
 474         int r = WSAStartup(MAKEWORD(2,2), &wsaData);
 475         if (r != 0) {
 476             SetLastError(r);
 477             Scm_SysError("WSAStartup failed");
 478         }
 479         /* windows voodoo to make _open_osfhandle magic work */
 480         opt = SO_SYNCHRONOUS_NONALERT;
 481         r = setsockopt(INVALID_SOCKET, SOL_SOCKET,
 482                        SO_OPENTYPE, (char*)&opt, sizeof(opt));
 483         if (r == SOCKET_ERROR) {
 484             Scm_SysError("winsock initialization failed");
 485         }
 486     }
 487 #endif /*__MINGW32__*/
 488     Scm_InitStaticClass(&Scm_SocketClass, "<socket>", mod, NULL, 0);
 489     Scm_Init_NetAddr(mod);
 490     Scm_Init_NetDB(mod);
 491     Scm_Init_netlib(mod);
 492     Scm_Init_netaux();
 493 }

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