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. http内网转发

    package main import ( "io" "log" "net/http" "strings" ) func ...

  2. ******可用 SpringBoot 项目打包分开lib,配置和资源文件

    spring-boot多模块打包后,无法找到其他模块中的类https://blog.csdn.net/Can96/article/details/96172172 关于SpringBoot项目打包没有 ...

  3. thinkphp 分页类 url 编码处理

    在做thinkphp分页的时候  thinkphp 中的分页 有一个小问题 就是 在有form 表单 搜索中文的时候,点击下一页的话 中文会被转换成编码. 如图: 最直接的方法就是 直接修改 thin ...

  4. 安卓访问https错误,访问http可以,可能是nginx ssl证书配置有问题

    开发中遇到react-native生成的android访问UAT和开发环境的http api都可以,但是访问生产环境的https就报错,还有就是第三方webhook调用你https网站的api也可能会 ...

  5. JS提交表单页面不跳转、JS下载、动态创建from

    JS下载 function downloadFile(id) {     var url =  "<%=request.getContextPath()%>/cer/downlo ...

  6. AspNet Core使用Mysql一些问题及解决方案

    本文假设的你的AspNet Core 2.2的Web程序通过EntityFrameworkCore连接使用MSSQL数据库,能正常使用. 如何想转为使用Mysql,其实不难. 1.安装Mysql这个简 ...

  7. axios FastMock 跨域 代理

    发送请求: 实现:发送请求,获取数据. 原本想自己写服务,后来无意间找到FastMock这个东东,于是就有了下文... 首先我安装了axios,在fastmock注册好了并创建了一个接口,怎么搞自行百 ...

  8. DatetimeHelper类的编写

    公共类 DAtaTimeHelper类的编写 public class Appointment { public DateTime StartDate { get; set; } public Dat ...

  9. PIE SDK主成分变换

    1.算法功能简介   主成分变换(Principal Component Analysis,PCA)又称K-L(Karhunen-Loeve)变换或霍特林(Hotelling)变换,是基于变量之间的相 ...

  10. vue知识点小结

    vue.js中==和===的区别 1.== 用于比较.判断两者相等,比较时可自动换数据类型 2.=== 用于(严格)比较.判断两者(严格)相等,不会进行自动转换,要求进行比较的操作数必须类型一致,不一 ...