详解C语言开发unix/Linux下安全套接字(SSL)的TCP服务端程序

本文详细说明了用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会存在于链表容器的节点池中。

发布了19 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qman007/article/details/6208574
今日推荐