asr1601芯片平台实现ssl加密的websocket

首先感谢SGuniver_22,本文实现内容,是在他实现的websocket基础上,移植而来。
他的博客:https://blog.csdn.net/SGuniver_22
他的github:https://github.com/wexiangis/websocket_for_linux
移植代码下载:https://download.csdn.net/download/zn2857/16671309
1.首先去git下载websocket源码
。。。
2.实现ssl(asr1601平台实现了,只调用库函数,没有源代码)

#ifdef CA_CERT
const unsigned char app_ca1_cert[] = {
"-----BEGIN CERTIFICATE-----\r\n"
"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\r\n"
"-----END CERTIFICATE-----\r\n"
};
#endif

#ifdef OWN_CERT
const unsigned char client_cert[] = {
};

const unsigned char client_key[] = {
};

#endif

static struct ssl_client * ssl_client_init(int fd);
static void ssl_client_shutdown(struct ssl_client * client);
static int ssl_client_write( void *ssl, const unsigned char *buf, int len );
static int ssl_client_read( void *ssl, unsigned char *buf, int len );

static unsigned int havege_rand(void *unused, unsigned char * unusedstr, size_t unusedt)
{
	char * p = (char *)malloc(16);
	unsigned int rand = (unsigned int)p;
	free(p);
	if ((rand & 0xff) == 0) {
		rand |= 0x96;
	}
	return rand;
}

static void debug(void *userdata, int level,
                     const char *filename, int line,
                     const char *msg)
{
    //ssl_debug("%s", msg);
}

//生成握手key的长度
#define WEBSOCKET_SHAKE_KEY_LEN 16

struct ssl_client {
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config config;
    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_entropy_context entropy;
    int fd;
};

struct ssl_client * ssl_c = NULL;

static int ssl_client_recv(void * ctx, unsigned char * buf, unsigned int len)
{
    struct ssl_client * client = (struct ssl_client *)ctx;
    return recv(client->fd, buf, len, 0);
}

static int ssl_client_send(void * ctx, const unsigned char *buf, unsigned int len)
{
    struct ssl_client * client = (struct ssl_client *)ctx;
    return send(client->fd, buf, len, 0);
}

#ifdef CA_CERT
#define HOSTNAME "asr"
#endif
static struct ssl_client * ssl_client_init(int fd)
{
	char *pers = "ssl_client";
	int ret;
	struct ssl_client * client = (struct ssl_client *)malloc(sizeof(struct ssl_client));
	if (!client) {
		printf("Cannot malloc memory(ssl_client_init)\n");
		return NULL;
	}
	
	memset(client, 0, sizeof(struct ssl_client));

#ifdef CA_CERT
	mbedtls_x509_crt *ca_chain; 
	ca_chain = (mbedtls_x509_crt *)malloc(sizeof(mbedtls_x509_crt));
	memset(ca_chain, 0, sizeof(mbedtls_x509_crt));
#endif

	mbedtls_entropy_init(&client->entropy);
	mbedtls_ctr_drbg_init(&client->ctr_drbg);
	if((ret = mbedtls_ctr_drbg_seed(&client->ctr_drbg, mbedtls_entropy_func, 
                                    &client->entropy,
                                    (unsigned char *)pers, strlen(pers))) != 0)
	{
		printf( " failed\n  ! ctr_drbg_init returned %d\n", ret );
		goto failed;
	}

	mbedtls_ssl_init(&(client->ssl));
	mbedtls_ssl_config_init(&(client->config));
	client->fd = fd;
	mbedtls_ssl_conf_rng(&(client->config), mbedtls_ctr_drbg_random, &client->ctr_drbg);

#ifdef CA_CERT
    mbedtls_x509_crt_parse(ca_chain,app_ca1_cert,strlen(app_ca1_cert));
	mbedtls_ssl_conf_ca_chain(&(client->config), ca_chain, NULL);
    mbedtls_ssl_set_hostname(&(client->ssl), HOSTNAME);
#endif

#ifdef OWN_CERT
    mbedtls_x509_crt *client_chain = NULL;
    mbedtls_pk_context *client_rsa = NULL;

    client_chain = (mbedtls_x509_crt *)malloc(sizeof(mbedtls_x509_crt));
    memset(client_chain, 0, sizeof(mbedtls_x509_crt));
    mbedtls_x509_crt_parse(client_chain,client_cert,strlen(client_cert));
    
    client_rsa = (mbedtls_pk_context *)malloc(sizeof(mbedtls_pk_context));
    memset(client_rsa, 0, sizeof(mbedtls_rsa_context));  
    mbedtls_pk_parse_key(client_rsa, client_key, strlen(client_key), NULL,0);
    mbedtls_ssl_conf_own_cert(&client->config, client_chain, client_rsa);
#endif

