基于libevent和openssl实现的https 的服务端(c++)

此处说明一下:
1.ssl的初始化整个进程只需执行一次,请勿多次初始化。谨防析构函数多次析构ctx
2.此处因为封装为类,故将回调函数设置为静态。如有需要回调函数返回值,可用类成员变量存储,调用回调函数时传入this指针,以此将返回值带出,需将获取返回值的函数阻塞。防止获取返回值时,回调函数还未返回
3.密钥等需自行生成
https_server.h
4.此时openssl库用的较低版本libssl.so.1,libevent库用的大约2.0或2.1版本

#ifndef HTTPS_SERVER_H
#define HTTPS_SERVER_H
#include <iostream>
#include <openssl/ssl.h>
#include <event2/event.h>
#include <event2/bufferevent_ssl.h>
#include <event2/http.h>

class HttpsServer {
public:
    HttpsServer();
    ~HttpsServer();
    int StartServerHttps ();
    int ServerSetCerts ();
    int Init();

private:
    event_base*                     m_base;
    evhttp*                         m_http;
    SSL_CTX*                        m_ctx;
    EC_KEY*                         m_ecdh;
};

#endif

https_server.cpp

#include "https_server.h"
#include <event2/buffer.h>
#include "json/json.h"
#include <unistd.h>

#define MYHTTPD_SIGNATURE   "MoCarHttpd v0.1"
#define HTTPS_PORT 10999
#define HTTP_CERT_PEM "cert.pem"
#define HTTP_KEY_PEM "key.pem"

static void *MyZeroMalloc (size_t howmuch)
{ 
    return calloc (1, howmuch); 
}
HttpsServer::HttpsServer():m_base(NULL),m_http(NULL),m_ctx(NULL),m_ecdh(NULL)
{
}
HttpsServer::~HttpsServer()
{
    if (m_base != NULL)
    {
        event_base_free(m_base);
    }
    if (m_http != NULL)
    {
        evhttp_free(m_http);
    }
    if (m_ctx != NULL)
    {
        SSL_CTX_free(m_ctx);
    }
    if (m_ecdh != NULL)
    {
        EC_KEY_free(m_ecdh);
    }
}
static void Login (struct evhttp_request *req, void *arg)
{ 

    HttpsServer* self = static_cast<HttpsServer*>(arg);
    struct evbuffer *evb = NULL;
    const char *uri = evhttp_request_get_uri (req);
    struct evhttp_uri *decoded = NULL;
 
    /* 判断 req 是否是GET 请求 */
    if (evhttp_request_get_command (req) != EVHTTP_REQ_POST)
    {
        evhttp_send_reply(req, 405, "Method Not Allowed", nullptr);
        return;
    }
 
    //判断此URI是否合法
    decoded = evhttp_uri_parse (uri);
    if (! decoded)
    { 
        printf("It's not a good URI. Sending BADREQUEST\n");
        evhttp_send_error (req, HTTP_BADREQUEST, 0);
        return;
    }
 
    /* Decode the payload */
    struct evbuffer *buf = evhttp_request_get_input_buffer (req);
    evbuffer_add (buf, "", 1);    /* NUL-terminate the buffer */
    char *payload = (char *) evbuffer_pullup (buf, -1);
    int post_data_len = evbuffer_get_length(buf);
    char request_data_buf[4096] = {0};
    memcpy(request_data_buf, payload, post_data_len);
    printf("https server received body : \n%s ",payload);
 
    evhttp_add_header(evhttp_request_get_output_headers(req), "Server", MYHTTPD_SIGNATURE);
    evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/plain; charset=UTF-8");
    evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
 

    Json::Value jsonData;
	jsonData["code"] = 0;
	jsonData["msg"] = "post login success !";
    std::string jsonString = jsonData.toStyledString();

    evb = evbuffer_new ();
    evbuffer_add_printf(evb, "%s", jsonString.c_str());
    //将封装好的evbuffer 发送给客户端
    evhttp_send_reply(req, HTTP_OK, "OK", evb);
    if (decoded)
        evhttp_uri_free (decoded);
    if (evb)
        evbuffer_free (evb);
}

int HttpsServer::Init()
{
    CRYPTO_set_mem_functions (MyZeroMalloc, realloc, free);
    SSL_library_init ();
    SSL_load_error_strings ();
    OpenSSL_add_all_algorithms ();
    m_base = event_base_new ();
    if (!m_base)
    { 
        printf("Couldn't create an event_base: exiting\n");
        return -1;
    }
    m_http = evhttp_new (m_base);
    if (!m_http)
    { 
        printf("couldn't create evhttp. Exiting.\n");
        return -2;
    }
    m_ctx = SSL_CTX_new (SSLv23_server_method ());
    SSL_CTX_set_options (m_ctx,
            SSL_OP_SINGLE_DH_USE |
            SSL_OP_SINGLE_ECDH_USE |
            SSL_OP_NO_SSLv2);
    m_ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
    if (!m_ecdh)
    {
        printf("EC_KEY_new_by_curve_name fail");
        return -3;
    }
    if (1 != SSL_CTX_set_tmp_ecdh (m_ctx, m_ecdh))
    {
        printf("SSL_CTX_set_tmp_ecdh fail");
        return -4;
    }
    int ret = ServerSetCerts();
    if (ret < 0 )
    {
        return ret;
    }
    return 0;       
}
static struct bufferevent* bevcb (struct event_base *base, void *arg)
{ 
    struct bufferevent* r;
    SSL_CTX *ctx = (SSL_CTX *) arg;
 
    r = bufferevent_openssl_socket_new (base,
            -1,
            SSL_new (ctx),
            BUFFEREVENT_SSL_ACCEPTING,
            BEV_OPT_CLOSE_ON_FREE);
    return r;
}
int HttpsServer::ServerSetCerts ()
{
    if (1 != SSL_CTX_use_certificate_chain_file (m_ctx, HTTP_CERT_PEM))
    {
        printf("SSL_CTX_use_certificate_chain_file fail");
        return -1;
    }
    if (1 != SSL_CTX_use_PrivateKey_file (m_ctx, HTTP_KEY_PEM, SSL_FILETYPE_PEM))
    {
        printf("SSL_CTX_use_PrivateKey_file fail");
        return -2;
    }
    if (1 != SSL_CTX_check_private_key (m_ctx))
    {
        printf("SSL_CTX_check_private_key fail");
        return -3;
    }
    return 0;
}

int HttpsServer::StartServerHttps ()
{ 
    evhttp_set_bevcb (m_http, bevcb, m_ctx);
    evhttp_set_cb(m_http, "/login", Login, this); 
    evhttp_bound_socket* handle = evhttp_bind_socket_with_handle (m_http, "0.0.0.0", HTTPS_PORT);
    if (!handle)
    { 
        fprintf (stderr, "couldn't bind to port %d. Exiting.\n",(int) HTTPS_PORT);
        return 1;
    }
    event_base_dispatch (m_base);
    return 0;
}

main.cpp

#include "https_server.h"
int main()
{
    HttpsServer* server = new HttpsServer;
	server->Init();
	server->StartServerHttps();

    return 0;
}

make.sh

g++ *.cpp  -L/usr/local/lib64 -lssl -lcrypto -levent_openssl -levent -ljsoncpp -o server -ggdb -std=c++11 -Wno-deprecated-declarations

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值