! Copyright (C) 2007 Matthew Willis ! See http://factorcode.org/license.txt for BSD license. USING: cryptlib cryptlib.libcl kernel alien sequences continuations byte-arrays namespaces io.buffers math generic io strings io.streams.lines io.streams.plain io.streams.duplex combinators alien.c-types continuations ; IN: cryptlib.streams : set-attribute ( handle attribute value -- ) cryptSetAttribute check-result ; : set-attribute-string ( handle attribute value -- ) dup length swap string>char-alien swap cryptSetAttributeString check-result ; : default-buffer-size 64 1024 * ; inline TUPLE: crypt-stream handle eof? ; : init-crypt-stream ( handle -- ) dup CRYPT_OPTION_NET_READTIMEOUT 1 set-attribute CRYPT_SESSINFO_ACTIVE 1 set-attribute ; : ( handle -- stream ) dup init-crypt-stream default-buffer-size { set-crypt-stream-handle set-delegate } crypt-stream construct dup swap ; : check-read ( err -- eof? ) { { [ dup CRYPT_ERROR_READ = ] [ drop t ] } { [ dup CRYPT_ERROR_COMPLETE = ] [ drop t ] } { [ dup CRYPT_ERROR_TIMEOUT = ] [ drop f ] } { [ t ] [ check-result f ] } } cond ; : (refill) ( stream -- err ) dup [ crypt-stream-handle ] keep [ buffer@ ] keep buffer-capacity "int" dup >r cryptPopData r> *int rot n>buffer ; : refill ( stream -- ) dup (refill) check-read swap set-crypt-stream-eof? ; : read-step ( n stream -- ) dup refill tuck buffer-length 2dup <= [ drop swap buffer> % ] [ - swap dup buffer>> % dup crypt-stream-eof? [ 2drop ] [ read-step ] if ] if ; M: crypt-stream stream-read ( n stream -- str/f ) tuck buffer-length 2dup <= [ drop swap buffer> ] [ pick buffer>> [ % - swap read-step ] "" make f like ] if ; M: crypt-stream stream-read1 ( stream -- ch/f ) 1 swap stream-read [ first ] [ f ] if* ; : read-until-step ( seps stream -- sep/f ) dup refill 2dup buffer-until [ swap % 2nip ] [ % dup crypt-stream-eof? [ 2drop f ] [ read-until-step ] if ] if* ; M: crypt-stream stream-read-until ( seps stream -- str/f sep/f ) 2dup buffer-until [ >r 2nip r> ] [ [ % read-until-step ] "" make f like swap ] if* ; M: crypt-stream stream-flush ( cl-stream -- ) crypt-stream-handle cryptFlushData check-result ; M: crypt-stream stream-write ( str stream -- ) crypt-stream-handle over string>char-alien rot length "int" cryptPushData check-result ; M: crypt-stream stream-write1 ( ch stream -- ) >r 1string r> stream-write ; : check-close ( err -- ) dup CRYPT_ERROR_PARAM1 = [ drop ] [ check-result ] if ; M: crypt-stream dispose ( stream -- ) crypt-stream-handle cryptDestroySession check-close ; : create-session ( format -- session ) "int" tuck CRYPT_UNUSED rot cryptCreateSession check-result *int ; : crypt-client ( server port -- handle ) CRYPT_SESSION_SSL create-session [ CRYPT_SESSINFO_SERVER_PORT rot set-attribute ] keep [ CRYPT_SESSINFO_SERVER_NAME rot set-attribute-string ] keep ; : crypt-server ( port -- handle ) CRYPT_SESSION_SSL_SERVER create-session [ CRYPT_SESSINFO_SERVER_PORT rot set-attribute ] keep ; : crypt-login ( handle user pass -- ) swap pick CRYPT_SESSINFO_USERNAME rot set-attribute-string CRYPT_SESSINFO_PASSWORD swap set-attribute-string ; : test-server ( -- stream ) init 8888 crypt-server dup "user" "pass" crypt-login "Welcome to cryptlib!" over stream-print dup stream-flush dup stream-readln print dispose end ; : test-client ( -- stream ) init "localhost" 8888 crypt-client dup "user" "pass" crypt-login dup stream-readln print "Thanks!" over stream-print dup stream-flush dispose end ; : (rpl) ( stream -- stream ) readln { { [ dup "." = ] [ drop dup stream-readln "READ: " write print flush (rpl) ] } { [ dup "q" = ] [ drop ] } { [ t ] [ over stream-print dup stream-flush (rpl) ] } } cond ; : test-rpl ( client? -- ) ! a server where you type responses to the client manually init [ "localhost" 8888 crypt-client ] [ 8888 crypt-server ] if dup "user" "pass" crypt-login (rpl) dispose end ;