На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > Winsock. SMTP connection
      Всем привет. Недавно начал разбираться с сокетами, написал пару простых программ для обмена данными по локальной сети. Сейчас захотел попробовать подключиться к smtp-серверу для отправки email письма и возникли некоторые сложности, решения которых я не нашел в google.
      ExpandedWrap disabled
        DWORD SendMessage(const char * email, const char * msg, const char * from)
        {
                WSADATA _wsa;
                WSAStartup(MAKEWORD(2,2), &_wsa);
                hostent * h;
            int handle = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(handle <= 0)
                printf("Error with creation socket %i", GetLastError());
         
            char * em = getSMTPServer(email);
            h = gethostbyname(em);
            delete em;
            if(h == NULL)
            {
                printf("ERROR WITH GETTING HOSTBYNAME - %i\n", GetLastError());
                closesocket(handle);
                return EXIT_FAILURE;
            }
            sockaddr_in destination;
            destination.sin_family = AF_INET;
            destination.sin_port = htons(25);
            destination.sin_addr.s_addr = *((unsigned long *) h->h_addr);
            if(connect(handle,(const sockaddr *)&destination, sizeof(sockaddr_in) == SOCKET_ERROR))
            {
                printf("ERROR WITH CONNECT SMTP-SERVER - %i\n", GetLastError());
                closesocket(handle);
                return EXIT_FAILURE;
            }
         
                ...
         
               WSACleanup();
        }


      Функция getSMTPServer() самописная и возвращает smtp-сервер, основываясь на email-адресе.
      После вызова функции connect() возвращается SOCKET_ERROR и GetLastError() == 10014
        Тебе интересно чисто разобраться?

        Есть два момента, я не знаю с кем ты хочешь связать по 25 порту, но это обычный SMTP вроде и многие так уже не работают, а только с SSL ну и другим портом. И еще если ты пользуешься например gmail или еще кем не своим, полезь в настройки почты и сделай доступным для внешних программ.
          Цитата linuxoid @
          После вызова функции connect() возвращается SOCKET_ERROR и GetLastError() == 10014

          А что означает эта ошибка, ты посмотрел ?
          Попробуй так:
          ExpandedWrap disabled
              
            ..
            if(connect(handle,(const sockaddr *)&destination, sizeof(destination) == SOCKET_ERROR))
            ..

          connect, пример
          Исходники sources.ru
          Сообщение отредактировано: ЫукпШ -
            Цитата ter_nk_ @
            Тебе интересно чисто разобраться?

            Есть два момента, я не знаю с кем ты хочешь связать по 25 порту, но это обычный SMTP вроде и многие так уже не работают, а только с SSL ну и другим портом. И еще если ты пользуешься например gmail или еще кем не своим, полезь в настройки почты и сделай доступным для внешних программ.

            не просто разобраться, а сделать так, чтобы письмо все-таки отправилось куда нужно. Наткнулся на статью, в которой говорилось что smtp использует 25 порт, вот я и пробую, возможно, это и правда уже неактуально и следует пробовать другой порт. Но если я буду использовать порт с ssl тогда мне нужно использовать шифрование. Я хотел написать на чистом С, без подключения сторонних библиотек.
              Вполне возможно что самописная функция неверно формирует аргумент для gethostbyname()
              Проверьте - поле h_addr структуры hostent
              Скажем распечатайте.
                Цитата linuxoid @
                не просто разобраться, а сделать так, чтобы письмо все-таки отправилось куда нужно. Наткнулся на статью, в которой говорилось что smtp использует 25 порт, вот я и пробую, возможно, это и правда уже неактуально и следует пробовать другой порт. Но если я буду использовать порт с ssl тогда мне нужно использовать шифрование. Я хотел написать на чистом С, без подключения сторонних библиотек.


                А ты пробовал смотреть не статью, а конкретные настройки сервера, они могут убирать такие дыры безопасности, кто сейчас 25 порт использует?
                  Цитата ter_nk_ @
                  А ты пробовал смотреть не статью, а конкретные настройки сервера, они могут убирать такие дыры безопасности, кто сейчас 25 порт использует?

                  я попробовал.
                  Можно законнектится на smtp.mail.ru:25.
                  С операцией "connect" нет проблем.
                    Цитата ЫукпШ @
                    я попробовал.
                    Можно законнектится на smtp.mail.ru:25.
                    С операцией "connect" нет проблем.


                    С gmail это не пройдет.
                      Согласен, что почтовик может и требовать аутентификации, и совсем на другой порт и прочая.
                      Но в любом случае коннект все равно проходил бы, если связка Ip:port была бы реальной. А тут сам коннект не проходит - т.е. первый SYN не находит адресат...
                        Цитата ter_nk_ @
                        Цитата ЫукпШ @
                        я попробовал.
                        Можно законнектится на smtp.mail.ru:25.
                        С операцией "connect" нет проблем.


                        С gmail это не пройдет.

                        Предлагаешь все сервера проверять ?
                        user posted image
                          Извините не знал. У них в настройках для клиента указан только порт с SSL, да я думал на хрена типа оставлять обычный.
                            Именно поэтому я считаю что засада в формировании адреса почтовика...
                              Доброго всем дня. Не был дома несколько дней, не мог отвечать вам на форуме. По поводу ваших доводов о неправильной работе getSMTPServer(const char * email);
                              Возвращаемое значение функцией перед инициализацией gethostbyname();
                              Прикреплённая картинка
                              Прикреплённая картинка

                              структура hostent после инициализации:
                              Прикреплённая картинка
                              Прикреплённая картинка

                              Кажется, что все в порядке с этим
                                И тем не менее для коннекта эта ошибка обозначает неверно сформированный адрес назначения.
                                У меня вызывает подозрение приведение типа
                                destination.sin_addr.s_addr = *((unsigned long *) h->h_addr);
                                Такая запись характерна для связывания локального сокета для BIND на сервере.
                                Попробуйте привести к типу struct in_addr таким образом
                                destination.sin_addr = * ((struct in_addr *) h-> h_addr);
                                И еще проверка - просто возьмите значение возвращенное значение h_addr и посмотрите - получается ли IP-адрес назначения. Адрес идет уже в сетевом порядке.
                                  Цитата Oleg2004 @
                                  И тем не менее для коннекта эта ошибка обозначает неверно сформированный адрес назначения.
                                  У меня вызывает подозрение приведение типа
                                  destination.sin_addr.s_addr = *((unsigned long *) h->h_addr);
                                  Такая запись характерна для связывания локального сокета для BIND на сервере.
                                  Попробуйте привести к типу struct in_addr таким образом
                                  destination.sin_addr = * ((struct in_addr *) h-> h_addr);
                                  И еще проверка - просто возьмите значение возвращенное значение h_addr и посмотрите - получается ли IP-адрес назначения. Адрес идет уже в сетевом порядке.

                                  Попробовал изменить преобразование типов как указали Вы, но результата это особого не дало. Структура sin_addr заполнилась тем же самым IP-адресом, с которым я и пытался установить соединение.
                                  [attach=#0][/attach]

                                  Кстати, попробовал вывести на консоль значение h->h_addr;
                                  Результат следующий:
                                  [attach=#1][/attach]

                                  Возможно, в этом и таится проблема? или такое значение это норма?
                                  Сообщение отредактировано: linuxoid -

                                  Прикреплённая картинка
                                  Прикреплённая картинка

                                  Прикреплённая картинка
                                  Прикреплённая картинка
                                    Цитата Oleg2004 @
                                    Попробуйте привести к типу struct in_addr таким образом
                                    destination.sin_addr = * ((struct in_addr *) h-> h_addr);

                                    Тест я делал так:
                                    ExpandedWrap disabled
                                        hostent       *sh;
                                      //..
                                        sh = ::gethostbyname(pName);
                                      //..
                                        DWORD dwIP  = ((in_addr* )sh->h_addr)->s_addr;
                                      //..
                                       peer.sin_addr.s_addr = dwIP;
                                      //..
                                    Сообщение отредактировано: ЫукпШ -
                                      Скорее всего необходимые преобразования и приведения к типу можно выполнить несколькими способами. :)
                                      Однако эта хрень что на втором аттаче это вообще ни в какие ворота...
                                      ExpandedWrap disabled
                                        struct hostent
                                        {
                                           char *h_name;        /* Официальное имя хоста.*/
                                           char **h_aliases;    /* Массив псевдонимов данного хоста, заканчивающийся нулем */
                                           int  h_addrtype;     /* Тип возвращенного функцией адреса; для Интернет это AF_INET */
                                           int  h_length;       /* Длина адреса в байтах. Для типа AF_INET длина всегда 4 байта */
                                           char **h_addr_list;  /* Указатель на массив указателей IPv4 (IPv6) адресов хоста. Он заканчивается нулем, порядок  следования байтов сетевой. */
                                        #define h_addr h_addr_list[0]/*Определяет h_addr как самый первый адрес хоста в списке*/
                                        };

                                      Ведь h_addr - это 4-х байтовый адрес хоста в сетевом порядке.
                                      Я пропинговал и получилось
                                      Pinging smtp.mail.ru [94.100.180.160] with 32 bytes of data:
                                      Адрес именно тот, который у вас на первой картинке - в s_b1 s_b2 s_b3 s_b4
                                      А вот что и откуда взялось на второй? кракозябрыsmtp.mail.ru?
                                      Кстати, на той же первой картинке порт не 25-й, а 6400.
                                      Это так надо? Связка 94.100.180.160:6400 тоже даст bad address
                                      Кстати, было бы интересно посмотреть уходящий от коннекта первый TCP-SYN-сегмент программой типа TCPView, потому что в таблице TCP соединений соединение не зафиксировано, и адрес точки соединения там не виден.
                                      Сообщение отредактировано: Oleg2004 -
                                        Цитата Oleg2004 @
                                        Скорее всего необходимые преобразования и приведения к типу можно выполнить несколькими способами. :)

                                        Всё это будет работать:
                                        ExpandedWrap disabled
                                            dwIP  = ((in_addr* )sh->h_addr)->s_addr;
                                            dwIP  = *(DWORD *) sh->h_addr_list[0];
                                            dwIP  = *(DWORD *) sh->h_addr;

                                        Выяснилось вот что: результат connect-а зависит от провайдера.
                                        Или системного администратора.
                                        С домашнего компа connect всегда удачный. С рабочего компа - всегда нет.
                                        Кто-то запретил..
                                          Цитата ЫукпШ @
                                          С домашнего компа connect всегда удачный. С рабочего компа - всегда нет.
                                          Кто-то запретил..

                                          Ну, честно говоря я бы такие выводы не делал.
                                          Если бы такое происходило, реакция на коннект была бы другая.
                                          Все TCP- соединения начинаются с SYN-сегмента. И он должен уходить всегда. Если только на провайдере не отслеживаются все такие сегменты. Это практически невозможно. Т.е. бессмысленно. Разве что на каком то суперзасекреченном компе. :)

                                          Добавлено
                                          Однако судя по описанию ошибки
                                          Цитата
                                          Bad address (неверный адрес).
                                          Система обнаружила неверный указатель на адрес при попытке использовать его в вызове функции. Эта ошибка происходит при передачи приложением неверного указателя, или если размер буфера слишком мал - например, если длина аргумента, представляющего собой структуру типа sockaddr, меньше, чем sizeof(struct sockaddr).

                                          сегмент TCP вообще не инициируется.
                                          Т.е. из локального хоста он не уходит, так как функция встретила проблемы с указателем на ее параметр
                                          Блин, просто какой то бред - еще раз проверил код ТС - да нет, ошибки не вижу... :wall:

                                          Добавлено
                                          Единственная совершенно нетипичная команда для подобного кода, которая присутствует в коде, так это удаление аргумента функции gethost...
                                          ExpandedWrap disabled
                                            h = gethostbyname(em);
                                                delete em;

                                          Зачем???
                                          Сообщение отредактировано: Oleg2004 -
                                            Цитата Oleg2004 @
                                            Цитата ЫукпШ @
                                            С домашнего компа connect всегда удачный. С рабочего компа - всегда нет.
                                            Кто-то запретил..

                                            Ну, честно говоря я бы такие выводы не делал.
                                            Если бы такое происходило, реакция на коннект была бы другая.

                                            Да, я забыл упомянуть, что ошибка совсем другая.
                                            А именно - 10061. Очень часто это результат деятельности фиревола.
                                            В нашей организации так - что сделаешь..
                                            До smtp - сервера конторы я дотягиваюсь, а во внешнии сети - нет.
                                              Цитата ЫукпШ @
                                              А именно - 10061.

                                              :yes:
                                                Цитата Oleg2004 @

                                                ExpandedWrap disabled
                                                  h = gethostbyname(em);
                                                      delete em;

                                                Зачем???

                                                В переменной em хранится строка с адресом (smtp.mail.ru). После того, как я вызываю функцию gethostbyname() я очищаю память этой переменной, т.к. она больше не нужна.

                                                Добавлено
                                                Сейчас ради интереса попробовал пропинговать любой внешний хост и результат был отрицательный. Пинг таких хостов как google.com, mail.ru, yandex.ru, smtp.mail.ru заканчиваются тем, что команде ping не удается обнаружить данные узлы. Не сильный эксперт в сетях, но, кажется, что существует какая-то блокировка или какой-то прокси. Кстати, пингую я и запускаю программу не с домашнего компьютера, а с рабочего. И как упомянул [ЫукпШ] возможно, с рабочего компьютера connect всегда завершается ошибкой.
                                                Сообщение отредактировано: linuxoid -
                                                  Цитата linuxoid @
                                                  Пинг таких хостов как google.com, mail.ru, yandex.ru, smtp.mail.ru заканчиваются тем, что команде ping не удается обнаружить данные узлы. Не сильный эксперт в сетях, но, кажется, что существует какая-то блокировка или какой-то прокси. Кстати, пингую я и запускаю программу не с домашнего компьютера, а с рабочего.

                                                  С моего домашнего пингуются все.
                                                  Цитата
                                                  И как упомянул [ЫукпШ] возможно, с рабочего компьютера connect всегда завершается ошибкой.

                                                  Ну так что мешает вашу прогу запустить с домашнего???
                                                  Но еще раз повторю - коннект с ошибкой 10014 вообще не покидает комп.
                                                  Это не ошибка соединения или его блокировка файрволлом или провом. Это онибка в запуске коннекта - он вообще не запускается.
                                                  Цитата linuxoid @
                                                  В переменной em хранится строка с адресом (smtp.mail.ru). После того, как я вызываю функцию gethostbyname() я очищаю память этой переменной, т.к. она больше не нужна.

                                                  Это понятно... а смысл какой глубокий? Эта строка занимает пусть десяток байтов...Что за экономия?
                                                  Сообщение отредактировано: Oleg2004 -
                                                    Цитата Oleg2004 @
                                                    Цитата linuxoid @
                                                    Пинг таких хостов как google.com, mail.ru, yandex.ru, smtp.mail.ru заканчиваются тем, что команде ping не удается обнаружить данные узлы. Не сильный эксперт в сетях, но, кажется, что существует какая-то блокировка или какой-то прокси. Кстати, пингую я и запускаю программу не с домашнего компьютера, а с рабочего.

                                                    С моего домашнего пингуются все.
                                                    Цитата
                                                    И как упомянул [ЫукпШ] возможно, с рабочего компьютера connect всегда завершается ошибкой.

                                                    Ну так что мешает вашу прогу запустить с домашнего???
                                                    Но еще раз повторю - коннект с ошибкой 10014 вообще не покидает комп.
                                                    Это не ошибка соединения или его блокировка файрволлом или провом. Это онибка в запуске коннекта - он вообще не запускается.
                                                    Цитата linuxoid @
                                                    В переменной em хранится строка с адресом (smtp.mail.ru). После того, как я вызываю функцию gethostbyname() я очищаю память этой переменной, т.к. она больше не нужна.

                                                    Это понятно... а смысл какой глубокий? Эта строка занимает пусть десяток байтов...Что за экономия?

                                                    Экономии может и нет, но это уже привычка. Так научили. Ладно, я с ошибкой разобрался. Тему можно закрыть! Всем спасибо
                                                      Цитата linuxoid @
                                                      Ладно, я с ошибкой разобрался. Тему можно закрыть! Всем спасибо

                                                      Разобрались - это плюс. :)
                                                      А вот не поделились с коллегами о причине ее - это минус.
                                                      Мы тут старались, время свое тратили на поиск ошибки, пытаясь вам помочь, и на тебе...секрет.
                                                      Ведь форум учит не только ТС, но и всех других - чтобы они не делали подобных ошибок. <_<
                                                      А для закрытия темы нажмите справа вверху - Вопрос решен.
                                                      Сообщение отредактировано: Oleg2004 -
                                                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                      0 пользователей:


                                                      Рейтинг@Mail.ru
                                                      [ Script execution time: 0,0723 ]   [ 21 queries used ]   [ Generated: 29.03.24, 15:53 GMT ]