美文网首页
Bufferevents:advanced topics

Bufferevents:advanced topics

作者: 食梦狸猫 | 来源:发表于2019-03-20 21:07 被阅读0次

成对bufferevents

我们可以创建一对bufferevents,使其中一端所有写的数据都能在另一端收到。而且没有真正用到套接字

int bufferevent_pair_new(struct event_base *base, int options,
    struct bufferevent *pair[2]);

这个函数设置pair[0]和pair[1]是一对互相连接的bufferevents对。同时也支持所有参数,除了BEV_OPT_CLOSE_ON_FREE没实际作用,BEV_OP_DEFER_CALLBACKS一直保持。

释放掉其中一端的bufferevent不会自动释放另一端的bufferevent或者造成EOF事件,这只会让释放的那端不可连接,而且不能成功读写。

如果你想获得另一端的bufferevent,可以调用

struct bufferevent *bufferevent_pair_get_partner(struct bufferevent *bev)

bufferevents过滤器

如果我们想通过一个bufferevent传输数据并且进行一些过滤。

enum bufferevent_filter_result {
        BEV_OK = 0,
        BEV_NEED_MORE = 1,
        BEV_ERROR = 2
};
typedef enum bufferevent_filter_result (*bufferevent_filter_cb)(
    struct evbuffer *source, struct evbuffer *destination, ev_ssize_t dst_limit,
    enum bufferevent_flush_mode mode, void *ctx);


struct bufferevent *bufferevent_filter_new(struct bufferevent *underlying,
        bufferevent_filter_cb input_filter,
        bufferevent_filter_cb output_filter,
        int options,
        void (*free_context)(void *),
        void *ctx);

在创建bufferevent过滤器时,会有一个underlying的bufferevent,所有进入underlying的数据都会进过input_filter过滤,同理,输出的也会通过output_filter过滤。但是给一个bufferevent创建过滤器的话,会屏蔽掉bufferevent自己的回调函数。

设置最大读写量

int bufferevent_set_max_single_read(struct bufferevent *bev, size_t size);
int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);

ev_ssize_t bufferevent_get_max_single_read(struct bufferevent *bev);
ev_ssize_t bufferevent_get_max_single_write(struct bufferevent *bev);

Bufferevents和SSL

Bufferevents可以使用OpenSSL库来支持SSL/TLS安全传输层。

  • 设置和使用一个OpenSSL-based bufferevent
enum bufferevent_ssl_state {
        BUFFEREVENT_SSL_OPEN = 0,
        BUFFEREVENT_SSL_CONNECTING = 1,
        BUFFEREVENT_SSL_ACCEPTING = 2
};

struct bufferevent *
bufferevent_openssl_filter_new(struct event_base *base,
    struct bufferevent *underlying,
    SSL *ssl,
    enum bufferevent_ssl_state state,
    int options);

struct bufferevent *
bufferevent_openssl_socket_new(struct event_base *base,
    evutil_socket_t fd,
    SSL *ssl,
    enum bufferevent_ssl_state state,
    int options);

我们可以创造两种SSLbufferevents:一种有过滤器可以和其他下层bufferevent传输的的bufferevent,一种有socket的bufferevent可以让OpenSSL和互联网直接连接的bufferevent

SSL *ctx = bufferevent_openssl_get_ssl(bev);

/*
 * SSL_RECEIVED_SHUTDOWN tells SSL_shutdown to act as if we had already
 * received a close notify from the other end.  SSL_shutdown will then
 * send the final close notify in reply.  The other end will receive the
 * close notify and send theirs.  By this time, we will have already
 * closed the socket and the other end's real close notify will never be
 * received.  In effect, both sides will think that they have completed a
 * clean shutdown and keep their sessions valid.  This strategy will fail
 * if the socket is not ready for writing, in which case this hack will
 * lead to an unclean shutdown and lost session on the other end.
 */
SSL_set_shutdown(ctx, SSL_RECEIVED_SHUTDOWN);
SSL_shutdown(ctx);
bufferevent_free(bev);
SSL *bufferevent_openssl_get_ssl(struct bufferevent *bev);

如果bev是个OpenSSL bufferevent这个函数返回SSL对象

unsigned long bufferevent_get_openssl_error(struct bufferevent *bev);
int bufferevent_ssl_renegotiate(struct bufferevent *bev);
int bufferevent_openssl_get_allow_dirty_shutdown(struct bufferevent *bev);
void bufferevent_openssl_set_allow_dirty_shutdown(struct bufferevent *bev,
    int allow_dirty_shutdown);

例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>

#include <event.h>
#include <event2/listener.h>
#include <event2/bufferevent_ssl.h>

static void
ssl_readcb(struct bufferevent * bev, void * arg)
{
    struct evbuffer *in = bufferevent_get_input(bev);

    printf("Received %zu bytes\n", evbuffer_get_length(in));
    printf("----- data ----\n");
    printf("%.*s\n", (int)evbuffer_get_length(in), evbuffer_pullup(in, -1));

    bufferevent_write_buffer(bev, in);
}