	//mbedtls_ssl_conf_endpoint(&(client->config), MBEDTLS_SSL_IS_CLIENT);
	mbedtls_ssl_config_defaults(&client->config, MBEDTLS_SSL_IS_CLIENT,
								MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
//    mbedtls_ssl_conf_ciphersuites_for_version(&client->config, 0, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3);

#ifdef CA_CERT
	mbedtls_ssl_conf_authmode(&client->config, MBEDTLS_SSL_VERIFY_REQUIRED);
#else
	mbedtls_ssl_conf_authmode(&client->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
#endif

	mbedtls_ssl_conf_rng(&client->config, mbedtls_ctr_drbg_random, &client->ctr_drbg);
	mbedtls_ssl_conf_dbg(&client->config, debug, NULL);
	//mbedtls_debug_set_threshold(1000);
	mbedtls_ssl_set_bio(&client->ssl, client,
                        ssl_client_send, ssl_client_recv, NULL);

	mbedtls_ssl_setup(&client->ssl, &client->config);
	return client;
failed:
#ifdef CA_CERT
	if(ca_chain) free(ca_chain);
#endif
	if (client) free(client);
	return NULL;
}

static int ssl_client_write( void *ssl, const unsigned char *buf, int len )
{
    return ssl_write(ssl, buf, len );
}

static int ssl_client_read( void *ssl, unsigned char *buf, int len )
{
    return ssl_read( ssl, buf, len );
}

3.在ws_connectToServer函数里将socket创建,连接,改为asr1601芯片平台实现方式。注意有的websocket服务器不需要调用fcntl函数设置非阻塞

int ws_createSocket(char *ip, int port)
{
    int ret, sock = -1;
    struct addrinfo hints;
    struct addrinfo *result, *rp;
    int port_buf[10] = {0};
    
    printf("websocket_createSocket!\n");

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = 0;
    
    itoa(port,port_buf);
    ret = getaddrinfo(ip, port_buf, &hints, &result);
    if (ret != 0) {
        printf("ws_createSocket: resolve error\n");
        return result;
    }

    for (rp = result; rp; rp = rp->ai_next) {
        sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sock < 0) {
            printf("ws_createSocket: socket error\n");
            continue;
        }
//        ret = fcntl(sock, F_GETFL, 0);
//        fcntl(sock, F_SETFL, ret | O_NONBLOCK);
        ret = connect(sock, rp->ai_addr, rp->ai_addrlen);
        if (ret < 0) {
            printf("ws_createSocket:socket connect error\n");
            close(sock);
            sock = -1;
            continue;
        } else {
            break;
        }
    }

    freeaddrinfo(result);
    return sock;

}

int ws_connectToServer(char *ip, int port, char *path, int timeoutMs)
{
    int32_t ret, fd = -1;
    int32_t timeoutCount = 0;
    char retBuff[512] = {0};
    char httpHead[512] = {0};
    char shakeKey[128] = {0};
    char *p;

    fd = ws_createSocket(ip,port);
    if(fd < 0)
        return fd;
   
    if(!ssl_c){
        ssl_c = ssl_client_init(fd);
        if(NULL == ssl_c)
            return -1;
    }
    //发送http协议头
    memset(shakeKey, 0, sizeof(shakeKey));
    ws_buildShakeKey(shakeKey);                                   //创建握手key
    memset(httpHead, 0, sizeof(httpHead));                        //创建协议包
    ws_buildHttpHead(ip, port, path, shakeKey, (char *)httpHead); //组装http请求头
    ssl_client_write(&(ssl_c->ssl), httpHead, strlen((const char *)httpHead));

#ifdef WS_DEBUG
    sdk_uart_printf("ws_connectToServer: \r\n%s\r\n", httpHead);
#endif
    while (1)
    {
        memset(retBuff, 0, sizeof(retBuff));
        ret = ssl_client_read(&(ssl_c->ssl), retBuff, sizeof(retBuff));
        if (ret > 0)
        {
#ifdef WS_DEBUG
            //显示http返回
            sdk_uart_printf("ws_connectToServer: %d \r\n%s\r\n", ret, retBuff);
#endif
            //返回的是http回应信息
            if (strncmp((const char *)retBuff, "HTTP", 4) == 0)
            {
                //定位到握手字符串
                if ((p = strstr((char *)retBuff, "sec-websocket-accept: ")) != NULL)
                {
                    p += strlen("sec-websocket-accept: ");
                    sscanf((const char *)p, "%s\r\n", p);
                    //比对握手信息
                    if (ws_matchShakeKey(shakeKey, strlen((const char *)shakeKey), p, strlen((const char *)p)) == 0)
                    {
                        sdk_uart_printf("shake hands success\r\n");
                        return ssl_c;
                    }
                    //握手信号不对, 重发协议包
                    else
                    {
                        sdk_uart_printf("shake hands info err, resend pkg\r\n");
                        ret = ssl_client_write(&(ssl_c->ssl), httpHead, strlen((const char *)httpHead));
                    }
                }
                //重发协议包
                else
                {
                    sdk_uart_printf("shake hands signal err, resend pkg\r\n");
                    ret = ssl_client_write(&(ssl_c->ssl), httpHead, strlen((const char *)httpHead));
                }
            }
            //显示异常返回数据
            else
            {
                //#ifdef WS_DEBUG
                if (retBuff[0] >= ' ' && retBuff[0] <= '~')
                    sdk_uart_printf("ws_connectToServer: %d\r\n%s\r\n", ret, retBuff);
                else
                {
                    p = retBuff;
                    sdk_uart_printf("ws_connectToServer: %d\r\n", ret);
                    while (*p)
                        sdk_uart_printf("%.2X ", *p++);
                    sdk_uart_printf("\r\n");
                }
                //#endif
            }
        }
        else
        {
            ssl_client_write(&(ssl_c->ssl), httpHead, strlen((const char *)httpHead));
            sdk_uart_printf("ws_connectToServer: \r\n%s\r\n", httpHead);
        }
        ws_delayms(1000);
        //超时检查
        if (++timeoutCount > timeoutMs * 2)
            break;
    }
    //连接失败,返回耗时(负值)
    ws_close(fd);
    sdk_uart_printf("connect err\n");
    return -timeoutCount;
}

4.实现初始化

// extern void update_the_cp_ver(char *cp_ver);  // max length 128
// Device bootup hook before Phase1Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
void Phase1PreInits(void)
{
    sdk_uart_printf("[CUST] enter %s\n", __func__);
    sdk_uart_printf("[CUST] enter %s\n", __func__);
}

// Device bootup hook after Phase1Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
void Phase1PostInits(void)
{
    sdk_uart_printf("[CUST] enter %s\n", __func__);
    sdk_uart_printf("[CUST] enter %s\n", __func__);
}

// Device bootup hook before Phase2Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
void Phase2PreInits(void)
{
    sdk_uart_printf("[CUST] enter %s\n", __func__);
    sdk_uart_printf("[CUST] enter %s\n", __func__);
}

// Device bootup hook after Phase2Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
void Phase2PostInits(void)
{
    int ret;
    sdk_uart_printf("[CUST] enter %s\n", __func__);
    sdk_uart_printf("[CUST] enter %s\n", __func__);
    
    ret = OSAFlagCreate(&_flag_app_ref);
    ASSERT(ret == OS_SUCCESS);

    ret = OSATaskCreate(&_task_app_ref, _task_app_stack, _TASK_APP_STACK_SIZE, 120, "_task_app", _task_app, NULL);
    ASSERT(ret == OS_SUCCESS);

    ret = OSATimerCreate(&_timer_ref);
    ASSERT(ret == OS_SUCCESS);
}

5.实现任务函数

static void _timer_callback(UINT32 tmrId)
{
    OSAFlagSet(_flag_app_ref, TASK_TIMER_CHANGE_FLAG_BIT, OSA_FLAG_OR);
}

static int wait_dialer_reg_net(void)
{
    while (!CM_GetDefaultConnectStatus()) {
        sdk_uart_printf("[app]wait net ...");
        ws_delayms(5000);
    }
    sdk_uart_printf("[app]NetWork dialer success");
    return OS_SUCCESS;
}
static void _task_app(void *ptr)
{
    int ret;
    OSA_STATUS status;
    UINT32 flag_value;
    UINT32 flag_mask = TASK_TIMER_CHANGE_FLAG_BIT;
    char send_buff[4096];
    memset(send_buff, 0, sizeof(send_buff));
    sprintf(send_buff, "Say hi~ from client");
    WsData_Type retPkgType;
    char recv_buff[4096];

    //等待网络附着
    wait_dialer_reg_net();
    //连接websocket,尝试10次
    if ((fd = ws_connectToServer(ip, port, "/api/ws", 5)) <= 0) //1-ssl  
    {
        sdk_uart_printf("ws failed !\r\n");
    }else
    {
        sdk_uart_printf("ws connect success! \n");
    }
    //开启定时器,驱动代码执行
    OSATimerStart(_timer_ref, 3 * 200, 3 * 200, _timer_callback, 0); // 30 seconds timer
    
    while(1) {
        status = OSAFlagWait(_flag_app_ref, flag_mask, OSA_FLAG_OR_CLEAR, &flag_value, OSA_SUSPEND);
        ASSERT(status == OS_SUCCESS);

        if(fd)
        {
            ret = ws_send(fd, send_buff, strlen(send_buff), true, WDT_TXTDATA);
            if(ret <= 0) 
                sdk_uart_printf("ws send err\n");
            else
                sdk_uart_printf("wst send: %s\n",send_buff);
            memset(recv_buff, 0, sizeof(recv_buff));
            ret = ws_recv(fd,recv_buff,sizeof(recv_buff) - 1,NULL);
            if (ret <= 0) {
                sdk_uart_printf("ws: recv error: %d", ret);
                ws_close(fd);
                
            } 
            sdk_uart_printf("ws ssl rcv: %s,len: %d\n",recv_buff,ret);	
        }
    }
    ws_close(fd);
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值