libevent笔记6:ssl bufferevent
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的更多相关文章
- (转)Libevent(4)— Bufferevent
转自:http://name5566.com/4215.html 参考文献列表:http://www.wangafu.net/~nickm/libevent-book/ 此文编写的时候,使用到的 Li ...
- libevent学习七(bufferevent)
1. 每个bufferevent 都拥有类型为struct evbuffer的input buffer和out buffer,分别供数据读取和数据写入使用. 2.读取和写入数据是通过编写和设置对应的回 ...
- libevent笔记5:水位watermarks
bufferevent中提供了对读写回调的触发条件及最大缓存长度的设置,即低高水位: 低水位:是读写回调函数的最低触发数据长度,当输入/输出缓存区中的数据长度小于低水位时,读/写回调函数不会被触发: ...
- libevent笔记4:Filter_bufferevent过滤器
Filter_bufferevent是一种基于bufferevent的过滤器,其本身也是一个bufferevent.能够对底层bufferevent输入缓存区中的数据进行操作(加/解密等)后再读取,同 ...
- libevent笔记3:evbuffer
evbuffer 之前提到bufferevent结构体提供两个缓存区用来为读写提供缓存,并自动进行IO操作.这两个缓存区是使用Libevent中的evbuffer实现的,同样,Libevent中也提供 ...
- libevent笔记2:Hello_World
本篇通过libevent提供的Hello_World demo简单介绍基于libevent的TCP服务器的实现 listener listener是libevent提供的一种监听本地端口的数据结构,在 ...
- Python Web学习笔记之SSL,TLS,HTTPS
一. SSL 1. SSL简介 SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持.SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可 ...
- libevent笔记1:安装及DEMO
本篇简单记录了libevent的安装过程及基础的先进先出管道Demo,其中demo来自这篇博客,安装过程在这篇博客 实验环境 系统:Ubuntu 18.04.3 libevent版本:libevent ...
- Libevent学习笔记(五) 根据例子学习bufferevent
libevent中提供了一个Hello-world.c 的例子,从这个例子可以学习libevent是如何使用bufferevent的. 这个例子在Sample中 这个例子之前讲解过,这次主要看下buf ...
随机推荐
- Redux-saga-整理
介绍 在redux中更好的解决异步操作 redux-saga相当于在redux原来的数据流中多了一层,对action进行监听 接收到action时,派发一个任务维护state saga通过Genera ...
- 【leetcode-198】打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...
- 解密“CDO-首席数据官”的价值、挑战及发展
数据,不论形态.格式和类型,已经迅速成为企业最有战略意义的资产:数据资产已经成为了可以形成业务洞察及优势的战略资源,数据的体量.多样性和复杂性也正以指数级增长.就像其他重要的企业资产,数据需要适当的管 ...
- python爬取豆瓣电影首页超链接
什么是爬虫? 我们可以把互联网比作一张大网,而爬虫(即网络爬虫)便是在网上爬行的蜘蛛.把网的节点比作一个个网页,爬虫爬到这就相当于访问了该页面,获取了其信息.可以把节点间的连线比作网页与网页之间的链 ...
- JNDI学习总结(一):JNDI到底是什么?
https://blog.csdn.net/wn084/article/details/80729230 分类专栏: JNDI JNDI是 Java 命名与目录接口(Java Naming and ...
- Java向MySQL新增记录时间误差问题
参考文档 https://www.jianshu.com/p/115861aad147 https://blog.csdn.net/ai932820942/article/details/845804 ...
- Java学习之初识Maven
简介 功能特点 Maven主要作用类似于VS的包管理器,能够帮助开发者完成以下工作:构建.文档生成.报告.依赖.SCMs.发布.分发.邮件列表等. 详细请阅读:https://www.runoob.c ...
- NET/Regex 处理连续空格
问题: 就是一个字符串呀,一个字符串,里面的话有一个空格,有可能有连续空格,你遇到连续空格,把这个连续空格变成一个空格,一个空格地不处理. 代码: /// <summary> /// 处理 ...
- Ajax实现附件上传
前两篇文章有介绍使用form.submit 实现附件的上传,但是这种方式使用起来很不方便,如过需要再上传成功以后执行一些其他的操作的时候比较麻烦.下面我为大家介绍下使用ajax实现附件上传的功能: 1 ...
- 在VB编程中,若一行代码太长需要换行时,行尾要加什么符号
& _ 注意,&与_之间一定要有一个空格 例如: aa="select " & _ " a,b,c" & _ ...