(define threads-going 0)

(define (read-word-integer-line) ; reads an integer between 0 and 65535 from the current input port
  (let* ([l (read-line)]
         [n (string->number l)])
    (if (and (integer? n)
             (<= 0 n 65535))
        n
        (begin (display l) (display " is incorrect. Please enter an integer between 0 and 65535: ")
               (read-word-integer-line)))))

(define (connect-ports i o) ; connects i to o (like a reverse pipe) using a thread.
  (define (end)
    (with-handlers ([exn? (lambda (e) #f)]) (close-input-port i))
    (with-handlers ([exn? (lambda (e) #f)]) (close-output-port o))
    (set! threads-going (- threads-going 1))
    (kill-thread (current-thread)))
  (define (iter)
    (sleep)
    (let ([c (with-handlers ([exn? (lambda (e) (end))])
               (read-char i))])
      (if (equal? c eof)
          (end)
          (with-handlers ([exn? (lambda (e) (end))])
            (display c o)
            (iter)))))
  (set! threads-going (+ threads-going 1))
  (thread iter))

(define (wait-until-cease) ; waits until threads-going reaches 0 then exits
  (if (> threads-going 0)
      (begin (sleep)
             (wait-until-cease))
      (exit)))

(define-values (local-i local-o)
  (values (current-input-port) (current-output-port)))

(define-values (remote-i remote-o)
  (let ([ip (begin (display "Please enter ip: ") (read-line))]
        [port (begin (display "Please enter port: ") (read-word-integer-line))])
    (with-handlers ([exn? (lambda (e) (display "Couldn't connect - ") (display (exn-message e)) (exit))])
      (tcp-connect ip port))))

(connect-ports local-i remote-o)
(connect-ports remote-i local-o)
(wait-until-cease)
