Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.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(); 1.png (, : 1195) структура hostent после инициализации: 2.png (, : 1139) Кажется, что все в порядке с этим |
Автор: 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 |
Разобрались - это плюс. А вот не поделились с коллегами о причине ее - это минус. Мы тут старались, время свое тратили на поиск ошибки, пытаясь вам помочь, и на тебе...секрет. Ведь форум учит не только ТС, но и всех других - чтобы они не делали подобных ошибок. А для закрытия темы нажмите справа вверху - Вопрос решен. |