1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/notrynohigh-BabyOS

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
b_srv_tcpip.c 19 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
notrynohigh Отправлено 10 месяцев назад 0de069c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
/**
*!
* \file b_srv_tcpip.c
* \version v0.0.1
* \date 2023/08/27
* \author Bean(notrynohigh@outlook.com)
*******************************************************************************
* @attention
*
* Copyright (c) 2023 Bean
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*******************************************************************************
*/
/*Includes ----------------------------------------------*/
#include "services/inc/b_srv_tcpip.h"
#if (defined(_TCPIP_SERVICE_ENABLE) && (_TCPIP_SERVICE_ENABLE == 1))
#include <stdio.h>
#include <string.h>
#include "core/inc/b_sem.h"
#include "core/inc/b_task.h"
#include "modules/inc/b_mod_ssl.h"
#include "thirdparty/http-parser/http_parser.h"
#include "utils/inc/b_util_log.h"
#include "utils/inc/b_util_memp.h"
#include "utils/inc/b_util_utc.h"
/**
* \addtogroup BABYOS
* \{
*/
/**
* \addtogroup SERVICES
* \{
*/
/**
* \addtogroup TCPIP
* \{
*/
/**
* \defgroup TCPIP_Private_TypesDefinitions
* \{
*/
typedef struct
{
uint32_t seconds;
uint32_t fraction;
} bNtpTimestamp_t;
typedef struct
{
uint8_t li_vn_mode; // Leap indicator, version number, and mode
uint8_t stratum; // Stratum level of the local clock
uint8_t poll; // Maximum interval between successive messages
uint8_t precision; // Precision of the local clock
uint32_t root_delay; // Total round trip delay time
uint32_t root_dispersion; // Max error allowed from primary clock source
uint32_t ref_id; // Reference clock identifier
bNtpTimestamp_t ref_time; // Reference timestamp
bNtpTimestamp_t orig_time; // Originate timestamp
bNtpTimestamp_t recv_time; // Receive timestamp
bNtpTimestamp_t trans_time; // Transmit timestamp
} bNtpPacket_t;
typedef struct
{
bTaskId_t task_id;
int sockfd;
uint32_t interval_s;
} bNtpPcb_t;
//----------------------------------------------------------------------------
typedef enum
{
B_HTTP_STA_INIT,
B_HTTP_STA_CONNECTING,
B_HTTP_STA_CONNECTED,
B_HTTP_STA_RECV_DATA,
B_HTTP_STA_DISCONNECT,
B_HTTP_STA_DEINIT,
B_HTTP_STA_DESTROY,
} bHttpState_t;
typedef struct
{
uint8_t is_https;
bHttpState_t state;
char host[_HTTP_HOST_LEN_MAX + 1];
char path[_HTTP_PATH_LEN_MAX + 1];
uint16_t port;
pHttpCb_t callback;
void *user_data;
char *request;
int sockfd;
bTaskAttr_t attr;
bTaskId_t task_id;
http_parser parse;
http_parser_settings parse_cb;
uint8_t *precv;
uint16_t recvbuf_len;
uint16_t recvbuf_index;
#if (defined(_SSL_ENABLE) && (_SSL_ENABLE == 1))
bSSLHandle_t ssl;
#endif
} bHttpStruct_t;
/**
* \}
*/
/**
* \defgroup TCPIP_Private_Defines
* \{
*/
// NTP时间的起始时间
#define B_NTP_TIMESTAMP_DELTA 2208988800ull
#define B_NTP_SERVER_NUM (3)
#define B_NTP_TIMEOUT_S (20)
/**
* \}
*/
/**
* \defgroup TCPIP_Private_Macros
* \{
*/
/**
* \}
*/
/**
* \defgroup TCPIP_Private_Variables
* \{
*/
static bNtpPcb_t bNtpPcb = {
.task_id = 0,
};
B_TASK_CREATE_ATTR(bNtpTask);
static const char *bNtpServer[B_NTP_SERVER_NUM] = {_NTP_SERVER_1, _NTP_SERVER_2, _NTP_SERVER_3};
//------------------------------------------------------------------------------------------------
/**
* \}
*/
/**
* \defgroup TCPIP_Private_FunctionPrototypes
* \{
*/
/**
* \}
*/
/**
* \defgroup TCPIP_Private_Functions
* \{
*/
static void _bTcpipSrvFree(void *addr)
{
bFree(addr);
}
static void _bNtpConnCallback(bTransEvent_t event, void *param, void *arg)
{
;
}
PT_THREAD(_bNtpTaskFunc)(struct pt *pt, void *arg)
{
static uint8_t ntp_server_index = 0;
bNtpPacket_t packet;
uint16_t rlen = 0;
uint64_t ntp_time = 0;
PT_BEGIN(pt);
while (1)
{
bNtpPcb.sockfd = bSocket(B_TRANS_CONN_UDP, _bNtpConnCallback, NULL);
if (bNtpPcb.sockfd < 0)
{
b_log_e("socket fail...\r\n");
break;
}
b_log("sockfd: %x %d\r\n", bNtpPcb.sockfd, ntp_server_index);
bConnect(bNtpPcb.sockfd, (char *)bNtpServer[ntp_server_index], 123);
PT_WAIT_UNTIL(pt, bSockIsWriteable(bNtpPcb.sockfd) == 1, B_NTP_TIMEOUT_S * 1000);
if (pt->retval == PT_RETVAL_TIMEOUT)
{
b_log_e("ntp send fail...\r\n");
PT_WAIT_UNTIL_FOREVER(pt, bShutdown(bNtpPcb.sockfd) >= 0);
b_log_e("shutdown..\r\n");
ntp_server_index = (ntp_server_index + 1) % B_NTP_SERVER_NUM;
break;
}
memset(&packet, 0, sizeof(bNtpPacket_t));
packet.li_vn_mode = 0x1b;
bSend(bNtpPcb.sockfd, (uint8_t *)&packet, sizeof(bNtpPacket_t), NULL);
PT_WAIT_UNTIL(pt, bSockIsReadable(bNtpPcb.sockfd) == 1, B_NTP_TIMEOUT_S * 1000);
if (pt->retval == PT_RETVAL_TIMEOUT)
{
b_log_e("ntp recv timeout.. \r\n");
PT_WAIT_UNTIL_FOREVER(pt, bShutdown(bNtpPcb.sockfd) >= 0);
b_log_e("shutdown..\r\n");
ntp_server_index = (ntp_server_index + 1) % B_NTP_SERVER_NUM;
bTaskDelayMs(pt, 10000);
break;
}
bRecv(bNtpPcb.sockfd, (uint8_t *)&packet, sizeof(bNtpPacket_t), &rlen);
if (rlen == sizeof(bNtpPacket_t))
{
if (packet.recv_time.seconds <= packet.trans_time.seconds &&
(packet.trans_time.seconds - packet.recv_time.seconds) <= 1)
{
ntp_time = B_SWAP_32(packet.trans_time.seconds) - B_NTP_TIMESTAMP_DELTA;
bUTC_SetTime(ntp_time);
}
}
PT_WAIT_UNTIL_FOREVER(pt, bShutdown(bNtpPcb.sockfd) >= 0);
b_log_e("shutdown..\r\n");
bTaskDelayMs(pt, bNtpPcb.interval_s * 1000);
}
PT_END(pt);
}
//--------------------------------------------------------http--
//--------------------------------------------------------http--
static int _bHttpParseUrl(const char *url, char *host, char *path, uint16_t *port, uint8_t *ishttps)
{
// 检查是否是HTTPS
if (strncmp(url, "https://", 8) == 0)
{
*ishttps = 1;
}
else if (strncmp(url, "http://", 7) == 0)
{
*ishttps = 0;
}
else
{
return -1;
}
// 跳过"http://"或"https://"
const char *start = url + (*ishttps ? 8 : 7);
// 查找host的结束位置
const char *end = strchr(start, '/');
if (end == NULL)
{
end = url + strlen(url);
}
if ((end - start) > _HTTP_HOST_LEN_MAX)
{
return -1;
}
// 复制host到目标字符串
strncpy(host, start, end - start);
host[end - start] = '\0';
// 解析port
const char *portStart = strchr(host, ':');
if (portStart != NULL)
{
*port = atoi(portStart + 1);
}
else
{
*port = (*ishttps ? 443 : 80);
}
// 解析path
if (*end != '\0')
{
if (strlen(end) > _HTTP_PATH_LEN_MAX)
{
return -1;
}
strcpy(path, end);
}
else
{
strcpy(path, "/");
}
return 0;
}
static char *_bHttpGetRequest(bHttpStruct_t *http)
{
char *request = NULL;
int request_size = 0;
request_size = strlen("GET /") + strlen(http->path) + strlen(" HTTP/1.1\r\n") +
strlen("Host: ") + strlen(http->host) + strlen("\r\n") +
strlen("Connection: close\r\n") + strlen("\r\n") + 1;
request = (char *)bMalloc(request_size);
if (request != NULL)
{
memset(request, 0, request_size);
snprintf(request, request_size, "GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",
http->path, http->host);
}
return request;
}
static char *_bHttpPostRequest(bHttpStruct_t *http, const char *head, const char *body)
{
char *request = NULL;
int request_size = 0;
request_size = strlen("POST /") + strlen(http->path) + strlen(" HTTP/1.1\r\n") +
strlen("Host: ") + strlen(http->host) + strlen("\r\n") +
strlen("Content-Length: xxxxxx\r\n") + strlen("\r\n") + strlen(body) +
strlen("\r\n") + 1;
if (head != NULL)
{
request_size += strlen(head);
}
request = (char *)bMalloc(request_size);
if (request == NULL)
{
return NULL;
}
memset(request, 0, request_size);
// 组装请求字符串
if (head != NULL)
{
snprintf(request, request_size,
"POST /%s HTTP/1.1\r\nHost: %s\r\n%sContent-Length: %d\r\n\r\n"
"%s\r\n",
http->path, http->host, head, strlen(body), body);
}
else
{
snprintf(request, request_size,
"POST /%s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n"
"%s\r\n",
http->path, http->host, strlen(body), body);
}
return request;
}
static void _bHttpResult(bHttpStruct_t *http, bHttpEvent_t evt, void *param)
{
if (evt < 0 || evt == B_HTTP_EVENT_RECV_DATA || evt == B_HTTP_STA_DESTROY)
{
if (http->request)
{
bFree(http->request);
http->request = NULL;
}
http->sockfd = -1;
#if (defined(_SSL_ENABLE) && (_SSL_ENABLE == 1))
if (http->ssl != NULL)
{
bSSLDeinit(http->ssl);
http->ssl = NULL;
}
#endif
http->state = B_HTTP_STA_DEINIT;
}
http->callback(evt, param, http->user_data);
if (http->precv)
{
bFree(http->precv);
http->precv = NULL;
}
http->recvbuf_index = 0;
http->recvbuf_len = 0;
}
static void _bHttpTransCb(bTransEvent_t event, void *param, void *arg)
{
}
static int _bHttpParseComplete(http_parser *parser)
{
bHttpStruct_t *http = (bHttpStruct_t *)parser->data;
http->state = B_HTTP_STA_RECV_DATA;
return 0;
}
PT_THREAD(_bHttpTaskFunc)(struct pt *pt, void *arg)
{
int ret = 0;
void *param = NULL;
bHttpEvent_t event = B_HTTP_EVENT_ERROR;
bHttpStruct_t *http = (bHttpStruct_t *)arg;
bHttpRecvData_t dat;
PT_BEGIN(pt);
while (1)
{
if (http->state == B_HTTP_STA_DEINIT)
{
return 0;
}
if (http->state == B_HTTP_STA_DESTROY)
{
if (http->sockfd > 0)
{
SOCKET_SHUTDOWN(pt, http->sockfd);
_bHttpResult(http, B_HTTP_EVENT_DESTROY, NULL);
}
bTaskRemove(http->task_id);
bFree(http);
break; // task end
}
http->sockfd = bSocket(B_TRANS_CONN_TCP, _bHttpTransCb, http);
if (http->sockfd < 0)
{
event = B_HTTP_EVENT_ERROR;
param = NULL;
goto http_restart;
}
b_log("sockfd: %x %s %d %s\r\n", http->sockfd, http->host, http->port, http->path);
bConnect(http->sockfd, http->host, http->port);
PT_WAIT_UNTIL(pt, bSockIsWriteable(http->sockfd) == 1, 5000);
if (pt->retval == PT_RETVAL_TIMEOUT)
{
event = B_HTTP_EVENT_CONN_FAIL;
param = NULL;
goto http_restart;
}
///////////////////////////////////////////////////////////////
#if (defined(_SSL_ENABLE) && (_SSL_ENABLE == 1))
static uint16_t ssl_timeout = 0;
ssl_timeout = 0;
while (http->is_https)
{
ret = bSSLHandshake(http->ssl, http->sockfd);
if (ret < 0)
{
event = B_HTTP_EVENT_SSL_FAIL;
param = &ret;
goto http_restart;
}
else if (ret == 0)
{
break; // ssl handshake ok ...
}
else
{
bTaskDelayMs(pt, 10);
ssl_timeout++;
if (ssl_timeout >= 200)
{
ssl_timeout = 0;
event = B_HTTP_EVENT_SSL_FAIL;
param = &ret;
goto http_restart;
}
}
}
#endif
//////////////////////////////////////////////////////////////
_bHttpResult(http, B_HTTP_EVENT_CONNECTED, NULL);
b_log("http req:%s\r\n", http->request);
#if (defined(_SSL_ENABLE) && (_SSL_ENABLE == 1))
if (http->is_https)
{
bSSLSend(http->ssl, (uint8_t *)http->request, strlen(http->request), NULL);
}
else
#endif
{
bSend(http->sockfd, (uint8_t *)http->request, strlen(http->request), NULL);
}
http->parse.data = http;
http_parser_init(&http->parse, HTTP_RESPONSE);
http_parser_settings_init(&http->parse_cb);
http->parse_cb.on_message_complete = _bHttpParseComplete;
int parse_len = 0;
uint16_t readlen = 0;
for (;;)
{
PT_WAIT_UNTIL(pt, bSockIsReadable(http->sockfd) == 1, 5000);
if (pt->retval == PT_RETVAL_TIMEOUT)
{
event = B_HTTP_EVENT_RECV_TIMEOUT;
param = NULL;
goto http_restart;
}
if ((http->recvbuf_len - http->recvbuf_index) <= 128)
{
http->recvbuf_len += 1024;
http->precv = bRealloc(http->precv, http->recvbuf_len);
if (http->precv == NULL)
{
event = B_HTTP_EVENT_ERROR;
param = NULL;
goto http_restart;
}
}
#if (defined(_SSL_ENABLE) && (_SSL_ENABLE == 1))
if (http->is_https)
{
bSSLRecv(http->ssl, http->precv + http->recvbuf_index,
http->recvbuf_len - http->recvbuf_index, &readlen);
}
else
#endif
{
bRecv(http->sockfd, http->precv + http->recvbuf_index,
http->recvbuf_len - http->recvbuf_index, &readlen);
}
if (readlen > 0)
{
parse_len =
http_parser_execute(&http->parse, &http->parse_cb,
(const char *)(http->precv + http->recvbuf_index), readlen);
b_log("parse_len %d readlen %d index:%d\r\n", parse_len, readlen,
http->recvbuf_index);
http->recvbuf_index += readlen;
if (http->state == B_HTTP_STA_RECV_DATA)
{
dat.pdat = http->precv;
dat.len = http->recvbuf_index;
dat.release = NULL;
event = B_HTTP_EVENT_RECV_DATA;
param = &dat;
goto http_restart;
}
else if (parse_len < 0)
{
event = B_HTTP_EVENT_ERROR;
param = NULL;
goto http_restart;
}
}
}
http_restart:
SOCKET_SHUTDOWN(pt, http->sockfd);
_bHttpResult(http, event, param);
bTaskRestart(pt);
}
PT_END(pt);
}
/**
* \}
*/
/**
* \addtogroup TCPIP_Exported_Functions
* \{
*/
int bTcpipSrvInit()
{
return 0;
}
int bSntpStart(uint32_t interval_s)
{
if (bNtpPcb.task_id == NULL)
{
memset(&bNtpPcb, 0, sizeof(bNtpPcb));
bNtpPcb.sockfd = -1;
bNtpPcb.interval_s = 60 * 60;
bNtpPcb.task_id = bTaskCreate("ntp", _bNtpTaskFunc, NULL, &bNtpTask);
}
if (interval_s == 0)
{
return -1;
}
bNtpPcb.interval_s = interval_s;
return 0;
}
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
int bHttpInit(pHttpCb_t cb, void *user_data)
{
bHttpStruct_t *http = NULL;
if (cb == NULL)
{
return -1;
}
http = (bHttpStruct_t *)bMalloc(sizeof(bHttpStruct_t));
if (http == NULL)
{
return -2;
}
memset(http, 0, sizeof(bHttpStruct_t));
http->callback = cb;
http->request = NULL;
http->sockfd = -1;
http->state = B_HTTP_STA_DEINIT;
http->user_data = user_data;
http->precv = NULL;
http->recvbuf_index = 0;
http->recvbuf_len = 0;
if ((http->task_id = bTaskCreate(NULL, _bHttpTaskFunc, http, &http->attr)) == NULL)
{
b_log_e("task create fail..\r\n");
bFree(http);
return -3;
}
return ((int)http);
}
int bHttpRequest(int httpfd, bHttpReqType_t type, const char *url, const char *head,
const char *body)
{
int ret = -1;
char *request = NULL;
bHttpStruct_t *http = (bHttpStruct_t *)httpfd;
if (httpfd <= 0 || !HTTPREQ_TYPE_IS_VALID(type) || url == NULL || http->callback == NULL)
{
b_log_e("http param errror..%p %d %p\r\n", http, type, url);
return -1;
}
if (http->state != B_HTTP_STA_DEINIT)
{
b_log_e("http busy...\r\n");
return -2;
}
memset(http->host, 0, sizeof(http->host));
memset(http->path, 0, sizeof(http->path));
ret = _bHttpParseUrl(url, http->host, http->path, &http->port, &http->is_https);
if (ret < 0)
{
b_log_e("parse url fail..%d \r\n", ret);
return -3;
}
b_log("host:%s port %d\n", http->host, http->port);
b_log("path:%s \n", http->path);
if (type == B_HTTP_GET)
{
request = _bHttpGetRequest(http);
}
else if (type == B_HTTP_POST)
{
request = _bHttpPostRequest(http, head, body);
}
if (request == NULL)
{
b_log_e("http create request fail...\r\n");
return -4;
}
http->request = request;
if (http->is_https)
{
#if (defined(_SSL_ENABLE) && (_SSL_ENABLE == 1))
http->ssl = bSSLInit(http->host, NULL);
if (SSLHANDLE_IS_INVALID(http->ssl))
{
bFree(http->request);
http->request = NULL;
return -5;
}
#endif
}
http->state = B_HTTP_STA_INIT;
return 0;
}
int bHttpDeInit(int httpfd)
{
if (httpfd <= 0)
{
return -1;
}
bHttpStruct_t *http = (bHttpStruct_t *)httpfd;
http->state = B_HTTP_STA_DESTROY;
return 0;
}
/**
* \}
*/
/**
* \}
*/
/**
* \}
*/
/**
* \}
*/
#endif
/************************ Copyright (c) 2023 Bean *****END OF FILE****/

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/notrynohigh-BabyOS.git
git@gitlife.ru:oschina-mirror/notrynohigh-BabyOS.git
oschina-mirror
notrynohigh-BabyOS
notrynohigh-BabyOS
master