deployd/client/main.c
Arija A. 2cabc6d883
Implement better error checking
Signed-off-by: Arija A. <ari@ari.lt>
2025-07-24 20:15:31 +03:00

186 lines
4.6 KiB
C

#include "include/conf.h"
#include <netdb.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "include/pow.h"
#include "include/main.h"
#include "include/proto.h"
#include "include/commands.h"
#include "server/include/pow.h"
#include "server/include/log.h"
#include "server/include/blake2s.h"
static dp_Logger dc_logger = {0};
static inline int dc_parse_commands(SSL *ssl, int argc, const char *argv[]) {
while (argc > 0) {
int ret = 0;
if (strcmp(*argv, "command") == 0) {
ret = dc_cmd_command(ssl, argc, argv, &dc_logger);
} else {
dp_lohf(&dc_logger, DP_LOG_ERROR, "Unknown packet: %s", *argv);
return 1;
}
if (ret < 1) {
dp_loh(&dc_logger, DP_LOG_ERROR, "Command failed");
return 1;
}
argc -= ret;
argv += ret;
}
return 0;
}
int main(const int argc, const char *argv[]) {
/* Initialize logger level */
dp_log_set_level(&dc_logger, DP_LOG_INFO);
if (argc < 4) {
dp_lohf(&dc_logger, DP_LOG_ERROR,
"Usage: %s <host> <port> <command...>", argv[0]);
return 1;
}
const char *hostname = argv[1];
const int port = atoi(argv[2]);
dp_log_set_target(&dc_logger, hostname);
/* Initialize OpenSSL */
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
dp_erh(&dc_logger, "Unsable to ignore SIGPIPE signal");
return 1;
}
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
/* Create an SSL context */
const SSL_METHOD *method = TLS_client_method();
SSL_CTX *ctx = SSL_CTX_new(method);
if (!ctx) {
dp_erh(&dc_logger, "Unable to create SSL context");
ERR_print_errors_fp(stderr);
return 1;
}
/* Resolve hostname */
struct hostent *host = gethostbyname(hostname);
if (!host) {
dp_lohf(&dc_logger, DP_LOG_ERROR, "Unable to resolve host: %s",
hostname);
SSL_CTX_free(ctx);
return 1;
}
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
dp_lohf(&dc_logger, DP_LOG_ERROR, "Unable to create socket: %s",
strerror(errno));
SSL_CTX_free(ctx);
return 1;
}
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) <
0) {
dp_loh(&dc_logger, DP_LOG_WARN,
"Failed to set receive timeout to 5 seconds");
SSL_CTX_free(ctx);
close(sockfd);
return 1;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) <
0) {
dp_loh(&dc_logger, DP_LOG_WARN,
"Failed to set send timeout to 5 seconds");
SSL_CTX_free(ctx);
close(sockfd);
return 1;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons((uint16_t)port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) !=
0) {
dp_lohf(&dc_logger, DP_LOG_ERROR, "Connection to %s:%d failed: %s",
hostname, port, strerror(errno));
close(sockfd);
SSL_CTX_free(ctx);
return 1;
}
/* Create SSL object and attach to socket */
SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, sockfd);
/* Perform SSL handshake */
if (SSL_connect(ssl) <= 0) {
dp_erh(&dc_logger, "SSL handshake failed");
ERR_print_errors_fp(stderr);
SSL_free(ssl);
close(sockfd);
SSL_CTX_free(ctx);
return 1;
}
dp_lohf(&dc_logger, DP_LOG_INFO, "Connected with %s encryption",
SSL_get_cipher(ssl));
int ret = 0;
/* Server info */
if (!dc_proto_read_server_info(ssl, &dc_logger)) {
dp_loh(&dc_logger, DP_LOG_FATAL, "Failed to read server information");
ret = 1;
goto finish;
}
/* Solve PoW */
if (!dc_proto_pow_solve(ssl, &dc_logger)) {
dp_loh(&dc_logger, DP_LOG_FATAL,
"Failed to solve proof-of-work challenge");
ret = 1;
goto finish;
}
/* Send command */
ret = dc_parse_commands(ssl, argc - 3, &argv[3]);
finish:
/* Cleanup */
dp_proto_exit(ssl);
SSL_shutdown(ssl);
SSL_free(ssl);
close(sockfd);
SSL_CTX_free(ctx);
dp_loh(&dc_logger, DP_LOG_INFO, "Connection closed");
return ret;
}