【发布时间】:2018-10-01 21:00:40
【问题描述】:
我正在使用 OpenSSL 库来保护网络消息,但由于某种原因,它似乎并不总是有效。实际上大多数时候它是行不通的。当我运行编译后的代码并连接到套接字时,大多数时候它也只是在子进程中运行主进程的代码,但有时它会运行子指令。显然,这不是它应该工作的方式,孩子应该退出,在它一直处理客户端(handle_client(newfd))之后。一个有趣的部分是,如果我从子指令中删除handle_client(newfd) 行并在那里放一些小东西,比如printf("test"),那么孩子每次都按预期工作,它会打印测试并在此之后立即退出。这是 fork() 中的某种限制,还是我不应该在孩子身上运行这么多代码?或者是其他东西?任何帮助都会非常感激!
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/wait.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include "json.h"
#include "create_socket.h"
#include "get_addr.h"
#include "handle_income.h"
#include "handle_client.h"
int main(void) {
int newfd;
struct sockaddr_storage their_addr;
char s[INET6_ADDRSTRLEN];
pid_t pid;
unsigned int cpc = 0;
int listenfd = create_socket("8069");
if (listenfd < 0)
exit(1);
while(1) {
socklen_t sin_size = sizeof their_addr;
if ((newfd = accept(listenfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
continue;
inet_ntop(their_addr.ss_family,
get_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("conn %s siz %d\n", s, (int) sin_size); //REMOVE
if ((pid = fork()) < 0) {
exit(1);
} else if (pid == 0) {
close(listenfd);
handle_client(newfd);
exit(0);
}
printf("child %d\n", (int) pid); //REMOVE
cpc++;
while(cpc) {
pid = waitpid((pid_t) -1, NULL, WNOHANG);
if (pid < 0)
exit(1);
else if (pid == 0)
break;
else
cpc--;
}
}
EVP_cleanup();
exit(0);
}
handle_client.h:
#define READ_SIZE 32
void handle_client(int newfd) {
char *buffer = NULL;
char *tmp_buffer = malloc(READ_SIZE);
unsigned long buffer_size = 0;
unsigned long received = 0;
int status = 0;
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *sslctx = SSL_CTX_new(SSLv23_server_method());
if (sslctx) {
SSL_CTX_set_ecdh_auto(sslctx, 1);
if ((SSL_CTX_use_certificate_file(sslctx, "/ssl-cert.pem", SSL_FILETYPE_PEM)) > 0) {
if ((SSL_CTX_use_PrivateKey_file(sslctx, "/ssl-key.pem", SSL_FILETYPE_PEM)) > 0) {
SSL *ssl = SSL_new(sslctx);
SSL_set_fd(ssl, newfd);
if (SSL_accept(ssl) > 0) {
fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK);
do {
if (received >= buffer_size) {
char *tmp;
buffer_size += READ_SIZE;
if ((tmp = realloc(buffer, buffer_size)) == NULL) {
break;
} else {
buffer = tmp;
}
}
status = SSL_read(ssl, tmp_buffer, READ_SIZE);
if (status > 0) {
received += status;
strncat(buffer, tmp_buffer, status);
} else {
ERR_print_errors_fp(stderr);
}
} while (status > 0);
free(tmp_buffer);
buffer[received] = 0;
if (received < buffer_size) {
buffer = realloc(buffer, received);
}
printf("%s\n", buffer); //REMOVE
char *response = handle_income(buffer);
SSL_write(ssl, response, strlen(response));
printf("%s\n", response); //REMOVE
}
SSL_free(ssl);
}
}
}
SSL_CTX_free(sslctx);
close(newfd);
}
【问题讨论】:
-
目前还不清楚你得到了什么错误。请看minimal reproducible example
-
我知道我需要简约,但如果我喜欢将 handle_client(newfd) 替换为 printf("test") 那么结果将不一样。我想说的是,大部分代码对于重现错误很重要,但我肯定会删除多余的行。
-
我不是说要删除代码,而是要准确添加启动软件时发生的情况,它显示的内容...
-
“它不起作用”不是正确的错误描述。根据经验,当您遇到“不起作用”的事情时,请尝试回答这些不同的问题:您期望会发生什么?反而发生了什么?你为什么对这件事感到惊讶?
-
对不起,我误解了你的要求,那天我很累。我已经编辑了这个问题,希望现在可以理解了。
标签: c linux ssl networking openssl