Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] WinSock, brak odpowiedzi z serwera SMTP

Ostatnio zmodyfikowano 2018-12-17 14:28
Autor Wiadomość
Jah00
Temat założony przez niniejszego użytkownika
[C++] WinSock, brak odpowiedzi z serwera SMTP
» 2018-12-16 22:17:59
Witam, podczas nauki winsock postanowiłem napisać prosty program który połączy się z serwerem SMTP (dowolnym), i ewentualnie wyślę maila. Obecnie utknąłem na etapie odpowiedzi z serwera. Program poprawnie łączy się z zadanym serwerem (testowałem smtp.gmail.com na porcie 587), oto pierwsza wiadomość jaką dostaje z serwera:

220 smtp.gmail.com ESMTP d4sm11349893wrp.89 - gsmtp


Gdy wysyłam odpowiedź HELO lub EHLO z parametrem lub bez nie otrzymuje już nic więcej. Wklejam kod bo podejrzewam że w mojej pętli coś jest nie tak.


C/C++
#define _WIN32_WINNT 0x501
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <cstdlib>

int main()
{
    struct addrinfo * result = NULL;
    struct addrinfo hints;
   
    ZeroMemory( & hints, sizeof( hints ) ); // KONIECZNE
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    WSADATA wsaData;
   
    char recvbuf[ 512 ];
    char sendbuf[ 512 ];
    int bytesSent = 0;
    int bytesRecv = 0;
    ZeroMemory( & recvbuf, sizeof( recvbuf ) );
   
    if( WSAStartup( MAKEWORD( 2, 2 ), & wsaData ) )
    {
        std::cout << "Failed to startup wsa!\n";
        return 1;
    }
   
    if( getaddrinfo( "smtp.gmail.com", "587", & hints, & result ) )
    {
        std::cout << "Getaddrinfo error!\n";
        WSACleanup();
        return 1;
    };
   
    SOCKET mSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if( mSocket == INVALID_SOCKET )
    {
        std::cout << "Socket error: " << WSAGetLastError();
        WSACleanup();
        return 1;
    }
   
    if( connect( mSocket, result->ai_addr,( int ) result->ai_addrlen ) != 0 )
    {
        std::cout << "Unable to connect to server!\n";
        WSACleanup();
        return 1;
    }
   
   
    do
    {
        bytesRecv = recv( mSocket, recvbuf, 512, 0 );
        if( bytesRecv < 0 )
        {
            std::cout << "Connection closed!\n";
            return 1;
        }
        std::cout << recvbuf;
        std::cout << "> ";
        std::cin.getline( sendbuf, 512 );
        bytesSent = send( mSocket, sendbuf, strlen( sendbuf ), 0 );
    } while( bytesSent > 0 );
   
    closesocket( mSocket );
    WSACleanup();
   
    return 0;
}
P-173269
pekfos
» 2018-12-16 22:28:38
Nie wysyłasz znaku nowej linii po poleceniu.
P-173270
Jah00
Temat założony przez niniejszego użytkownika
» 2018-12-16 23:14:54
Teraz działa, jednak jak już wkleiłem cały kod to mam jeszcze pytanie, jak serwer zwróci wiadomość dłuższą niż 512 bajtów to podejrzewam że ona zostanie obcięta natomiast zastanawiam się jak najlepiej zrobić aby wszystko co wyśle serwer było wyświetlane a potem moja odpowiedź

Edit

I zapomniałem, mój warunek wyjścia z pętli i zakończenia połączenia też raczej nie jest najlepszy
P-173271
pekfos
» 2018-12-16 23:46:43
Nie ma uniwersalnego sposobu. Musisz sam to rozstrzygnąć na podstawie odebranych danych.
P-173272
Jah00
Temat założony przez niniejszego użytkownika
» 2018-12-17 13:33:24
Ok, mam jeszcze ostatnie pytanie co do samego serwera pocztowego. Nie znam się na tym za bardzo a nie mogę się zalogować. Po wpisaniu AUTH LOGIN wyskakują dodatkowe znaczki, a czego nie wpiszę to zostaję odrzucone i serwer nie wysyła nic więcej. Wrzucam ss:

https://postimg.cc/n9hKLbQC

STARTTLS jest wymagane, jeśli tego nie ma to serwer po wpisaniu AUTH LOGIN wyrzuci że najpierw trzeba STARTTLS. Próbowałem szukać w google, na jednej stronie znalazłem ss jak powinno wyglądać logowanie, po wpisaniu AUTH LOGIN serwer powinien zwrócić wiadomość o wpisaniu e-maila, jednak tak nie jest.
P-173278
pekfos
» 2018-12-17 13:54:14
Po poleceniu STARTTLS musisz przeprowadzić TLS handshake i dopiero potem możesz wysyłać dalsze polecenia SMTP, przy czym stan protokołu zostaje zresetowany, wiec zaczynasz od wysłania EHLO drugi raz. Wszystko co wysyłasz po ustanowieniu TLS jest już szyfrowane.

wyskakują dodatkowe znaczki
Bo twoje wyświetlanie jest błędne. recv() odbiera blok danych, nie tekst. Przekazanie bufora prosto do std::cout ma niezdefiniowane zachowanie.
P-173279
Jah00
Temat założony przez niniejszego użytkownika
» 2018-12-17 14:20:50
Ok rozumiem, a wiesz może jak wygląda przeprowadzenie tls handshake w praktyce?
P-173280
pekfos
» 2018-12-17 14:28:59
Najprościej z użyciem takich bibliotek jak OpenSSL.
P-173281
« 1 »
  Strona 1 z 1