Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Программа проверяет работоспособность POP3 сервера
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/select.h>
- #include <netdb.h>
- #include <poll.h>
- //-------------------------------------------------------------------
- #define RETCODE_SUCCESS 0
- #define RETCODE_ERROR 1
- #define POLL_TIMEOUT 5000
- #define APP_NAME "pop3_check"
- #define DEFAULT_POP3_PORT "110"
- #define BUF_SIZE 256
- //-------------------------------------------------------------------
- //-------------------------------------------------------------------
- // Прототипы функций
- //-------------------------------------------------------------------
- // Функция создает клиентское подключение к серверу с именем srv_name
- // на порт srv_port и, в случае успеха, возвращает по указателю
- // client_fd файловый дескриптор сокета для этого соединения.
- // При этом сама функция возвращает 1. Если же произошла неудача, то
- // функция возвращает 0, а по указателю client_fd будет записано
- // число -1
- int create_client_socket( const char* srv_name,
- const char* srv_port, int* client_fd );
- // Обходит связанный список структур addrinfo и пытается установить
- // соединение на основе его данных
- // Возвращает 1 в случае успеха и 0 при неудаче
- int try_connect( struct addrinfo* ai_list, int* client_fd );
- // Закрывает сокет
- void close_socket( int sock_fd );
- // Читает ответ сервера, ожидая его не более ms_timeout миллисекунд
- void read_server_response( int sock_fd, int ms_timeout );
- //-------------------------------------------------------------------
- int main( int argc, char* argv[] )
- {
- int retcode = RETCODE_SUCCESS;
- int sock_fd;
- const char* port = DEFAULT_POP3_PORT;
- if( argc > 1 )
- {
- if( argc > 2 )
- {
- port = argv[2];
- }
- if( create_client_socket( argv[1], port, &sock_fd ) )
- {
- printf( "Соединение установлено\n" );
- // Пообщаемся с сервером через сокет
- read_server_response( sock_fd, POLL_TIMEOUT );
- close_socket( sock_fd );
- }
- else
- {
- retcode = RETCODE_ERROR;
- }
- }
- else
- {
- printf( "Usage: %s <pop3_server_name> [port]\n", APP_NAME );
- }
- return retcode;
- }
- //-------------------------------------------------------------------
- void close_socket( int sock_fd )
- {
- // Флаг повторного вызова, если нашу функцию прервут
- int retry_flag;
- do
- {
- retry_flag = 0;
- if( close( sock_fd ) != 0 )
- {
- // Прервали сигналом?
- if( errno == EINTR )
- {
- // Попробуем еще разок
- retry_flag++;
- }
- else
- {
- perror( "close" );
- }
- }
- }
- while( retry_flag );
- }
- //-------------------------------------------------------------------
- // Обходим связанный список структур addrinfo и пытаемся установить
- // соединение на основе его данных
- // Возвращает 1 в случае успеха и 0 при неудаче
- int try_connect( struct addrinfo* ai_list, int* client_fd )
- {
- int result = 0;
- // Указатель на текущий элемент связанного списка
- struct addrinfo* ai_ptr;
- // Если все пойдет пучком, то тут будет дескриптор сокета
- int sock_fd;
- ai_ptr = ai_list;
- while( ai_ptr )
- {
- // Попробуем создать сокет
- sock_fd = socket( ai_ptr -> ai_family,
- ai_ptr -> ai_socktype, ai_ptr -> ai_protocol );
- if( sock_fd != -1 )
- {
- // Попробуем соединиться с сервером
- if( connect( sock_fd, ai_ptr->ai_addr,
- ai_ptr->ai_addrlen ) == 0 )
- {
- result++;
- // Вернем дескриптор клиентского сокета
- *client_fd = sock_fd;
- break;
- }
- // Попытка соединения не удалась, закроем сокет
- else
- {
- close_socket( sock_fd );
- perror( "connect" );
- }
- }
- else
- {
- perror( "socket" );
- }
- ai_ptr = ai_ptr -> ai_next;
- }
- return result;
- }
- //-------------------------------------------------------------------
- // Функция создает клиентское подключение к серверу с именем srv_name
- // на порт srv_port и, в случае успеха, возвращает по указателю
- // client_fd файловый дескриптор сокета для этого соединения.
- // При этом сама функция возвращает 1. Если же произошла неудача, то
- // функция возвращает 0, а по указателю client_fd будет записано
- // число -1
- int create_client_socket( const char* srv_name,
- const char* srv_port, int* client_fd )
- {
- int result = 0;
- // Флаг повторного вызова, если нашу функцию прервут
- int retry_flag;
- // Результат завершения функции getaddrinfo
- int r;
- // Структуры данных для getaddrinfo
- // В этой структуре устанавливаются "фильтры" для выдаваемых
- // функцией адресов
- struct addrinfo hints;
- // Указатель на возвращаемый связанный список структур
- // с информацией об адресах
- struct addrinfo* ai_list;
- // Структура для хранения данных сокета
- struct sockaddr_storage sstor;
- // Для файловых дескрипторов значение -1 - это ошибка, поэтому
- // сразу установим его в ошибочное значение
- *client_fd = -1;
- if( srv_name && srv_port )
- {
- // Подготовим структуры
- memset( &hints, 0, sizeof(struct addrinfo) );
- memset( &sstor, 0, sizeof(struct sockaddr_storage) );
- // Заполним структуру с фильтрами-подсказками
- hints.ai_family = AF_UNSPEC; // Обрабатываем IPv4 и IPv6
- hints.ai_socktype = SOCK_STREAM; // Потоковый сокет
- hints.ai_protocol = IPPROTO_TCP; // Нам нужен tcp
- // Исходим из оптимистичной стратегии, что все сработает
- // с первого раза и нам не помешают
- retry_flag = 0;
- do
- {
- ai_list = NULL; // Пустой список
- r = getaddrinfo( srv_name, srv_port,
- &hints, &ai_list );
- // Посмотрим, что у нас получилось
- if( r == 0 )
- {
- // С одним именем может быть связано
- // много адресов, поэтому getaddrinfo
- // возвращает не одно значение а много
- // в виде связанного списка
- // Обойдем список и будем пробовать
- // соединиться с адресами
- result = try_connect( ai_list, client_fd );
- }
- // Что-то пошло не так :(
- else
- {
- if( r == EAI_AGAIN )
- {
- // Попробуем еще разок
- retry_flag++;
- }
- else
- {
- // Полный писец
- perror( "getaddrinfo" );
- }
- }
- if( ai_list )
- {
- // Осовободим память
- freeaddrinfo( ai_list );
- }
- }
- while( retry_flag );
- }
- return result;
- }
- //-------------------------------------------------------------------
- // Читает ответ сервера, ожидая его не более ms_timeout миллисекунд
- void read_server_response( int sock_fd, int ms_timeout )
- {
- // Структура с данными, описывающими файловый дескриптор
- struct pollfd pfd;
- int pr; // poll result
- char buf[ BUF_SIZE ];
- ssize_t len;
- // Подготовим структуру для poll
- memset( &pfd, 0, sizeof(struct pollfd) );
- pfd.fd = sock_fd;
- // Будем отслеживать событие "Появились данные для чтения"
- pfd.events = POLLIN;
- printf( "Ожидаю ответ сервера (не более %d мс)\n", ms_timeout );
- fflush( stdout );
- pr = poll( &pfd, 1, ms_timeout );
- if( pr == 0 )
- {
- printf( "Нет ответа от сервера. Выход по таймауту\n" );
- }
- else
- {
- if( pr > 0 )
- {
- // Есть данные для чтения
- len = read( sock_fd, buf, BUF_SIZE-1 );
- if( len != -1 )
- {
- if( len )
- {
- // Терминируем буфер
- buf[ len ] = '\0';
- // Уберем перевод строки
- while( len )
- {
- if( buf[len-1] == '\n' )
- {
- len--;
- buf[ len ]='\0';
- }
- else
- if( buf[len-1] == '\r' )
- {
- len--;
- buf[ len ]='\0';
- }
- else
- {
- break;
- }
- }
- printf( "Ответ от сервера: '%s'\n",
- buf );
- }
- }
- else
- {
- printf( "Ошибка чтения из сокета!\n" );
- }
- }
- else
- {
- perror( "poll" );
- }
- }
- }
- //-------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement