Advertisement
Guest User

pop3_check.c

a guest
Dec 11th, 2019
190
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.92 KB | None | 0 0
  1. //  Программа проверяет работоспособность POP3 сервера
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <errno.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <sys/select.h>
  9. #include <netdb.h>
  10. #include <poll.h>
  11.  
  12. //-------------------------------------------------------------------
  13. #define RETCODE_SUCCESS 0
  14. #define RETCODE_ERROR   1
  15. #define POLL_TIMEOUT    5000
  16. #define APP_NAME    "pop3_check"
  17. #define DEFAULT_POP3_PORT   "110"
  18. #define BUF_SIZE    256
  19. //-------------------------------------------------------------------
  20.  
  21. //-------------------------------------------------------------------
  22. //  Прототипы функций
  23. //-------------------------------------------------------------------
  24. //  Функция создает клиентское подключение к серверу с именем srv_name
  25. //  на порт srv_port и, в случае успеха, возвращает по указателю
  26. //  client_fd файловый дескриптор сокета для этого соединения.
  27. //  При этом сама функция возвращает 1. Если же произошла неудача, то
  28. //  функция возвращает 0, а по указателю client_fd будет записано
  29. //  число -1
  30. int create_client_socket( const char* srv_name,
  31.         const char* srv_port, int* client_fd );
  32. //  Обходит связанный список структур addrinfo и пытается установить
  33. //  соединение на основе его данных
  34. //  Возвращает 1 в случае успеха и 0 при неудаче
  35. int try_connect( struct  addrinfo* ai_list, int* client_fd );
  36. //  Закрывает сокет
  37. void    close_socket( int sock_fd );
  38. //  Читает ответ сервера, ожидая его не более ms_timeout миллисекунд
  39. void    read_server_response( int sock_fd, int ms_timeout );
  40. //-------------------------------------------------------------------
  41.  
  42. int main( int argc, char* argv[] )
  43. {
  44.     int retcode = RETCODE_SUCCESS;
  45.     int sock_fd;
  46.     const   char*   port = DEFAULT_POP3_PORT;
  47.  
  48.     if( argc > 1 )
  49.     {
  50.         if( argc > 2 )
  51.         {
  52.             port = argv[2];
  53.         }
  54.            
  55.         if( create_client_socket( argv[1], port, &sock_fd ) )
  56.         {
  57.             printf( "Соединение установлено\n" );
  58.  
  59.             //  Пообщаемся с сервером через сокет
  60.             read_server_response( sock_fd, POLL_TIMEOUT );
  61.  
  62.             close_socket( sock_fd );
  63.         }
  64.         else
  65.         {
  66.             retcode = RETCODE_ERROR;
  67.         }
  68.     }
  69.     else
  70.     {
  71.         printf( "Usage: %s <pop3_server_name> [port]\n", APP_NAME );
  72.     }
  73.  
  74.     return  retcode;
  75. }
  76. //-------------------------------------------------------------------
  77. void    close_socket( int sock_fd )
  78. {
  79.     //  Флаг повторного вызова, если нашу функцию прервут
  80.     int retry_flag;
  81.     do
  82.     {
  83.         retry_flag = 0;
  84.         if( close( sock_fd ) != 0 )
  85.         {
  86.             //  Прервали сигналом?
  87.             if( errno == EINTR )
  88.             {
  89.                 //  Попробуем еще разок
  90.                 retry_flag++;
  91.             }
  92.             else
  93.             {
  94.                 perror( "close" );
  95.             }
  96.         }
  97.     }
  98.     while( retry_flag );
  99. }
  100. //-------------------------------------------------------------------
  101. //  Обходим связанный список структур addrinfo и пытаемся установить
  102. //  соединение на основе его данных
  103. //  Возвращает 1 в случае успеха и 0 при неудаче
  104. int try_connect( struct  addrinfo* ai_list, int* client_fd )
  105. {
  106.     int result = 0;
  107.         //      Указатель на текущий элемент связанного списка
  108.         struct  addrinfo*       ai_ptr;
  109.     //  Если все пойдет пучком, то тут будет дескриптор сокета
  110.     int sock_fd;
  111.  
  112.     ai_ptr = ai_list;
  113.     while( ai_ptr )
  114.     {
  115.         //  Попробуем создать сокет
  116.         sock_fd = socket( ai_ptr -> ai_family,
  117.             ai_ptr -> ai_socktype, ai_ptr -> ai_protocol );
  118.         if( sock_fd != -1 )
  119.         {
  120.             //  Попробуем соединиться с сервером
  121.             if( connect( sock_fd, ai_ptr->ai_addr,
  122.                     ai_ptr->ai_addrlen ) == 0 )
  123.             {
  124.                 result++;
  125.                 //  Вернем дескриптор клиентского сокета
  126.                 *client_fd = sock_fd;
  127.                 break;
  128.             }
  129.             //  Попытка соединения не удалась, закроем сокет
  130.             else
  131.             {
  132.                 close_socket( sock_fd );
  133.                 perror( "connect" );
  134.             }
  135.         }
  136.         else
  137.         {
  138.             perror( "socket" );
  139.         }
  140.         ai_ptr = ai_ptr -> ai_next;
  141.     }
  142.  
  143.     return  result;
  144. }
  145. //-------------------------------------------------------------------
  146. //  Функция создает клиентское подключение к серверу с именем srv_name
  147. //  на порт srv_port и, в случае успеха, возвращает по указателю
  148. //  client_fd файловый дескриптор сокета для этого соединения.
  149. //  При этом сама функция возвращает 1. Если же произошла неудача, то
  150. //  функция возвращает 0, а по указателю client_fd будет записано
  151. //  число -1
  152. int create_client_socket( const char* srv_name,
  153.         const char* srv_port, int* client_fd )
  154. {
  155.     int result = 0;
  156.     //  Флаг повторного вызова, если нашу функцию прервут
  157.     int retry_flag;
  158.     //  Результат завершения функции getaddrinfo
  159.     int r;
  160.         //      Структуры данных для getaddrinfo
  161.         //      В этой структуре устанавливаются "фильтры" для выдаваемых
  162.         //      функцией адресов
  163.         struct  addrinfo        hints;
  164.         //      Указатель на возвращаемый связанный список структур
  165.         //      с информацией об адресах
  166.         struct  addrinfo*       ai_list;
  167.         //      Структура для хранения данных сокета
  168.         struct  sockaddr_storage        sstor;
  169.  
  170.  
  171.     //  Для файловых дескрипторов значение -1 - это ошибка, поэтому
  172.     //  сразу установим его в ошибочное значение
  173.     *client_fd = -1;
  174.  
  175.     if( srv_name && srv_port )
  176.     {
  177.             //      Подготовим структуры
  178.             memset( &hints, 0, sizeof(struct addrinfo) );
  179.             memset( &sstor, 0, sizeof(struct sockaddr_storage) );
  180.  
  181.             //      Заполним структуру с фильтрами-подсказками
  182.             hints.ai_family = AF_UNSPEC;     // Обрабатываем IPv4 и IPv6
  183.             hints.ai_socktype = SOCK_STREAM; // Потоковый сокет
  184.             hints.ai_protocol = IPPROTO_TCP; // Нам нужен tcp
  185.  
  186.         //  Исходим из оптимистичной стратегии, что все сработает
  187.         //  с первого раза и нам не помешают
  188.         retry_flag = 0;
  189.         do
  190.         {
  191.             ai_list = NULL; //  Пустой список
  192.             r = getaddrinfo( srv_name, srv_port,
  193.                     &hints, &ai_list );
  194.             //  Посмотрим, что у нас получилось
  195.             if( r == 0 )
  196.             {
  197.                 //  С одним именем может быть связано
  198.                 //  много адресов, поэтому getaddrinfo
  199.                 //  возвращает не одно значение а много
  200.                 //  в виде связанного списка
  201.                 //  Обойдем список и будем пробовать
  202.                 //  соединиться с адресами
  203.                 result = try_connect( ai_list, client_fd );
  204.             }
  205.             //  Что-то пошло не так :(
  206.             else
  207.             {
  208.                 if( r == EAI_AGAIN )
  209.                 {
  210.                     //  Попробуем еще разок
  211.                     retry_flag++;
  212.                 }
  213.                 else
  214.                 {
  215.                     //  Полный писец
  216.                     perror( "getaddrinfo" );
  217.                 }
  218.             }
  219.             if( ai_list )
  220.             {
  221.                 //  Осовободим память
  222.                 freeaddrinfo( ai_list );
  223.             }
  224.         }
  225.         while( retry_flag );
  226.     }
  227.  
  228.     return  result;
  229. }
  230. //-------------------------------------------------------------------
  231. //  Читает ответ сервера, ожидая его не более ms_timeout миллисекунд
  232. void    read_server_response( int sock_fd, int ms_timeout )
  233. {
  234.     //      Структура с данными, описывающими файловый дескриптор
  235.     struct  pollfd  pfd;
  236.     int pr; //  poll result
  237.     char    buf[ BUF_SIZE ];
  238.     ssize_t len;
  239.  
  240.     //  Подготовим структуру для poll
  241.     memset( &pfd, 0, sizeof(struct pollfd) );
  242.     pfd.fd = sock_fd;
  243.     //  Будем отслеживать событие "Появились данные для чтения"
  244.     pfd.events = POLLIN;
  245.  
  246.     printf( "Ожидаю ответ сервера (не более %d мс)\n", ms_timeout );
  247.     fflush( stdout );
  248.  
  249.     pr = poll( &pfd, 1, ms_timeout );
  250.     if( pr == 0 )
  251.     {
  252.         printf( "Нет ответа от сервера. Выход по таймауту\n" );
  253.     }
  254.     else
  255.     {
  256.         if( pr > 0 )
  257.         {
  258.             //  Есть данные для чтения
  259.             len = read( sock_fd, buf, BUF_SIZE-1 );
  260.             if( len != -1 )
  261.             {
  262.                 if( len )
  263.                 {
  264.                     //  Терминируем буфер
  265.                     buf[ len ] = '\0';
  266.                     //  Уберем перевод строки
  267.                     while( len  )
  268.                     {
  269.                         if( buf[len-1] == '\n' )
  270.                         {
  271.                             len--;
  272.                             buf[ len ]='\0';
  273.                         }
  274.                         else
  275.                         if( buf[len-1] == '\r' )
  276.                         {
  277.                             len--;
  278.                             buf[ len ]='\0';
  279.                         }
  280.                         else
  281.                         {
  282.                             break;
  283.                         }
  284.                     }
  285.                    
  286.                     printf( "Ответ от сервера: '%s'\n",
  287.                             buf );
  288.                 }
  289.             }
  290.             else
  291.             {
  292.                 printf( "Ошибка чтения из сокета!\n" );
  293.             }
  294.         }
  295.         else
  296.         {
  297.             perror( "poll" );
  298.         }
  299.     }
  300. }
  301. //-------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement