安全传输平台项目——密钥协商共享内存-守护进程-脚本

在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

10-安全传输平台项目-第06天(密钥协商共享内存-守护进程-脚本)

目录:
一、复习
二、密钥协商共享内存-守护进程-脚本
1、共享内存操作函数接口设计
2、共享内存操作函数实现领读
3、生成密钥-组织密钥结构体信息
4、客户端写密钥信息到共享内存
5、服务器内存释放
6、共享内存补充说明
7、服务器守护进程创建
8、守护进程管理脚本
9、借助信号管理守护进程
10、密钥校验流程分析

 

一、复习

1、客户端:keymngclient.c—负责业务逻辑;keymngclientop.c—负责功能实现

2、服务器:keymngserver.c—负责业务逻辑;keymngserverop.c—负责功能实现

密钥协商业务逻辑图

 

二、安全传输平台项目——密钥协商共享内存-守护进程-脚本

1、共享内存操作函数接口设计

----共享内存    函数接口。
    分析网点密钥信息 元素            --- struct shmNodeInfo{}                   
        shmNodeInfo{ seckey, clientID, serverID, seckeyid, status, time }

    模块组织关系:
        客户端:
            协商密钥成功,写 密钥节点信息 到 共享内存。 密钥校验, 读 取共享内存密钥信息。

        服务器:
            协商密钥成功,写 密钥节点信息 到 共享内存。 密钥校验, 读 取共享内存密钥信息。

    存储:   
        服务器:struct shmNodeInfo     shmInfo[N];
          1
          :
          N
        客户端:struct shmNodeInfo     shmInfo;

    初始化/创建共享内存
        int shmInit(int shmkey, int size, int *shmhdle);   int -- map(shmat) --->void *

    写网点信息共享内存
        int shmNode_write(int shmhdle, struct shmNodeInfo *pShmNode, int maxnode);

    读网点信息共享内存
        int shmNode_Read(int shmhdle, struct shmNodeInfo **pShmNode, char *clientID,char *serverID);

 

2、共享内存操作函数实现领读

》函数封装:shmget()--> myipc_shm.c --> keymng_shmop.c  --- keymng_shmop.h

分析了keymng_shmop.h和keymng_shmop.c

>keymng_shmop.h

// keymng_shmop.h

#ifndef _KEYMNG_SHMOP_H_
#define _KEYMNG_SHMOP_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#ifdef __cplusplus 
extern "C" {
#endif

//将网点密钥信息写共享内存, 网点共享内存结构体
typedef struct _NodeSHMInfo
{    
    int             status;            //密钥状态 0-有效 1无效
    char            clientId[12];    //客户端id
    char            serverId[12];    //服务器端id    
    int                seckeyid;        //对称密钥id
    unsigned char    seckey[128];    //对称密钥 //hash1 hash256 md5
}NodeSHMInfo;


//int KeyMng_ShmInit(int keyid, int keysize, void *shmid )
//打开共享内存 共享内存存在则使用 不存在则创建(此函数并不是初始化)
int KeyMng_ShmInit(int key, int maxnodenum, int *shmhdl);

int KeyMng_ShmWrite(int shmhdl, int maxnodenum, NodeSHMInfo *pNodeInfo);//pNodeInfo是传入参数

int KeyMng_ShmRead(int shmhdl, char *clientId, char *serverId,  int maxnodenum, NodeSHMInfo *pNodeInfo);//pNodeInfo是传出参数


#ifdef __cplusplus
}
#endif
#endif
keymng_shmop.h

>keymng_shmop.c

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include "keymnglog.h"
#include "keymng_shmop.h"
#include "myipc_shm.h"
#include "keymngclientop.h"

//查看共享内存是否存在
//若 存在使用旧 
//若 不存在创建
int KeyMng_ShmInit(int key, int maxnodenum, int *shmhdl)
{
    int                ret = 0;
    
    //打开共享内存
    ret = IPC_OpenShm(key, maxnodenum*sizeof(NodeSHMInfo), shmhdl);
    if (ret == MYIPC_NotEXISTErr)
    {
        printf("keymng监测到共享内存不存在 正在创建共享内存...\n");
        ret = IPC_CreatShm(key, maxnodenum*sizeof(NodeSHMInfo), shmhdl);
        if (ret != 0)
        {
            printf("keymng创建共享内存 err:%d \n", ret);
            return ret;
        }
        else
        {
            void     *mapaddr = NULL;
            printf("keymng创建共享内存 ok...\n");
            
            ret = IPC_MapShm(*shmhdl, (void **) &mapaddr);
            if (ret != 0)
            {
                printf("fun IPC_MapShm() err:%d 清空共享内存失败\n", ret);
                return ret;
            }
            memset(mapaddr, 0, maxnodenum*sizeof(NodeSHMInfo));
            IPC_UnMapShm(mapaddr);
            printf("keymng清空共享内存ok\n");
        }
    }
    else if (ret == 0)
    {
        printf("keymng监测到共享内存存在 使用旧的共享内存...\n");
    }
    else 
    {
        printf("fun IPC_OpenShm() err:%d\n", ret);
    }
    
    return ret;    
}

