我正在尝试通过创建创建客户端和服务器套接字以在套接字之间回显字符串的程序来测试OpenSSL DTLS。但是,当我尝试测试DTLSv1_Listen()函数时,即使我不尝试在套接字之间连接或发送数据,我的程序似乎也暂停了。注意:我使用的是1.0.2 OpenSSL,这是在重写DTLSv1_Listen()之后的。
这是我完整的C++ winsock特定代码:
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//#include <openssl/applink.c>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
struct DTLSStuff { //struct to contain DTLS object instances
SSL_CTX *ctx;
SSL *ssl;
BIO *bio;
};
void DTLSErr() { //DTLS error reporting
ERR_print_errors_fp(stderr);
exit(1);
}
int newSocket(sockaddr_in addr) { //creates a socket and returns the file descriptor //TODO expand for multi-platform
WSADATA wsaData;
int fd;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); //Initialize Winsock
if (iResult != 0) { printf("WSAStartup failed: %d\n", iResult); exit(1); }
fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("Unable to create socket"); exit(1); } //create socket
printf("New Socket: %i\n", fd);
if (bind(fd, (struct sockaddr *)&addr, sizeof(sockaddr)) < 0) { printf("bind failed with error %u\n", WSAGetLastError()); exit(1); }
return fd; //file descriptor
}
void InitCTX(SSL_CTX *ctx, bool IsClient) { //Takes a ctx object and initializes it for DTLS communication
if (IsClient) {
if(SSL_CTX_use_certificate_chain_file(ctx, "client-cert.pem") < 0) { printf("Failed loading client cert");}
if(SSL_CTX_use_PrivateKey_file(ctx, "client-key.pem", SSL_FILETYPE_PEM) < 0) { printf("Failed loading client key"); }
}
else {
if (SSL_CTX_use_certificate_chain_file(ctx, "server-cert.pem") < 0) { printf("Failed loading client cert"); }
if (SSL_CTX_use_PrivateKey_file(ctx, "server-key.pem", SSL_FILETYPE_PEM) < 0) { printf("Failed loading client key"); }
}
//SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cert); //omitted for testing
//SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); //omitted for testing
//SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); //omitted for testing
SSL_CTX_set_read_ahead(ctx, 1);
}
int main() { //creates client and server sockets and DTLS objects. TODO: have client complete handshake with server socket and send a message and have the server echo it back to client socket
BIO_ADDR *faux_addr = BIO_ADDR_new(); // for DTLSv1_listen(), since we are this is both client and server (meaning client address is known) it is only used to satisfy parameters.
ERR_load_BIO_strings();
SSL_load_error_strings();
SSL_library_init();
//Set up addresses
sockaddr_in client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(25501);
client_addr.sin_addr.s_addr = INADDR_ANY;
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(25500);
server_addr.sin_addr.s_addr = INADDR_ANY;
//*********CLIENT
DTLSStuff ClientInf;
ClientInf.ctx = SSL_CTX_new(DTLSv1_client_method());
InitCTX(ClientInf.ctx,true);
int ClientFD = newSocket(client_addr);
ClientInf.bio = BIO_new_dgram(ClientFD, BIO_NOCLOSE);
ClientInf.ssl = SSL_new(ClientInf.ctx);
//SSL_set_options(ClientInf.ssl, SSL_OP_COOKIE_EXCHANGE); //omitted for testing
SSL_set_bio(ClientInf.ssl, ClientInf.bio, ClientInf.bio);
//*********SERVER
DTLSStuff ServerInf;
ServerInf.ctx = SSL_CTX_new(DTLSv1_server_method());
InitCTX(ServerInf.ctx,false);
int ServerFD = newSocket(server_addr);
ServerInf.bio = BIO_new_dgram(ServerFD, BIO_NOCLOSE);
ServerInf.ssl = SSL_new(ServerInf.ctx);
//SSL_set_options(ServerInf.ssl, SSL_OP_COOKIE_EXCHANGE); //omitted for testing
SSL_set_bio(ServerInf.ssl, ServerInf.bio, ServerInf.bio);
printf("Listen attempt...\n");
int ret = DTLSv1_listen(ServerInf.ssl, faux_addr);
if (ret < 0) { DTLSErr(); }
printf("this print should occur, but it never does");
exit(1);
}
我希望结果如下:
NewSocket: 356
NewSocket: 360
Listen attempt...
this print should occur but it never does
但是,在运行程序时,它永远不会打印最后一行。该程序似乎响应,因为我可以通过ctrl + c取消可执行文件,因此我假设它没有崩溃或冻结,但除此之外,我很茫然。我的理解是,如果什么都没发生,该方法应该返回0,如果听到clienthello,则返回> 1,如果发生错误,则返回<0。
此外,还有一个相关的问题:由于DTLSv1_Listen()需要BIO_ADDR来存储传入的请求地址,这是否意味着单独的客户端和服务器程序如果要能够发送和侦听,都将需要2个套接字?通常,UDP客户端和服务器仅需要一个套接字,但是我似乎无法找到一种通过OpenSSL的DTLS保留该套接字的设计。
多谢您的宝贵时间。
最佳答案
我看不到代码中将套接字设置为非阻塞状态。在默认阻止模式下,当您尝试从套接字读取数据时,程序将暂停直到数据到达。如果您不希望这样做,请确保设置适当的选项(我不是Windows程序员,但ioctlsocket似乎可以完成工作:https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx)
does that mean that separate client and servers programs will both require 2 sockets if they want to be able to both send and listen
使用DTLSv1_listen()时,您使用的套接字处于未连接状态,因此您可能会收到来自多个客户端的UDP数据包。 DTLS基于连接,因此一旦DTLSv1_listen()成功返回,您应该创建一个到客户端地址的“已连接”套接字。因此,您有一个用于监听新连接的套接字,每个客户端与您的服务器进行通信时有一个套接字。
关于c++ - OpenSSL的DTLSv1_Listen()在运行时暂停程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47665360/