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 ...
随机推荐
- Python 3 的 int 类型详解(为什么 int 不存在溢出问题?)
在以前的Python2中,整型分为int和long,也就是整型和长整型, 长整型不存在溢出问题, 即可以存放任意大小的数值,理论支持无限大数字. 因此在Python3 中,统一使用长整型,用int表示 ...
- Jaeger接入Python应用:jaeger-client-python【非完全教程】
目录 Jaeger接入Python应用 1. 安装 jaeger-client 2. (示例)创建 Tracer 对象,并通过 Tracer 对象创建 Span 来追踪业务流程. 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 ...
- 深入V8引擎-默认Platform之mac篇(2)
先说结论,V8引擎在默认Platform中初始化的这个线程是用于处理类似于setTimeout的延时任务. 另外附一些图,包括继承树.关键属性归属.纯逻辑工作流程,对代码木得兴趣的看完图可以X掉了. ...
- c# asp.net core取当月第一天和最后一天及删除最后一个字符的多种方法
当月第一天0时0分0秒 DateTime.Now.AddDays( - DateTime.Now.Day).Date 当月最后一天23时59分59秒 DateTime.Now.AddDays( - D ...
- Python: 截屏
最近项目中想实现截屏功能,使用的笔记本是高清屏,实际屏幕设置成了150%,所以在截屏的时候遇到个各种问题. 最开始使用PIL ImageGrab来截取屏幕,如果本来是100%的设置没有问题,能截取到全 ...
- Java内功心法,行为型设计模式
行为型 1. 责任链(Chain Of Responsibility) Intent 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系. 将这些对象连成一条链,并沿着这条链发送该 ...
- 用Python爬E站本
用Python爬E站本 一.前言 参考并改进自 OverJerry 大佬的 教你怎么用Python爬取E站的本子_OverJerry. 本文为技术学习记录,不提供访问无存在网站的任何方法,也不包含不和 ...
- Python检测URL状态
需求:Python检测URL状态,并追加保存200的URL 代码一: #! /usr/bin/env python #coding=utf-8 import sys import requests d ...
- Kubernetes概念之deployment
一整天一整天的坐在办公室,真的很~~~,懵圈中....,求解救. 本文通过<Kubernetes权威指南>的概念部分学习总结 Deployment作用 Deployment与RC的作用其实 ...