//写网点密钥 
//若存在 则修改 
//若不存在 则找一个空的位置写入
int KeyMng_ShmWrite(int shmhdl, int maxnodenum, NodeSHMInfo *pNodeInfo)
{
    int                ret = 0, i = 0;
    NodeSHMInfo      tmpNodeInfo;         //空结点
    NodeSHMInfo        *pNode = NULL;
    
    void             *mapaddr = NULL;
    
    memset(&tmpNodeInfo, 0, sizeof(NodeSHMInfo));
    //连接共享内存
    ret = IPC_MapShm(shmhdl, (void **) &mapaddr);
    if (ret != 0)
    {
        KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"func IPC_MapShm() err");
        goto End;
    }
    
    //判断传入的网点密钥 是否已经 存在
    for (i=0; i<maxnodenum; i++)
    {
        pNode = mapaddr + sizeof(NodeSHMInfo)*i;
        
        if (strcmp(pNode->clientId, pNodeInfo->clientId) == 0 &&
            strcmp(pNode->serverId, pNodeInfo->serverId) == 0 )
        {
            KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[3], ret,"系统检测到 共享内存中已经存在网点信息cliented:%s serverid%s", pNode->clientId, pNode->serverId);
            memcpy(pNode, pNodeInfo, sizeof(NodeSHMInfo));
            goto End;
        } 
    }    
    
    //若不存在
    for (i=0; i<maxnodenum; i++)
    {
        pNode = mapaddr + sizeof(NodeSHMInfo)*i;
        if (memcmp(&tmpNodeInfo, pNode, sizeof(NodeSHMInfo)) == 0 )
        {
            KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[3], ret,"系统检测到 有一个空的位置 ");
            memcpy(pNode, pNodeInfo, sizeof(NodeSHMInfo));
            goto End;
        }
    }
    
    if (i == maxnodenum)
    {
        ret = 1111;
        KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"系统检测到共享内存已满 ");
        goto End;
    }
    
End:
    IPC_UnMapShm(mapaddr);
    return ret;
}

//根据clientid和serverid 去读网点信息
int KeyMng_ShmRead(int shmhdl, char *clientId, char *serverId,  int maxnodenum, NodeSHMInfo *pNodeInfo)
{
    int            ret = 0, i = 0;
    NodeSHMInfo      tmpNodeInfo; //空结点
    NodeSHMInfo        *pNode = NULL;
    
    void             *mapaddr = NULL;
    
    memset(&tmpNodeInfo, 0, sizeof(NodeSHMInfo));
    //连接共享内存
    ret = IPC_MapShm(shmhdl, (void **) &mapaddr);
    if (ret != 0)
    {
        KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"func IPC_MapShm() err");
        goto End;
    }
    
    //遍历网点信息
    for (i=0; i<maxnodenum; i++)
    {
        pNode = mapaddr + sizeof(NodeSHMInfo)*i;
        
        if ( strcmp(pNode->clientId, clientId) == 0 &&
            strcmp(pNode->serverId, serverId) == 0 )
        {
            KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[3], ret,"系统检测到 有一个空的位置 ");
            memcpy(pNodeInfo, pNode, sizeof(NodeSHMInfo));
            goto End;
        }
    }
    
    if (i == maxnodenum)
    {
        ret = 1111;
        KeyMng_Log(__FILE__, __LINE__,KeyMngLevel[4], ret,"系统检测到共享内存已满 ");
        goto End;
    }
    
End:
    IPC_UnMapShm(mapaddr);
    return ret;
    
}
keymng_shmop.c

 

》网点密钥信息结构体            --- struct shmNodeInfo{}                   
        shmNodeInfo{ seckey, clientID, serverID, seckeyid, status, time }

       clientid        serverid    status        seckeyid    time        seckey
        1111        0001        1        100        2017/7/2    a1b2c3
        2222        0001        1        101        2017/7/4    abc123
        3333        0001        1        102        2017/7/1    ab12c3
        4444        0001        1        105        2017/7/3    a1bc23

》存共享内存分析图:

 

3、生成密钥-组织密钥结构体信息

》生成密钥:
    1)借助开源算法  md5  sha1  sha256
    2)  自定义算法:
        123    abc    a1b2c3 
        abc      abc    aabbcc

将keymng_shmop.h放入./secmng/inc/目录下,keymng_shmop.c放入./secmng/src/目录下。

>vi keymngclientop.c

1)将头文件"keymng_shmop.h"包含

2)在MngClient_InitInfo中调用KeyMng_ShmInit

3)在MngClient_Agree中组织密钥结构体信息

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "keymnglog.h"
#include "poolsocket.h"
#include "keymng_msg.h"
#include "keymngclientop.h"
#include "keymng_shmop.h"

int MngClient_InitInfo(MngClient_Info *pCltInfo)
{
    int ret = 0;
     
    strcpy(pCltInfo->clientId, "1111");
    strcpy(pCltInfo->AuthCode, "1111");
    strcpy(pCltInfo->serverId, "0001");
    strcpy(pCltInfo->serverip, "127.0.0.1");
    pCltInfo->serverport = 8001;
    
    pCltInfo->maxnode = 1;
    pCltInfo->shmkey = 0x0011;
    pCltInfo->shmhdl = 0;    
    
    ret = KeyMng_ShmInit(pCltInfo->shmkey, pCltInfo->maxnode, &pCltInfo->shmhdl);
    if (ret != 0) {
        printf("---------客户端创建/打开 共享内存失败-----\n");
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "KeyMng_ShmInit() err:%d", ret);
        return 0;
    }
    
    return 0;
}

int MngClient_Agree(MngClient_Info *pCltInfo)
{
    int i = 0; 
    int ret = 0; 
    int time = 3;
    
    int connfd = -1;
    
    // 存放编码 TLV 完成的 req
    unsigned char    *msgKey_Req_Data = NULL;   
    int             msgKey_Req_DataLen = 0;
    
    // 存放编码 TLV 完成的 res
    unsigned char    *msgKey_Res_Data = NULL;
    int             msgKey_Res_DataLen = 0;
    
    MsgKey_Res         *pStruct_Res = NULL;
    int             iType = 0;

    // 初始化密钥请求结构体
    MsgKey_Req msgKey_req;
    
    msgKey_req.cmdType = KeyMng_NEWorUPDATE;
    strcpy(msgKey_req.clientId, pCltInfo->clientId);
    strcpy(msgKey_req.AuthCode, pCltInfo->AuthCode);
    strcpy(msgKey_req.serverId, pCltInfo->serverId);    
    
    // 产生随机数         c: abcdefg    s: abcdefg        aabbccddeeffgg    
    for (i = 0; i < 64; i++) {
        msgKey_req.r1[i] = 'a' + i;    
    }
    
    // 编码密钥请求 结构体 req
    ret = MsgEncode(&msgKey_req, ID_MsgKey_Req, &msgKey_Req_Data, &msgKey_Req_DataLen);
    if (ret != 0) {        
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgEncode() err:%d", ret);
        goto END;    
    }
    
    // 初始化建立连接函数
    ret = sckClient_init();
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_init() err:%d", ret);
        goto END;    
    }
        
    // 创建连接。
    ret = sckClient_connect(pCltInfo->serverip, pCltInfo->serverport, time, &connfd);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_connect() err:%d", ret);
        goto END;    
    }
        
    // 发送数据  TLV
    ret = sckClient_send(connfd, time, msgKey_Req_Data, msgKey_Req_DataLen);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_send() err:%d", ret);
        goto END;    
    }
        
    // ---- 等待服务器回发数据
    
    // 接收数据
    ret = sckClient_rev(connfd, time, &msgKey_Res_Data, &msgKey_Res_DataLen);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_rev() err:%d", ret);
        goto END;    
    }    
    
    // 解码密钥应答 结构体 res ---> rv r2
    ret = MsgDecode(msgKey_Res_Data, msgKey_Res_DataLen, (void **)&pStruct_Res, &iType);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgDecode() err:%d", ret);
        goto END;    
    }    
    
    if (pStruct_Res->rv != 0) {
        ret    = -1;
        goto END;
    } else if (pStruct_Res->rv == 0) {
        printf("---当前生成的密钥编号为:%d\n", pStruct_Res->seckeyid);    
    }
    
    // --组织密钥信息结构体    
    NodeSHMInfo nodeSHMInfo;
    
    // --利用 r1 r2 生成密钥
    for (i = 0; i < 64; i++) {
        nodeSHMInfo.seckey[2*i] = msgKey_req.r1[i];
        nodeSHMInfo.seckey[2*i+1] = pStruct_Res->r2[i];
    }
    
    nodeSHMInfo.status = 0;                  //0-有效  1无效
    strcpy(nodeSHMInfo.clientId, msgKey_req.clientId);
    strcpy(nodeSHMInfo.serverId, msgKey_req.serverId);
    nodeSHMInfo.seckeyid = pStruct_Res->seckeyid;

    // --写入共享内存。
    
END:
    if (msgKey_Req_Data != NULL) 
        MsgMemFree((void **)&msgKey_Req_Data, 0);
    if (msgKey_Res_Data != NULL) 
        MsgMemFree((void **)&msgKey_Res_Data, 0);
    if (pStruct_Res != NULL) 
        MsgMemFree((void **)&pStruct_Res, iType);
    
    return ret;    
}
keymngclientop.c

 

4、客户端写密钥信息到共享内存

>vi keymngclientop.c

在MngClient_Agree中调用写入共享内存的函数KeyMng_ShmWrite

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "keymnglog.h"
#include "poolsocket.h"
#include "keymng_msg.h"
#include "keymngclientop.h"
#include "keymng_shmop.h"

int MngClient_InitInfo(MngClient_Info *pCltInfo)
{
    int ret = 0;
     
    strcpy(pCltInfo->clientId, "1111");
    strcpy(pCltInfo->AuthCode, "1111");
    strcpy(pCltInfo->serverId, "0001");
    strcpy(pCltInfo->serverip, "127.0.0.1");
    pCltInfo->serverport = 8001;
    
    pCltInfo->maxnode = 1;
    pCltInfo->shmkey = 0x0011;
    pCltInfo->shmhdl = 0;    
    
    ret = KeyMng_ShmInit(pCltInfo->shmkey, pCltInfo->maxnode, &pCltInfo->shmhdl);
    if (ret != 0) {
        printf("---------客户端创建/打开 共享内存失败-----\n");
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "KeyMng_ShmInit() err:%d", ret);
        return 0;
    }
    
    return 0;
}

int MngClient_Agree(MngClient_Info *pCltInfo)
{
    int i = 0; 
    int ret = 0; 
    int time = 3;
    
    int connfd = -1;
    
    // 存放编码 TLV 完成的 req
    unsigned char    *msgKey_Req_Data = NULL;   
    int             msgKey_Req_DataLen = 0;
    
    // 存放编码 TLV 完成的 res
    unsigned char    *msgKey_Res_Data = NULL;
    int             msgKey_Res_DataLen = 0;
    
    MsgKey_Res         *pStruct_Res = NULL;
    int             iType = 0;

    // 初始化密钥请求结构体
    MsgKey_Req msgKey_req;
    
    msgKey_req.cmdType = KeyMng_NEWorUPDATE;
    strcpy(msgKey_req.clientId, pCltInfo->clientId);
    strcpy(msgKey_req.AuthCode, pCltInfo->AuthCode);
    strcpy(msgKey_req.serverId, pCltInfo->serverId);    
    
    // 产生随机数         c: abcdefg    s: abcdefg        aabbccddeeffgg    
    for (i = 0; i < 64; i++) {
        msgKey_req.r1[i] = 'a' + i;    
    }
    
    // 编码密钥请求 结构体 req
    ret = MsgEncode(&msgKey_req, ID_MsgKey_Req, &msgKey_Req_Data, &msgKey_Req_DataLen);
    if (ret != 0) {        
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgEncode() err:%d", ret);
        goto END;    
    }
    
    // 初始化建立连接函数
    ret = sckClient_init();
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_init() err:%d", ret);
        goto END;    
    }
        
    // 创建连接。
    ret = sckClient_connect(pCltInfo->serverip, pCltInfo->serverport, time, &connfd);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_connect() err:%d", ret);
        goto END;    
    }
        
    // 发送数据  TLV
    ret = sckClient_send(connfd, time, msgKey_Req_Data, msgKey_Req_DataLen);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_send() err:%d", ret);
        goto END;    
    }
        
    // ---- 等待服务器回发数据
    
    // 接收数据
    ret = sckClient_rev(connfd, time, &msgKey_Res_Data, &msgKey_Res_DataLen);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func sckClient_rev() err:%d", ret);
        goto END;    
    }    
    
    // 解码密钥应答 结构体 res ---> rv r2
    ret = MsgDecode(msgKey_Res_Data, msgKey_Res_DataLen, (void **)&pStruct_Res, &iType);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "func MsgDecode() err:%d", ret);
        goto END;    
    }    
    
    if (pStruct_Res->rv != 0) {
        ret    = -1;
        goto END;
    } else if (pStruct_Res->rv == 0) {
        printf("---当前生成的密钥编号为:%d\n", pStruct_Res->seckeyid);    
    }
    
    // --组织密钥信息结构体    
    NodeSHMInfo nodeSHMInfo;
    
    // --利用 r1 r2 生成密钥
    for (i = 0; i < 64; i++) {
        nodeSHMInfo.seckey[2*i] = msgKey_req.r1[i];
        nodeSHMInfo.seckey[2*i+1] = pStruct_Res->r2[i];
    }
    
    nodeSHMInfo.status = 0;                  //0-有效  1无效
    strcpy(nodeSHMInfo.clientId, msgKey_req.clientId);
    strcpy(nodeSHMInfo.serverId, msgKey_req.serverId);
    nodeSHMInfo.seckeyid = pStruct_Res->seckeyid;

    // --写入共享内存。
    ret = KeyMng_ShmWrite(pCltInfo->shmhdl, pCltInfo->maxnode, &nodeSHMInfo);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "KeyMng_ShmWrite() err:%d", ret);
        goto END;    
    }
    printf("--------------写共享内存完成------\n");
    
END:
    if (msgKey_Req_Data != NULL) 
        MsgMemFree((void **)&msgKey_Req_Data, 0);
    if (msgKey_Res_Data != NULL) 
        MsgMemFree((void **)&msgKey_Res_Data, 0);
    if (pStruct_Res != NULL) 
        MsgMemFree((void **)&pStruct_Res, iType);
    
    return ret;    
}
keymng_shmop.c

 >vi makefile

.PHONY:clean all

WORKDIR=.
VPATH = ./src

CC=gcc
CFLGS= -Wall -g -I$(WORKDIR)/inc/
LIBFLAG = -L$(HOME)/lib


BIN = keymngclient  keymngserver 


all:$(BIN)

keymngclient:keymngclient.o  keymnglog.o  keymngclientop.o  myipc_shm.o keymng_shmop.o
    $(CC) $(LIBFLAG) -lpthread -litcastsocket -lmessagereal $^ -o $@ 

#myipc_shm.o  keymng_shmop.o keymng_dbop.o         -lclntsh  -licdbapi
keymngserver:keymngserver.o  keymngserverop.o  keymnglog.o  
    $(CC) $(LIBFLAG) $^ -o $@ -lpthread -litcastsocket -lmessagereal  
 
#testdbapi:testdbapi.o  
#    $(CC) $(LIBFLAG) $^ -o $@ -lpthread  -lclntsh  -licdbapi
        
%.o:%.c
    $(CC) $(CFLGS) -c $< -o $@    

clean:
    rm -f *.o $(BIN)
    
    
    
makefile

 

>make

>./keymngclient

打开另一个终端,执行>./keymngserver,分别查看终端执行情况。

客户端情况:(输入:1):

“Ctrl+c”结束进程后,>ipcs 查看共享内存的创建情况

服务器端情况:

 

》同理,将服务器添加共享内存:

>vi keymngserverop.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "keymngserverop.h"
#include "keymng_msg.h"
#include "keymnglog.h" 
#include "keymng_shmop.h"

static int    seckeyid = 100;

int MngServer_InitInfo(MngServer_Info *svrInfo)
{
    int ret = 0;
    strcpy(svrInfo->serverId, "0001");
    strcpy(svrInfo->dbuse, "SECMNG");
    strcpy(svrInfo->dbpasswd, "SECMNG");
    strcpy(svrInfo->dbsid, "orcl");
    svrInfo->dbpoolnum = 8;    
    strcpy(svrInfo->serverip, "127.0.0.1");
    svrInfo->serverport = 8001;
    svrInfo->maxnode = 10;
    svrInfo->shmkey = 0x0001;
    svrInfo->shmhdl = 0;
    
    ret = KeyMng_ShmInit(svrInfo->shmkey, svrInfo->maxnode, &svrInfo->shmhdl);
    if (ret != 0) {
        printf("---------服务器创建/打开 共享内存失败-----\n");
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMng_ShmInit() err:%d", ret);
        return ret;
    }
    
    return 0;    
}

int MngServer_Agree(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
{
    int ret = 0;
    int i = 0;
    MsgKey_Res msgKey_Res;
    
    NodeSHMInfo nodeSHMInfo;
    
    // --结合 r1 r2 生成密钥  ---> 成功、失败 rv
    
    if (strcmp(svrInfo->serverId, msgkeyReq->serverId) != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "客户端访问了错误的服务器");
        return -1;    
    }
    
    // 组织 应答结构体 res : rv r2 clientId serverId  seckeyid
    msgKey_Res.rv = 0;     //0 成功 1 失败。
    strcpy(msgKey_Res.clientId, msgkeyReq->clientId); 
    strcpy(msgKey_Res.serverId, msgkeyReq->serverId); 
    
    // 生成随机数 r2
    for (i = 0; i < 64; i++) {
        msgKey_Res.r2[i] = 'a' + i;            
    }    
    msgKey_Res.seckeyid = seckeyid++;
    
    // 组织密钥节点信息结构体
    for (i = 0; i < 64; i++) {
        nodeSHMInfo.seckey[2*i] = msgkeyReq->r1[i];
        nodeSHMInfo.seckey[2*i+1] = msgKey_Res.r2[i];
    }
    nodeSHMInfo.status = 0;  //0-有效 1无效
    strcpy(nodeSHMInfo.clientId, msgkeyReq->clientId);
    strcpy(nodeSHMInfo.serverId, msgkeyReq->serverId);
    nodeSHMInfo.seckeyid = msgKey_Res.seckeyid;

    // --写入共享内存。
    ret = KeyMng_ShmWrite(svrInfo->shmhdl, svrInfo->maxnode, &nodeSHMInfo);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMng_ShmWrite() err:%d", ret);
        return ret;    
    }

    // --写数据库

    // 编码应答报文  传出
    ret = MsgEncode(&msgKey_Res, ID_MsgKey_Res, outData, datalen);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "serverAgree MsgEncode() err:%d", ret);    
        return ret;
    }
    
    return 0;    
}


int MngServer_Check(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
{
    
    
    return 0;    
}
keymngserverop.c

>vi makefile

.PHONY:clean all

WORKDIR=.
VPATH = ./src

CC=gcc
CFLGS= -Wall -g -I$(WORKDIR)/inc/
LIBFLAG = -L$(HOME)/lib


BIN = keymngclient  keymngserver 


all:$(BIN)

keymngclient:keymngclient.o  keymnglog.o  keymngclientop.o  myipc_shm.o keymng_shmop.o
    $(CC) $(LIBFLAG) -lpthread -litcastsocket -lmessagereal $^ -o $@ 

# keymng_dbop.o         -lclntsh  -licdbapi
keymngserver:keymngserver.o  keymngserverop.o  keymnglog.o  myipc_shm.o  keymng_shmop.o 
    $(CC) $(LIBFLAG) $^ -o $@ -lpthread -litcastsocket -lmessagereal  
 
#testdbapi:testdbapi.o  
#    $(CC) $(LIBFLAG) $^ -o $@ -lpthread  -lclntsh  -licdbapi
        
%.o:%.c
    $(CC) $(CFLGS) -c $< -o $@    

clean:
    rm -f *.o $(BIN)
    
    
    
makefile

 

5、服务器内存释放

>free(在该释放内存的地方加入 相应创建的函数中寻找释放内存的函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
 
#include "poolsocket.h"  
#include "keymngserverop.h"
#include "keymng_msg.h"
#include "keymnglog.h"  

MngServer_Info serverInfo;

 
void *start_routine(void * arg)
{
     int ret;
     int timeout = 3;
     int connfd = (int)arg;
     
     unsigned char *out = NULL;
     int outlen = 0;
     
     MsgKey_Req *pStruct_req = NULL;
     int iType = 0;
     
     unsigned char *res_outData = NULL;
     int res_outDataLen = 0;
     
     while (1) {
                 
        //服务器端端接受报文
        ret = sckServer_rev(connfd, timeout, &out, &outlen); 
        if (ret == Sck_ErrPeerClosed) {
            // 检测到 对端关闭,关闭本端。
            printf("----------------ErrPeerClosed 关闭服务器\n");
            break;
        } else if (ret == Sck_ErrTimeOut) {
            if (out != NULL)  sck_FreeMem((void **)&out);
            continue;
        } else if (ret != 0) {
            printf("未知错误\n");
            break;
        }

        // 解码客户端 密钥请求报文 ---> cmdType
        ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);    
            break;    
        }

        switch(pStruct_req->cmdType) {
            case KeyMng_NEWorUPDATE:
                ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
            
            case KeyMng_Check:
                MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
            /*    
            case 密钥注销:
                mngServer_Agree();
                */
            default:
                break;
        }
        if (ret != 0) {        
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
            break;                
        }

         //服务器端发送报文
        ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
         if (ret == Sck_ErrPeerClosed) {
            // 检测到 对端关闭,关闭本端。
            printf("---ErrPeerClosed \n");
            break;
        } else if (ret == Sck_ErrTimeOut) {
            printf("---服务器检测到本端发送数据 超时 \n");
            if (out != NULL) sck_FreeMem((void **)&out);
            if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
            if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
            continue;
        } else if (ret != 0) {
            printf("未知错误\n");
            break;
        }
    }
    
    if (out != NULL) sck_FreeMem((void **)&out);
    if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
    if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
    
    sckServer_close(connfd);
    
     return NULL;
}


int main(void)
{
    int listenfd;
    int ret = 0;
    
    int timeout = 3;
    int connfd = -1;
    
    pthread_t pid;
    
    
    // 服务器信息初始化。
    ret = MngServer_InitInfo(&serverInfo);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);    
        return ret;
    }
    
    //服务器端初始化
    ret = sckServer_init(serverInfo.serverport, &listenfd);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);    
        return ret;
    }
    
    while (1) {    
        
        ret = sckServer_accept(listenfd, timeout, &connfd);
        if (ret == Sck_ErrTimeOut){
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
            continue;    
        } else if(ret != 0)  {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);    
            return ret;
        }
        
        ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);                    
    }
     
     //服务器端环境释放 
    sckServer_destroy();
    

    return 0;    
}
keymngserver.c

>make

>./keymngclient

打开另一个终端,执行>./keymngserver,分别查看终端执行情况。

客户端情况:(输入:1):

服务器端情况:

打开第三个终端,输入>ipcs,查看共享内存:

 

6、共享内存补充说明

问题:密钥协商业务逻辑图中两块共享内存是一块吗?有什么关系吗?

分析:服务器和客户端是两个PC,两个共享内存是分别在不同的PC的内核区创建的,图中上边的共享内存(服务器的共享内存)用于app1和keymngserver进行通信,图中下边的的共享内存(客户端的共享内存)用于app2和keymngclient进行通信。而这两个共享内存没有任何关系!

 

7、服务器守护进程创建

问题:当>./keymngserver 运行时,当前终端,不能输入shell指令,完全被服务器进程占据?

解决:守护进程。

》守护进程创建:
    守护进程:
        运行于操作系统后台的服务进程。周期性的执行某个任务,或者等待某些事件发生。
        不占用控制终端。不随用户的注销而结束、退出。  通常以 d 结尾命名。  daemon
        位于一个新会话中。新的进程组。 脱离控制终端。

    1. fork 子进程, 父进程exit。
    2. 子进程 调用 setsid()创建新会话。 成为会长。进程组组长。 子进程 pid。
    3. 修改工作目录位置。防止可执行占用可卸载磁盘空间。   chdir();
    4. 设定 创建文件的权限 掩码 umask
    5. 关闭/重定向(dup2) 0/1/2 --> /dev/null  ---- /dev/zero
    6. 守护进程 循环逻辑。
    7. 守护进程管理。———— 脚本

>vi keymngserver.c(添加守护进程CREATE_DAEMON

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
 
#include "poolsocket.h"  
#include "keymngserverop.h"
#include "keymng_msg.h"
#include "keymnglog.h"  

MngServer_Info serverInfo;

//注意定义宏的时候最后是一个整体,不能有空格!
#define CREATE_DAEMON if(fork()>0)exit(1);setsid();
 
void *start_routine(void * arg)
{
     int ret;
     int timeout = 3;
     int connfd = (int)arg;
     
     unsigned char *out = NULL;
     int outlen = 0;
     
     MsgKey_Req *pStruct_req = NULL;
     int iType = 0;
     
     unsigned char *res_outData = NULL;
     int res_outDataLen = 0;
     
     while (1) {
                 
        //服务器端端接受报文
        ret = sckServer_rev(connfd, timeout, &out, &outlen); 
        if (ret == Sck_ErrPeerClosed) {
            // 检测到 对端关闭,关闭本端。
            printf("----------------ErrPeerClosed 关闭服务器\n");
            break;
        } else if (ret == Sck_ErrTimeOut) {
            if (out != NULL)  sck_FreeMem((void **)&out);
            continue;
        } else if (ret != 0) {
            printf("未知错误\n");
            break;
        }

        // 解码客户端 密钥请求报文 ---> cmdType
        ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);    
            break;    
        }

        switch(pStruct_req->cmdType) {
            case KeyMng_NEWorUPDATE:
                ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
            
            case KeyMng_Check:
                MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
            /*    
            case 密钥注销:
                mngServer_Agree();
                */
            default:
                break;
        }
        if (ret != 0) {        
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
            break;                
        }

         //服务器端发送报文
        ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
         if (ret == Sck_ErrPeerClosed) {
            // 检测到 对端关闭,关闭本端。
            printf("---ErrPeerClosed \n");
            break;
        } else if (ret == Sck_ErrTimeOut) {
            printf("---服务器检测到本端发送数据 超时 \n");
            if (out != NULL) sck_FreeMem((void **)&out);
            if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
            if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
            continue;
        } else if (ret != 0) {
            printf("未知错误\n");
            break;
        }
    }
    
    if (out != NULL) sck_FreeMem((void **)&out);
    if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
    if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
    
    sckServer_close(connfd);
    
     return NULL;
}


int main(void)
{
    int listenfd;
    int ret = 0;
    
    int timeout = 3;
    int connfd = -1;
    
    pthread_t pid;
    
    CREATE_DAEMON
    
    
    // 服务器信息初始化。
    ret = MngServer_InitInfo(&serverInfo);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);    
        return ret;
    }
    
    //服务器端初始化
    ret = sckServer_init(serverInfo.serverport, &listenfd);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);    
        return ret;
    }
    
    while (1) {    
        
        ret = sckServer_accept(listenfd, timeout, &connfd);
        if (ret == Sck_ErrTimeOut){
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
            continue;    
        } else if(ret != 0)  {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);    
            return ret;
        }
        
        ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);                    
    }
     
     //服务器端环境释放 
    sckServer_destroy();
    

    return 0;    
}
keymngserver.c

>make

>./keymngserver

 

8、守护进程管理脚本

问题抛出:当服务器进程变为守护进程后,无法使用Ctrl+c 结束服务器进程,只能通过>ps aux | grep keymngserver 查到pid,然后 kill -9 pid。但是用户怎么办?用户无法结束服务器进程?

所以,采用shell脚本。

》shell脚本:
    集成 一系列 shell命令。组织到一个文件中。统一运行。
    第一行: 指定解析器。  #!/bin/bash   /bin/shell
    awk 处理列
    sed 处理行

在UltraEdit中编辑文件:

>touch myshell

#! /bin/bash
ls -l
date
echo $HOME

>ls -l myshell

>chmod a+x myshell

但是运行脚本,会报错:

分析:错误由于wind和Linux换行不一致造成的:
    windows         \r\n       
    ---
    Linux            \n    \r --> ^M    
解决:
    vim        --> :set ff=unix(fileformat可以简写为ff)

再次执行>./myshell

但是,在myshell新增加行,设置就失效了,

法一:把set ff=unix写到vim的配置文件vimrc中;

法二:在Linux中写脚本

如何提取pid?如何提取服务器进程?-u指定用户,awk指定列,$1指定第一列

>ps -u test04 | grep keymngserver | awk '{print $1}'

