Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > C/C++: Сетевое программирование > Winsock. SMTP connection |
Автор: linuxoid 01.12.17, 05:21 |
Всем привет. Недавно начал разбираться с сокетами, написал пару простых программ для обмена данными по локальной сети. Сейчас захотел попробовать подключиться к smtp-серверу для отправки email письма и возникли некоторые сложности, решения которых я не нашел в google. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 |
Автор: ter_nk_ 01.12.17, 06:07 |
Тебе интересно чисто разобраться? Есть два момента, я не знаю с кем ты хочешь связать по 25 порту, но это обычный SMTP вроде и многие так уже не работают, а только с SSL ну и другим портом. И еще если ты пользуешься например gmail или еще кем не своим, полезь в настройки почты и сделай доступным для внешних программ. |
Автор: ЫукпШ 01.12.17, 17:53 |
Цитата linuxoid @ После вызова функции connect() возвращается SOCKET_ERROR и GetLastError() == 10014 А что означает эта ошибка, ты посмотрел ? Попробуй так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> .. if(connect(handle,(const sockaddr *)&destination, sizeof(destination) == SOCKET_ERROR)) .. connect, пример Исходники sources.ru |
Автор: linuxoid 01.12.17, 18:34 |
Цитата ter_nk_ @ Тебе интересно чисто разобраться? Есть два момента, я не знаю с кем ты хочешь связать по 25 порту, но это обычный SMTP вроде и многие так уже не работают, а только с SSL ну и другим портом. И еще если ты пользуешься например gmail или еще кем не своим, полезь в настройки почты и сделай доступным для внешних программ. не просто разобраться, а сделать так, чтобы письмо все-таки отправилось куда нужно. Наткнулся на статью, в которой говорилось что smtp использует 25 порт, вот я и пробую, возможно, это и правда уже неактуально и следует пробовать другой порт. Но если я буду использовать порт с ssl тогда мне нужно использовать шифрование. Я хотел написать на чистом С, без подключения сторонних библиотек. |
Автор: Oleg2004 01.12.17, 19:37 |
Вполне возможно что самописная функция неверно формирует аргумент для gethostbyname() Проверьте - поле h_addr структуры hostent Скажем распечатайте. |
Автор: ter_nk_ 02.12.17, 06:40 |
Цитата linuxoid @ не просто разобраться, а сделать так, чтобы письмо все-таки отправилось куда нужно. Наткнулся на статью, в которой говорилось что smtp использует 25 порт, вот я и пробую, возможно, это и правда уже неактуально и следует пробовать другой порт. Но если я буду использовать порт с ssl тогда мне нужно использовать шифрование. Я хотел написать на чистом С, без подключения сторонних библиотек. А ты пробовал смотреть не статью, а конкретные настройки сервера, они могут убирать такие дыры безопасности, кто сейчас 25 порт использует? |
Автор: ЫукпШ 02.12.17, 11:51 |
Цитата ter_nk_ @ А ты пробовал смотреть не статью, а конкретные настройки сервера, они могут убирать такие дыры безопасности, кто сейчас 25 порт использует? я попробовал. Можно законнектится на smtp.mail.ru:25. С операцией "connect" нет проблем. |
Автор: ter_nk_ 02.12.17, 12:51 |
Цитата ЫукпШ @ я попробовал. Можно законнектится на smtp.mail.ru:25. С операцией "connect" нет проблем. С gmail это не пройдет. |
Автор: Oleg2004 02.12.17, 14:13 |
Согласен, что почтовик может и требовать аутентификации, и совсем на другой порт и прочая. Но в любом случае коннект все равно проходил бы, если связка Ip:port была бы реальной. А тут сам коннект не проходит - т.е. первый SYN не находит адресат... |
Автор: ЫукпШ 02.12.17, 14:29 |
Цитата ter_nk_ @ Цитата ЫукпШ @ я попробовал. Можно законнектится на smtp.mail.ru:25. С операцией "connect" нет проблем. С gmail это не пройдет. Предлагаешь все сервера проверять ? ![]() |
Автор: ter_nk_ 02.12.17, 14:47 |
Извините не знал. У них в настройках для клиента указан только порт с SSL, да я думал на хрена типа оставлять обычный. |
Автор: Oleg2004 02.12.17, 14:51 |
Именно поэтому я считаю что засада в формировании адреса почтовика... |
Автор: linuxoid 05.12.17, 06:39 |
Доброго всем дня. Не был дома несколько дней, не мог отвечать вам на форуме. По поводу ваших доводов о неправильной работе getSMTPServer(const char * email); Возвращаемое значение функцией перед инициализацией gethostbyname(); ![]() структура hostent после инициализации: ![]() Кажется, что все в порядке с этим |
Автор: Oleg2004 05.12.17, 09:37 |
И тем не менее для коннекта эта ошибка обозначает неверно сформированный адрес назначения. У меня вызывает подозрение приведение типа 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-адрес назначения. Адрес идет уже в сетевом порядке. |
Автор: linuxoid 05.12.17, 10:17 |
Цитата 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] Возможно, в этом и таится проблема? или такое значение это норма? |
Автор: ЫукпШ 05.12.17, 12:16 |
Цитата Oleg2004 @ Попробуйте привести к типу struct in_addr таким образом destination.sin_addr = * ((struct in_addr *) h-> h_addr); Тест я делал так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> hostent *sh; //.. sh = ::gethostbyname(pName); //.. DWORD dwIP = ((in_addr* )sh->h_addr)->s_addr; //.. peer.sin_addr.s_addr = dwIP; //.. |
Автор: Oleg2004 05.12.17, 15:38 |
Скорее всего необходимые преобразования и приведения к типу можно выполнить несколькими способами. ![]() Однако эта хрень что на втором аттаче это вообще ни в какие ворота... <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> 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 соединений соединение не зафиксировано, и адрес точки соединения там не виден. |
Автор: ЫукпШ 06.12.17, 18:21 |
Цитата Oleg2004 @ Скорее всего необходимые преобразования и приведения к типу можно выполнить несколькими способами. ![]() Всё это будет работать: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> dwIP = ((in_addr* )sh->h_addr)->s_addr; dwIP = *(DWORD *) sh->h_addr_list[0]; dwIP = *(DWORD *) sh->h_addr; Выяснилось вот что: результат connect-а зависит от провайдера. Или системного администратора. С домашнего компа connect всегда удачный. С рабочего компа - всегда нет. Кто-то запретил.. |
Автор: Oleg2004 06.12.17, 20:05 |
Цитата ЫукпШ @ С домашнего компа connect всегда удачный. С рабочего компа - всегда нет. Кто-то запретил.. Ну, честно говоря я бы такие выводы не делал. Если бы такое происходило, реакция на коннект была бы другая. Все TCP- соединения начинаются с SYN-сегмента. И он должен уходить всегда. Если только на провайдере не отслеживаются все такие сегменты. Это практически невозможно. Т.е. бессмысленно. Разве что на каком то суперзасекреченном компе. ![]() Добавлено Однако судя по описанию ошибки Цитата Bad address (неверный адрес). Система обнаружила неверный указатель на адрес при попытке использовать его в вызове функции. Эта ошибка происходит при передачи приложением неверного указателя, или если размер буфера слишком мал - например, если длина аргумента, представляющего собой структуру типа sockaddr, меньше, чем sizeof(struct sockaddr). сегмент TCP вообще не инициируется. Т.е. из локального хоста он не уходит, так как функция встретила проблемы с указателем на ее параметр Блин, просто какой то бред - еще раз проверил код ТС - да нет, ошибки не вижу... ![]() Добавлено Единственная совершенно нетипичная команда для подобного кода, которая присутствует в коде, так это удаление аргумента функции gethost... <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> h = gethostbyname(em); delete em; Зачем??? |
Автор: ЫукпШ 06.12.17, 21:14 |
Цитата Oleg2004 @ Цитата ЫукпШ @ С домашнего компа connect всегда удачный. С рабочего компа - всегда нет. Кто-то запретил.. Ну, честно говоря я бы такие выводы не делал. Если бы такое происходило, реакция на коннект была бы другая. Да, я забыл упомянуть, что ошибка совсем другая. А именно - 10061. Очень часто это результат деятельности фиревола. В нашей организации так - что сделаешь.. До smtp - сервера конторы я дотягиваюсь, а во внешнии сети - нет. |
Автор: Oleg2004 06.12.17, 21:17 |
![]() |
Автор: linuxoid 07.12.17, 04:16 |
В переменной em хранится строка с адресом (smtp.mail.ru). После того, как я вызываю функцию gethostbyname() я очищаю память этой переменной, т.к. она больше не нужна. Добавлено Сейчас ради интереса попробовал пропинговать любой внешний хост и результат был отрицательный. Пинг таких хостов как google.com, mail.ru, yandex.ru, smtp.mail.ru заканчиваются тем, что команде ping не удается обнаружить данные узлы. Не сильный эксперт в сетях, но, кажется, что существует какая-то блокировка или какой-то прокси. Кстати, пингую я и запускаю программу не с домашнего компьютера, а с рабочего. И как упомянул [ЫукпШ] возможно, с рабочего компьютера connect всегда завершается ошибкой. |
Автор: Oleg2004 07.12.17, 14:43 |
Цитата linuxoid @ Пинг таких хостов как google.com, mail.ru, yandex.ru, smtp.mail.ru заканчиваются тем, что команде ping не удается обнаружить данные узлы. Не сильный эксперт в сетях, но, кажется, что существует какая-то блокировка или какой-то прокси. Кстати, пингую я и запускаю программу не с домашнего компьютера, а с рабочего. С моего домашнего пингуются все. Цитата И как упомянул [ЫукпШ] возможно, с рабочего компьютера connect всегда завершается ошибкой. Ну так что мешает вашу прогу запустить с домашнего??? Но еще раз повторю - коннект с ошибкой 10014 вообще не покидает комп. Это не ошибка соединения или его блокировка файрволлом или провом. Это онибка в запуске коннекта - он вообще не запускается. Цитата linuxoid @ В переменной em хранится строка с адресом (smtp.mail.ru). После того, как я вызываю функцию gethostbyname() я очищаю память этой переменной, т.к. она больше не нужна. Это понятно... а смысл какой глубокий? Эта строка занимает пусть десяток байтов...Что за экономия? |
Автор: linuxoid 07.12.17, 17:40 |
Цитата Oleg2004 @ Цитата linuxoid @ Пинг таких хостов как google.com, mail.ru, yandex.ru, smtp.mail.ru заканчиваются тем, что команде ping не удается обнаружить данные узлы. Не сильный эксперт в сетях, но, кажется, что существует какая-то блокировка или какой-то прокси. Кстати, пингую я и запускаю программу не с домашнего компьютера, а с рабочего. С моего домашнего пингуются все. Цитата И как упомянул [ЫукпШ] возможно, с рабочего компьютера connect всегда завершается ошибкой. Ну так что мешает вашу прогу запустить с домашнего??? Но еще раз повторю - коннект с ошибкой 10014 вообще не покидает комп. Это не ошибка соединения или его блокировка файрволлом или провом. Это онибка в запуске коннекта - он вообще не запускается. Цитата linuxoid @ В переменной em хранится строка с адресом (smtp.mail.ru). После того, как я вызываю функцию gethostbyname() я очищаю память этой переменной, т.к. она больше не нужна. Это понятно... а смысл какой глубокий? Эта строка занимает пусть десяток байтов...Что за экономия? Экономии может и нет, но это уже привычка. Так научили. Ладно, я с ошибкой разобрался. Тему можно закрыть! Всем спасибо |
Автор: Oleg2004 07.12.17, 19:03 |
Разобрались - это плюс. ![]() А вот не поделились с коллегами о причине ее - это минус. Мы тут старались, время свое тратили на поиск ошибки, пытаясь вам помочь, и на тебе...секрет. Ведь форум учит не только ТС, но и всех других - чтобы они не делали подобных ошибок. ![]() А для закрытия темы нажмите справа вверху - Вопрос решен. |