我正在使用非阻塞DTLS服务器,并且无法解释来自SSL_read的响应。根据文档,当SSL_ERROR_WANT_READ
使用的套接字超时时,我应该得到SSL_read
,但是我一直得到SSL_ERROR_SYSCALL
。
这是我的服务器代码的一部分:
/* Initialize SSL Engine and context */
ctx = ssl_initialize();
/* Main loop */
done = false;
while (done != true) {
/* Create a new socket */
sock = create_ipv4_socket(4433);
printf("Listening on port %d\n", 4433);
client_len = sizeof(cliaddr);
do {
connfd = recvfrom(sock, (char *)&buff, sizeof(buff), MSG_PEEK, (struct sockaddr*)&cliaddr, &client_len);
if (connfd < 0) {
if (errno != EWOULDBLOCK) {
printf("recvfrom() failed: %s\n", strerror(errno));
ssl_cleanup(ctx);
exit(1);
}
}
} while (connfd < 0);
if (connect(sock, (const struct sockaddr *)&cliaddr, sizeof(cliaddr)) != 0) {
printf("UDP connect failed.\n");
ssl_cleanup(ctx);
exit(1);
} else {
printf("Connected to %s on port %d\n", inet_ntop(AF_INET, &(cliaddr.sin_addr), ipAddress, INET_ADDRSTRLEN), cliaddr.sin_port);
/* Create the OpenSSL object */
if ((ssl = SSL_new(ctx)) == NULL) {
ssl_print_error("SSL_new", SSL_get_error(ssl, 0));
ssl_cleanup(ctx);
exit(1);
}
/* Set the session ssl to client connection port */
SSL_set_fd(ssl, sock);
/* Accept the connection */
if (SSL_accept(ssl) != 1) {
ssl_print_error("SSL_accept", SSL_get_error(ssl, 0));
ssl_cleanup(ctx);
exit(1);
}
printf("%s data connection accepted, using cipher %s (%d bits)\n", SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl), SSL_get_cipher_bits(ssl, NULL));
bool blocking = false;
do {
if ((rx_length = SSL_read(ssl, buff, sizeof(buff))) > 0) {
buff[rx_length] = 0;
printf("Received 0x%04x bytes:\n", rx_length);
if (SSL_write(ssl, reply, sizeof(reply)) < 0) {
ssl_print_error("SSL_write", SSL_get_error(ssl, 0));
ssl_cleanup(ctx);
exit(1);
} else {
printf("Transmitted 0x%04x bytes:\n", (int)sizeof(reply));
blocking = false;
}
} else {
ssl_errno = SSL_get_error(ssl, 0);
printf("%i - %i\n", rx_length, ssl_errno);
if(ssl_errno != SSL_ERROR_WANT_READ){
ssl_print_error("SSL_read", ssl_errno);
ssl_cleanup(ctx);
exit(1);
} else
blocking = true;
}
} while (blocking == true);
printf("Closing connection\n");
SSL_shutdown(ssl);
SSL_free(ssl);
}
}
ssl_cleanup(ctx);
return 0;
}
/* Initialize OpenSSL and create a new SSL context */
SSL_CTX* ssl_initialize(void) {
SSL_CTX* ctx;
/* Initialize OpenSSL */
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
/* Set OpenSSL context to DTLS 1.2 */
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
if ((ctx = SSL_CTX_new(DTLSv1_2_server_method())) == NULL) {
printf("SSL_CTX_new error.\n");
exit(1);
}
#else
if ((ctx = SSL_CTX_new(DTLS_server_method())) == NULL) {
printf("SSL_CTX_new(DTLS_server_method) error.\n");
exit(1);
}
if (SSL_CTX_set_min_proto_version(ctx, DTLS1_2_VERSION) != 1) {
printf("Warning: dtls_InitContextFromKeystore: cannot set minimum supported protocol version\n");
}
#endif
/* Load CA certificates */
if (SSL_CTX_load_verify_locations(ctx, CA, 0) != 1) {
printf("Error loading %s, please check the file.\n", CA);
exit(1);
}
/* Load server certificates */
if (SSL_CTX_use_certificate_file(ctx, CERT, SSL_FILETYPE_PEM) != 1) {
printf("Error loading %s, please check the file.\n", CERT);
exit(1);
}
/* Load server Keys */
if (SSL_CTX_use_PrivateKey_file(ctx, PRIVKEY, SSL_FILETYPE_PEM) != 1) {
printf("Error loading %s, please check the file.\n", PRIVKEY);
exit(1);
}
if (SSL_CTX_check_private_key(ctx) != 1) {
printf("Private key %s not valid.\n", PRIVKEY);
exit(1);
}
return ctx;
}
/* Clean up the SSL context and shutdown the SSL engine */
void ssl_cleanup(SSL_CTX *ctx) {
SSL_CTX_free(ctx);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ERR_remove_thread_state(NULL);
#endif
ENGINE_cleanup();
CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup(); // Cleanup for OpenSSL_add_all_algorithms();
CRYPTO_cleanup_all_ex_data();
}
/* Print an user readable SSL error */
void ssl_print_error(const char *function, int sslerrno) {
printf("%s failed with error ", function);
switch (sslerrno) {
case SSL_ERROR_NONE :
printf("SSL_ERROR_NONE.\n");
break;
case SSL_ERROR_WANT_READ :
printf("SSL_ERROR_WANT_READ.\n");
break;
case SSL_ERROR_WANT_WRITE :
printf("SSL_ERROR_WANT_WRITE.\n");
break;
case SSL_ERROR_SYSCALL :
printf("SSL_ERROR_SYSCALL.\n");
break;
default :
printf("unknown error.\n");
break;
}
}
int create_ipv4_socket(unsigned short port) {
int sock, reuseconn, result;
struct timeval timeout;
struct sockaddr_in addr; /* our server's address */
/* Create a UDP/IP socket */
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
printf("create_ipv4_socket: socket() failed.\n");
return(-1);
}
/* Set IP header */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
/* Set socket to allow multiple connections */
reuseconn = 1;
if ((result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseconn, sizeof(reuseconn))) < 0) {
printf("create_ipv4_socket: setsockopt(SO_REUSEADDR) failed.\n");
return(-3);
}
/* Set timeout on socket to prevent recvfrom from blocking execution */
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
printf("_createSocket: Error setting timeout on socket");
}
/* Bind Socket */
if ((result = bind(sock, (struct sockaddr*)&addr, sizeof(addr))) < 0) {
printf("create_ipv4_socket: bind() failed.\n");
return(-4);
}
return(sock);
}
在客户端,我使用OpenSSL的内置客户端:
openssl s_client -dtls -connect 127.0.0.1 -port 4433
有人知道为什么我不断得到SSL_ERROR_SYSCALL
而不是预期的SSL_ERROR_WANT_READ
吗?预先非常感谢。
PS。我正在使用OpenSSL v1.1.0h-fips 2018年3月27日