BSD INET Sockets Implementation

From: Erick Gallesio <eg_at_kaolin.unice.fr>
Date: Tue, 19 Jul 1994 11:44:25 +0100

This a contribution of David Tolpin <dvd_at_jet.msk.su> which is very
interesting.
Hereafter is his message.


------- Forwarded Message

Replied: Tue, 19 Jul 1994 11:41:18 +0100
Replied: eg_at_kaolin.unice.fr
Replied: David Tolpin <dvd_at_jet.msk.su>
Return-Path: from
        (5.61+++/IDA-1.2.8) id AA23529; Wed, 13 Jul 94 15:03:06 +0100
Received: from charybda.sovam.com by taloa.unice.fr with SMTP
        (5.65c8/IDA-1.2.8) id AA28903; Wed, 13 Jul 1994 15:00:12 +0200
Received: from scylla.sovam.com by charybda.sovam.com with SMTP id AA25806
  (5.67b8s3p1/IDA-1.5 for <eg_at_kaolin.unice.fr>); Wed, 13 Jul 1994 16:59:25
+0400
Received: from jetinf by scylla.sovam.com id aa29415; 13 Jul 94 16:59 MMTDST
Received: from swan.msk.su (swan) by tiger.jet.msk.su with SMTP id AA02266
  (5.65c/IDA-1.4.4 for <eg_at_kaolin.unice.fr>); Wed, 13 Jul 1994 16:01:46 +0400
From: David Tolpin <dvd_at_jet.msk.su>
Message-Id: <199407131201.AA02266_at_tiger.jet.msk.su>
Subject: BSD INET Sockets Implementation
To: eg_at_kaolin.unice.fr
Date: Wed, 13 Jul 1994 15:01:42 +0300 (GMT+3:00)
X-Mailer: ELM [version 2.4 PL20]
Content-Type: text
Content-Length: 9533


The package is an STk extension that implements BSD sockets (INET only).
The interface is very simple and it's obviously not full-featured; it allows,
however,
for creation of applications that communicate over an IP network.

The implementation was written with mind to make sockets fully compatible with
scheme ports,
so, there is no new type 'socket' - a list of two ports is returned instead.
One supplementary
type 'socket-handle' is introduced to implement listening sockets.

The source text is in stk_socket.[ch] and it is tested under SunOS 4.1 and
Linux.
Below is a commented list of the primitives.

        either primitive that returns an object other than the #undefined may also
