25 июн. 2013 г.

Проброс последовательного порта по сети в Linux (serial over ip)

 

Входные данные

Есть два хоста:
  • server: компьютер, на котором есть терминал (последовательный порт) /dev/ttyS0
  • client: компьютер, на котором нужно иметь доступ к этому порту

Данные, переданные с клиента, должны быть переданы через сервер тому, кто подключен с другой стороны порта. Для тестирования можно с помощью qemu создать виртуальную машину с портом RS-232, другой конец которого будет присоединен к символьному устройству на хосте.

 

Способ 1: socat

Самый простой способ – использовать socat. С его помощью можно соединить последовательное устройство и сокет.
На server создаем сокет на tcp-порту 12345, привязанный к /dev/ttyS0:
server$ socat tcp-l:12345 /dev/ttyS0
На client создаем виртуальный терминал в /dev/pts/N и привязываем его к сокету server:12345:
client$ socat tcp:server:12345 pty,raw,echo=0
При такой схеме передаются данные, но не управляющая информация. Настройка виртуального терминала на хосте client никак не отражается на реальном терминале на хосте server. Это значит, что приложения, которые используют ioctl(2) или termios(3), не будут работать так, как ожидается.

Аналогичные решения:

 

Способ 2: RFC 2217

Более сложный способ – использовать RFC 2217 для удаленного управления терминалом. Это расширение telnet, которое описывает передачу управляющей информации для последовательного порта.

 

Сервер

  • ser2net
    ser2net реализует телнет-сервер RFC 2217.
    Запускаем на хосте server на порту 23:
    server$ ser2net -d -C '23:telnet:0:/dev/ttyS0'
    
    ser2net можно также запускать в режиме демона или с помощью inetd.

  • sredird
    sredird – другая реализация сервера RFC 2217. Он лучше совместим с клиентом cyclades-serial-client.
    Запускаем на хосте server на порту 23 с помощью netcat:
    server$ nc -l -p 23 -c '/usr/sbin/sredird 5 /dev/ttyS0 sredird.lock'
    
    sredird можно также запускать с помощью inetd.

  • sercd
    sercd – еще одна реализация. Он основан на sredird.

 

Клиент

  • telnet
    После запуска сервера к удаленному терминалу можно подключиться по телнет:
    client$ telnet SERVER_IP
    

  • ckermit
    Вместо telnet можно использовать C-Kermit, который поддерживает RFC 2217:
    client$ kermit -q
    C-Kermit>set carrier-watch off
    C-Kermit>telnet SERVER_IP
    
    С ним помимо телнет будут также доступны команды для конфигурирования порта.

  • cyclades-serial-client

    Версия из Debian Squeeze у меня не заработала, я собирал из SVN.

    cyclades-serial-client – клиент для сервера RFC 2217. Он работает с помощью трюка с LD_PRELOAD.

    Для каждого удаленного терминала создается:
    1. Виртуальный терминал /dev/pts/N.
    2. Символическая ссылка на него /dev/NAME.
    3. Локальный сокет /dev/NAME.control

    Затем пользователь с помощью LD_PRELOAD может заставить приложение, использующее терминал /dev/NAME, перенаправлять вызовы ioctl(2) и tcsetattr(3) в сокет /dev/NAME.control, откуда они будут прочитаны демоном cyclades-ser-cli и отправлены в удаленный терминал.

    Настраиваем конфиг клиента /etc/cyclades-devices (без этого не будет работать трюк с LD_PRELOAD):
    /dev/mytty:prts:SERVER_IP:0:rfc2217:
    
    Запускаем демон, обслуживающий виртуальный терминал:
    client$ cyclades-ser-cli -d 3 -m 1 -x /dev/mytty SERVER_IP 0
    
    Можно также запускать демон с помощью cyclades-serial-client.
    Проверяем передачу данных:
    client$ echo hello > /dev/mytty
    
    Cообщение hello должен получить тот, кто подключен к порту /dev/ttyS0 на хосте server.
    Проверяем настройку baud rate:
    client$ export LD_PRELOAD=/usr/lib/libcyclades-ser-cli.so
    client$ stty -F /dev/mytty 38400
    
    На хосте server у терминала /dev/ttyS0 должно обновиться значение:
    server$ stty -F /dev/ttyS0
    speed 38400 baud; ....
    
    У меня этот клиент работает с сервером sredird, но не работает с ser2net.

    Другие проблемы:
    • Не все параметры ioctl() реализованы.
    • Подход с использованием LD_PRELOAD для ioctl() и tcgetattr() работает не для всех приложений. У меня так и не заработала команда setserial(8).

  • Network Virtual Terminal
    nvtty – это драйвер ядра, реализующий виртуальный терминал, перенаправляющий все запросы удаленному серверу RFC 2217. Патч основан на cyclades-serial-client.

    Патч и обсуждение в списке рассылки:

    Патч так и не был принят в ядро:
    And this is still something that should be done in userspace if necessary
    by fixing up the tty layer to support pty/tty pair modem lines and
    termios change reporting, or some kind of generic vt that can also
    expose all the config other net protocols might need.

    (Alan Cox)

 

TTYredirector

TTYredirector реализует сервер и клиент RFC 2217, создавая на клиенте виртуальный терминал. Автоматического перенаправления управляющих команд с локального терминала на удаленный нет, его нужно настраивать вручную с помощью специальной утилиты, так что это решение подвержено тем же проблемам, что способ в socat.

 

Способ 3: Serial to Ethernet Converter

Serial to Ethernet Converter – устройство, преобразующее RS-232 (и/или другие протоколы) в Ethernet и обратно.

Есть как минимум два производителя, поставляющие вместе со своими преобразователями драйвер для Linux, который создает виртуальный COM-порт и перенаправляет все запросы к нему в сеть: