Я преподаю класс, где я хотел бы показать студентам, как открыть сокет в C ++ и читать веб-страницы как http:, так и https: под Linux и Windows. Версия для Linux была легким OpenSSL. Но под Windows, используя библиотеку сокетов WSA от Microsoft, я мог читать только не-ssl-страницы. Я не могу понять, как получить их WSASetSocketSecurity () функция для работы.
С закомментированным вызовом WSASetSocketSecurity в следующем фрагменте кода я могу читать страницы http: (порт 80). Я могу подключения () на https: (порт 443) хосты, но пытается отправить запрос HTML GET, а затем RECV () сбой страницы, как и ожидалось, либо ничего не возвращено, либо страница с 400 ошибочными запросами с некоторых серверов, потому что я не согласовал шифрование.
Раскомментируя вызов WSASetSocketSecurity для гарантии шифрования, вызов connect всегда завершается неудачно с помощью WSAGetLastError = 10060 (Время ожидания истекло) на страницах http: и https :.
Вызов WSASetSocketSecurity, но указание разрешенных небезопасных подключений позволяет мне читать http: страницы, но происходит сбой с https: pages таким же образом, как если бы WSASetSocketSecurity вообще не вызывался.
По сути, я не могу включить шифрование, а затем подключиться, и я не знаю почему.
Я пробовал эксперименты по замене сокетов, подключений и других вызовов версиями WSAxxx (), представляя, что может быть различие, подобное тому, как вы выполняете вызов SSL_connect после подключения в Linux, но это не имеет значения. Единственное, что я могу вспомнить, это то, что я еще не пробовал, это аутентификация хоста с использованием WSASetSocketPeerTargetName (), но мне не кажется, что мне нужно это делать, если все, что я хочу, это ссылка SSL.
Что мне здесь не хватает? Кто-нибудь сделал эту работу?
// Initialize the socket library.
// wVersionRequested = 2.2 (current latest)
WSADATA wsaData;
int wsaStartupResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
assert( wsaStartupResult == 0 );
// Get the host address.
ADDRINFOA *addressInfo;
int addrInfoResult = getaddrinfo( url.Host, url.Service,
nullptr, &addressInfo );
assert( addrInfoResult == 0 );
sockaddr *socketAddress = addressInfo->ai_addr;
size_t socketAddressLength = addressInfo->ai_addrlen;
PrintAddress( socketAddress, socketAddressLength );
// Create a TCP/IP socket.
SOCKET s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
assert( s != INVALID_SOCKET );
// Turn on SSL.
SOCKET_SECURITY_SETTINGS security =
{
SOCKET_SECURITY_PROTOCOL_DEFAULT,
SOCKET_SETTINGS_GUARANTEE_ENCRYPTION
// SOCKET_SETTINGS_ALLOW_INSECURE
};
/*
int setSecurityResult = WSASetSocketSecurity( s,
&security, sizeof( security ), nullptr, nullptr );
assert( setSecurityResult == 0 );
*/
// Connect to the host.
int connectResult = connect( s, socketAddress, socketAddressLength );
if ( connectResult != 0 )
cerr << "Connect failed, WSAGetLastError = " << WSAGetLastError( ) << endl;
assert( connectResult == 0 );
// Send a GET message for the desired page.
string getMessage = "GET ";
getMessage += url.CompleteUrl;
getMessage += " HTTP/1.1\r\nHost: ";
getMessage += url.Host;
getMessage += "\r\nConnection: close\r\n\r\n";
cout << getMessage << endl;
send( s, getMessage.c_str( ), getMessage.length( ), 0 );
// Read from the socket until there's no more data.
HANDLE Stdout = GetStdHandle( STD_OUTPUT_HANDLE );
char buffer[ 10240 ];
int bytes;
DWORD length;
while ( ( bytes = recv( s, buffer, sizeof( buffer ), 0 ) ) > 0 )
WriteFile( Stdout, buffer, bytes, &length, nullptr );
freeaddrinfo( addressInfo );
closesocket( s );
WSACleanup( );
Ваше предположение, что защита сокетов включает SSL / TLS, неверно. Это на самом деле для обеспечения использования протокола IPsec. Увидеть Winsock Secure Socket Extensions. Если вам нужен SSL / TLS, вы должны использовать Безопасный канал (встроенная библиотека Windows SSL / TLS), OpenSSL или другая выделенная библиотека, работающая поверх сокетов.
Других решений пока нет …