Title

Basic socket interface

Author

Takashi Kato

Abstract

This document specifies basic socket interfaces.

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 high and middle range of socket interfaces which are commonly used to write socket programming. That should make it easier to write portable programs that need to send or receive data from their socket.

Specification

All procedures defined in this SRFI may raise an error when the procedure failed because of the connection problem or other socket related problem. This document does not specify which condition should be raised. The end of this section, I put a table described which condition will be raised by some of the Scheme implementations.
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
    
Flag operations
      socket-merge-flags
      socket-parge-flags
    
Constant values
      AF_UNSPEC AF_INET AF_INET6
      SOCK_STREAM SOCK_DGRAM
      AI_PASSIVE AI_CANONNAME AI_NUMERICHOST
      AI_V4MAPPED AI_ALL AI_ADDRCONFIG
      IPPROTO_IP IPPROTO_TCP IPPROTO_UDP
      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.
If the optional argument(s) is omitted, then following flags should be used as default.
ai-family
AF_INET
ai-socktype
SOCK_STREAM
ai-flags
(socket-merge-flags AI_V4MAPPED AI_ADDRCONFIG)
ai-protocol
IPPROTO_IP
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.
If the optional argument(s) is omitted, then following flags should be used as default.
ai-family
AF_INET
ai-socktype
SOCK_STREAM
ai-protocol
IPPROTO_IP
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. If flags is ommited, then the procedure should behave as if no flag is given.
socket-recv socket size [flags] -> bv
Receives a binary data block from a socket. If zero length bytevector is returned, it means the peer connection is closed.
flags may specify the procedure's behaviour. If flags is ommited, then the procedure should behave as if no flag is given.
socket-shutdown socket how -> (unspecified)
Shutdows a socket.
how must be one of the following constants;
  • SHUT_RD
  • SHUT_WR
  • SHUT_RDWR
socket-close socket -> (unspecified)
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.
If given proc returns then it returns the result of proc and socket will be automatically closed. If proc doesn't return then given socket won't be closed automatically. It's analogy of call-with-port.

Flag operations

socket-merge-flags flags ... -> new-flags
Merges given flags and returns a new flag.
socket-parge-flags base-flag flags ... -> new-flags
Removes flags from base-flag if exists and returns a new flag.

Constants

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

Conditions

These are some of conditions raised when networking error occurs.
Implementation nameCondition type
Gauche<system-error>
Larcenyno error, returns #f
Mosh&i/o-read
Racketexn:fail:network
Sagittarius&i/o
Ypsilon&i/o

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 (srfi :106 socket)
    (export make-client-socket make-server-socket
       	    socket? socket-port call-with-socket
            socket-merge-flags socket-parge-flags
       	    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
            IPPROTO_IP IPPROTO_TCP IPPROTO_UDP
       	    SHUT_RD SHUT_WR SHUT_RDWR)
    (import (srfi :106 socket impl)))

Implementation dependent layer

For Ypsilon

(library (srfi :106 socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            (rename (bitwise-ior socket-merge-flags)
                    (bitwise-xor socket-parge-flags))
            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
            IPPROTO_IP IPPROTO_TCP IPPROTO_UDP
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (rnrs) (rename (ypsilon socket)
                           (socket-send %socket-send)
                           (socket-recv %socket-recv)))
  (define IPPROTO_IP 0)
  (define IPPROTO_TCP 6)
  (define IPPROTO_UDP 17)

  (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 (srfi :106 socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            (rename (bitwise-ior socket-merge-flags)
                    (bitwise-xor socket-parge-flags))
            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
            IPPROTO_IP IPPROTO_TCP IPPROTO_UDP
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (rnrs) (mosh socket)
  (define IPPROTO_IP 0)
  )

For Sagittarius

(library (srfi :106 socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            (rename (bitwise-ior socket-merge-flags)
                    (bitwise-xor socket-parge-flags))
            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
            IPPROTO_IP IPPROTO_TCP IPPROTO_UDP
            SHUT_RD SHUT_WR SHUT_RDWR)
    (import (rnrs) (rename (sagittarius socket)
                           (socket-send %socket-send)
                           (socket-recv %socket-recv)))
  (define IPPROTO_IP 0)
  (define IPPROTO_TCP 6)
  (define IPPROTO_UDP 17)

  (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 (srfi :106 socket impl)
    (export make-client-socket make-server-socket
            socket? socket-port call-with-socket
            (rename (bitwise-ior socket-merge-flags)
                    (bitwise-xor socket-parge-flags))
            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
            IPPROTO_IP IPPROTO_TCP IPPROTO_UDP
            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 IPPROTO_IP)
  (define-unsupported IPPROTO_TCP)
  (define-unsupported IPPROTO_UDP)

  (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: Dave Mason
Author: Takashi Kato
Last modified: Sun Jan 28 14:21:14 MET 2007