\documentstyle[russian,fancyheadings,twoside,epsf,indentfirst]{article} % Vertical sizes %\vsize=20cm %\voffset=-2.3cm %\topmargin=0cm %\headheight=0.9cm %\footskip=1cm %\footheight=0.9cm %\textheight=16cm %\headrulewidth 0.01cm %\footrulewidth 0.0cm % horisontal sizes %\hsize=30cm %\hoffset=-4.3cm %\hoffset=-2.3cm %\textwidth=13cm % Modes % \special{landscape} \pagestyle{empty} \pagestyle{fancyplain} \newcommand{\tit}[1]{#1} \rhead[\fancyplain{}{\tit{\leftmark}}]{\fancyplain{}{\tit{\rightmark}}} \lhead[\fancyplain{}{\tit{\rightmark}}]{\fancyplain{}{\tit{\leftmark}}} \chead{\hfill} \lfoot[\fancyplain{}{\tit{\thepage}}]{\fancyplain{}{\hfill}} \rfoot[\fancyplain{}{\hfill}]{\fancyplain{}{\tit{\thepage}}} \cfoot{\hfill} \renewcommand{\sectionmark}[1]{\markboth{#1}{\ }} \renewcommand{\subsectionmark}[1]{\markright{\ }} \newcommand{\look}[1]{(Глава~\ref{#1}, стр.~\pageref{#1})} \newcommand{\toindex}[1]{\underline{\bf#1}\index{#1}} \newcommand{\add}[1]{\symbol{64}} \newcommand{\ps}[1]{\symbol{37}s} \newcommand{\twcol}[4]{ \noindent\parbox[t]{#1\textwidth}{#3} \hfill \parbox[t]{#2\textwidth}{#4\hfill}\\ } \newcommand{\tc}[2]{\twcol{0.49}{0.49}{#1}{#2}} \newcommand{\tcc}[2]{\twcol{0.49}{0.49}{\toindex{#1}}{#2}} \newcommand{\ttt}[2]{\bigskip {\bf#1} #2} \newcommand{\ts}[1]{{\bf#1}} \newcommand{\dl}[2]{\parbox[t]{0.4\textwidth}{#1\hfill}\hfill \parbox[t]{0.4\textwidth}{#2\hfill}} \makeindex \begin{document} \title{\bf\it РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ БИБЛИОТЕКИ "LIBFTP"} \author{Олег Орел} \date{\today} \newpage \maketitle \section*{Лицензия} Продукт предназначен для написания свободного некоммерческого программного обеспечения. Он может исправляться и дописываться. Автор будет благодарен за получение советов, новых компонент и правок существующих подпрограмм. Коммерческое использование этой библиотеки возможно с привлечением е\"е автора. \section*{Причины создания и история развития} Для людей, которые хотя бы один раз писали программу с использованием системных вызовов типа socket, connect, bind.... не секрет, что почти всегда последовательность вызовов функций для создания соединения по протоколу TCP одна и та же. Отсюда возникает резонный вопрос ``А почему собственно не иметь библиотеки более высокого уровня, для упрощения процесса программирования?''. Это послужило причиной создания \ts{libftp}. После реализации ``нижней'' части библиотеки, были созданы функции более высокого уровня, такие как передача целого файла или чтение списка файлов. При написании этих процедур возникла необходимость удобной отладки сбойных случаев, для освобождения программы от бесконечного числа условий (обработка возвращаемого библиотечными функциями статуса). Для этого был создан макрос \ts{EXIT}, который при возврате функциями статуса, проверяет его, и в случае необходимости вызывает заранее установленные функции. При передачи файлов по сети, которая в основном состоит из dialup-slip'ов (типичная ситуация для exUSSR) часто возникают ситуации ``поломки сети'' и файл большого размера передать становится практически невозможно\footnote{Конечно можно периодически запускать ftp, и говорить в нем ``reget filename''}, это послужило причиной написания программы \toindex{ftptry}\footnote{Программа \ts{ftptry} будет описана ниже} с использованием библиотеки libftp. Для е\"е реализации в библиотеку были добавлены функции \toindex{FtpRestorTimeout} и \toindex{FtpReretrTimeout}, которые в отличии от функций \ts{FtpStorTimeout} и \ts{FtpRetrTimeout} не передают а докачивают файлы. \section*{Недостатки - для исправления в следующих версиях} \begin{itemize} \item В процедурах чтения потока из socket'ов используется механизмы setjmp-longjmp, alarm+SIGALRM, SIGIO, которые будут заменены на select. Этот недостаток (использование SIGALRM) проявляется при работе с X11 \footnote{там тоже используется alarm} \item Переменная FtpDataStart\footnote{С какого байта передавать файлы} не принадлежит структуре FTP, а является обшей для всех. \item Отсутствие работы с \toindex{site-specific} ftpd командами \end{itemize} \section*{Идеи для дальнейших реализации} \begin{itemize} \item Разработка программы дублирования дерева директорий одной машины на другую. \footnote{Разработка идет в данный момент} \item Разработка интерфейса в окружении X-window's для манипуляции файлами находящихся на разных машинах с возможностью неинтерактивной передачи (для медленных сетей) \item Создание мультиплексирующего аппарата для одновременной обработки нескольких потоков данных. \item Создание объекта FTP для C++ \end{itemize} \section*{Введение} Библиотека ``libftp'' предназначена для написания прикладных программ в которых существует необходимость передавать файлы по сети TCP/IP. Oна является набором функций начиная от примитивных функций, таких как открытие соединения по протоколу FTP на удаленную машину, до функций высокого уровня, которые передают файлы сами производя соединение/разъединение с сервером. Все функции имеют прототипы в файле \toindex{FtpLibrary.h}, который должен быть помещен в каталог стандартных заголовков\footnote{Например /usr/include}. Эти прототипы практически полностью описывают назначение функций и их аргументы, но тем не менее необходимо сказать об общей идеологии построения библиотеки и ее компонент. Вся библиотека, являясь клиентом, использует с противоположной стороны соединения стандартный \toindex{FTPD} \footnote{Для работы функций FtpRertrTimeout, FtpRestorTimeout необходимо чтобы сервер отрабатывал команду REST}. Во многих операционных системах существует проблема обработки разного рода ошибок, в том числе ошибок ввода/вывода, в данном инструментарии использован единый механизм возврата результата работы любой функции (макрокоманда \ts{EXIT}, определенная в \ts{FtpLibrary.h}) который позволяет предварительно установив свои или стандартные функции обработки ошибок и функции отладки, писать смысловую часть программы, думая только о ее методе работы в идеальных условиях. В функциях передачи данных в обе стороны существует возможность установить максимальное время ожидания потока данных, по истечении которого, возможно вызвать определенную процедуру. При работе с библиотекой, первой всегда вызывается процедура соединения с сервером\footnote{За исключением FtplibDebug} (\ts{FtpLogin} или \ts{FtpConnect}) которая возвращает указатель на вновь созданную структуру данных (типа \ts{FTP}) о соединении с сервером. \section{Структура данных FTP} \tc{int \toindex{sock}}{--- дескриптор канала передачи команд на сервер;} \tc{FILE *\toindex{data}}{--- описание канала для передачи данных на сервер;} \tc{int \toindex{errno}}{ --- значение последнего возвращенного библиотекой значения. В случае если оно отрицательно или равно нулю, то произошла ошибка;} \tc{char \toindex{mode}}{--- тип передачи данных;} \tc{int ch}{--- вспомогательная переменная используемая для преобразования потока в режиме передачи текстовых файлов;} \tc{STATUS (*func)()}{--- адрес функции, которая вызывается в случае когда от сервера получен ответ об ошибке;} \tc{STATUS (*debug)()}{--- адрес функции, которая вызывается для отладки протокола;} \tc{STATUS (*IO)()}{--- функция вызываемая в случае потери связи с сервером, или по истечению максимального времени на прием/передачу одного символа.} \section{ Процедуры соединения/разъединения с сервером} \ttt{STATUS \toindex{FtpConnect}(FTP~**, char~*hostname \footnote{Имя машины может быть как символьное так и цифровое, например \ts{dxcern.cern.ch} или \ts{128.141.201.96}} )} { Создает канал соединения с сервером, находящимся на машине hostname, и создает структуру FTP, возвращая на нее указатель. Если предварительно была выполнена процедура \toindex{FtplibDebug}(1), то до соединения с сервером включает стандартные подпрограммы обработки ошибок \toindex{FtpDebugDebug}, \toindex{FtpDebugError}, \toindex{FtpDebugIO} \look{debug}. } \ttt{STATUS \toindex{FtpUser}(FTP~*, char~*user)} { Посылает серверу имя пользователя. Ранее должно было быть произведено соединение } \ttt{STATUS \toindex{FtpPassword}(FTP~*, char~*password)} { Посылает серверу пароль. Ранее должна была быть выполнена процедура \ts{FtpUser} }\ttt{STATUS \toindex{FtpAccount}(FTP~*, char~*acct)} { Посылает серверу имя account'a Эта функция сделана для полного соответствия библиотеки протоколу \ts{FTP}, но т.к. мало таких операционных систем в которых необходим этот атрибут пользователя то функция \ts{FtpAccount} в общем то не нужна. Предварительно должна была быть выполнена процедура \ts{FtpUser}. } \ttt{ STATUS \toindex{FtpLogin}(FTP~**, char~*hostname, char~*user, char~*password, char~*account)} { Последовательно выполняет процедуры \ts{FtpConnect}, \ts{FtpUser}, \ts{FtpPassword}, \ts{FtpAccount} (если параметр account равен NULL, то процедура FtpAccount не вызывается)} \ttt{STATUS \toindex{FtpBye}(FTP~*)} { Завершает сеанс работы с сервером \footnote{Как видно из описания процедур соединения/разъединения из одной программы можно одновременно соединятся с несколькими серверами} } \section{Процедуры отладки программы} \label{debug} Существует возможность предварительно определить три процедуры:~\footnote{Если в любую из функций, описанных ниже, вместо параметра function передать значение \ts{NULL}, то это будет означать отключение отладки. При отключенной отладке результат работы можно определить или же по возвращаемому функцией значению (Если она типа \toindex{STATUS}) или по переменной errno в структуре \ts{FTP}} \ttt{\toindex{FtpSetDebugHandler}(FTP *,function)} { Устанавливает процедуру отладки протокола с удаленным сервером. Если ее определить, то она всегда будет вызывается из стандартной функции приема/передачи сообщения с/на сервера. Должна делать возврат, но в принципе имеет полное право прерывать выполнение программы в случае необходимости. } \ttt{\toindex{FtpSetErrorHandler}(FTP *,function)} { Определяет функцию обработки ошибок. После ее определения, в случае возвращения сервером неудовлетворительного ответа, будет вызываться указанная функция. При этом знак у кода ошибки меняется на '-', и т.о. результат становится меньше нуля. } \ttt{\toindex{FtpSetIOHandler}(FTP *,function)} { Определение функции обработки ошибок ввода/вывода. При передаче данных или команд на сервер, может возникнуть ситуация когда связь с сервером будет потеряна (сюда входят практически все сбои сети и сбои при работе сервера на удаленной машине) при этом будет вызвана указанная функция. Она вызывается так же по истечению максимального времени при ожидании очередного символа с сервера во время передачи данных. (\toindex{timeout}) } \ttt{\toindex{FtpDebug}(FTP *)} { Подключение стандартных функций отладки протокола таких как \tc{\toindex{FtpDebugError}}{--- печатает строку возвращенную сервером и прерывает программу;} \tc{\toindex{FtpDebugDebug}}{--- печатает строку возвращенную сервером;} \tc{\toindex{FtpDebugIO}}{--- печатает строку \ts{strerror(errno)} и прерывает программу.} } Во все процедуры передаются три аргумента:\\ 1. Структура \ts{FTP};\\ 2. Значение возвращенное функцией, если оно меньше единицы то произошла ошибка;\\ 3. Символьное сообщение об ошибке (char *). \ttt{\toindex{FtplibDebug}(\ts{on} or \ts{off})} { Включает/выключает автоматическое включение всех видов отладки при выполнении функции \ts{FtpConnect(FtpLogin)}} \section{Процедуры передачи данных с сервера} \ttt{STATUS \toindex{FtpRetrTimeout}(FTP~*, char~*command, char~*inp, char~*out \footnote{Если имя локального файла \ts{out} совпадет со строками \ts{*STDIN*}, \ts{*STDOUT*}, \ts{*STDERR*} то вместо открытия нового файла произойдет дублирование потока соответственно с каналами \ts{stdin}, \ts{stdout}, \ts{stderr} (Обработку данной спецификации файлов производит функция \toindex{Ftpfopen}, которая при необходимости может быть вызвана самостоятельно, с такими же аргументами, как системная функция fopen)}, long~time)} { Посылает команду \ts{command} на сервер, причем если в команде встретится подстрока \ps, то на ее место будет подставлена строка \ts{inp}. Создает канал для передачи данных, и то что будет передано сервером в этот канал будет скопировано в локальный файл \ts{out}. Если в течении времени \ts{time}(в секундах) с сервера не придет не одного символа, то функция возвратит статус который будет означать ошибку ввода/вывода. В случае когда \toindex{timeout}=0, максимальное время ожидания на уровне библиотеки равно бесконечности, в этом случае ошибка ввода/вывода может возникнуть по истечению timeout'a в ядре TCP/IP (или системы). Таким образом, если \ts{timeout} в параметре time больше чем timeout в ядре TCP/IP, он никогда не прервет передачу данных. \footnote{\ts{Timeout} в ядрах разных TCP/IP(системах) разный} } \ttt{STATUS \toindex{FtpReretrTimeout}(FTP~*, char~*command, char~*inp, char~*out, long~time)} { Производит тo же сaмое действие что и функция \ts{FtpRetrTimeout}, за исключение того, что перед передачей проверяется файл \ts{out}, и в случае его существования передача с сервера начинается с байта с номером \ts{<размер файла out>}+1.} \ttt{\toindex{FtpRetr}(FTP~*, char~*command, char~*inp, char~*out)} { Вызывает то же действие что и FtpRetrTimeout, но с выключенным timeout'ом. } \ttt{\toindex{FtpGetTimeout}(FTP~*, char~*inp, char~*out, long~time)} { Передает с сервера файл \ts{inp} в локальный файл \ts{out}, при этом устанавливается \ts{timeout=time}. } \ttt{\toindex{FtpGet}(FTP~*, char~*in, char~*out)} { Вызывает функцию \ts{FtpGetTimeout} с выключенным максимальным временем ожидания данных} \ttt{\toindex{FtpDirectory}(FTP~*, char~*pat\footnote{Это первый аргумент для команды ls(dir)}, char~*out)} { Передает содержимое директории, описанного параметром \ts{pat}, с сервера в файл \ts{out}. } \ttt{\toindex{FtpDir}(FTP~*, char~*out)} { Передает содержимое текущей директории с сервера в файл \ts{out}. } \section{Процедуры передачи данных на сервер} \ttt{\toindex{FtpStorTimeout}(FTP~*, char~*command, char~*inp, char~*out, long~time)} { Передает содержимое локального файла \ts{inp} на сервер, предварительно послав ему команду, составленную из \ts{command} и \ts{out}. Параметр \ts{time}, задает максимальное время на отправку одного символа. } \ttt{STATUS \toindex{FtpRestorTimeout}(FTP~*, char~*command, char~*inp, char~*out, long~time)} { Производит тo же сaмое действие что и функция \ts{FtpStorTimeout}, за исключение того, что перед передачей проверяется файл \ts{out} на сервере, и, в случае его существования, передача на сервер начинается с байта с номером \ts{<размер файла out>}+1.} \ttt{\toindex{FtpStor}(FTP~*, char~*command, char~*inp, char*~out)} { Вызывает запуск процедуры \ts{FtpStorTimeout} с параметром \ts{time=0}. } \ttt{\toindex{FtpPutTimeout}(FTP~*, char~*in, char~*out, long~time)} { Передает локальный файл \ts{in} на сервер в файл с именем \ts{out}, при этом \ts{timeout=time}} \ttt{\toindex{FtpPut}(FTP~*, char~*in, char~*out)} { Вызывает процедуру \ts{FtpPutTimeout} с параметром \ts{time=0}} \section{Процедуры чтения/записи в файл на сервере} Для того, чтобы производить ввод/вывод из/в файлы которые находятся на сервере, причем не копируя их предварительно в локальный файл, а работая непосредственно с оригиналом, существует возможность открыть файл на сервере на чтение/запись/дозапись и затем с помощью обычных процедур ввода/вывода или же при помощи процедур \ts{FtpRead} и \ts{FtpWrite}, которые в отличии от первых преобразуют текстовые файлы, производить необходимые операции. \footnote{Естественно, такие функции как \ts{seek}, \ts{ioctl}, ... для этих файлов недопустимы.} \ttt{\toindex{FtpData}(FTP~*, char~*command, char~*param, char~*mode)} { Создает канал для передачи данных предварительно послав серверу команду которая составляется из параметров \ts{command} и \ts{param}. Параметр \ts{mode} указывает может быть или ``r'' или ``w''} \ttt{\toindex{FtpOpenRead}(FTP~*,char~*filename)} { Открывает для чтения файл с именем \ts{filename} на сервере } \ttt{\toindex{FtpOpenWrite}(FTP~*,char~*filename)} { Открывает для записи файл с именем \ts{filename} на сервере } \ttt{\toindex{FtpOpenAppend}(FTP~*,char~*filename)} { Открывает для дозаписи файл с именем \ts{filename} на сервере } \ttt{\toindex{FtpOpenDir}(FTP~*, char~*files)} { Создает канал для чтения удаленного листинга директории, параметр files передается команде \ts{ls} на сервере в качестве 1-го параметра } \ttt{int \toindex{FtpRead}(FTP~*)}{Читает символ из потока данных, если была установлена текстовая мода передачи \footnote{Установлена по умолчанию.}, преобразует переходы на новую строку. При обнаружении конца потока возвращает \toindex{EOF}} \ttt{\toindex{FtpGetString}(FTP~*, char~*str)} { Чтение одной строки из потока данных при помощи функции \ts{FtpRead}.} \ttt{\toindex{FtpWrite}(FTP~*, char~c)}{Пишет символ в поток данных, если была установлена текстовая мода передачи, преобразует переходы на новую строку. При обнаружении ошибки ввода/вывода возвращает \toindex{EOF}} \ttt{\toindex{FtpClose}(FTP~*)} {Закрывает ранее открытый поток данных.} \section{Команды для сервера и вспомогательные функции} \ttt{\toindex{FtpCommand}(FTP~*, char~*command, char~*param, int~ok1, ok2, ok3, ..., okN, EOF)} { Посылает команду, составленную из параметров \ts{command} и \ts{param}, и считывает ответ сервера, если код ответа не совпадает не с одним значением \ts{ok}, то знак кода ответа меняется на '-'. В случае если установлен handler обработки ошибок вызывает его. } \ttt{\toindex{FtpType}(FTP~*,char~*mode)} {Устанавливает моду передачи файлов, mode может быть ``A'', ``I'', ``S'',....} \ttt{\toindex{FtpBinary}(FTP~*)} {Устанавливает двоичную моду передачи файлов} \ttt{\toindex{FtpAscii}(FTP~*)} {Устанавливает текстовую моду передачи файлов} \ttt{\toindex{FtpMkdir}(FTP~*,char *dirname)} {Создает директорию на сервере} \ttt{\toindex{FtpChdir}(FTP~*,char *dirname)} {Меняет активную директорию на сервере} \ttt{\toindex{FtpRm}(FTP~*,char *filename)} {Удаляет файл на сервере} \ttt{char~*\toindex{FtpPwd}(FTP~*)} {Возвращает активную директорию на сервере} \ttt{int \toindex{FtpSize}(FTP~*,char *filename)} {Возвращает размер файла в байтах, если файл с указанным именем отсутствует, то возвращается статус ошибки, т.е. значение меньше нуля} \ttt{\toindex{FtpMove}(FTP~*,char *oldfilename, char *newfilename)} {Переименовывает на сервере файл \ts{oldfilename} в файл \ts{newfilename}} \ttt{\toindex{FtpPort}(FTP~*, int~a, int~b, int~c, int~d, int~e, int~f)} {Команда серверу создать канал для передачи данных. Причем \ts{a.b.c.d} это IP адрес клиента а \ts{e*256+f} номер порта.} \ttt{struct hostent *\toindex{FtpGetHost}(char *hostname)} {Возвращает указатель на структуру типа hostent. Аргумент -- это строка содержащая или имя машины, или ее IP адрес в строчном виде\footnote{Например: ``dxunk8.oea.ihep.su'' или ``192.102.229.71''}.} \section{Подпрограммы передачи сообщений в/из сервера} \ttt{\toindex{FtpSendMessage}(FTP~*, char~*message)} {Посылает сообщение серверу} \ttt{int \toindex{FtpGetMessage}(FTP~*)} {Принимает сообщение от сервера и возвращает его код} \ttt{\toindex{FtpMessage}(int Number)} {Возвращает по коду сообщения его содержимое} \section{Функции полного сеанса работы} \ttt{FILE *\toindex{FtpFullOpen}(char *filename,char *mode)} { Разбирает строку filename, которая должна быть типа \\ \ts{host/user/password:filename} или же типа \ts{filename}, в зависимости от этого открывается файл или на сервере \ts{host} или локальный файл. Параметр mode должен содержать один или два символа. Первый задает тип открытия файла ``r'',``w'' или ``a''. Второй символ может содержать символ ``b'' что будет задавать двоичную моду передачи} \ttt{\toindex{FtpFullClose}(FILE *f)} {Закрытие файла} \section{Описание примеров и прикладных программ} \subsection{Программа get}\index{get} Копирование файла с сервера в локальный файл с таким же именем с использованием функций полного сеанса. \subsection{Программа fcp}\index{fcp} Программа fcp демонстрирует простое использование функций полного сеанса работы (FtpFullOpen и FtpFullClose). Имя файла передаваемого в качестве параметра, может описывать и локальный и удаленный файл. Это позволяет производить передачу как с сервера в локальный файл, так и наоборот, а также с сервера на сервер. \subsection{Программа ftptry}\index{ftptry} Предназначена для передачи файлов большого размера по сетям которые очень часто ``ломаются''. Это прежде всего относится к сетям построенных на dialup-линиях. \ts{ftptry} в основном предназначен для неитерактивной передачи данных, поэтому необходимая информация для выполнения передачи задаeтся в виде опций при запуске программы. При запуске \ts{ftptry} без ключей, на экран выводится список всех допустимых опций и один пример запуска, поэтому в данном руководстве ключи и их назначения описывать не имеет смысла. Необходимо только сказать о том, что так как некоторые опции необходимо ставить практически всегда, то можно предварительно установить переменную окружения ``FTPTRY''\index{FTPTRY enviroment} по аналогии с тем как это делается в программе ``less'' \footnote{Например: \% setenv FTPTRY ``-DBb -u anonymous -s 60 -t 15''}, и писать в командной строке только те опции которые редко используются или не писать их вообще. \newpage \input rus.ind \newpage \tableofcontents \end{document}