》获取 命令结果:(两种方式,常用第二种
    src=$(whoami)
    src=`whoami`  --> “反引号”

>vi myshell

#! /bin/bash

userN=`whoami`

mypid=`ps -u ${userN} | grep keymngserver | awk '{print $1}'`

if [ -z ${mypid} ];then
    echo "The process is not started."
    exit 1;
fi

kill -9 ${mypid}
echo "kill keymngserver successful"

如果启动服务器>./keymngserver,执行>./myshell

 

9、借助信号管理守护进程

问题抛出:当服务器进程当运行在某处时,执行>./myshell,服务器进程终止,导致可能服务器正和客户端协商,终止了,导致共享内存,堆空间都消失了;服务器里边某些内存没释放,某些进程没有正常终止?

查看kill -l 中这几个信号:

 

>man sigaction(设置信号捕捉)

>man signal

 

》加入信号捕捉函数:signal(SIGUSR1, catchSignal);

>vi keymngserver.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
 
#include "poolsocket.h"  
#include "keymngserverop.h"
#include "keymng_msg.h"
#include "keymnglog.h"  

MngServer_Info serverInfo;

int flg = 1;

//注意定义宏的时候最后是一个整体,不能有空格!
#define CREATE_DAEMON if(fork()>0)exit(1);setsid();
 
void *start_routine(void * arg)
{
     int ret;
     int timeout = 3;
     int connfd = (int)arg;
     
     unsigned char *out = NULL;
     int outlen = 0;
     
     MsgKey_Req *pStruct_req = NULL;
     int iType = 0;
     
     unsigned char *res_outData = NULL;
     int res_outDataLen = 0;
     
     while (1) {
                 
        if (flg == 0) 
            break;    

        //服务器端端接受报文
        ret = sckServer_rev(connfd, timeout, &out, &outlen); 
        if (ret == Sck_ErrPeerClosed) {
            // 检测到 对端关闭,关闭本端。
            printf("----------------ErrPeerClosed 关闭服务器\n");
            break;
        } else if (ret == Sck_ErrTimeOut) {
            if (out != NULL)  sck_FreeMem((void **)&out);
            continue;
        } else if (ret != 0) {
            printf("未知错误\n");
            break;
        }

        // 解码客户端 密钥请求报文 ---> cmdType
        ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);    
            break;    
        }

        switch(pStruct_req->cmdType) {
            case KeyMng_NEWorUPDATE:
                ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
            
            case KeyMng_Check:
                MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
            /*    
            case 密钥注销:
                mngServer_Agree();
                */
            default:
                break;
        }
        if (ret != 0) {        
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
            break;                
        }

         //服务器端发送报文
        ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
         if (ret == Sck_ErrPeerClosed) {
            // 检测到 对端关闭,关闭本端。
            printf("---ErrPeerClosed \n");
            break;
        } else if (ret == Sck_ErrTimeOut) {
            printf("---服务器检测到本端发送数据 超时 \n");
            if (out != NULL) sck_FreeMem((void **)&out);
            if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
            if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
            continue;
        } else if (ret != 0) {
            printf("未知错误\n");
            break;
        }
    }
    
    if (out != NULL) sck_FreeMem((void **)&out);
    if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
    if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
    
    sckServer_close(connfd);
    
     return NULL;
}

void catchSignal(int signum)
{
    flg = 0;
    printf(" catch signal %d, process is going to die.\n", signum);
    
    return ;
}

int main(void)
{
    int listenfd;
    int ret = 0;
    
    int timeout = 3;
    int connfd = -1;
    
    pthread_t pid;
    
    CREATE_DAEMON
    
    signal(SIGUSR1, catchSignal);
    
    // 服务器信息初始化。
    ret = MngServer_InitInfo(&serverInfo);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);    
        return ret;
    }
    
    //服务器端初始化
    ret = sckServer_init(serverInfo.serverport, &listenfd);
    if (ret != 0) {
        KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);    
        return ret;
    }
    
    while (1) {    
        if (flg == 0) 
            break;
        
        ret = sckServer_accept(listenfd, timeout, &connfd);
        if (ret == Sck_ErrTimeOut){
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
            continue;    
        } else if(ret != 0)  {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);    
            return ret;
        }
        
        ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);                    
    }
     
     //服务器端环境释放 
    sckServer_destroy();
    
    printf("服务器 优雅退出。\n");

    return 0;    
}
keymngserver.c

>vi myshell(更改为发送10号信号

#! /bin/bash

userN=`whoami`

mypid=`ps -u ${userN} | grep keymngserver | awk '{print $1}'`

if [ -z ${mypid} ];then
    echo "The process is not started."
    exit 1;
fi

kill -10 ${mypid}
echo "kill keymngserver successful"
myshell

>make

>./keymngserver

打开另一个终端,执行>./myshell,

查看服务器端:

 

10、密钥校验流程分析

密钥校验:

》服务器:

    int MngServer_check()
    {

        //读出 密钥请求结构体中 r1[] (10字节的密钥数据)

        //依据 clientid、serverid 读共享内存 --> seckey 密钥 --> 提取前10字节 --> 比较
        
        //根据比较结果填充 res.rv

        //组织密钥应答结构体 res 其他成员变量

        //编码密钥应答结构体 --> 传出。
    }

》客户端:

    校验方法:
        1. a1b2c3 --> 再加密(非对称加密)--> jqk678
        2. 片段校验法: 0-10 密钥信息一致  --> 一致。

    int MngServer_check()
    {

        //读共享内存 --> seckey 密钥 --> 提取前10字节 --> req.r1[];

        //组织密钥请求结构体(校验的事)

        //编码密钥请求结构体 req

        //初始化连接 --> listenfd

        //建立连接 --> connfd

        //发送请求报文 -->  TLV send

        //接收应答报文 --> fwq TLV res

        //解析应答报文 --> TLV --> Struct --> rv --> 0 一致 1 不一致。

        //给用户返回校验结果。    
    }

 

 

在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

posted on 2020-07-29 09:57  Alliswell_WP  阅读(321)  评论(0编辑  收藏  举报

导航