/* ADDRS is a list of socket addresses; if 'from' address type matches one of them, it is used to store the information so that we can avoid allocation. If no addresses match the incoming type, and ADDRS is a complete list, the information of 'from' is discarded. If no addresses match the incoming type, and the last cdr of ADDRS is #t (this case includes ADDRS == #t), a new sockaddr is allocated and returned. */ ScmObj Scm_SocketRecvFromX(ScmSocket *sock, ScmUVector *buf, ScmObj addrs, int flags) { int r; u_int size; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); ScmObj addr = SCM_FALSE; CLOSE_CHECK(sock->fd, "recv from", sock); char *z = get_message_buffer(buf, &size); SCM_SYSCALL(r, recvfrom(sock->fd, z, size, flags, (struct sockaddr*)&from, &fromlen)); if (r < 0) { Scm_SysError("recvfrom(2) failed"); } ScmObj cp; SCM_FOR_EACH(cp, addrs) { ScmObj a = SCM_CAR(cp); if (Scm_SockAddrP(a)) { if (SCM_SOCKADDR_FAMILY(a) == from.ss_family) { memcpy(&SCM_SOCKADDR(a)->addr, &from, SCM_SOCKADDR(a)->addrlen); addr = a; break; } } }
ScmObj Scm_SocketSendTo(ScmSocket *sock, ScmObj msg, ScmSockAddr *to, int flags) { int r; u_int size; CLOSE_CHECK(sock->fd, "send to", sock); const char *cmsg = get_message_body(msg, &size); SCM_SYSCALL(r, sendto(sock->fd, cmsg, size, flags, &SCM_SOCKADDR(to)->addr, SCM_SOCKADDR(to)->addrlen)); if (r < 0) Scm_SysError("sendto(2) failed"); return SCM_MAKE_INT(r); }
ScmObj Scm_SocketAccept(ScmSocket *sock) { Socket newfd; struct sockaddr_storage addrbuf; socklen_t addrlen = sizeof(addrbuf); ScmSocket *newsock; ScmClass *addrClass = Scm_ClassOf(SCM_OBJ(sock->address)); CLOSE_CHECK(sock->fd, "accept from", sock); SCM_SYSCALL(newfd, accept(sock->fd, (struct sockaddr*)&addrbuf, &addrlen)); if (SOCKET_INVALID(newfd)) { if (errno == EAGAIN) { return SCM_FALSE; } else { Scm_SysError("accept(2) failed"); } } newsock = make_socket(newfd, sock->type); newsock->address = SCM_SOCKADDR(Scm_MakeSockAddr(addrClass, (struct sockaddr*)&addrbuf, addrlen)); newsock->status = SCM_SOCKET_STATUS_CONNECTED; return SCM_OBJ(newsock); }
ScmObj Scm_SocketBind(ScmSocket *sock, ScmSockAddr *addr) { int r; CLOSE_CHECK(sock->fd, "bind", sock); SCM_SYSCALL(r, bind(sock->fd, &addr->addr, addr->addrlen)); if (r < 0) { Scm_SysError("bind failed to %S", addr); } /* The system may assign different address than <addr>, especially when <addr> contains some 'wild card' (e.g. port=0). We call getsockname to obtain the exact address. Patch provided by ODA Hideo */ ScmSockAddr *naddr = SCM_SOCKADDR( Scm_MakeSockAddr(SCM_CLASS_OF(addr), &addr->addr, addr->addrlen)); SCM_SYSCALL(r, getsockname(sock->fd, &naddr->addr, &naddr->addrlen)); if (r < 0) { Scm_SysError("getsockname failed to %S", addr); } sock->address = naddr; sock->status = SCM_SOCKET_STATUS_BOUND; return SCM_OBJ(sock); }
void sockaddr_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx) { Scm_Printf(port, "#<sockaddr %S %S>", Scm_SockAddrFamily(SCM_SOCKADDR(obj)), Scm_SockAddrName(SCM_SOCKADDR(obj))); }
ScmClass *Scm_SockAddrCPL[] = { SCM_CLASS_STATIC_PTR(Scm_SockAddrClass), SCM_CLASS_STATIC_PTR(Scm_TopClass), NULL }; SCM_DEFINE_BUILTIN_CLASS(Scm_SockAddrClass, sockaddr_print, NULL, NULL, sockaddr_allocate, NULL); void sockaddr_print(ScmObj obj, ScmPort *port, ScmWriteContext *ctx SCM_UNUSED) { Scm_Printf(port, "#<sockaddr %S %S>", Scm_SockAddrFamily(SCM_SOCKADDR(obj)), Scm_SockAddrName(SCM_SOCKADDR(obj))); } int Scm_SockAddrP(ScmObj obj) { return Scm_SubtypeP(Scm_ClassOf(obj), SCM_CLASS_SOCKADDR); } /* C interface of sockaddr-name and sockaddr-family */ ScmObj Scm_SockAddrName(ScmSockAddr *addr) { return Scm_ApplyRec(SCM_OBJ(&Scm_GenericSockAddrName), SCM_LIST1(SCM_OBJ(addr))); }