#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define MAXBUF 1024 * 100
#define SERVER_CERT "cert.pem"
#define SERVER_KEY "key.pem"
const char *rootKey = "123456";
/*自动填入密码*/
int PemPasswdCb(char *buf, int size, int rwflag, void *password)
{
strncpy(buf, (char *)(password), size);
buf[size - 1] = '\0';
return(strlen(buf));
}
/*openssl库的初始化*/
void LibSslInit()
{
SSL_library_init(); /* 为SSL加载加密和哈希算法 */
OpenSSL_add_all_algorithms();/* 加载加密算法函数和单向散列算法函数 */
SSL_load_error_strings();/* 为了更友好的报错,加载错误码的描述字符串 */
}
/*启动服务器监听*/
int StartListenServer(unsigned int portnum)
{
struct sockaddr_in my_addr;
int listenfd = -1;
int reuse = 1;
int lisnum = 5;
int ret = -1;
listenfd = socket(PF_INET, SOCK_STREAM, 0);
if (listenfd == -1) {
perror("socket");
exit(1);
}
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
if (ret < 0) {
printf("setsockopet error\n");
return -1;
}
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(portnum);
my_addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(listenfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr));
if (ret == -1) {
perror("bind");
exit(1);
}
ret = listen(listenfd, lisnum);
if (ret == -1) {
perror("listen");
exit(1);
}
return listenfd;
}
/*加载配置文件*/
void SslLoadConf(SSL_CTX *ctx)
{
/*加载公钥证书*/
if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stdout);
exit(1);
}
/*设置私钥*/
if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
printf("use private key fail.\n");
ERR_print_errors_fp(stdout);
exit(1);
}
if (!SSL_CTX_check_private_key(ctx)) {
ERR_print_errors_fp(stdout);
exit(1);
}
}
/*设置密码从程序里面读取*/
void SslSetPassWd(SSL_CTX *ctx)
{
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)rootKey);
SSL_CTX_set_default_passwd_cb(ctx, PemPasswdCb);
}
/*构造响应消息*/
int BuildSendBuf(char *buf, int maxBufLen)
{
int bufLen = 0;
char fileBuf[1024] = {0};
int i;
for (i = 0; i < 1024; i++)
{
fileBuf[i] = '1';
}
bufLen += snprintf(buf, maxBufLen, "%s", "HTTP/1.1 200 OK\r\n Server: Apache/1.1\r\n Content-Length:1024\r\n Content-Type:text/plain\r\n");
bufLen += snprintf(buf + bufLen, maxBufLen, "%s", fileBuf);
return bufLen;
}
/*处理SSL连接*/
int HandleSslConnect(SSL_CTX *ctx, int clientfd)
{
SSL *ssl = NULL;
char buf[MAXBUF + 1];
int i = 0;
int bufLen = 0;
int ret = -1;
int len;
ssl = SSL_new(ctx);
SSL_set_fd(ssl, clientfd);
if (SSL_accept(ssl) == -1) {
perror("ssl accept");
ret = -1;
goto finish;
}
bzero(buf, MAXBUF + 1);
len = SSL_read(ssl, buf, MAXBUF);
if (len <= 0) {
printf("read msg failed");
ret = -1;
goto finish;
}
printf("recv buf is %s.\n", buf);
bufLen = BuildSendBuf(buf, MAXBUF);
len = SSL_write(ssl, buf, bufLen);
if (len <= 0) {
printf("msg '%s' send failed %d!\n", buf);
ret = -1;
goto finish;
}
printf("msg '%s' send success,%d byte!\n", buf, len);
ret = 0;
finish:
SSL_shutdown(ssl);
SSL_free(ssl);
return ret;
}
int main(int argc, char **argv)
{
int listenfd = -1;
int clientfd = -1;
int ret = -1;
socklen_t len;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
unsigned int myport;
SSL_CTX *ctx;
if (argv[1]) {
myport = atoi(argv[1]);
} else {
myport = 8888;
}
LibSslInit();
ctx = SSL_CTX_new(SSLv23_server_method());
if (ctx == NULL) {
ERR_print_errors_fp(stdout);
exit(1);
}
SslSetPassWd(ctx);
SslLoadConf(ctx);
listenfd = StartListenServer(myport);
while (1) {
len = sizeof(struct sockaddr);
clientfd = accept(listenfd, (struct sockaddr *) &their_addr, &len);
if (clientfd == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), clientfd);
ret = HandleSslConnect(ctx, clientfd);
if (ret != 0)
{
printf("handle ssl connect failed close clientfd %d.\n", clientfd);
}
finish:
close(clientfd);
}
close(listenfd);
SSL_CTX_free(ctx);
return 0;
}