/*! \file client-argc. */
/*!
* \note
add _CRT_SECURE_NO_WARNINGS to VS2019 option
*/
/*
* Copyright 2013-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <stdbool.h> // for false
#include <assert.h> // for assert()
#include <openssl/err.h>
#include <openssl/ssl.h>
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
#include <openssl/applink.c> /*! for OPENSSL_Uplink(00007FF8B7EF0FE8,08): no OPENSSL_Applink */
/*! client-arg.c 是个TLS客户端程序 */
int main(int argc, char** argv)
{
FILE* fpFileOut = NULL;
FILE* fpFileErr = NULL;
BIO* sbio = NULL, * out = NULL;
int len;
char tmpbuf[1024];
SSL_CTX* ctx;
SSL_CONF_CTX* cctx;
SSL* ssl;
char** args = argv + 1;
const char* connect_str = "localhost:4433";
int nargs = argc - 1;
int ret = EXIT_FAILURE;
do {
fpFileOut = fopen("prj_out.txt", "wb");
assert(NULL != fpFileOut);
fpFileErr = fopen("prj_log.log", "wb");
assert(NULL != fpFileErr);
ctx = SSL_CTX_new(TLS_client_method());
cctx = SSL_CONF_CTX_new();
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
// 可以由外面给定TLS服务器ip/port, 这里用connect_str
//while (*args && **args == '-') {
// int rv;
// /* Parse standard arguments */
// rv = SSL_CONF_cmd_argv(cctx, &nargs, &args);
// if (rv == -3) {
// fprintf(stderr, "Missing argument for %s\n", *args);
// goto end;
// }
// if (rv < 0) {
// fprintf(stderr, "Error in command %s\n", *args);
// ERR_print_errors_fp(stderr);
// goto end;
// }
// /* If rv > 0 we processed something so proceed to next arg */
// if (rv > 0)
// continue;
// /* Otherwise application specific argument processing */
// if (strcmp(*args, "-connect") == 0) {
// connect_str = args[1];
// if (connect_str == NULL) {
// fprintf(stderr, "Missing -connect argument\n");
// goto end;
// }
// args += 2;
// nargs -= 2;
// continue;
// } else {
// fprintf(stderr, "Unknown argument %s\n", *args);
// goto end;
// }
//}
if (!SSL_CONF_CTX_finish(cctx)) {
fprintf(fpFileErr, "Finish error\n");
ERR_print_errors_fp(fpFileErr);
break;
}
/*
* We'd normally set some stuff like the verify paths and * mode here
* because as things stand this will connect to * any server whose
* certificate is signed by any CA.
*/
/*! 从ssl上下文中来的bio */
sbio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(sbio, &ssl);
if (!ssl) {
fprintf(fpFileErr, "Can't locate SSL pointer\n");
break;
}
/* We might want to do other things with ssl here */
BIO_set_conn_hostname(sbio, connect_str);
/*! 从文件中来的bio
* 为了适应非命令行程序, 将stdout, stderr换成自己的实际文件FILE*
*/
out = BIO_new_fp(fpFileOut, BIO_NOCLOSE); /*!< OPENSSL_Uplink(00007FF8B7EF0FE8,08): no OPENSSL_Applink */
if (BIO_do_connect(sbio) <= 0) {
fprintf(fpFileErr, "Error connecting to server\n");
ERR_print_errors_fp(fpFileErr);
break;
}
/* Could examine ssl here to get connection info */
BIO_puts(sbio, "GET / HTTP/1.0\n\n");
for (;;) {
len = BIO_read(sbio, tmpbuf, 1024);
if (len <= 0)
break;
BIO_write(out, tmpbuf, len);
}
ret = EXIT_SUCCESS;
} while (false);
SSL_CONF_CTX_free(cctx); /*! 已经将ctx配置进了cctx, 所以不用释放ctx, 由cctx负责释放ctx */
/*! 由BIO_new_xx()来的BIO*, 必须调用BIO_free来释放 */
BIO_free_all(sbio); /*! 由ssl链接上下文来的bio*, 要调用BIO_free_all() */
BIO_free(out); /*! 由文件来的bio*, 调用BIO_free() */
if (NULL != fpFileOut)
{
fclose(fpFileOut);
fpFileOut = NULL;
}
if (NULL != fpFileErr)
{
fclose(fpFileErr);
fpFileErr = NULL;
}
printf("END\n");
return ret;
}