static void
ssl_acceptcb(struct evconnlistener *serv, int sock, struct sockaddr *sa,
             int sa_len, void *arg)
{
    struct event_base *evbase;
    struct bufferevent *bev;
    SSL_CTX *server_ctx;
    SSL *client_ctx;

    server_ctx = (SSL_CTX *)arg;
    client_ctx = SSL_new(server_ctx);
    evbase = evconnlistener_get_base(serv);

    bev = bufferevent_openssl_socket_new(evbase, sock, client_ctx,
                                         BUFFEREVENT_SSL_ACCEPTING,
                                         BEV_OPT_CLOSE_ON_FREE);

    bufferevent_enable(bev, EV_READ);
    bufferevent_setcb(bev, ssl_readcb, NULL, NULL, NULL);
}
static SSL_CTX *
evssl_init(void)
{
    SSL_CTX  *server_ctx;

    /* Initialize the OpenSSL library */
    SSL_load_error_strings();
    SSL_library_init();
    /* We MUST have entropy, or else there's no point to crypto. */
    if (!RAND_poll())
        return NULL;

    server_ctx = SSL_CTX_new(SSLv23_server_method());

    if (! SSL_CTX_use_certificate_chain_file(server_ctx, "cert") ||
        ! SSL_CTX_use_PrivateKey_file(server_ctx, "pkey", SSL_FILETYPE_PEM)) {
        puts("Couldn't read 'pkey' or 'cert' file.  To generate a key\n"
           "and self-signed certificate, run:\n"
           "  openssl genrsa -out pkey 2048\n"
           "  openssl req -new -key pkey -out cert.req\n"
           "  openssl x509 -req -days 365 -in cert.req -signkey pkey -out cert");
        return NULL;
    }
    SSL_CTX_set_options(server_ctx, SSL_OP_NO_SSLv2);

    return server_ctx;
}
int
main(int argc, char **argv)
{
    SSL_CTX *ctx;
    struct evconnlistener *listener;
    struct event_base *evbase;
    struct sockaddr_in sin;

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(9999);
    sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */

    ctx = evssl_init();
    if (ctx == NULL)
        return 1;
    evbase = event_base_new();
    listener = evconnlistener_new_bind(
                         evbase, ssl_acceptcb, (void *)ctx,
                         LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 1024,
                         (struct sockaddr *)&sin, sizeof(sin));

    event_base_loop(evbase, 0);

    evconnlistener_free(listener);
    SSL_CTX_free(ctx);

    return 0;
}

线程安全OpenSSL

例子

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pthread.h>
#include <openssl/ssl.h>
#include <openssl/crypto.h>

pthread_mutex_t * ssl_locks;
int ssl_num_locks;

/* Implements a thread-ID function as requied by openssl */
static unsigned long
get_thread_id_cb(void)
{
    return (unsigned long)pthread_self();
}

static void
thread_lock_cb(int mode, int which, const char * f, int l)
{
    if (which < ssl_num_locks) {
        if (mode & CRYPTO_LOCK) {
            pthread_mutex_lock(&(ssl_locks[which]));
        } else {
            pthread_mutex_unlock(&(ssl_locks[which]));
        }
    }
}
int
init_ssl_locking(void)
{
    int i;

    ssl_num_locks = CRYPTO_num_locks();
    ssl_locks = malloc(ssl_num_locks * sizeof(pthread_mutex_t));
    if (ssl_locks == NULL)
        return -1;

    for (i = 0; i < ssl_num_locks; i++) {
        pthread_mutex_init(&(ssl_locks[i]), NULL);
    }

    CRYPTO_set_id_callback(get_thread_id_cb);
    CRYPTO_set_locking_callback(thread_lock_cb);

    return 0;
}


相关文章

  • Bufferevents:advanced topics

    成对bufferevents 我们可以创建一对bufferevents,使其中一端所有写的数据都能在另一端收到。而...

  • Advanced Topics in Java

    下载地址:Advanced Topics in Java一本免费的电子书,胜过一杯付费的咖啡

  • React Advanced Topics

    背景 大家都在使用React,之前呢,也给大家分享过一次主题为“浅谈Hooks&&生命周期”的内容。今天呢,作为延...

  • [译] Android - Jetpack - Advanced

    翻译自 Advanced WorkManager topics WorkManager可以轻松设置和安排缜密的任务...

  • Advanced ADS-B topics

    一、ADS-B versions 主要由0,1,2 三个版本 1.1 version changes从0 - > ...

  • Bufferevents:concept and basics

    当我们想写入数据时,一般情况下是: 决定我们将要写一些数据到一个连接里,把这些数据放入缓存里 等待连接可写 写足够...

  • 图形学笔记十四 科普向Advanced Topics in Re

    参考课程:https://www.bilibili.com/video/BV1X7411F744?p=18[htt...

  • Topics

    索拉里斯星 我会看一些讲书的节目,但通常不会真的去买去看。索拉里斯星是一个科幻小说,他说的是人们探索一个奇怪星球的...

  • Topics

    As long as I am remember I enjoy my cozy home I crazy abo...

  • How we are going to address Busi

    --> From managers' perspective Topics General topics: 1. ...

网友评论

      本文标题:Bufferevents:advanced topics

      本文链接:https://www.haomeiwen.com/subject/fafxvqtx.html