void Scm_FlushUnsafe(ScmPort *p) #endif { VMDECL; SHORTCUT(p, Scm_FlushUnsafe(p); return); WALKER_CHECK(p); LOCK(p); CLOSE_CHECK(p); switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: SAFE_CALL(p, bufport_flush(p, 0, TRUE)); UNLOCK(p); break; case SCM_PORT_OSTR: UNLOCK(p); break; case SCM_PORT_PROC: SAFE_CALL(p, p->src.vt.Flush(p)); UNLOCK(p); break; default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_OUTPUT, "bad port type for output: %S", p); } }
void Scm_PutbUnsafe(ScmByte b, ScmPort *p) #endif { VMDECL; SHORTCUT(p, Scm_PutbUnsafe(b, p); return); WALKER_CHECK(p); LOCK(p); CLOSE_CHECK(p); switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: if (p->src.buf.current >= p->src.buf.end) { SAFE_CALL(p, bufport_flush(p, (int)(p->src.buf.current - p->src.buf.buffer), FALSE)); } SCM_ASSERT(p->src.buf.current < p->src.buf.end); *p->src.buf.current++ = b; if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_NONE) { SAFE_CALL(p, bufport_flush(p, 1, FALSE)); } UNLOCK(p); break; case SCM_PORT_OSTR: SCM_DSTRING_PUTB(&p->src.ostr, b); UNLOCK(p); break; case SCM_PORT_PROC: SAFE_CALL(p, p->src.vt.Putb(b, p)); UNLOCK(p); break; default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_OUTPUT, "bad port type for output: %S", p); } }
/* 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_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_SocketSend(ScmSocket *sock, ScmObj msg, 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, send(sock->fd, cmsg, size, flags)); if (r < 0) Scm_SysError("send(2) failed"); return SCM_MAKE_INT(r); }
ScmObj Scm_SocketRecv(ScmSocket *sock, int bytes, int flags) { int r; CLOSE_CHECK(sock->fd, "recv from", sock); char *buf = SCM_NEW_ATOMIC2(char*, bytes); SCM_SYSCALL(r, recv(sock->fd, buf, bytes, flags)); if (r < 0) { Scm_SysError("recv(2) failed"); } return Scm_MakeString(buf, r, r, SCM_STRING_INCOMPLETE); }
ScmObj Scm_SocketListen(ScmSocket *sock, int backlog) { int r; CLOSE_CHECK(sock->fd, "listen to", sock); SCM_SYSCALL(r, listen(sock->fd, backlog)); if (r < 0) { Scm_SysError("listen(2) failed"); } sock->status = SCM_SOCKET_STATUS_LISTENING; return SCM_OBJ(sock); }
ScmObj Scm_SocketRecvX(ScmSocket *sock, ScmUVector *buf, int flags) { int r; u_int size; CLOSE_CHECK(sock->fd, "recv from", sock); char *z = get_message_buffer(buf, &size); SCM_SYSCALL(r, recv(sock->fd, z, size, flags)); if (r < 0) { Scm_SysError("recv(2) failed"); } return Scm_MakeInteger(r); }
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_SocketConnect(ScmSocket *sock, ScmSockAddr *addr) { int r; CLOSE_CHECK(sock->fd, "connect to", sock); SCM_SYSCALL(r, connect(sock->fd, &addr->addr, addr->addrlen)); if (r < 0) { Scm_SysError("connect failed to %S", addr); } sock->address = addr; sock->status = SCM_SOCKET_STATUS_CONNECTED; return SCM_OBJ(sock); }
ScmObj Scm_SocketGetPeerName(ScmSocket *sock) { int r; struct sockaddr_storage addrbuf; socklen_t addrlen = sizeof(addrbuf); CLOSE_CHECK(sock->fd, "get the name of", sock); SCM_SYSCALL(r, getpeername(sock->fd, (struct sockaddr*)&addrbuf, &addrlen)); if (r < 0) { Scm_SysError("getpeername(2) failed"); } return SCM_OBJ(Scm_MakeSockAddr(NULL, (struct sockaddr*)&addrbuf, addrlen)); }
int Scm_GetzUnsafe(char *buf, int buflen, ScmPort *p) #endif { VMDECL; SHORTCUT(p, return Scm_GetzUnsafe(buf, buflen, p)); LOCK(p); CLOSE_CHECK(p); if (p->scrcnt) { int r = GETZ_SCRATCH(buf, buflen, p); UNLOCK(p); return r; } if (p->ungotten != SCM_CHAR_INVALID) { p->scrcnt = SCM_CHAR_NBYTES(p->ungotten); SCM_CHAR_PUT(p->scratch, p->ungotten); p->ungotten = SCM_CHAR_INVALID; int r = GETZ_SCRATCH(buf, buflen, p); UNLOCK(p); return r; } switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: { int siz = 0; SAFE_CALL(p, siz = bufport_read(p, buf, buflen)); p->bytes += siz; UNLOCK(p); if (siz == 0) return EOF; else return siz; } case SCM_PORT_ISTR: { int r = GETZ_ISTR(p, buf, buflen); p->bytes += r; UNLOCK(p); return r; } case SCM_PORT_PROC: { int r = 0; SAFE_CALL(p, r = p->src.vt.Getz(buf, buflen, p)); p->bytes += r; UNLOCK(p); return r; } default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_INPUT, "bad port type for input: %S", p); } return -1; /* dummy */ }
ScmObj Scm_SocketRecvFrom(ScmSocket *sock, int bytes, int flags) { int r; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); CLOSE_CHECK(sock->fd, "recv from", sock); char *buf = SCM_NEW_ATOMIC2(char*, bytes); SCM_SYSCALL(r, recvfrom(sock->fd, buf, bytes, flags, (struct sockaddr*)&from, &fromlen)); if (r < 0) { Scm_SysError("recvfrom(2) failed"); } return Scm_Values2(Scm_MakeString(buf, r, r, SCM_STRING_INCOMPLETE), Scm_MakeSockAddr(NULL, (struct sockaddr*)&from, fromlen)); }
ScmObj Scm_SocketSendMsg(ScmSocket *sock, ScmObj msg, int flags) { #if !GAUCHE_WINDOWS int r; u_int size; CLOSE_CHECK(sock->fd, "send to", sock); const char *cmsg = get_message_body(msg, &size); SCM_SYSCALL(r, sendmsg(sock->fd, (struct msghdr*)cmsg, flags)); if (r < 0) Scm_SysError("sendmsg(2) failed"); return SCM_MAKE_INT(r); #else /*GAUCHE_WINDOWS*/ Scm_Error("sendmsg is not implemented on this platform."); return SCM_UNDEFINED; /* dummy */ #endif /*GAUCHE_WINDOWS*/ }
int Scm_GetbUnsafe(ScmPort *p) #endif { int b = 0; VMDECL; SHORTCUT(p, return Scm_GetbUnsafe(p)); LOCK(p); CLOSE_CHECK(p); /* check if there's "pushed back" stuff */ if (p->scrcnt) { b = getb_scratch(p); } else if (p->ungotten != SCM_CHAR_INVALID) { b = getb_ungotten(p); } else { switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: if (p->src.buf.current >= p->src.buf.end) { int r = 0; SAFE_CALL(p, r = bufport_fill(p, 1, FALSE)); if (r == 0) { UNLOCK(p); return EOF; } } b = (unsigned char)*p->src.buf.current++; break; case SCM_PORT_ISTR: if (p->src.istr.current >= p->src.istr.end) b = EOF; else b = (unsigned char)*p->src.istr.current++; break; case SCM_PORT_PROC: SAFE_CALL(p, b = p->src.vt.Getb(p)); break; default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_INPUT, "bad port type for input: %S", p); } p->bytes++; } UNLOCK(p); return b; }
void Scm_PutsUnsafe(ScmString *s, ScmPort *p) #endif { VMDECL; SHORTCUT(p, Scm_PutsUnsafe(s, p); return); WALKER_CHECK(p); LOCK(p); CLOSE_CHECK(p); switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: { u_int size; const char *ss = Scm_GetStringContent(s, &size, NULL, NULL); SAFE_CALL(p, bufport_write(p, ss, size)); if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_LINE) { const char *cp = p->src.buf.current; while (cp-- > p->src.buf.buffer) { if (*cp == '\n') { SAFE_CALL(p, bufport_flush(p, (int)(cp - p->src.buf.current), FALSE)); break; } } } else if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_NONE) { SAFE_CALL(p, bufport_flush(p, 0, TRUE)); } UNLOCK(p); break; } case SCM_PORT_OSTR: Scm_DStringAdd(&p->src.ostr, s); UNLOCK(p); break; case SCM_PORT_PROC: SAFE_CALL(p, p->src.vt.Puts(s, p)); UNLOCK(p); break; default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_OUTPUT, "bad port type for output: %S", p); } }
void Scm_PutcUnsafe(ScmChar c, ScmPort *p) #endif { VMDECL; SHORTCUT(p, Scm_PutcUnsafe(c, p); return); WALKER_CHECK(p); LOCK(p); CLOSE_CHECK(p); switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: { int nb = SCM_CHAR_NBYTES(c); if (p->src.buf.current+nb > p->src.buf.end) { SAFE_CALL(p, bufport_flush(p, (int)(p->src.buf.current - p->src.buf.buffer), FALSE)); } SCM_ASSERT(p->src.buf.current+nb <= p->src.buf.end); SCM_CHAR_PUT(p->src.buf.current, c); p->src.buf.current += nb; if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_LINE) { if (c == '\n') { SAFE_CALL(p, bufport_flush(p, nb, FALSE)); } } else if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_NONE) { SAFE_CALL(p, bufport_flush(p, nb, FALSE)); } UNLOCK(p); break; } case SCM_PORT_OSTR: SCM_DSTRING_PUTC(&p->src.ostr, c); UNLOCK(p); break; case SCM_PORT_PROC: SAFE_CALL(p, p->src.vt.Putc(c, p)); UNLOCK(p); break; default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_OUTPUT, "bad port type for output: %S", p); } }
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 Scm_PutzUnsafe(const char *s, int siz, ScmPort *p) #endif { VMDECL; SHORTCUT(p, Scm_PutzUnsafe(s, siz, p); return); WALKER_CHECK(p); LOCK(p); CLOSE_CHECK(p); if (siz < 0) siz = (int)strlen(s); switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: SAFE_CALL(p, bufport_write(p, s, siz)); if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_LINE) { const char *cp = p->src.buf.current; while (cp-- > p->src.buf.buffer) { if (*cp == '\n') { SAFE_CALL(p, bufport_flush(p, (int)(cp - p->src.buf.current), FALSE)); break; } } } else if (SCM_PORT_BUFFER_MODE(p) == SCM_PORT_BUFFER_NONE) { SAFE_CALL(p, bufport_flush(p, 0, TRUE)); } UNLOCK(p); break; case SCM_PORT_OSTR: Scm_DStringPutz(&p->src.ostr, s, siz); UNLOCK(p); break; case SCM_PORT_PROC: SAFE_CALL(p, p->src.vt.Putz(s, siz, p)); UNLOCK(p); break; default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_OUTPUT, "bad port type for output: %S", p); } }
int Scm_GetcUnsafe(ScmPort *p) #endif { VMDECL; SHORTCUT(p, return Scm_GetcUnsafe(p)); LOCK(p); CLOSE_CHECK(p); if (p->scrcnt > 0) { int r = GETC_SCRATCH(p); UNLOCK(p); return r; } if (p->ungotten != SCM_CHAR_INVALID) { int c = p->ungotten; p->ungotten = SCM_CHAR_INVALID; UNLOCK(p); return c; } switch (SCM_PORT_TYPE(p)) { case SCM_PORT_FILE: { int c = 0; if (p->src.buf.current >= p->src.buf.end) { int r = 0; SAFE_CALL(p, r = bufport_fill(p, 1, FALSE)); if (r == 0) { UNLOCK(p); return EOF; } } int first = (unsigned char)*p->src.buf.current++; int nb = SCM_CHAR_NFOLLOWS(first); p->bytes++; if (nb > 0) { if (p->src.buf.current + nb > p->src.buf.end) { /* The buffer doesn't have enough bytes to consist a char. move the incomplete char to the scratch buffer and try to fetch the rest of the char. */ int rest, filled = 0; p->scrcnt = (unsigned char)(p->src.buf.end - p->src.buf.current + 1); memcpy(p->scratch, p->src.buf.current-1, p->scrcnt); p->src.buf.current = p->src.buf.end; rest = nb + 1 - p->scrcnt; for (;;) { SAFE_CALL(p, filled = bufport_fill(p, rest, FALSE)); if (filled <= 0) { /* TODO: make this behavior customizable */ UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_INPUT, "encountered EOF in middle of a multibyte character from port %S", p); } if (filled >= rest) { memcpy(p->scratch+p->scrcnt, p->src.buf.current, rest); p->scrcnt += rest; p->src.buf.current += rest; break; } else { memcpy(p->scratch+p->scrcnt, p->src.buf.current, filled); p->scrcnt += filled; p->src.buf.current = p->src.buf.end; rest -= filled; } } SCM_CHAR_GET(p->scratch, c); p->scrcnt = 0; } else { SCM_CHAR_GET(p->src.buf.current-1, c); p->src.buf.current += nb; } p->bytes += nb; } else { c = first; if (c == '\n') p->line++; } UNLOCK(p); return c; } case SCM_PORT_ISTR: { if (p->src.istr.current >= p->src.istr.end) { UNLOCK(p); return EOF; } int c = 0; int first = (unsigned char)*p->src.istr.current++; int nb = SCM_CHAR_NFOLLOWS(first); p->bytes++; if (nb > 0) { if (p->src.istr.current + nb > p->src.istr.end) { /* TODO: make this behavior customizable */ UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_INPUT, "encountered EOF in middle of a multibyte character from port %S", p); } SCM_CHAR_GET(p->src.istr.current-1, c); p->src.istr.current += nb; p->bytes += nb; } else { c = first; if (c == '\n') p->line++; } UNLOCK(p); return c; } case SCM_PORT_PROC: { int c = 0; SAFE_CALL(p, c = p->src.vt.Getc(p)); if (c == '\n') p->line++; UNLOCK(p); return c; } default: UNLOCK(p); Scm_PortError(p, SCM_PORT_ERROR_INPUT, "bad port type for input: %S", p); } return 0;/*dummy*/ }