return
        an object of type integer, that indicates an error condition.

        (prepare-server-socket portnum)
         bound socket to a local address. Returns an object of type socket-handle

        (release-server-socket! handle)
        close server socket (created by prepare-server-socket

        (socket-handle? handle)
        returns truth if the handle is of type socket-handle, false otherwise

        (listen-socket! handle)
        listen for connection requests

        (accept-connection handle)
        returns a new socket in response to a detected connection request,
        the return value is a list of two ports, (car sp) is opened for reading,
(cadr sp) - for writing

        (open-client-socket hostname portnum)
        connect to a socket on a remote machine, returns the same data structure as
the function described above

        (shutdown-connection! skt)
        shutdown socket, the mode of shutting down is determined according to the
mode of the port (read or write)

David Tolpin, dvd_at_pizza.msk.su

The following is a shell archive containing the sources:

#!/bin/sh
sed -n 's/^X\(.*\)$/\1/p' <<END-OF-TEXT > stk_socket.h
X#ifndef STK_SOCKET_INCLUDE
X#define STK_SOCKET_INCLUDE
X
X/*
X$Id: stk_socket.h,v 1.2 1994/06/26 18:11:47 dvd Exp dvd $
X*/
X
X/* IP BSD sockets interface from stk */
X
X/* primitives
X ; either primitive that returns an object other than the #undefined may also
return
X ; an object of type integer, that indicates an error condition.
X
X (prepare-server-socket portnum)
X ; bound socket to a local address. Returns an object of type socket-handle
X
X (release-server-socket! handle)
X ; close server socket (created by prepare-server-socket
X
X (socket-handle? handle)
X ; returns truth if the handle is of type socket-handle, false otherwise
X
X (listen-socket! handle)
X ; listen for connection requests
X
X (accept-connection handle)
X ; returns a new socket in response to a detected connection request,
X ; the return value is a list of two ports, (car sp) is opened for reading,
(cadr sp) - for writing
X
X (open-client-socket hostname portnum)
X ; connect to a socket on a remote machine, returns the same data structure
as the function described above
X
X (shutdown-connection! skt)
X ; shutdown socket, the mode of shutting down is determined according to the
mode of the port (read or write)
X*/
X
XPRIMITIVE prepare_server_socket(SCM portnum);
XPRIMITIVE release_server_socket(SCM handle);
XPRIMITIVE socket_handlep(SCM handle);
XPRIMITIVE listen_socket(SCM handle);
XPRIMITIVE accept_connection(SCM handle);
XPRIMITIVE open_client_socket(SCM hostname, SCM portnum);
XPRIMITIVE shutdown_connection(SCM skt);
X
X#endif
X
END-OF-TEXT
sed -n 's/^X\(.*\)$/\1/p' <<END-OF-TEXT > stk_socket.c
X#include "stk.h"
X#include "stk_socket.h"
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X/*
X$Id: stk_socket.c,v 1.4 1994/06/26 19:14:55 dvd Exp dvd $
X*/
X
X/*
X$Log: stk_socket.c,v $
X * Revision 1.4 1994/06/26 19:14:55 dvd
X * *** empty log message ***
X *
X * Revision 1.3 1994/06/26 18:55:27 dvd
X * Verbose error reporting is added
X *
X*/
X
X#ifdef __sun__
Xextern char *sys_errlist[];
X#endif
X
Xstruct socket_handle {
X int portnum;
X char *hostname;
X int handle;
X};
X
Xstatic int tc_sockhandle;
X
Xstatic void free_sockhandle(SCM handle);
Xstatic void mark_sockhandle(SCM handle);
Xstatic void displ_sockhandle(SCM x, FILE *f, int mode);
X
Xstatic extended_scheme_type sockhandle_type = {
X "sockhandle", /* name */
X 0, /* is_procp */
X mark_sockhandle, /* gc_mark_fct */
X free_sockhandle, /* gc_free_fct */
X NULL, /* apply_fct */
X displ_sockhandle /* display_fct */
X};
X
X
X#define SOCKHANDLE(x) ((struct socket_handle*)(x->storage_as.extension.data))
X#define SOCKHANDLEP(x) (TYPEP(x,tc_sockhandle))
X#define NSOCKHANDLEP(x) (NTYPEP(x,tc_sockhandle))
X
Xvoid mark_sockhandle(SCM handle)
X{
X}
X
Xvoid free_sockhandle(SCM handle)
X{
X struct socket_handle *sh;
X sh = SOCKHANDLE(handle);
X if(sh->hostname) free(sh->hostname);
X close(sh->handle);
X free(sh);
X SOCKHANDLE(handle) = NULL;
X}
X
Xvoid displ_sockhandle(SCM handle, FILE *f, int mode)
X{
X struct socket_handle *sh;
X sh = SOCKHANDLE(handle);
X sprintf(tkbuffer, "#[socket-handle %s %i]", sh->hostname, sh->portnum);
X Puts(tkbuffer,f);
X}
X
X
Xstatic SCM makesp(int s, char *hn, int portnum)
X{
X int t;
X int hnlen;
X FILE *fs, *ft;
X SCM zs, zt;
X long flag;
X
X flag = no_interrupt(1);
X
X t = dup(s); /* duplicate handles so that we are able to access one socket
channel */
X /* via two scheme ports */
X if(!((fs = fdopen(s, "r")) && (ft = fdopen(s, "w"))))
X err("internal(makesp): cannot create ports", NIL);
X NEWCELL(zs, tc_iport);
X NEWCELL(zt, tc_oport);
X zs->storage_as.port.f = fs; setbuf(fs, NULL); /* unbuffered input/output */
X zt->storage_as.port.f = ft; setbuf(ft, NULL);
X zs->storage_as.port.name = (char*)must_malloc((hnlen = strlen(hn))+16);
X sprintf(zs->storage_as.port.name, "%s:%i(r)", hn, portnum);
X zt->storage_as.port.name = (char*)must_malloc((hnlen = strlen(hn))+16);
X sprintf(zt->storage_as.port.name, "%s:%i(w)", hn, portnum);
X
X no_interrupt(flag);
X return(cons(zs, cons(zt, NIL)));
X}
X
XPRIMITIVE prepare_server_socket(SCM portnum)
X{
X struct sockaddr_in sin;
X int s;
X long flag;
X SCM ys;
X
X if(NINTEGERP(portnum))
X err("not a port number", portnum);
X sin.sin_port = INTEGER(portnum);
X sin.sin_addr.s_addr = INADDR_ANY;
X if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
X err(sys_errlist[errno], portnum);
X if(bind(s, (struct sockaddr*)&sin, sizeof sin) < 0)
X switch(errno) {
X case EADDRINUSE:
X case EADDRNOTAVAIL: {
X SCM errcode;
X NEWCELL(errcode, tc_integer);
X SET_INTEGER(errcode, errno);
X return errcode;
X }
X break;
X default: err(sys_errlist[errno], portnum);
X }
X /* now we're ready to create the object */
X NEWCELL(ys, tc_sockhandle);
X SOCKHANDLE(ys) = (struct socket_handle*)must_malloc(sizeof (struct
socket_handle));
X SOCKHANDLE(ys)->portnum = sin.sin_port;
X SOCKHANDLE(ys)->hostname = (char*)must_malloc(strlen("localhost")+1);
X strcpy(SOCKHANDLE(ys)->hostname, "localhost");
X SOCKHANDLE(ys)->handle = s;
X
X return ys;
X}
X
X
XPRIMITIVE release_server_socket(SCM handle)
X{
X if(NSOCKHANDLEP(handle)) err("not a socket handle", handle);
X close(SOCKHANDLE(handle)->handle);
X return UNDEFINED;
X}
X
XPRIMITIVE socket_handlep(SCM handle)
X{
X return SOCKHANDLEP(handle)? truth: ntruth;
X}
X
XPRIMITIVE listen_socket(SCM handle)
X{
X if(NSOCKHANDLEP(handle))
X err("not a socket handle", handle);
X if(listen(SOCKHANDLE(handle)->handle, 5) < 0)
X err(sys_errlist[errno], handle);
X return UNDEFINED;
X}
X
XPRIMITIVE accept_connection(SCM handle)
X{
X int s;
X
X if(NSOCKHANDLEP(handle))
X err("not a socket handle", handle);
X if((s = accept(SOCKHANDLE(handle)->handle, NULL, NULL)) < 0)
X err(sys_errlist[errno], handle);
X return makesp(s, SOCKHANDLE(handle)->hostname, SOCKHANDLE(handle)->portnum);
X}
X
XPRIMITIVE open_client_socket(SCM hostname, SCM portnum)
X{
X char *hn;
X struct hostent *hp;
X struct sockaddr_in server;
X int s;
X
X if(NSTRINGP(hostname)) err("bad hostname", hostname);
X if(NINTEGERP(portnum)) err("bad port number", portnum);
X hp = gethostbyname(hn = CHARS(hostname));
X if(!hp) err("unknown or misspelled host name", hostname);
X bzero((char*)&server,sizeof server);
X bcopy(hp->h_addr,(char*)&server.sin_addr, hp->h_length);
X server.sin_family = hp->h_addrtype;
X server.sin_port = INTEGER(portnum);
X if((s = socket(AF_INET,SOCK_STREAM,0)) < 0)
X err(sys_errlist[errno], NIL);
X if(connect(s, (struct sockaddr *)&server, sizeof server) < 0)
X switch(errno) {
X case EADDRINUSE:
X case EADDRNOTAVAIL:
X case ETIMEDOUT:
X case ECONNREFUSED: {
X SCM errcode;
X NEWCELL(errcode, tc_integer);
X SET_INTEGER(errcode, errno);
X return errcode;
X }
X break;
X default: err(sys_errlist[errno], NIL);
X }
X return makesp(s, hn, server.sin_port);
X}
X
XPRIMITIVE shutdown_connection(SCM skt)
X{
X if(NIPORTP(skt) && NOPORTP(skt))
X err("not a port", skt);
X if(shutdown(fileno(skt->storage_as.port.f), IPORTP(skt)?0:1) < 0)
X err(sys_errlist[errno], NIL);
X return UNDEFINED;
X}
X
Xvoid init_stk_socket(void)
X{
X tc_sockhandle = add_new_type(&sockhandle_type);
X
X add_new_primitive("prepare-server-socket", tc_subr_1,
prepare_server_socket);
X add_new_primitive("release-server-socket!", tc_subr_1,
release_server_socket);
X add_new_primitive("socket-handle?", tc_subr_1, socket_handlep);
X add_new_primitive("listen-socket!", tc_subr_1, listen_socket);
X add_new_primitive("accept-connection", tc_subr_1, accept_connection);
X add_new_primitive("open-client-socket", tc_subr_2, open_client_socket);
X add_new_primitive("shutdown-connection!", tc_subr_1, shutdown_connection);
X};
END-OF-TEXT

------- End of Forwarded Message
Received on Tue Jul 19 1994 - 11:44:26 CEST

This archive was generated by hypermail 2.3.0 : Mon Jul 21 2014 - 19:38:59 CEST