附一个PJSIP库的基础介绍链接:
http://www.zhimax.com/article/tcp/pjlib.html
PJLIB的测试源码链接:
https://trac.pjsip.org/repos/browser/pjproject/tags/2.9/pjlib/src?order=name#pjlib-test
基于测试源码,自己动手写了一个SSL加密的TCP服务器和客户端。开发环境是centos7.
服务端代码:
#include <pjlib.h>
#include <iostream>
#include <netinet/in.h>
#include "PQTEL.pb.h"
using namespace std;
using namespace pqtel_msg;
#define CERT_CA_FILE "./ca.crt"
#define CERT_FILE "./server.crt"
#define CERT_PRIVKEY_FILE "./server.pem"
#define CERT_PRIVKEY_PASS ""
#define SVR_IP "127.0.0.1"
#define SVR_PORT 14789
//全局变量
pj_caching_pool cachingPool;
pj_pool_factory *mem;
struct send_key {
pj_ioqueue_op_key_t op_key;
};
struct PJ_Data
{
pj_pool_t *pool;
pj_ioqueue_t *ioqueue;
pj_bool_t is_server;
pj_bool_t is_verbose;
pj_bool_t is_done;
struct send_key send_key;
};
struct pqtel_head
{
short type;
short msglen;
};
static void dump_ssl_info(const pj_ssl_sock_info *si)
{
const char *tmp_st;
/* Print cipher name */
tmp_st = pj_ssl_cipher_name(si->cipher);
if (tmp_st == NULL)
tmp_st = "[Unknown]";
PJ_LOG(3, ("", ".....Cipher: %s", tmp_st));
/* Print remote certificate info and verification result */
if (si->remote_cert_info && si->remote_cert_info->subject.info.slen)
{
char buf[2048];
const char *verif_msgs[32];
unsigned verif_msg_cnt;
/* Dump remote TLS certificate info */
PJ_LOG(3, ("", ".....Remote certificate info:"));
pj_ssl_cert_info_dump(si->remote_cert_info, " ", buf, sizeof(buf));
PJ_LOG(3,("", "\n%s", buf));
/* Dump remote TLS certificate verification result */
verif_msg_cnt = PJ_ARRAY_SIZE(verif_msgs);
pj_ssl_cert_get_verify_status_strings(si->verify_status, verif_msgs, &verif_msg_cnt);
PJ_LOG(3,("", ".....Remote certificate verification result: %s",(verif_msg_cnt == 1? verif_msgs[0]:"")));
if (verif_msg_cnt > 1) {
unsigned i;
for (i = 0; i < verif_msg_cnt; ++i)
PJ_LOG(3,("", "..... - %s", verif_msgs[i]));
}
}
}
const char* SVR_MakeHead(char* output, char *sendbuf, int length)
{
//拼接应用层协议头
pqtel_head *head = (pqtel_head *)sendbuf;
head->type = htons(0x5051);
head->msglen = htons(length + 2);
short ncrc = htons(0x2022);
memcpy(sendbuf, head, sizeof(pqtel_head));
memcpy(sendbuf + sizeof(pqtel_head), output, length);
memcpy(sendbuf + sizeof(pqtel_head) + length, (char*)&ncrc, sizeof(short));
return sendbuf;
}
int SVR_SendRep(pj_ssl_sock_t *ssock)
{
pj_status_t status;
char output[256] = {
0};
char sendbuf[512] = {
0};
int length;
bool flag;
pj_ssize_t size;
PqtelMsg msg;
Response *rep = msg.mutable_response();
rep->set_result(200);
rep->set_error_describe("login OK ");
length = msg.ByteSize();
flag = msg.SerializeToArray(output,length);
if(!flag)
{
printf("SendRep SerializeToArray is wrong \n");
return -1;
}
SVR_MakeHead(output,sendbuf,length);
size = length + 6;
struct PJ_Data *st = (struct PJ_Data*) pj_ssl_sock_get_user_data(ssock);
status = pj_ssl_sock_send(ssock, (pj_ioqueue_op_key_t*)&st->send_key, sendbuf, &size, 0);
if(status == PJ_SUCCESS)
printf("Send login rep OK,size---%d \n",(int)size);
return 0;
}
int SVR_RecvData(pj_ssl_sock_t *ssock, char *data, pj_size_t size)
{
short ncrc;
int proto_len;
char proto_msg[512] = {
0};
pqtel_head *head = (pqtel_head *)data;
if (ntohs(head->type) != 0x5051)
{
printf("SVR_RecvData Get type is wrong \n");
return -1;
}
proto_len = ntohs(head->msglen) - 2;
memcpy((char*)&ncrc, data + sizeof(pqtel_head) + proto_len, sizeof(short));
memcpy(proto_msg, data + sizeof(pqtel_head), proto_len);
//反序列化protobuf数据
PqtelMsg msg;
bool flag = msg.ParseFromArray(proto_msg, proto_len);
if (!flag)
{
printf("SVR_RecvData ParseFromArray is wrong \n");
return -2;
}
if (msg.type() == Login_Request)
{
string uuid = msg.request().login().uuid();
printf("SVR_RecvData Get Login_Req uuid --- [%s] \n", uuid.c_str());
//发送回应
SVR_SendRep(ssock);
}
return 0;
}
pj_bool_t SVR_DataRead(pj_ssl_sock_t