首页 技术 正文
技术 2022年11月15日
0 收藏 838 点赞 2,670 浏览 5398 个字

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
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,489
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,904
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,737
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,490
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,128
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,291