Monday, February 8, 2016

Interactive Modemspeed - SSH like it's 1995.

A couple of years ago I created a simple python program to simulate various modem speeds when you piped a command through it.  Easy, fun, but of limited use.

So, I revisited it and made the read portion non-blocking so that it can be used interactively.  The aim is to have a script I can pipe SSH through to make the remote connection act like it's behind an oldschool modem.


Usage:
$ ssh remotehost | /path/interactive-modemspeed.py speed

Substitute /path/ with the location of the script.
Substitute speed with the speed (in bits per second) you want to experience. 

If you omit speed, you get 300 bits per second.   

Did your friend leave a terminal unlocked?  Why not have some fun?

$ function ssh() { /usr/bin/ssh "$@" | /path/interactive-modemspeed 2400 ;}

(Make sure to put the absolute path to the ssh binary so you don't create a bash fork loop.  :-P)

Now they'll wonder why all their new SSH sessions feel like they're on a BBS in 1989.

Here's the code: interactive-modemspeed.py


#!/usr/bin/python2.7

import fcntl
import os
import sys
from time import sleep

def modem(text, speed):
  # Assume speed is in bits/sec, and we're running at 8,N,1
  # So, 10 bits per character.  (1 start, 8 char, 1 stop)
  delay = 1.0 / (speed / 10)  # = seconds per character
  for char in text:
    sys.stdout.write(char)
    sys.stdout.flush()
    sleep(delay)

if __name__ == "__main__":
   if len(sys.argv) > 1:
     baud = int(sys.argv[1])
   else:
     baud = 300
   # open stdin in non-blocking mode so we can read 1 character at a time
   fd = sys.stdin.fileno()
   fl = fcntl.fcntl(fd, fcntl.F_GETFL)
   fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

   while True:
     try:
       c = sys.stdin.read(1)
       modem(c, baud)
     except IOError:
       sleep(.01)
       continue  # Resource temporarily unavailable