;;;; ;;;; w i n s o c k e t . s t k l o s -- Socket for Win32 ;;;; ;;;; Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI ;;;; ;;;; Permission to use, copy, and/or distribute this software and its ;;;; documentation for any purpose and without fee is hereby granted, provided ;;;; that both the above copyright notice and this permission notice appear in ;;;; all copies and derived works. Fees for distribution or use of this ;;;; software or derived works may only be charged with express written ;;;; permission of the copyright holder. ;;;; This software is provided ``as is'' without express or implied warranty. ;;;; ;;;; ;;;; Author: Steve Pruitt [steve@pruitt.net] ;;;; Creation date: 13-Mar-1999 12:59 ;;;; Last file update: 23-Aug-1999 00:12 ;;;; ;;;; socket object class was provided to simulate stdio ;;;; when i/o ports can not be assigned to sockets. ;;;; ;;;; Limiting socket interface to these methods is more ;;;; portable than using standard i/o ports. ;;;; ;;;; (unless (symbol-bound? ') (require "stklos") ;;;;*********************************************************************** ;;;; ;;;; socket-port class definitions (adds port i/o facilities) ;;;; ;;;;*********************************************************************** (define-class () ((socket :accessor socket-of :init-keyword :socket :initform -1) (buffer-size :init-keyword :buffer-size :initform 1024) (output-buf :accessor buffer-of :initform 0) (output-len :initform 0) (input-buf :initform 0) (input-loc :initform 0) (input-len :initform 0) ;; default recv-monitor (count number of bytes input from socket) (bytes-input :initform 0) (recv-monitor :init-keyword :recv-monitor :initform (lambda (self bytes-read) (let* ((bytes-input (slot-ref self 'bytes-input))) (slot-set! self 'bytes-input (+ bytes-input bytes-read)) ))) ;; default send-monitor (count number of bytes output to socket) (bytes-output :initform 0) (send-monitor :init-keyword :send-monitor :initform (lambda (self bytes-written) (let* ((bytes-output (slot-ref self 'bytes-output))) (slot-set! self 'bytes-output (+ bytes-output bytes-written)) ))) )) ;;;; ;;;; Initialize socket ;;;; (define-method initialize ((self ) initargs) (next-method) (require "socket") (if (not (socket? (socket-of self))) (slot-set! self 'buffer-size -1) )) ;;;; ;;;; handle-of (get socket-handle) ;;;; (define-method handle-of ((self )) (socket-handle (socket-of self))) ;;;; ;;;; address-of (socket-local-address) ;;;; (define-method address-of ((self )) (socket-local-address (socket-of self))) ;;;; ;;;; close-socket-port (socket-shutdown) ;;;; (define-method close-socket-port ((self )) (if (> (slot-ref self 'buffer-size) 0) (let* ((sock (socket-of self))) (flush self) (socket-shutdown sock) (slot-set! self 'buffer-size -1) (slot-set! self 'output-buf 0) (slot-set! self 'input-buf 0) ))) ;;;;*********************************************************************** ;;;; ;;;; client-socket class definition ;;;; ;;;;*********************************************************************** (define-class () ((port :init-keyword :port :accessor port) (host :init-keyword :host :accessor host) )) ;;;; ;;;; Initialize client-socket (make ) ;;;; (define-method initialize ((self ) initargs) (let* ((port (get-keyword :port initargs 21)) (host (get-keyword :host initargs "not-specified"))) (require "socket") (slot-set! self 'socket (initialize-client-socket host port)) (slot-set! self 'port port) (slot-set! self 'host host) (next-method) )) ;;;;*********************************************************************** ;;;; ;;;; server-socket class definition ;;;; ;;;;*********************************************************************** (define-class () ((connection :accessor connection-of) (port-number :init-keyword :port :accessor port-of) )) ;;;; ;;;; Initialize (make server socket) ;;;; (define-method initialize ((self ) initargs) (let* ((port (get-keyword :port initargs 0))) (require "socket") (slot-set! self 'socket (make-server-socket port)) (slot-set! self 'port-number (socket-port-number (socket-of self))) (slot-set! self 'connection -1) (next-method) )) ;;;; ;;;; accept-server-connection (accept server connection) ;;;; (define-method accept-server-connection ((self )) (let* ((sock (socket-of self))) (slot-set! self 'connection (accept-connection sock)) )) ;;;; ;;;; handle-of (get server connection handle) ;;;; (define-method handle-of ((self )) (slot-ref self 'connection)) ;;;; ;;;; close-server-connection (close server connection) ;;;; (define-method close-server-connection ((self )) (let* ((connection (slot-ref self 'connection))) (if (not (= connection -1)) (close-connection connection)) (slot-set! self 'connection -1) )) ;;;; ;;;; close-socket-port (close-server-connection and socket-shutdown) ;;;; (define-method close-socket-port ((self )) (if (> (slot-ref self 'buffer-size) 0) (let* ((sock (socket-of self))) (flush self) (close-server-connection self) (socket-shutdown sock) (slot-set! self 'buffer-size -1) (slot-set! self 'output-buf 0) (slot-set! self 'input-buf 0) ))) ;;;;*********************************************************************** ;;;; ;;;; i/o utilities (commmon to all classes) ;;;; ;;;;*********************************************************************** ;;;; ;;;; read-char ;;;; (define-method read-char ((self )) (let* ((chr #\newline) (loc (slot-ref self 'input-loc))) (if (not (string? (slot-ref self 'input-buf))) ;; initialize buffer (let* ((size (slot-ref self 'buffer-size))) (if (> size 0) (let* ((buffer (make-string size)) (len (socket-recv (handle-of self) buffer))) (set! loc 0) (slot-set! self 'input-buf buffer) (set! chr (string-ref buffer 0)) (slot-set! self 'input-len 0) (if (eof-object? len) (set! chr len) (let* ((recv-monitor (slot-ref self 'recv-monitor))) (slot-set! self 'input-len len) (recv-monitor self len) ))) )) ;; get next character in buffer (if (< loc (slot-ref self 'input-len)) (set! chr (string-ref (slot-ref self 'input-buf) loc)) ;; buffer is empty, get another buffer from socket (let* ((size (slot-ref self 'buffer-size))) (if (> size 0) (let* ((buffer (make-string size)) (len (socket-recv (handle-of self) buffer))) (set! loc 0) (slot-set! self 'input-buf buffer) (set! chr (string-ref buffer 0)) (slot-set! self 'input-len 0) (if (eof-object? len) (set! chr len) (let* ((recv-monitor (slot-ref self 'recv-monitor))) (slot-set! self 'input-len len) (recv-monitor self len) ))))) )) (slot-set! self 'input-loc (+ loc 1)) chr )) ;;;; ;;;; write-char ;;;; (define-method write-char (chr (self )) (let* ((loc (slot-ref self 'output-len))) (if (not (string? (slot-ref self 'output-buf))) ;; initialize buffer (if (> (slot-ref self 'buffer-size) 0) (let* ((size (slot-ref self 'buffer-size))) (slot-set! self 'output-buf (make-string size chr)) (set! loc 0) )) ;; add character to end of buffer (if (< loc (slot-ref self 'buffer-size)) (string-set! (slot-ref self 'output-buf) loc chr) ;; buffer is full, flush buffer (if (> (slot-ref self 'buffer-size) 0) (let* ((send-monitor (slot-ref self 'send-monitor)) (handle (handle-of self))) (socket-send handle (slot-ref self 'output-buf) loc) (send-monitor self loc) (string-set! (slot-ref self 'output-buf) 0 chr) (set! loc 0) )) )) (slot-set! self 'output-len (+ loc 1)) )) ;;;; ;;;; flush ;;;; (define-method flush ((self )) (let* ((len (slot-ref self 'output-len))) (if (> len 0) (let* ((send-monitor (slot-ref self 'send-monitor))) (socket-send (handle-of self) (buffer-of self) len) (send-monitor self len) (slot-set! self 'output-len 0) )))) ;;;; ;;;; read-line ;;;; (define-method read-line ((self )) (let* ((lst ())) (do ((chr (read-char self) (read-char self))) ((or (eof-object? chr) (char=? chr #\newline))) (set! lst (cons chr lst))) (list->string (reverse lst)) )) ;;;; ;;;; write-line ;;;; (define-method write-line ((self ) line) (let* ((handle (handle-of self)) (send-monitor (slot-ref self 'send-monitor)) (len (+ (string-length line) 1)) (buf (string-append line "\n"))) (socket-send handle buf len) (send-monitor self len) )) ;;;; ;;;; copy-to-socket ;;;; (define-method copy(from (self )) (let* ((chr (read-char from)) (count (slot-ref self 'output-len))) (if (eof-object? chr) (flush self) (let* ((num-chars (+ count 1))) (write-char chr self) (let* ((send-monitor (slot-ref self 'send-monitor)) (buffer-size (slot-ref self 'buffer-size))) (set! count 0) (while (not (eof-object? chr)) ;; fill buffer with data (let* ((to (handle-of self))) (do ((i num-chars (+ i 1))) ((or (= i buffer-size) (eof-object? chr))) (set! num-chars (+ num-chars 1)) (set! chr (read-char from)) (if (eof-object? chr) (set! num-chars i) (string-set! (buffer-of self) i chr) )) ;; send buffer data to socket and flush (if (> num-chars 0) (socket-send to (buffer-of self) num-chars)) (send-monitor self num-chars) (set! count (+ count num-chars)) (set! num-chars (- num-chars buffer-size)) )) (slot-set! self 'output-len 0) ))) count )) ;;;; ;;;; copy-from-socket ;;;; (define-method copy((self ) to) (let* ((chr (read-char self))) (if (eof-object? chr) 0 (let* ((buffer (slot-ref self 'input-buf)) (recv-monitor (slot-ref self 'recv-monitor)) (from (handle-of self)) (count 0)) ;; flush first input buffer (let* ((loc (- (slot-ref self 'input-loc) 1)) (len (slot-ref self 'input-len))) (set! count (- len loc)) (do ((i loc (+ i 1))) ((= i len)) (write-char (string-ref buffer i) to) )) ;; copy remaining buffers until no more left (do ((num-chars (socket-recv from buffer) (socket-recv from buffer))) ((eof-object? num-chars)) (set! count (+ count num-chars)) (recv-monitor self num-chars) (do ((i 0 (+ i 1))) ((= i num-chars)) (write-char (string-ref buffer i) to) )) count )))) ;;;; ;;;; copy-socket-to-socket ;;;; (define-method copy((self ) (output )) (let* ((chr (read-char self)) (count 0)) (if (not (eof-object? chr)) (let* ((buffer (slot-ref self 'input-buf)) (recv-monitor (slot-ref self 'recv-monitor)) (send-monitor (slot-ref self 'send-monitor)) (loc (- (slot-ref self 'input-loc) 1)) (len (slot-ref self 'input-len)) (from (handle-of self)) (to (handle-of output))) (flush output) ;; flush first input buffer (set! count (- len loc)) (socket-send to (substring buffer loc len) count) (send-monitor self count) ;; copy remaining buffers until no more left (do ((num-chars (socket-recv from buffer) (socket-recv from buffer))) ((eof-object? num-chars)) (set! count (+ count num-chars)) (recv-monitor self num-chars) (socket-send to buffer num-chars) (send-monitor self num-chars) )) count ))) ;;;; ;;;; close-input-port ;;;; (define-method close-input-port ((self )) (close-socket-port self)) ;;;; ;;;; close-output-port ;;;; (define-method close-output-port ((self )) (close-socket-port self)) )