FAt Remoute SHell Перед сборкой убедиться, что в config-farshd.h выставлен нужный шелл. Выставить переменные окружения CC, CFLAGS и т.п. и собрать: export CFLAGS="-O2" make farsh make farshd Ну или вручную: cc -O2 -o farsh farsh.c cc -O2 -o farshd farshd.c Приблизительный алгоритм работы программы. Максимальный размер пакета задаётся MAX_PKT_SZ, это нужно чтоб не возиться с Path MTU Discovery. Интервал отправки пакетов задаётся в PKT_INT. Эти значения ограничивают макс. пропускную способность. Значение PKT_INT на клиенте рекоммендуется выставить меньше чем на сервере. Бесконечный цикл на клиенте: 1) Если есть данные с терминала, то пишем их в кольцевой буфер 2) Если пришёл пакет, то читаем из него данные и пишем их в stdout 3) Если прошло PKT_INT микросекунд или около того (PKT_INT - MIN_SLEEP), то пора сформировать пакет: 1) если соединение не установлено, то выставляем в пакете бит CONNECT и добавляем в него значение перемнной окружения TERM. 2) Получаем размеры терминала, если они отличаются от тех, что мы раньше отправляли на сервер, то выставляем в пакете бит PING и добавляем туда новые размеры терминала. 3) Если в кольцевом буфере есть данные, то добавляем их в пакет, а также добавляем состояния потоков: количество принятых от сервера байт данных (не просто байт а именно тех что пишем в терминал) и количество байт данных которое сервер получил от клиента (клиент получает эти данные с сервера). Выставляем бит SSTATE в пакете. 4) Если данных нет, но состояния потоков разные на сервере и клиенте, то выставляем бит SSTATE в пакете и добавляем состояния потоков в пакет. 5) Если получился не пустой пакет, то отправляем его. Если с момента последнего полученного от сервера пакета прошло TIMEOUT_P секунд, то добавляем в пакет PING, размеры терминала и шлём. Клиент перестаёт слать пакеты с битом CONNECT после получения пакета от сервера с таким битом. Бесконечный цикл на сервере: 1) Если что-то есть в клиентских псевдотерминалах, то читаем это в клиентские колцевые буферы. 2) Если есть пакет от клиента, то пишем данные из пакета в клиентский псевдотерминал. Обновляем состояния потоков. Обновляем размеры терминала, если они есть в паете. 3) Прошло PKT_INT микросекунд или около того. Пробегаем по всем клиентам и формируем пакет если: а) был пакет от клиента с битом PING б) был пакет от клиента с битом SSTATE в) в кольцевом буфере клиента есть данные. После установки соединения сервер шлёт пакеты с битом CONNECT пока не получит от клиента подряд NOT_CONNECTED пакетов без бита CONNECT. После этого сервер перстаёт добавлять CONNECT бит в пакет и если получит пакет с этим битом от клиента, то отключит его. NOT_CONNECTED пакетов подряд нужно на случай перестановки пакетов (хоть это и маловероятно из-за большого интервала между пакетами). Формат пакета: Первые два байта это u16 переменная, которая может содержать флаги: CONNECT, PING, SSTATE. Вторые 2 байта, это u16 переменная, в которой будет размер данных в пакете (может быть 0). Флаг CONNECT озанчает что сразу за первыми 4 байтами пакета идёт буфер размером CONNECT байт с содержимым клиентской переменной TERM (если пакет от сервера, то ничего не добавляется). Флаг PING означает что сразу за первыми 4 байтами (или за первыми 4+CONNECT байтами) идут две u16 переменных, в которых содержатся размеры терминала. Сервер должен ответить на этот пакет, и он шлёт те значения которые получил последние. Флаг SSTATE означает что в пакет добавлены состояния потоков: две u32 переменные. Значения флагов выбраны таким образом что образуемая ими u16 переменная содержит количество данных в пакете помимо данных для терминала (кроме случая, когда сервер шлёт пакет с битом CONNECT). Так добавив к этой переменной 4 (первые байты) можно получить смещение данных в пакете.