Libevent另外提供了基于openssl的bufferevent来支持ssl,通过特殊的ssl bufferevent来对数据进行加密。

ps:本文不对openssl相应的接口做介绍因为不熟

SSL bufferevent相关函数

  • struct bufferevent *bufferevent_openssl_socket_new(struct event_base *base, evutil_socket_t fd, struct ssl_st *ssl, enum bufferevent_ssl_state state, int options) 该函数能够基于给定的文件描述符及ssl对象创建一个ssl bufferevent。其中,bufferevent_ssl_state state参数表明了该bufferevent的角色,在作为服务端时一般使用BUFFEREVENT_SSL_ACCEPTING,在作为客户端时一般使用BUFFEREVENT_SSL_CONNECTING。

  • struct bufferevent *bufferevent_openssl_filter_new(struct event_base *base, struct bufferevent *underlying, struct ssl_st *ssl, enum bufferevent_ssl_state state, int options) 该函数能够基于给定的底层bufferevent及ssl对象创建一个过滤器,该过滤器的过滤函数已经由系统通过ssl对象定义好,我们只需另外定义过滤器读写回调函数即可。

ps:在下例的客户端代码中,注释中即为使用过滤器来实现ssl bufferevent。

Demo

  • 服务器,这段代码来自Libevent book。服务器的主要工作时回显客户端发来的数据。
