Title

Basic socket interface

Author

Takashi Kato

Abstract

This document specifies basic socket interfaces.

Status

This SRFI is currently in ``draft'' status. To see an explanation of each status that a SRFI can hold, see here. To provide input on this SRFI, please mail to <srfi minus 106 at srfi dot schemers dot org>. See instructions here to subscribe to the list. You can access previous messages via the archive of the mailing list.

Issues

Rationale

Many Scheme implementation have its own socket APIs however there are no portable way to write socket program. Therefore programmers need to provide implementation dependent layer for their program.

This document specifies a uniform interface to write socket programming. That should make it easier to write portable programs that need to send or receive data from their socket.

Specification

Names defined in this document:
Constructors and predicate
      make-client-socket make-server-socket socket?
    
Socket operations
      socket-accept socket-send socket-recv
      socket-shutdown socket-close
    
Port conversion
      socket-port
    
Control feature
      call-with-socket
    
Constant values
      AF_UNSPEC AF_INET AF_INET6
      SOCK_STREAM SOCK_DGRAM
      AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
      AI_V4MAPPED AI_ALL AI_ADDRCONFIG
      SHUT_RD SHUT_WR SHUT_RDWR
    

The procedures

The procedure description uses following notation;
socketa socket object
bva bytevector
objectany value

Constructors and predicate

make-client-socket node service [ai-family [ai-socktype [ai-flags [ai-protocol]]]] -> socket
Returns a client socket connected to an Internet addres.
The Internet address is identified by node and service. node and service must be string.
Example value of node: "localhost" "127.0.0.1"
Example value of service: "http" "80"
The optional parameter may specify the created socket's behaviour.
make-server-socket service [ai-family [ai-socktype [ai-protocol]]] -> socket
Returns a server socket waiting for connection.
The description of node argument is the same as make-client-socket.
The optional parameter may specify the created socket's behaviour.
socket? object -> boolean
Returns #t if given object is socket object. Otherwise #f.

Socket operations

socket-accept socket -> socket
Wait for an incomming connection request, and returns a fresh connected client socket.
socket-send socket bv [flags] -> size
Sends a binary data block to a socket and returns the sent data size.
flags may specify the procedure's behaviour.
socket-recv socket size [flags] -> bv
Receives a binary data block from a socket.
flags may specify the procedure's behaviour.
socket-shutdown socket how -> (unspeficied)
Shutdows a socket.
how must be one of the following constants;
  • SHUT_RD
  • SHUT_WR
  • SHUT_RDWR
socket-close socket -> (unspeficied)
Closes a socket.

Port conversion

socket-port socket -> binary-input/output-port
Returns a fresh binary input/output port associated with a socket.

Control feature

call-with-socket socket proc -> object
Calls a given procedure with a given socket as an argument.

Constants

The following variable should be defined but it highly depends on the platform.

Example

(import (rnrs) (socket))

(define echo-server-socket (make-server-socket "5000"))

