本文详细说明了用C语言开发UNIX/Linux下安全套接字(TCP SSL)
的服务端程序,采用IO多路复用,单进程单线程,自定义并实现
缓存,链表等数据结构,代码由本人亲自编写,在IBM AIX,
Solaris,Linux多个版本下都能够稳定运行,下面详解程序
软件要求:
OpenSSL
编译器 GCC
编译命令 GCC 文件名.c -o SSLServer.o -lpthread -lssl -lcrypto
//系统头文件
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
//SSL 头文件
#include <openssl/rsa.h> /* SSLeay stuff */
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//下面3个文件都存在于执行程序的路径下
//如何制作请参阅OpenSSL说明文档,这里就不细说了
#define USE_SSL_CERTF "server.crt" //服务器证书文件名
#define USE_SSL_KEYF "server.key" //密钥文件文件名
#define USE_SSL_CACERT "ca.crt" //CA 的证书文件名
//监听的端口号
#define TCP_LISTENPORT 9001
//最大接收发送的消息长度(字节)
#define MAX_RCVSNDMSG_SIZE 1024*16
//同是最多可连接的客户端数量
#define MAX_CLIENT_COUNT 512
//心跳消息内容,这里使用txt,如果是二进制的则需要从新构造和计算长度(字节)
#define HEARTBEAT_MESSAGE "HEARTBEAT/n"
#define HEARTBEAT_MSGLEN 10 //strlen("HEARTBEAT/n")
//心跳检测周期(秒)
#define HEARTBEAT_TIMEOUT 20
//SSL_accept的超时(秒),由于SSL_accept不影响select的结果,所以只能
//循环调用SSL_accept检查成功或失败
#define SSLACCEPT_TIMEOUT 20
//首先,初始化SSL库,下面定义的结构体
typedef struct _tagAgent_ssl
{
bool t_enable;
SSL_CTX *t_ssl_ctx;
SSL_METHOD *t_ssl_meth;
}AG_SSL,*LPAG_SSL;
bool InitSSL(struct AG_SSL *pAgSSL)
{
char strCWD[512],strName[512];
memset(strCWD,0,sizeof(strCWD));
memset(strName,0,sizeof(strName));
//获取当前路径
getcwd(strCWD,sizeof(strCWD)-1);
//进行SSL信息的初始化
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
//
pAgSSL->t_ssl_meth = SSLv23_server_method();
pAgSSL->t_ssl_ctx = SSL_CTX_new (pAgSSL->t_ssl_meth);
if (!pAgSSL->t_ssl_ctx)
{
printf("SSL_CTX_new failed!/n");
return false;
}
snprintf(strName,sizeof(strName)-1,"%s/%s",strCWD,USE_SSL_CERTF);
if (SSL_CTX_use_certificate_file(pAgSSL->t_ssl_ctx, strName, SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_certificate_file failed!/n");
return false;
}
EVP_PKEY *pkey;
snprintf(strName,sizeof(strName)-1,"%s/%s",strCWD,USE_SSL_KEYF);
if (SSL_CTX_use_PrivateKey_file(pAgSSL->t_ssl_ctx, strName, SSL_FILETYPE_PEM) <= 0)
{
printf("SSL_CTX_use_PrivateKey_file failed!/n");
return false;
}
if (!SSL_CTX_check_private_key(pAgSSL->t_ssl_ctx))
{
printf("Private key does not match the certificate public key/n");
return false;
}
pAgSSL->t_enable = true;
return true;
}
//监听端口
//以下是需要使用的数据结构和处理函数
//我们需要一个缓存结构,处理socket数据的发送和接收
typedef struct _tagAgent_DynticBuffer
{
unsigned int m_buf_length; //缓冲区长度
unsigned int m_buf_datalen; //缓冲区内数据长度
char *m_buf_ptr; //缓冲区首地址
}AG_BUFFER,*LPAG_BUFFER;
//控制函数:
//初始化
void AgBufferReady(LPAG_BUFFER pBuf);
//清空缓存数据
void AgBufferResetMem(LPAG_BUFFER pBuf);
//释放缓存空间
void AgBufferFreeMem(LPAG_BUFFER pBuf);
//创建缓存
LPAG_BUFFER AgBufferCreate(int iSize,bool IsZeroMem);
//从头移除数据块,剩余数据移动
void AgBufferDecLenFromHead(LPAG_BUFFER pBuf,int iOffset);
//从尾部添加数据块
void AgBufferAppendData(LPAG_BUFFER pBuf,char *pData,int iSize,bool bRemoveLastZero);
//从尾移除数据块,剩余数据不移动
void AgBufferDecLenFromTail(LPAG_BUFFER pBuf,int iOffset);
//以上函数代码在后面给出
//我们也需要一个结构体,存储socket连接信息
typedef enum _euSockStatus
{
sock_down = 1, //断开
sock_listen = 4, //监听
sock_accept = 5, //SSL_accept成功的client
}euSockStatus;
typedef enum _euSSLacceptChk
{
chk_success = 0, //检查通过
chk_fail = 2, //SSL_accept失败
chk_continue = 3 //SSL_accept 未决,继续检查
}euSSLacceptChk;
//存储活动套接字信息
typedef struct _tagAgent_Net
{
SOCKET t_sock; //套接字描述符
int t_flags; //套接字初始option(阻塞)
SOCKADDR_IN t_sa; //目标网络地址
SSL *t_ssl; //ssl结构指针
time_t t_sslaccp_begintime; //第一次调用SSL_accept时间
time_t t_connected_time; //连接上来的时间
enum _euSockStatus t_status; //当前状态
bool t_begin_stream; //是否通过了ssl_accept连接检查
AG_BUFFER *t_rcvbuf; //接收数据缓存指针
AG_BUFFER *t_sndbuf; //发送数据缓存指针
}AG_NET,*LPAG_NET;
//控制函数
//初始化
void AgNetItemReset(LPAG_NET pNetItem)
{
AgNetItemClear(pNetItem);
t_ssl = 0;
t_rcvbuf = 0;
t_sndbuf = 0;
//注意 t_ssl,t_rcvbuf,t_sndbuf 三个指针类型成员初始为空
}
//复位,除t_ssl,t_rcvbuf,t_sndbuf 这3个指针外,其余
//成员复位。
void AgNetItemClear(LPAG_NET pNetItem)
{
pNetItem->t_sock = -1;
memset(&pNetItem->t_sa,0,sizeof(SOCKADDR_IN));
memset(pNetItem->t_ansi_addr,0,sizeof(pNetItem->t_ansi_addr));
pNetItem->t_status = sock_down;
pNetItem->t_begin_stream = false;
pNetItem->t_sslaccp_begintime = 0;
}
//我们需要一个链表来存储活动套接字数据结构及控制函数定义如下
//函数实现后面给出
typedef struct _tagPosition {} TPOSITION,*LPTPOS;
//链表数据区结构
typedef struct _tagAgent_Data
{
int t_type; //数据类别,用户私有定义
char *t_data; //数据指针
int t_buf_len; //当前存储区总长度(字节)
int t_data_len; //当前数据长度(字节)
}AG_DATA,*LPAG_DATA;
//链表节点结构
typedef struct _tagAgent_ListNode
{
bool t_status; //是否分配的标志
struct _tagAgent_Data t_data; //数据区
struct _tagAgent_ListNode *t_list_next; //当前节点的next指针
struct _tagAgent_ListNode *t_list_pre; //当前节点的pre指针
struct _tagAgent_ListNode *t_pool_next; //当前节点的的节点池的next指针
struct _tagAgent_ListNode *t_pool_pre; //当前节点的的节点池的pre指针
}AG_NODE,*LPAG_NODE;
//链表容器结构
typedef struct _tagAgent_ListContainer
{
struct _tagAgent_ListNode *t_pool_head; //节点池的头指针
struct _tagAgent_ListNode *t_pool_tail; //节点池的尾指针
struct _tagAgent_ListNode *t_list_head; //链表头指针
struct _tagAgent_ListNode *t_list_tail; //链表尾指针
int t_pool_count;
int t_list_count;
}AG_LISTCONT,*LPAG_LISTCONT;
//控制函数:
//初始化链表节点
void ListNodeReset(AG_NODE *pListNode);
//初始化链表容器
void ListContainerReset(AG_LISTCONT *pListContainer);
//从头部添加节点
void ListContainerAddHead(AG_LISTCONT *pListContainer,AG_DATA nData,bool keepOldVal);
//从尾部添加节点
void ListContainerAddTail(AG_LISTCONT *pListContainer,AG_DATA nData,bool keepOldVal);
//Get头部节点存储的数据指针
AG_DATA *ListContainerGetHead(AG_LISTCONT *pListContainer);
//Get尾部节点存储的数据指针
AG_DATA *ListContainerGetTail(AG_LISTCONT *pListContainer);
//从头部移除节点
void ListContainerRemoveHead(AG_LISTCONT *pListContainer);
//从尾部移除节点
void ListContainerRemoveTail(AG_LISTCONT *pListContainer);
//移除指定节点
void ListContainerRemoveNode(LPAG_NODE pNode,AG_LISTCONT *pListContainer);
//移除所有节点
void ListContainerRemoveListAll(AG_LISTCONT *pListContainer);
//移除节点池所有节点,并释放所有存储
void ListContainerRemovePoolAll(AG_LISTCONT *pListContainer);
//从节点池中分配一个空闲节点
AG_NODE *_List_AllocFromPool(AG_LISTCONT *pListContainer);
//下面俩函数是验证链表长度和节点池长度的函数
int ListContainerPurListCount(AG_LISTCONT *pListContainer,bool *bValidate);
int ListContainerPurPoolCount(AG_LISTCONT *pListContainer,bool *bValidate);
//开始监听,参数 pNetList 是链表容器指针,listenport 监听的端口
bool start_tcplisten(AG_LISTCONT *pNetList,int listenport)
{
AG_NET listener;
AG_DATA agData,*pData;
agData.t_data = (void*)&listener;
agData.t_data_len = sizeof(listener);
agData.t_type = 10; //监听的socket
ListContainerAddTail(pNetList,agData,false);
pData = ListContainerGetTail(pNetList);
AG_NET *tail = (LPAG_NET)pData->t_data;
AgNetItemReset(tail);
tail->t_sock = socket(AF_INET, SOCK_STREAM, 0);
if (tail->t_sock < 0)
{
ListContainerRemoveTail(pNetList);
return false;
}
tail->t_rcvbuf = 0;
tail->t_sa.sin_family = AF_INET;
tail->t_sa.sin_port = htons(listenport);
tail->t_sa.sin_addr.s_addr = INADDR_ANY;
//设置SO_REUSEADDR标志
setsockopt(tail->t_sock,SOL_SOCKET,SO_REUSEADDR,
(void *)&tail->t_sa.sin_addr,sizeof(tail->t_sa.sin_addr));
//绑定端口
if(bind(tail->t_sock, (struct sockaddr *)&(tail->t_sa), sizeof(tail->t_sa)) < 0 )
{
ShutTCPSocket(tail);
ListContainerRemoveTail(pNetList);
return false;
}
//监听
if(listen(tail->t_sock, SOMAXCONN) < 0)
{
ShutTCPSocket(tail);
ListContainerRemoveTail(pNetList);
return false;
}
tail->t_status = sock_listen;
return true;
}
//监听建立起来之后,要开始接收客户端的连接,使用IO多路复用
//select 方式
//调用select之前,收集当前所有活动socket,并进行检查每个套接字的心跳周期
void net_beforeselects(AG_LISTCONT *pNetList,SOCKET *ptrSockMax,fd_set *ptrRD,
fd_set *ptrWD,bool *ptrWDFlg,time_t *ptrTmHeartbeatBegin);
//检查SSL_Accept结果,如果失败,则从链表中删除
euSSLacceptChk net_chk_SSLAcceptResult(LPAG_NODE pNetNode,AG_LISTCONT *pNetList);
//处理accept成功的client
void net_Accept(AG_NET *pListener,LPAG_SSL pSSL,AG_LISTCONT *pNetList);
//接收数据
bool read_Stream(LPAG_NODE pNetNode,AG_LISTCONT *pNetList)
//发送数据
bool send_Stream(LPAG_NODE pNetNode,AG_LISTCONT *pNetList)
//关闭socket连接
void ShutTCPSocket(AG_NET *pBroken);
//select 循环主函数
void net_Loop(LPAG_SSL pSSL,AG_LISTCONT *pNetList)
{
time_t _tm_begin = 0;
time_t _tm_cur;
bool bDoNext = false;
struct timeval tmsk;
tmsk.tv_sec=0;
tmsk.tv_usec=200000; //200 毫秒
int iSelect;
bool bwd_flg = false;
fd_set rd,wd;
SOCKET sockMax = -1;
LPAG_NET pItem = 0;
SOCKADDR_IN l_sa;
socklen_t l_nsca;
LPAG_NODE pNode = 0;
LPAG_NODE _pNode_tmp = 0;
while(1)
{
bDoNext = false;
pItem = 0;
sockMax = -1;
FD_ZERO(&rd);
FD_ZERO(&wd);
//收集活动套接字,并进行检查每个套接字的心跳周期
net_beforeselects(pNetList,&sockMax,&rd,&wd,&bwd_flg,&_tm_begin);
pItem = 0;
tmsk.tv_sec=0;
//timeout 200 毫秒
tmsk.tv_usec=200000;
iSelect = select(sockMax,&rd,bwd_flg?&wd:0,0,&tmsk);
switch(iSelect)
{
case -1:
//通讯失败
printf("select failed/n");
exit(0);
break;
case 0:
//超时,循环检查链表上每一个未决的ssl_accept的结果。
pNode = pNetList->t_list_head;
while(pNode)
{
_pNode_tmp = pNode;
pItem = (LPAG_NET)pNode->t_data.t_data;
pNode = pNode->t_list_next;
switch(pItem->t_status)
{
case sock_accept:
net_chk_SSLAcceptResult(_pNode_tmp,pNetList);
break;
}
}
break;
default:
//循环检查链表上每一个活动socket
pNode = pNetList->t_list_head;
while(pNode)
{
_pNode_tmp = pNode;
pItem = (LPAG_NET)pNode->t_data.t_data;
pNode = pNode->t_list_next;
switch(pItem->t_status)
{
case sock_listen:
if(FD_ISSET(pItem->t_sock,&rd))
{
//有连接请求
net_Accept(pItem,pSSL,pNetList);
}
break;
case sock_accept:
switch(net_chk_SSLAcceptResult(_pNode_tmp,pNetList))
{
case chk_success:
bDoNext = true;
if(FD_ISSET(pItem->t_sock,&rd))
{
//有数据可读
bDoNext = read_Stream(_pNode_tmp,pNetList);
}
if(bDoNext)
{
if(FD_ISSET(pItem->t_sock,&wd))
{
//有数据要发送
send_Stream(_pNode_tmp,pNetList);
}
}
break;
}
break;
}
}
break;
}
}
}
/*net_beforeselects*/
void net_beforeselects(AG_LISTCONT *pNetList,SOCKET *ptrSockMax,fd_set *ptrRD,
fd_set *ptrWD,bool *ptrWDFlg,time_t *ptrTmHeartbeatBegin)
{
SOCKET sockMax = -1;
LPAG_NET pItem = 0;
time_t _tm_cur;
bool _b_heartbeat = false;
if((*ptrTmHeartbeatBegin) == 0)
{
//设置检查HEARTBEAT(心跳)开始时间
time(ptrTmHeartbeatBegin);
}
else
{
time(&_tm_cur);
if(difftime(_tm_cur,*ptrTmHeartbeatBegin) >= (double)HEARTBEAT_TIMEOUT)
{
//当前应该发送心跳检测了
_b_heartbeat = true;
*ptrTmHeartbeatBegin = _tm_cur;
}
}
//遍历链表头节
LPAG_NODE pNode = pNetList->t_list_head;
while(pNode)
{
pItem = (LPAG_NET)pNode->t_data.t_data;
if(pItem->t_sock > sockMax)
{
sockMax = pItem->t_sock;
}
FD_SET(pItem->t_sock,ptrRD);
//判断是否通过SSL_Accept检查成功
if(pItem->t_status == sock_accept && pItem->t_begin_stream)
{
if(_b_heartbeat)
{
//将心跳信息数据追加写入发送缓存
AgBufferAppendData(pItem->t_sndbuf,HEARTBEAT_MESSAGE,HEARTBEAT_MSGLEN,false);
}
//判断发送缓存是否有数据要发送
if(pItem->t_sndbuf->m_buf_datalen > 0)
{
FD_SET(pItem->t_sock,ptrWD);
*ptrWDFlg = true;
}
}
pNode = pNode->t_list_next;
}
sockMax ++;
*ptrSockMax = sockMax;
}
/*net_chk_SSLAcceptResult*/
euSSLacceptChk net_chk_SSLAcceptResult(LPAG_NODE pNetNode,AG_LISTCONT *pNetList)
{
LPAG_NET pLink = (LPAG_NET)pNetNode->t_data.t_data;
if(pLink->t_begin_stream)
{
return chk_success;
}
//调用SSL_accept,由于pLink->t_sock被置成异步,所以该函数不会阻塞。
int ssl_accp = SSL_accept (pLink->t_ssl);
//取得错误码
int iErr = errno;
if(ssl_accp==-1 && iErr == 0)
{
//此种情况不会出现,因此不用处理
}
if( ssl_accp != -1)
{
//SSL_accept 成功
time(&pLink->t_connected_time);
//恢复pLink->t_sock的阻塞标志
fcntl(pLink->t_sock,F_SETFL,pLink->t_flags);
pLink->t_sslaccp_begintime = 0;
//获取连接者的证书信息
X509* client_cert = SSL_get_peer_certificate (pLink->t_ssl);
if (client_cert != NULL)
{
//连接者有证书,这里没做证书的验证,仅仅释放证书信息
X509_free (client_cert);
}
pLink->t_begin_stream = true;
return chk_success;
}
if(iErr != EINPROGRESS && iErr != EAGAIN )
{
//SSL_accept 失败
pLink->t_begin_stream = false;
ShutTCPSocket(pLink);
AgNetItemClear(pLink);
//从链表中移除(貌似删除了,但却存在于链表的节点池中,
//状态空闲,可以被分配)
ListContainerRemoveNode(pNetNode,pNetList);
return chk_fail;
}
time_t tCur;
time(&tCur);
double dOff = difftime(tCur,pLink->t_sslaccp_begintime);
if(dOff > (double)SSLACCEPT_TIMEOUT)
{
//从调用ssl_accept到目前为止,超过了SSLACCEPT_TIMEOUT秒,则认为
//ssl_accept失败。
pLink->t_begin_stream = false;
ShutTCPSocket(pLink);
AgNetItemClear(pLink);
//从链表中移除(貌似删除了,但却存在于链表的节点池中,
//状态空闲,可以被分配)
ListContainerRemoveNode(pNetNode,pNetList);
return chk_fail;
}
//还需要继续检查。
return chk_continue;
}
/*net_Accept*/
void net_Accept(AG_NET *pListener,LPAG_SSL pSSL,AG_LISTCONT *pNetList)
{
SOCKADDR_IN l_sa;
memset(&l_sa,0,sizeof(l_sa));
int l_sock,l_keepalive;
socklen_t l_nsca = sizeof(SOCKADDR_IN);
AG_NET accp;
AgNetItemReset(&accp);
AG_DATA agData,*pData;
agData.t_data = (void*)&accp;
agData.t_data_len = sizeof(accp);
agData.t_type = 11;
l_sock = accept(pListener->t_sock,(struct sockaddr *)&(l_sa),&l_nsca);
int iCurClients = ListContainerPurListCount(pNetList,0);
//当前连接者的client数量是否超过上限
if(iCurClients >= MAX_CLIENT_COUNT)
{
close(l_sock);
return;
}
//添加到链表尾部,注意,添加过程中是在
//链表的节点池中分配空闲节点,则
//成员 ssl,t_rcvbuf,t_sndbuf很有可能
//不为空,是有效的指针,所以下面有判断
ListContainerAddTail(pNetList,agData,true);
pData = ListContainerGetTail(pNetList);
AG_NET *tail = (LPAG_NET)pData->t_data;
tail->t_sock = l_sock;
memcpy(&tail->t_sa,&l_sa,sizeof(tail->t_sa));
tail->t_status = sock_accept;
if(!tail->t_rcvbuf)
{
//创建接收缓存
tail->t_rcvbuf = AgBufferCreate(MAX_RCVSNDMSG_SIZE,true);
}
if(!tail->t_sndbuf)
{
//创建发送缓存
tail->t_sndbuf = AgBufferCreate(MAX_RCVSNDMSG_SIZE,true);
}
AgBufferResetMem(tail->t_rcvbuf);
AgBufferResetMem(tail->t_sndbuf);
if(!tail->t_ssl)
{
tail->t_ssl = SSL_new (pSSL->t_ssl_ctx);
//判断 SSL_new 是否成功
if(!tail->t_ssl)
{
ShutTCPSocket(pLink);
AgNetItemClear(pLink);
ListContainerRemoveNode(pNetNode,pNetList);
return;
}
}
//设置SSL的套接字描述符
SSL_set_fd (tail->t_ssl, tail->t_sock);
//保存套接字初始flag
tail->t_flags = fcntl(tail->t_sock,F_GETFL,0);
//设置套接字为非阻塞模式,等SSL_accept成功后再恢复初始flag
fcntl(tail->t_sock,F_SETFL,tail->t_flags|O_NONBLOCK);
//调用 SSL_accept
int ssl_accp = SSL_accept (tail->t_ssl);
int iErr = errno;
if( ssl_accp != -1)
{
//立即就成功了,虽然有些不可思议
//但实际上该情况还真有(这个可以有,呵呵)
tail->t_begin_stream = true;
//恢复tail->t_sock的阻塞标志
fcntl(tail->t_sock,F_SETFL,tail->t_flags);
return;
}
if(iErr != EINPROGRESS && iErr != EAGAIN )
{
//失败
ShutTCPSocket(tail);
AgNetItemClear(tail);
ListContainerRemoveTail(pNetList);
return;
}
//设置第一次调用 SSL_accept 的时间
time(&tail->t_sslaccp_begintime);
}
/*关闭套接字描述符*/
void ShutTCPSocket(AG_NET *pBroken)
{
if(pBroken->t_ssl)
{
//调用 SSL_clear 清空ssl缓存数据,
//不调用SSL_free释放
SSL_clear(pBroken->t_ssl);
}
close(pBroken->t_sock);
}
/*read_Stream*/
bool read_Stream(LPAG_NODE pNetNode,AG_LISTCONT *pNetList)
{
time_t tmCur;
LPAG_NET pLink = (LPAG_NET)pNetNode->t_data.t_data;
LPAG_BUFFER pBuf = pLink->t_rcvbuf;
int iRet = 0;
//计算接收缓存的指针偏移量,就是从什么位置读
char *pRead = pBuf->m_buf_ptr + pBuf->m_buf_datalen;
//计算接收缓存剩余空间长度,就是还能读多少字节
int iReadLen = pBuf->m_buf_length - pBuf->m_buf_datalen-1;
if(iReadLen <= 0)
{
//当前接收缓存数据溢出。
goto LASTERR;
}
//SSL读数据
iRet = SSL_read(pLink->t_ssl, pRead, iReadLen);
if(iRet <= 0)
{
//连接中断了
goto LASTERR;
}
//数据解析
pBuf->m_buf_datalen += iRet;
{
//这里做数据解析,暂时来个最简单的,原封不动的反射回去
//将接收缓存里所有数据追加到发送缓存里
AgBufferAppendData(pLink->t_sndbuf,pBuf->m_buf_ptr ,pBuf->m_buf_datalen,false);
//将接收缓存里剩余数据往头部移动pBuf->m_buf_datalen长度(原封不动的反射的情况下,没有剩余数据了)
AgBufferDecLenFromHead(pLink->t_rcvdbuf,pBuf->m_buf_datalen);
}
return true;
LASTERR:
ShutTCPSocket(pLink);
AgNetItemClear(pLink);
ListContainerRemoveNode(pNetNode,pNetList);
return false;
}
/*send_Stream*/
bool send_Stream(LPAG_NODE pNetNode,AG_LISTCONT *pNetList)
{
int iRet = 0;
LPAG_NET pLink = (LPAG_NET)pNetNode->t_data.t_data;
LPAG_TuxAsynCallNode pTuxNode = 0;
SSL *ssl = pLink->t_ssl;
SOCKET sock = pLink->t_sock;
//从头开始
char *pSend = pLink->t_otherbuf->m_buf_ptr;
//尽量发送所有数据
int iSendLen = pLink->t_otherbuf->m_buf_datalen;
if(iSendLen > 0)
{
//SSL发送数据
iRet = SSL_write(ssl, pSend, iSendLen);
if(iRet <= 0)
{
//连接中断。
goto LASTERR;
}
//把剩余数据左移,因为发送成功的返回值(复制到系统发送缓存字节数)
//很有可能小于期望值
AgBufferDecLenFromHead(pLink->t_otherbuf,iRet);
}
return true;
LASTERR:
ShutTCPSocket(pLink);
AgNetItemClear(pLink);
ListContainerRemoveNode(pNetNode,pNetList);
return false;
}
//下面是全局变量
AG_LISTCONT g_net_List;
AG_SSL g_net_SSL;
//安全退出函数
void _safe_exit()
{
LPAG_NODE pNode = g_net_List.t_list_head;
while(pNode)
{
LPAG_NET pItem = (LPAG_NET)pNode->t_data.t_data;
ShutTCPSocket(pItem);
pNode = pNode->t_list_next;
}
}
//信号捕获函数
void _catchsignal(int sig)
{
switch(sig)
{
case SIGINT:
case SIGTERM:
_safe_exit();
break;
case SIGILL:
_safe_exit();
break;
}
}
//主程序入口
int main(int argc,char *argv[])
{
if(!InitSSL(&g_net_SSL))
{
printf("InitSSL failed/n");
exit(0)
}
signal(SIGPIPE,SIG_IGN); //忽略socket中断连接的信号
signal(SIGINT,_catchsignal);
signal(SIGTERM,_catchsignal);
signal(SIGILL,_catchsignal);
signal(SIGTRAP,SIG_IGN); //忽略陷阱信号
ListContainerReset(&g_net_List);
if(start_tcplisten(&g_net_List,TCP_LISTENPORT))
net_Loop(&g_net_SSL,&g_net_List);
else
printf("start_tcplisten failed/n");
}
//检查pData有效性
void _chk_data_validate(void *pData,void *pChk,const char *pErrdesc)
{
if(pData == pChk)
{
FILE *fp = fopen("./AgentC_Core","a");
if(fp)
{
AG_DATETIME dt;
_date_time(&dt);
fprintf(fp,"<_chk_data_validate>%s!<%04d-%02d-%02d %02d:%02d:%02d>/n",
pErrdesc,dt.year,dt.mon,dt.day,dt.hour,dt.min,dt.sec);
fflush(fp);
fclose(fp);
}
sleep(2);
exit(0);
}
}
/*下面是缓存控制函数*/
//初始化
void AgBufferReady(LPAG_BUFFER pBuf)
{
pBuf->m_buf_ptr = 0;
pBuf->m_buf_length = 0;
pBuf->m_buf_datalen = 0;
};
//清空缓存数据
void AgBufferResetMem(LPAG_BUFFER pBuf)
{
if(pBuf->m_buf_ptr)
{
memset(pBuf->m_buf_ptr,0,pBuf->m_buf_length);
pBuf->m_buf_datalen = 0;
}
}
//释放缓存空间
void AgBufferFreeMem(LPAG_BUFFER pBuf)
{
if(pBuf->m_buf_ptr)
{
free(pBuf->m_buf_ptr);
free(pBuf);
}
}
//创建缓存
LPAG_BUFFER AgBufferCreate(int iSize,bool IsZeroMem)
{
LPAG_BUFFER retBuf = (LPAG_BUFFER)malloc(sizeof(AG_BUFFER));
_chk_data_validate(retBuf,NULL,"AgBufferCreate()->malloc(AG_BUFFER) failed!");
AgBufferReady(retBuf);
retBuf->m_buf_ptr = (char*)malloc(iSize);
_chk_data_validate(retBuf->m_buf_ptr,NULL,"AgBufferCreate()->malloc(size) failed!");
if(IsZeroMem)
memset(retBuf->m_buf_ptr,0,iSize);
retBuf->m_buf_length = iSize;
return retBuf;
}
//往缓存追加数据块
void AgBufferAppendData(LPAG_BUFFER pBuf,char *pData,int iSize,bool bRemoveLastZero)
{
int iDataLen = pBuf->m_buf_datalen;
int iPreBufLen = pBuf->m_buf_length;
int iNewLen = 0;
char *pTR = pBuf->m_buf_ptr;
if(bRemoveLastZero)
{
if(pData[iSize-1] == '/0')
{
iSize --;
}
}
iDataLen += iSize;
pTR += pBuf->m_buf_datalen;
if(iPreBufLen-iDataLen > 0)
{
memcpy(pTR,pData,iSize);
pBuf->m_buf_datalen = iDataLen;
return;
}
iNewLen = iDataLen+1;
pTR = (char*)malloc(iNewLen);
_chk_data_validate(pTR,NULL,g_log.t_buf);
if(pBuf->m_buf_datalen > 0)
memcpy(pTR,pBuf->m_buf_ptr,pBuf->m_buf_datalen);
memcpy(pTR+pBuf->m_buf_datalen,pData,iSize);
free(pBuf->m_buf_ptr);
pTR[iDataLen] = '/0';
pBuf->m_buf_ptr = pTR;
pBuf->m_buf_length = iNewLen;
pBuf->m_buf_datalen = iDataLen;
}
//从头移除数据块,剩余数据移动
void AgBufferDecLenFromHead(LPAG_BUFFER pBuf,int iOffset)
{
char *pOffset = 0;
int iOffLen = 0;
if(pBuf->m_buf_datalen >= iOffset)
{
iOffLen = pBuf->m_buf_datalen - iOffset;
if(iOffLen > 0)
{
pOffset = pBuf->m_buf_ptr + iOffset;
memmove(pBuf->m_buf_ptr,pOffset,iOffLen);
pBuf->m_buf_ptr[iOffLen] = '/0';
}
pBuf->m_buf_datalen = iOffLen;
return;
}
}
//从尾移除数据块,剩余数据不移动
void AgBufferDecLenFromTail(LPAG_BUFFER pBuf,int iOffset)
{
pBuf->m_buf_datalen = pBuf->m_buf_datalen - iOffset;
if(pBuf->m_buf_datalen < 0)
{
pBuf->m_buf_datalen = 0;
}
}
/*下面给出链表控制函数*/
//初始化链表节点
void ListNodeReset(AG_NODE *pListNode)
{
pListNode->t_data.t_buf_len = 0;
pListNode->t_data.t_data = 0;
pListNode->t_data.t_data_len = 0;
pListNode->t_data.t_type = 0;
pListNode->t_list_next = 0;
pListNode->t_list_pre = 0;
pListNode->t_pool_next = 0;
pListNode->t_pool_pre = 0;
pListNode->t_status = false;
}
//初始化链表容器
void ListContainerReset(AG_LISTCONT *pListContainer)
{
pListContainer->t_pool_head = 0;
pListContainer->t_pool_tail = 0;
pListContainer->t_list_head = 0;
pListContainer->t_list_tail = 0;
pListContainer->t_list_count = 0;
pListContainer->t_pool_count = 0;
}
//从节点池中分配一个空闲节点
AG_NODE *_List_AllocFromPool(AG_LISTCONT *pListContainer)
{
if(pListContainer->t_pool_head == 0 || pListContainer->t_pool_tail == 0)
{
pListContainer->t_pool_head = (AG_NODE *)malloc(sizeof(AG_NODE));
if(!pListContainer->t_pool_head)
{
_chk_data_validate(NULL,NULL,"List malloc(...) failed!");
}
ListNodeReset(pListContainer->t_pool_head);
pListContainer->t_pool_tail = pListContainer->t_pool_head;
pListContainer->t_pool_count = 1;
pListContainer->t_pool_head->t_status = true;
return pListContainer->t_pool_head;
}
AG_NODE *pRight = pListContainer->t_pool_head,
*pLeft = pListContainer->t_pool_tail,*pReturn = 0;
while(1)
{
if(!pLeft && !pRight)
break;
if(pLeft)
{
if(!pLeft->t_status)
{
pReturn = pLeft;
break;
}
pLeft = pLeft->t_pool_pre;
}
if(pRight)
{
if(!pRight->t_status)
{
pReturn = pRight;
break;
}
pRight = pRight->t_pool_next;
}
}
if(!pReturn)
{
pReturn = (AG_NODE *)malloc(sizeof(AG_NODE));
if(!pReturn)
{
_chk_data_validate(NULL,NULL,"List malloc(...) failed!");
}
ListNodeReset(pReturn);
pReturn->t_pool_pre = pListContainer->t_pool_tail;
pReturn->t_pool_next = 0;
pListContainer->t_pool_tail->t_pool_next = pReturn;
pListContainer->t_pool_tail = pReturn;
pListContainer->t_pool_count ++;
}
pReturn->t_status = true;
return pReturn;
}
//从头部添加节点
void ListContainerAddHead(AG_LISTCONT *pListContainer,AG_DATA nData,bool keepOldVal)
{
AG_NODE *pNode = _List_AllocFromPool(pListContainer);
if(pNode->t_data.t_buf_len >= nData.t_data_len)
{
if(!keepOldVal)
{
//如果不保持原有数据的话就将节点的数据区清零
memset(pNode->t_data.t_data,0,pNode->t_data.t_buf_len);
memcpy(pNode->t_data.t_data,nData.t_data,nData.t_data_len);
pNode->t_data.t_type = nData.t_type;
}
}
else
{
if(pNode->t_data.t_data)
free(pNode->t_data.t_data);
pNode->t_data.t_data = (char*)malloc(nData.t_data_len);
if(!pNode->t_data.t_data)
{
_chk_data_validate(NULL,NULL,"List malloc(...) failed!");
}
memcpy(pNode->t_data.t_data,nData.t_data,nData.t_data_len);
pNode->t_data.t_buf_len = nData.t_data_len;
pNode->t_data.t_data_len = nData.t_data_len;
pNode->t_data.t_type = nData.t_type;
}
if(pListContainer->t_list_head == 0 || pListContainer->t_list_tail == 0)
{
pListContainer->t_list_head = pNode;
pListContainer->t_list_tail = pNode;
pNode->t_list_pre = 0;
pNode->t_list_next = 0;
pListContainer->t_list_count = 1;
}
else
{
pListContainer->t_list_head->t_list_pre = pNode;
pNode->t_list_pre = 0;
pNode->t_list_next = pListContainer->t_list_head;
pListContainer->t_list_head = pNode;
pListContainer->t_list_count ++;
}
}
//从尾部添加节点
void ListContainerAddTail(AG_LISTCONT *pListContainer,AG_DATA nData,bool keepOldVal)
{
AG_NODE *pNode = _List_AllocFromPool(pListContainer);
if(pNode->t_data.t_buf_len >= nData.t_data_len)
{
if(!keepOldVal)
{
//如果不保持原有数据的话就将节点的数据区清零
memset(pNode->t_data.t_data,0,pNode->t_data.t_buf_len);
memcpy(pNode->t_data.t_data,nData.t_data,nData.t_data_len);
pNode->t_data.t_type = nData.t_type;
}
}
else
{
if(pNode->t_data.t_data)
free(pNode->t_data.t_data);
pNode->t_data.t_data = (char*)malloc(nData.t_data_len);
if(!pNode->t_data.t_data)
{
_chk_data_validate(NULL,NULL,"List malloc(...) failed!");
}
memcpy(pNode->t_data.t_data,nData.t_data,nData.t_data_len);
pNode->t_data.t_buf_len = nData.t_data_len;
pNode->t_data.t_data_len = nData.t_data_len;
pNode->t_data.t_type = nData.t_type;
}
if(pListContainer->t_list_head == 0 || pListContainer->t_list_tail == 0)
{
pListContainer->t_list_head = pNode;
pListContainer->t_list_tail = pNode;
pNode->t_list_pre = 0;
pNode->t_list_next = 0;
pListContainer->t_list_count = 1;
}
else
{
pListContainer->t_list_tail->t_list_next = pNode;
pNode->t_list_next = 0;
pNode->t_list_pre = pListContainer->t_list_tail;
pListContainer->t_list_tail = pNode;
pListContainer->t_list_count ++;
}
}
//Get头部节点存储的数据指针
LPAG_DATA ListContainerGetHead(AG_LISTCONT *pListContainer)
{
return (pListContainer->t_list_head!=0)?&pListContainer->t_list_head->t_data:0;
}
//Get尾部节点存储的数据指针
LPAG_DATA ListContainerGetTail(AG_LISTCONT *pListContainer)
{
return (pListContainer->t_list_tail!=0)?&pListContainer->t_list_tail->t_data:0;
}
//从头部移除节点
void ListContainerRemoveHead(AG_LISTCONT *pListContainer)
{
LPAG_NODE pNode = pListContainer->t_list_head;
if(pNode)
{
if(pNode == pListContainer->t_list_tail)
{
//只有一个节点
pListContainer->t_list_head = 0;
pListContainer->t_list_tail = 0;
}
else
{
pListContainer->t_list_head = pNode->t_list_next;
pListContainer->t_list_head->t_list_pre = 0;
}
pNode->t_status = false;
pListContainer->t_list_count --;
}
}
//从尾部移除节点
void ListContainerRemoveTail(AG_LISTCONT *pListContainer)
{
LPAG_NODE pNode = pListContainer->t_list_tail;
if(pNode)
{
if(pNode == pListContainer->t_list_head)
{
//只有一个节点
pListContainer->t_list_head = 0;
pListContainer->t_list_tail = 0;
}
else
{
pListContainer->t_list_tail = pNode->t_list_pre;
pListContainer->t_list_tail->t_list_next = 0;
}
pNode->t_status = false;
pListContainer->t_list_count --;
}
}
//移除指定节点
void ListContainerRemoveNode(LPAG_NODE pNode,AG_LISTCONT *pListContainer)
{
if(pNode == pListContainer->t_list_head)
{
ListContainerRemoveHead(pListContainer);
return;
}
if(pNode == pListContainer->t_list_tail)
{
ListContainerRemoveTail(pListContainer);
return;
}
LPAG_NODE pPre = pNode->t_list_pre,pNext = pNode->t_list_next;
pPre->t_list_next = pNext;
pNext->t_list_pre = pPre;
pNode->t_status = false;
pListContainer->t_list_count --;
}
//移除所有节点
void ListContainerRemoveListAll(AG_LISTCONT *pListContainer)
{
LPAG_NODE pNode = pListContainer->t_list_head;
if(pNode && pNode == pListContainer->t_list_tail)
{
pListContainer->t_list_head = 0;
pListContainer->t_list_tail = 0;
pNode->t_status = false;
pListContainer->t_list_count --;
return;
}
while(pNode)
{
pNode->t_status = false;
pListContainer->t_list_count --;
pNode = pNode->t_list_next;
}
pListContainer->t_list_head = 0;
pListContainer->t_list_tail = 0;
}
//移除节点池所有节点,并释放所有存储
void ListContainerRemovePoolAll(AG_LISTCONT *pListContainer)
{
LPAG_NODE pNode = pListContainer->t_pool_head;
while(pNode)
{
LPAG_NODE pTmp = pNode->t_pool_next;
if(pNode->t_data.t_data)
{
free(pNode->t_data.t_data);
}
free(pNode);
pListContainer->t_pool_count --;
pNode = pTmp;
}
pListContainer->t_pool_head = 0;
pListContainer->t_pool_tail = 0;
}
//验证链表长度
int ListContainerPurListCount(AG_LISTCONT *pListContainer)
{
int i = 0;
LPAG_NODE pNode = pListContainer->t_list_head;
while(pNode)
{
i ++;
pNode = pNode->t_list_next;
}
if(i != pListContainer->t_list_count)
{
_chk_data_validate(NULL,NULL,"ListContainerPurListCount() != "/
"pListContainer->t_list_count");
}
return i;
}
//验证节点池长度
int ListContainerPurPoolCount(AG_LISTCONT *pListContainer)
{
int i = 0;
LPAG_NODE pNode = pListContainer->t_pool_head;
while(pNode)
{
i ++;
pNode = pNode->t_pool_next;
}
if(i != pListContainer->t_pool_count)
{
_chk_data_validate(NULL,NULL,"ListContainerPurPoolCount() != "/
"pListContainer->t_pool_count");
}
return i;
}
//一旦指针有效的话,就永远也不释放了,因为
//pNetItem会存在于链表容器的节点池中。