#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> #include "basicev.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_enable(bev, EV_WRITE);
bufferevent_setcb(bev, ssl_readcb, NULL, NULL, NULL); char buf[] = "Hello, this is ECHO";
bufferevent_write(bev, buf, sizeof(buf));
} 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, "cacert.pem") ||
! SSL_CTX_use_PrivateKey_file(server_ctx, "privkey.pem", 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 */ //初始化ssl环境
ctx = evssl_init();
if (ctx == NULL)
return 1; //初始化event2环境
evbase = event_base_new();
if(evbase == NULL)
{
printf("%s\n", strerror(errno));
exit(1);
} //创建监听器
listener = evconnlistener_new_bind(
evbase, ssl_acceptcb, (void *)ctx,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 1024,
(struct sockaddr *)&sin, sizeof(sin));
//添加中断信号处理事件
add_signal(evbase);
event_base_loop(evbase, 0); evconnlistener_free(listener);
SSL_CTX_free(ctx);
return 0;
}
  • 客户端
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h> #include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_ssl.h> #include "basicev.h" static void read_cb(struct bufferevent *bev, void *arg)
{
char buf[1024] = {0};
bufferevent_read(bev, buf, 1024);
printf("%s\n", buf);
} int main(int argc, char **argv)
{
int sockfd, len;
struct sockaddr_in dest;
SSL_CTX *ctx;
SSL *ssl; //初始化ssl环境
SSL_library_init();
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL) {
ERR_print_errors_fp(stdout);
exit(1);
} // 创建一个 socket 用于底层通信
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("Socket: %s\n", strerror(errno));
exit(1);
} // 初始化服务器端地址
memset(&dest, 0 ,sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(9999);
if (inet_aton("127.0.0.1", (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
exit(errno);
} // 连接服务器
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
printf("Connect: %s\n ", strerror(errno));
exit(errno);
} //初始化event2
struct event_base *base = NULL;
struct bufferevent *sslbev = NULL; base = event_base_new();
if(base == NULL)
{
printf("%s\n", strerror(errno));
exit(1);
} //创建一个ssl对象
ssl = SSL_new(ctx); //创建ssl的bufferevent
sslbev = bufferevent_openssl_socket_new(base, sockfd, ssl,
BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE); /* 使用过滤器的ssl bufferevent
struct bufferevent *bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
sslbev = bufferevent_openssl_filter_new(base, bev, ssl,
BUFFEREVENT_SSL_CONNECTING, BEV_OPT_CLOSE_ON_FREE);
*/ bufferevent_setcb(sslbev, read_cb, NULL, NULL, NULL);
bufferevent_enable(sslbev, EV_READ|EV_WRITE); //添加中断信号处理事件
add_signal(base);
//添加标准输入处理事件
//该事件的回调函数会将从标准输入得到的数据写入sslbev
add_stdin(base, sslbev);
event_base_dispatch(base); bufferevent_free(sslbev);
event_base_free(base);
SSL_CTX_free(ctx);
return 0;
}
  • 客户端输出
sunminming@sunminming:~/libevent/ssl$ ./client
Hello, this is ECHO
hello, this is client //这行为手动键入
hello, this is client //这行为服务器回显
  • 服务器输出
sunminming@sunminming:~/libevent/ssl$ ./server
Received 21 bytes
----- data ----
hello, this is client

libevent笔记6:ssl bufferevent的更多相关文章

  1. (转)Libevent(4)— Bufferevent

    转自:http://name5566.com/4215.html 参考文献列表:http://www.wangafu.net/~nickm/libevent-book/ 此文编写的时候,使用到的 Li ...

  2. libevent学习七(bufferevent)

    1. 每个bufferevent 都拥有类型为struct evbuffer的input buffer和out buffer,分别供数据读取和数据写入使用. 2.读取和写入数据是通过编写和设置对应的回 ...

  3. libevent笔记5:水位watermarks

    bufferevent中提供了对读写回调的触发条件及最大缓存长度的设置,即低高水位: 低水位:是读写回调函数的最低触发数据长度,当输入/输出缓存区中的数据长度小于低水位时,读/写回调函数不会被触发: ...

  4. libevent笔记4:Filter_bufferevent过滤器

    Filter_bufferevent是一种基于bufferevent的过滤器,其本身也是一个bufferevent.能够对底层bufferevent输入缓存区中的数据进行操作(加/解密等)后再读取,同 ...

  5. libevent笔记3:evbuffer

    evbuffer 之前提到bufferevent结构体提供两个缓存区用来为读写提供缓存,并自动进行IO操作.这两个缓存区是使用Libevent中的evbuffer实现的,同样,Libevent中也提供 ...

  6. libevent笔记2:Hello_World

    本篇通过libevent提供的Hello_World demo简单介绍基于libevent的TCP服务器的实现 listener listener是libevent提供的一种监听本地端口的数据结构,在 ...

  7. Python Web学习笔记之SSL,TLS,HTTPS

    一. SSL 1. SSL简介 SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持.SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可 ...

  8. libevent笔记1:安装及DEMO

    本篇简单记录了libevent的安装过程及基础的先进先出管道Demo,其中demo来自这篇博客,安装过程在这篇博客 实验环境 系统:Ubuntu 18.04.3 libevent版本:libevent ...

  9. Libevent学习笔记(五) 根据例子学习bufferevent

    libevent中提供了一个Hello-world.c 的例子,从这个例子可以学习libevent是如何使用bufferevent的. 这个例子在Sample中 这个例子之前讲解过,这次主要看下buf ...

随机推荐

  1. Python 3 的 int 类型详解(为什么 int 不存在溢出问题?)

    在以前的Python2中,整型分为int和long,也就是整型和长整型, 长整型不存在溢出问题, 即可以存放任意大小的数值,理论支持无限大数字. 因此在Python3 中,统一使用长整型,用int表示 ...

  2. Jaeger接入Python应用:jaeger-client-python【非完全教程】

    目录 Jaeger接入Python应用 1. 安装 jaeger-client 2. (示例)创建 Tracer 对象,并通过 Tracer 对象创建 Span 来追踪业务流程. 3. 初始化和配置 ...

  3. 【docker】centos7 上拉取docker镜像,一直拉取不到,报错:Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled while w

    镜像拉取一直报错: Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request cancel ...

  4. 深入V8引擎-默认Platform之mac篇(2)

    先说结论,V8引擎在默认Platform中初始化的这个线程是用于处理类似于setTimeout的延时任务. 另外附一些图,包括继承树.关键属性归属.纯逻辑工作流程,对代码木得兴趣的看完图可以X掉了. ...

  5. c# asp.net core取当月第一天和最后一天及删除最后一个字符的多种方法

    当月第一天0时0分0秒 DateTime.Now.AddDays( - DateTime.Now.Day).Date 当月最后一天23时59分59秒 DateTime.Now.AddDays( - D ...

  6. Python: 截屏

    最近项目中想实现截屏功能,使用的笔记本是高清屏,实际屏幕设置成了150%,所以在截屏的时候遇到个各种问题. 最开始使用PIL ImageGrab来截取屏幕,如果本来是100%的设置没有问题,能截取到全 ...

  7. Java内功心法,行为型设计模式

    行为型 1. 责任链(Chain Of Responsibility) Intent 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系. 将这些对象连成一条链,并沿着这条链发送该 ...

  8. 用Python爬E站本

    用Python爬E站本 一.前言 参考并改进自 OverJerry 大佬的 教你怎么用Python爬取E站的本子_OverJerry. 本文为技术学习记录,不提供访问无存在网站的任何方法,也不包含不和 ...

  9. Python检测URL状态

    需求:Python检测URL状态,并追加保存200的URL 代码一: #! /usr/bin/env python #coding=utf-8 import sys import requests d ...

  10. Kubernetes概念之deployment

    一整天一整天的坐在办公室,真的很~~~,懵圈中....,求解救. 本文通过<Kubernetes权威指南>的概念部分学习总结 Deployment作用 Deployment与RC的作用其实 ...