(define (server-run)
  (define (get-line-from-binary-port bin)
    (utf8->string
     (call-with-bytevector-output-port
      (lambda (out)
        (let loop ((b (get-u8 bin)))
          (case b
            ((#xA) #t) ;; newline
            ((#xD) (loop (get-u8 bin))) ;; carriage return
            (else (put-u8 out b) (loop (get-u8 bin))))))))
  (let ((addr (socket-accept echo-server-socket)))
    (call-with-socket
     addr
     (lambda (sock)
       (let ((p (socket-port sock)))
         (call-with-port
          p
          (lambda (p)
            (let lp2 ((r (get-line-from-binary-port p)))
              (put-bytevector p (string->utf8 (string-append r "\r\n"))
              (lp2 (get-line-from-binary-port p))))))))))
(server-run)

Implementation

The following implementation is written in R6RS.

Interface layer

(library (socket)
    (export make-client-socket make-server-socket
       	    socket? socket-port call-with-socket
       	    socket-accept socket-send socket-recv socket-shutdown socket-close
       	    AF_UNSPEC AF_INET AF_INET6
       	    SOCK_STREAM SOCK_DGRAM
       	    AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
       	    AI_V4MAPPED AI_ALL AI_ADDRCONFIG
       	    SHUT_RD SHUT_WR SHUT_RDWR)
    (import (socket impl)))

Implementation dependent layer

For Ypsilon

(library (socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            socket-accept socket-send socket-recv socket-shutdown socket-close
            AF_UNSPEC AF_INET AF_INET6
            SOCK_STREAM SOCK_DGRAM
            AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
            AI_V4MAPPED AI_ALL AI_ADDRCONFIG
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (rnrs) (rename (ypsilon socket)
                           (socket-send %socket-send)
                           (socket-recv %socket-recv)))

  (define (socket-send socket bv . flags)
    (let ((flags (if (null? flags) 0 (car flags))))
      (%socket-send socket bv flags)))

  (define (socket-recv socket size . flags)
    (let ((flags (if (null? flags) 0 (car flags))))
      (%socket-recv socket size flags)))
)

For Mosh

(library (socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            socket-accept socket-send socket-recv socket-shutdown socket-close
            AF_UNSPEC AF_INET AF_INET6
            SOCK_STREAM SOCK_DGRAM
            AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
            AI_V4MAPPED AI_ALL AI_ADDRCONFIG
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (mosh socket))

For Sagittarius

(library (socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            socket-accept socket-send socket-recv socket-shutdown socket-close
            AF_UNSPEC AF_INET AF_INET6
            SOCK_STREAM SOCK_DGRAM
            AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
            AI_V4MAPPED AI_ALL AI_ADDRCONFIG
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (rnrs) (rename (sagittarius socket)
                           (socket-send %socket-send)
                           (socket-recv %socket-recv)))

  (define (socket-send socket bv :optional (flags 0))
    (%socket-send socket bv flags))

  (define (socket-recv socket size :optional (flags 0))
    (%socket-recv socket size flags))
  )

For others

(library (socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            socket-accept socket-send socket-recv socket-shutdown socket-close
            AF_UNSPEC AF_INET AF_INET6
            SOCK_STREAM SOCK_DGRAM
            AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
            AI_V4MAPPED AI_ALL AI_ADDRCONFIG
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (rnrs))

  (define-syntax define-unsupported
    (syntax-rules ()
      ((_ (name))
       (define (name . _)
         (raise 
          (condition (make-implementation-restriction-violation)
                     (make-who-condition 'name)
                     (make-message-condition
                      "This SRFI is not supported on this implementation")))))
      ((_ name)
       (define name #f))))

  (define-unsupported (make-client-socket))
  (define-unsupported (make-server-socket))
  (define-unsupported (socket?           ))
  (define-unsupported (socket-port       ))
  (define-unsupported (call-with-socket  ))
  (define-unsupported (socket-accept     ))
  (define-unsupported (socket-send       ))
  (define-unsupported (socket-recv       ))
  (define-unsupported (socket-shutdown   ))
  (define-unsupported (socket-close      ))

  (define-unsupported AF_UNSPEC     )
  (define-unsupported AF_INET       )
  (define-unsupported AF_INET6      )
  (define-unsupported SOCK_STREAM   )
  (define-unsupported SOCK_DGRAM    )
  (define-unsupported AI_PASSIVE    )
  (define-unsupported AI_CANONNAME  )
  (define-unsupported AI_NUMERICHOST)
  (define-unsupported AI_V4MAPPED   )
  (define-unsupported AI_ALL        )
  (define-unsupported AI_ADDRCONFIG )

  (define-unsupported SHUT_RD)
  (define-unsupported SHUT_WR)
  (define-unsupported SHUT_RDWR))

Copyright

Copyright (C) Takashi Kato (2012). All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Editor: Mike Sperber
Author: Takashi Kato
Last modified: Sat Oct 6 19:23:20 MST 2012