Browse Source

add restartCanif and killself

master
zhaohe 4 months ago
parent
commit
20d00dc58a
  1. 248
      src/components/zcanreceiver/socket_can/socket_can.cpp
  2. 41
      src/components/zcanreceiver/socket_can/socket_can.hpp
  3. 48
      src/components/zcanreceiver/zcanreceiverhost.cpp
  4. 2
      src/components/zcanreceiver/zcanreceiverhost.hpp
  5. 49
      src/extapi_service.cpp
  6. 9
      src/extapi_service.hpp
  7. 4
      src/main_control_service.hpp
  8. 184
      src/utils/urlparser.hpp

248
src/components/zcanreceiver/socket_can/socket_can.cpp

@ -31,7 +31,12 @@ SocketCan::SocketCanError_t SocketCan::sendFrame(shared_ptr<SocketCanFrame> fram
logger->debug("TX:{}", frame->toString());
return writeFrame(canframe);
}
void SocketCan::reStartCanInterface() { startCanInterface(); }
SocketCan::SocketCanError_t SocketCan::writeFrame(const canfd_frame_t &_frame) {
lock_guard<recursive_mutex> lock(thislock);
if (!m_canBusIsReady) {
return kDeviceBusy;
}
@ -51,11 +56,26 @@ void SocketCan::initialize(shared_ptr<SocketCanConfig> socketCanConfig) { //
ZCHECK(socketCanConfig, "socketCanConfig is null");
m_socketCanConfig = socketCanConfig;
socketcanInitialize();
startCanInterface();
// start auto restart thread
m_autoRestartThread.reset(new Thread("SocketCanAutoRestartThread", [this]() {
ThisThread thisThread;
while (!thisThread.getExitFlag()) {
if (m_canErrorFlag) {
startCanInterface();
}
thisThread.sleepForMs(30);
}
}));
}
SocketCan::~SocketCan() {
if (m_thread) {
endListenThread();
if (m_readThread) {
m_readThread->join();
m_readThread = nullptr;
}
if (m_autoRestartThread) {
m_autoRestartThread->join();
m_autoRestartThread = nullptr;
}
if (m_socketCanFd > 0) {
close(m_socketCanFd);
@ -63,37 +83,47 @@ SocketCan::~SocketCan() {
}
}
void SocketCan::startListen() { startListenThread(); }
void SocketCan::setCanBitrate(string canName, int bitrate) {
logger->info("set can:{} bitrate:{}", canName, bitrate);
dosystem(fmt::format("ip link set {} down", canName));
dosystem(fmt::format("ip link set {} type can bitrate {}", canName, bitrate));
dosystem(fmt::format("ip link set {} up", canName));
}
bool SocketCan::findCan(string canName) { return access(fmt::format("/sys/class/net/{}", canName).c_str(), F_OK) == 0; }
void SocketCan::dosystem(string cmd) {
logger->info("do cmd:{}", cmd);
system(cmd.c_str());
}
void SocketCan::socketcanReInitialize() {}
void SocketCan::startCanInterface() {
lock_guard<recursive_mutex> lock(thislock);
void SocketCan::startListenThread() {
if (m_thread) {
endListenThread();
return;
// 尝试恢复CAN总线
if (m_readThread) {
logger->warn("try to recover can bus............................................");
m_readThread->join();
m_readThread = nullptr;
if (m_socketCanFd > 0) close(m_socketCanFd);
m_socketCanFd = -1;
}
logger->info("startListenThread");
m_thread.reset(new Thread("SocketCanThread", [this]() {
/**
* @brief call socketCanReadThreadLoop
*/
socketcanInitialize();
m_readThread.reset(new Thread("SocketCanThread", [this]() {
usleep(10 * 1000);
socketCanReadThreadLoop();
}));
m_canBusIsReady = true;
m_autoRestartThread.reset(new Thread("SocketCanAutoRestartThread", [this]() { monitorLoop(); }));
}
void SocketCan::endListenThread() {
logger->info("endListenThread");
if (m_thread) {
m_thread->join();
m_thread = nullptr;
}
m_canErrorFlag = false;
m_canBusIsReady = true;
logger->warn("start can bus ok............................................");
}
void SocketCan::socketcanInitialize() {
// setCanBitrate(canName, bitrate);
lock_guard<recursive_mutex> lock(thislock);
struct ifreq ifr = {0};
struct sockaddr_can addr = {0};
@ -108,8 +138,7 @@ void SocketCan::socketcanInitialize() {
return;
}
if (m_thread) endListenThread();
if (m_socketCanFd > 0) socketcanDeInitialize();
if (m_socketCanFd > 0) close(m_socketCanFd);
logger->info("socketcanInitialize,canName:{},canBaudrate:{}", m_socketCanConfig->m_canName, m_socketCanConfig->m_canBaudrate);
@ -171,138 +200,6 @@ error:
}
return;
}
void SocketCan::socketcanDeInitialize() {}
void SocketCan::canReadThread() {}
void SocketCan::setCanBitrate(string canName, int bitrate) {
logger->info("set can:{} bitrate:{}", canName, bitrate);
dosystem(fmt::format("ip link set {} down", canName));
dosystem(fmt::format("ip link set {} type can bitrate {}", canName, bitrate));
dosystem(fmt::format("ip link set {} up", canName));
}
bool SocketCan::findCan(string canName) { return access(fmt::format("/sys/class/net/{}", canName).c_str(), F_OK) == 0; }
void SocketCan::dosystem(string cmd) {
logger->info("do cmd:{}", cmd);
system(cmd.c_str());
}
#define TEST_CANDRIVER_DO(exptr) \
do { \
if ((exptr) != 0) { \
logger->error("do {} failed,{}", #exptr, strerror(errno)); \
if (socketId > 0) { \
close(socketId); \
socketId = -1; \
return -1; \
} \
} \
} while (0)
int SocketCan::dumpCanDriverInfo(string canDevice, int baudrate) {
int socketId = -1;
struct ifreq ifr = {0};
struct sockaddr_can addr = {0};
can_filter_t zerofilter = {0};
int recv_own_msgs = 0; /* 0 = disabled (default), 1 = enabled */
int localloop = 0;
int ret = 0;
fd_set readfds, readFileDescriptors;
timeval waitTime;
int loopTime = 0;
logger_t logger = GET_LOGGER(SocketCan);
if (!findCan(canDevice)) {
logger->error("can:{} not found", canDevice);
return -1;
}
// set bitrate
system(fmt::format("ip link set {} down", canDevice).c_str());
system(fmt::format("ip link set {} type can bitrate {}", canDevice, baudrate).c_str());
system(fmt::format("ip link set {} up", canDevice).c_str());
socketId = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (socketId < 0) {
logger->error("socket failed,{}", strerror(errno));
return -1;
}
// 设置依靠名字绑定CAN设备
strcpy(ifr.ifr_name, canDevice.c_str());
TEST_CANDRIVER_DO(ioctl(socketId, SIOCGIFINDEX, &ifr));
// BIND
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
TEST_CANDRIVER_DO(bind(socketId, (struct sockaddr *)&addr, sizeof(addr)));
// 设置过滤器
TEST_CANDRIVER_DO(setsockopt(socketId, SOL_CAN_RAW, CAN_RAW_FILTER, &zerofilter, sizeof(zerofilter)));
// 打开回环
localloop = 1; /* 0 = disabled (default), 1 = enabled */
TEST_CANDRIVER_DO(setsockopt(socketId, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &localloop, sizeof(localloop)));
recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */
TEST_CANDRIVER_DO(setsockopt(socketId, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs, sizeof(recv_own_msgs)));
// 发送一条消息
canfd_frame_t txframe = {0};
canfd_frame_t rxcanframe = {0};
int rxloopcount = 0;
txframe.can_id = 0x12;
txframe.len = 8;
txframe.data[0] = 0x01;
logger->info("write one frame");
ret = write(socketId, &txframe, txframe.len + 8);
if (ret < 0) {
logger->error("write failed,{}", strerror(errno));
close(socketId);
return -1;
}
FD_ZERO(&readFileDescriptors);
FD_SET(socketId, &readFileDescriptors);
while (loopTime < 10) {
loopTime++;
waitTime.tv_sec = 0;
waitTime.tv_usec = 100000; // 100ms
readfds = readFileDescriptors;
int n = select(socketId + 1, &readfds, 0, 0, &waitTime);
if (n <= 0) continue;
int readsize = read(socketId, &rxcanframe, sizeof(rxcanframe));
if (readsize < 0) {
logger->error("read failed,{}", strerror(errno));
close(socketId);
return -1;
}
if (rxcanframe.can_id == txframe.can_id && //
rxcanframe.data[0] == txframe.data[0] && //
rxcanframe.len == txframe.len) {
rxloopcount++;
logger->info("rx loop frame {}", rxloopcount);
}
}
logger->info("Test Can Driver OK!");
logger->info("=================Can Driver Info =================");
logger->info("canDevice :{}", canDevice);
logger->info("baudrate :{}", baudrate);
logger->info("loop count :{}", rxloopcount);
logger->info("shouldEnableLoop:{}", rxloopcount == 1);
logger->info("==================================================");
close(socketId);
return 0;
}
void SocketCan::socketCanReadThreadLoop() {
ThisThread thisThread;
@ -334,6 +231,7 @@ void SocketCan::socketCanReadThreadLoop() {
// /usr/include/linux/can/error.h
// x can-bus error event 20000004,0004000000000086
logger->error("rx can-bus error event {:x},{}", canframe.can_id, StringUtils().bytesToString(canframe.data, canframe.len));
m_canErrorFlag = true;
break;
} else {
shared_ptr<SocketCanFrame> socketCanFrame = SocketCanFrame::createFrame(canframe);
@ -342,39 +240,5 @@ void SocketCan::socketCanReadThreadLoop() {
}
}
m_canErrorFlag = true;
m_canBusIsReady = false;
}
void SocketCan::monitorLoop() {
ThisThread thisThread;
while (!thisThread.getExitFlag()) {
if (m_canErrorFlag) {
// 尝试恢复CAN总线
logger->warn("try to recover can bus............................................");
if (m_thread) {
m_thread->join();
m_thread = nullptr;
}
logger->warn("close can bus fd:{}", m_socketCanFd);
close(m_socketCanFd);
m_socketCanFd = -1;
logger->warn("re init can bus");
socketcanInitialize();
m_thread.reset(new Thread("SocketCanThread", [this]() {
usleep(10 * 1000);
socketCanReadThreadLoop();
}));
m_canErrorFlag = false;
m_canBusIsReady = true;
logger->warn("recover can bus ok............................................");
}
thisThread.sleepForMs(30);
}
}
}

41
src/components/zcanreceiver/socket_can/socket_can.hpp

@ -60,22 +60,8 @@ class SocketCan : public enable_shared_from_this<SocketCan> {
ENABLE_LOGGER(SocketCan);
public:
typedef enum {
kTxIdle,
kTxing,
} TxState_t;
class TxState {
public:
canfd_frame_t txbuf;
TxState_t txState = kTxIdle;
int txAckCount = 0;
zsteady_tp txLoopMessageRxTicket;
recursive_mutex lock;
};
private:
unique_ptr<Thread> m_thread;
unique_ptr<Thread> m_readThread;
unique_ptr<Thread> m_autoRestartThread;
int m_socketCanFd = -1;
bool m_startListen = false;
@ -84,6 +70,7 @@ class SocketCan : public enable_shared_from_this<SocketCan> {
bool m_canErrorFlag = false;
shared_ptr<SocketCanConfig> m_socketCanConfig;
recursive_mutex thislock;
public:
typedef enum {
@ -128,30 +115,15 @@ class SocketCan : public enable_shared_from_this<SocketCan> {
void initialize(shared_ptr<SocketCanConfig> socketCanConfig);
bool isError() { return false; }
void startListen();
SocketCanError_t sendFrame(shared_ptr<SocketCanFrame> frame, int overtime);
SocketCanError_t sendFrame(shared_ptr<SocketCanFrame> frame);
/**
* @brief 使CAN驱动的行为CAN总线上
*
* @param canDevice
* @param baudrate
* @return int
*/
static int dumpCanDriverInfo(string canDevice, int baudrate);
void reStartCanInterface();
private:
void socketcanInitialize();
void socketcanDeInitialize();
void socketcanReInitialize();
void startListenThread();
void endListenThread();
void socketCanReadThreadLoop();
void monitorLoop();
void startCanInterface();
private:
void dosystem(string cmd);
@ -159,8 +131,5 @@ class SocketCan : public enable_shared_from_this<SocketCan> {
static bool findCan(string canName);
SocketCanError_t writeFrame(const canfd_frame_t &frame);
private:
void canReadThread();
};
} // namespace iflytop

48
src/components/zcanreceiver/zcanreceiverhost.cpp

@ -20,12 +20,30 @@ void ZCanReceiverHost::initialize(string can_if_name, int baudrate) {
m_can_if_name = can_if_name;
m_baudrate = baudrate;
m_enablLoopback = false;
resetSocketCan();
auto socketCanConfig = make_shared<SocketCanConfig>();
socketCanConfig->enablLoopback = m_enablLoopback; // 根据 SocketCan::dumpCanDriverInfo() 的输出,确定该标志位是false还是true
socketCanConfig->m_canName = m_can_if_name;
socketCanConfig->m_canBaudrate = m_baudrate;
socketCanConfig->m_canfilters = {};
logger->debug("initialize() m_canName:{} {}", socketCanConfig->m_canName, socketCanConfig->m_canBaudrate);
m_socketCan.reset(new SocketCan());
m_socketCan->initialize(socketCanConfig);
m_socketCan->onSocketCanFrame.connect([this](shared_ptr<SocketCanFrame> canframe) { //
if (canframe->getId() == m_hostId) {
logger->debug("TX RAW: {} SUC", canframe->toString());
return;
}
logger->debug("RX RAW: {}", canframe->toString());
processRx(canframe);
});
}
void ZCanReceiverHost::registerListener(onpacket_t onpacket) { m_onpacket = onpacket; }
void ZCanReceiverHost::sendPacket(uint8_t *packet, size_t len) {
logger->info("TX: {}", StringUtils().bytesToString(packet, len));
logger->debug("TX: {}", StringUtils().bytesToString(packet, len));
int npacket = len / 7 + (len % 7 == 0 ? 0 : 1);
if (npacket > 255) {
return;
@ -58,7 +76,7 @@ bool ZCanReceiverHost::sendPacketSub(int npacket, int packetIndex, uint8_t *pack
// printf("\n");
shared_ptr<SocketCanFrame> frame = SocketCanFrame::createStdDataFrame(id, txdata, len + 1);
logger->info("TX RAW :{}", frame->toString());
logger->debug("TX RAW :{}", frame->toString());
m_socketCan->sendFrame(frame, overtimems);
return true;
}
@ -101,29 +119,9 @@ void ZCanReceiverHost::processRx(shared_ptr<SocketCanFrame> frame) {
/**
* @brief
*/
logger->info("RX: {}", StringUtils().bytesToString(rxbuf->m_rxdata, rxbuf->m_rxdataLen));
logger->debug("RX: {}", StringUtils().bytesToString(rxbuf->m_rxdata, rxbuf->m_rxdataLen));
processOnePacket(rxbuf, rxbuf->m_rxdata, rxbuf->m_rxdataLen);
}
}
void ZCanReceiverHost::resetSocketCan() {
auto socketCanConfig = make_shared<SocketCanConfig>();
socketCanConfig->enablLoopback = m_enablLoopback; // 根据 SocketCan::dumpCanDriverInfo() 的输出,确定该标志位是false还是true
socketCanConfig->m_canName = m_can_if_name;
socketCanConfig->m_canBaudrate = m_baudrate;
socketCanConfig->m_canfilters = {};
logger->info("initialize() m_canName:{} {}", socketCanConfig->m_canName, socketCanConfig->m_canBaudrate);
m_socketCan.reset(new SocketCan());
m_socketCan->initialize(socketCanConfig);
m_socketCan->startListen();
m_socketCan->onSocketCanFrame.connect([this](shared_ptr<SocketCanFrame> canframe) { //
if (canframe->getId() == m_hostId) {
logger->info("TX RAW: {} SUC", canframe->toString());
return;
}
logger->info("RX RAW: {}", canframe->toString());
processRx(canframe);
});
}
void ZCanReceiverHost::restartCanInterface() { m_socketCan->reStartCanInterface(); }

2
src/components/zcanreceiver/zcanreceiverhost.hpp

@ -47,13 +47,13 @@ class ZCanReceiverHost {
void initialize(string can_if_name, int baudrate);
void sendPacket(uint8_t *packet, size_t len);
void registerListener(onpacket_t onpacket);
void restartCanInterface();
private:
bool sendPacketSub(int npacket, int packetIndex, uint8_t *packet, size_t len, int overtimems);
void processRx(shared_ptr<SocketCanFrame> frame);
void processOnePacket(CanPacketRxBuffer *rxbuf, uint8_t *packet, size_t len);
void resetSocketCan();
void sendcmd(uint16_t packetindex, uint16_t cmdid, uint8_t subcmdid, uint8_t *data, size_t len);
};

49
src/extapi_service.cpp

@ -4,6 +4,7 @@
#include "configs/version.hpp"
#include "ixwebsocket/IXWebSocketServer.h"
#include "utils/stringutils.hpp"
#include "utils/urlparser.hpp"
// #include "iflytop/components/zcanreceiver/zcanreceiverhost.hpp"
// #include "iflytop/core/components/stringutils.hpp"
@ -16,7 +17,6 @@ using namespace nlohmann;
using namespace ix;
#define BIND
namespace iflytop {};
void ExtAPIService::initialize(string can_if_name, int baudrate) {
GET_TO_SERVICE(m_zconfig);
@ -26,8 +26,29 @@ void ExtAPIService::initialize(string can_if_name, int baudrate) {
initCanPassthroughServer();
};
void ExtAPIService::processRXData(weak_ptr<WebSocket> webSocket, const ix::WebSocketMessagePtr &msg) {}
void ExtAPIService::initCanPassthroughServer() {
m_httpServer.reset(new HttpServer(19004, "0.0.0.0"));
m_httpServer->listen();
m_httpServer->start();
m_httpServer->setOnConnectionCallback( //
[this](HttpRequestPtr request, std::shared_ptr<ConnectionState> connectionState) -> HttpResponsePtr {
HTTP_URL httpurl = URLParser::Parse(request->uri);
if (httpurl.getPath() == "/restartCanif") {
logger->info("call {}", request->uri);
m_zcanreceiverhost->restartCanInterface();
} else if (httpurl.getPath() == "/killself") {
logger->info("call {}", request->uri);
exit(1);
} else {
logger->warn("call unknown {}", httpurl.getPath());
}
return std::make_shared<HttpResponse>(200, "", HttpErrorCode::Ok, WebSocketHttpHeaders(), "");
});
/**
*
* protocol: websocket
@ -41,20 +62,28 @@ void ExtAPIService::initCanPassthroughServer() {
auto ws = webSocket.lock();
if (!ws) return;
ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) {
if (msg->type == ix::WebSocketMessageType::Message) {
logger->info("down can bin -> {}({})", msg->str, msg->wireSize);
vector<uint8_t> rxbyte;
StringUtils().hexStringToBytes(msg->str, "", rxbyte);
m_zcanreceiverhost->sendPacket(rxbyte.data(), rxbyte.size());
ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) { //
try {
if (msg->type == ix::WebSocketMessageType::Message) {
logger->info("websocket-ch -> {}({})", msg->str, msg->wireSize);
string hexStr = msg->str;
vector<uint8_t> rxbyte;
StringUtils().hexStringToBytes(hexStr, "", rxbyte);
m_zcanreceiverhost->sendPacket(rxbyte.data(), rxbyte.size());
} else if (msg->type == ix::WebSocketMessageType::Open) {
logger->info("websocket-ch on open");
}
} catch (const std::exception &e) {
logger->error("catch error: {}", e.what());
}
});
});
m_zcanreceiverhost->registerListener([this](uint8_t fromboardid, uint8_t *packet, size_t len) {
string hexStr = StringUtils().bytesToString((uint8_t *)packet, len);
logger->info("up can bin -> {}({})", hexStr, len);
auto clients = m_canPassthroughServer->getClients();
string hexStr = StringUtils().bytesToString((uint8_t *)packet, len);
auto clients = m_canPassthroughServer->getClients();
logger->info("websocket-ch <- {}({})", hexStr, len);
for (auto &each : clients) {
if (each) each->sendText(hexStr);
}

9
src/extapi_service.hpp

@ -22,11 +22,13 @@
// #include "iflytoplinuxsdk/src/iflytop/core/components/zservice_container/zservice_container.hpp"
//
#include "components/zcanreceiver/zcanreceiverhost.hpp"
#include "components/zservice_container/zservice_container.hpp"
#include "configs/gconfig.hpp"
#include "ixwebsocket/IXHttp.h"
#include "ixwebsocket/IXHttpServer.h"
#include "ixwebsocket/IXWebSocketServer.h"
#include "spdlogfactory/logger.hpp"
#include "components/zcanreceiver/zcanreceiverhost.hpp"
//
//
@ -42,12 +44,14 @@
namespace iflytop {
using namespace std;
using namespace core;
using namespace ix;
class ExtAPIService {
ENABLE_LOGGER(ExtAPIService);
shared_ptr<GConfig> m_zconfig;
shared_ptr<ix::WebSocketServer> m_canPassthroughServer; // 19003
shared_ptr<ix::WebSocketServer> m_canPassthroughServer; // 19005
shared_ptr<HttpServer> m_httpServer;//19004
shared_ptr<ZCanReceiverHost> m_zcanreceiverhost;
public:
@ -56,5 +60,6 @@ class ExtAPIService {
private:
void initCanPassthroughServer();
void processRXData(weak_ptr<WebSocket> webSocket, const ix::WebSocketMessagePtr &msg);
};
} // namespace iflytop

4
src/main_control_service.hpp

@ -23,8 +23,8 @@
// #include "iflytoplinuxsdk/src/iflytop/core/components/zservice_container/zservice_container.hpp"
//
#include "spdlogfactory/logger.hpp"
#include "extapi_service.hpp"
#include "spdlogfactory/logger.hpp"
//
//
@ -48,7 +48,7 @@ using namespace core;
class MainControlService : public enable_shared_from_this<MainControlService> {
ENABLE_LOGGER(MainControlService);
ExtAPIService m_extAPIService;
ExtAPIService m_extAPIService;
public:
MainControlService() {};

184
src/utils/urlparser.hpp

@ -0,0 +1,184 @@
#pragma once
#include <cstring>
#include <string>
#include <unordered_map>
#include <vector>
/**
* @brief
*
* string input_url = "http://127.0.0.1:40000/path_1/path_2/path_3/foo.git?test=1&test2=3";
* //string input_url = "http://127.0.0.1/path_1/path_2/path_3/foo.git?test=1&test2=3";
* //string input_url = "http://127.0.0.1/path_1/path_2/path_3";
* //string input_url = "/path_1/path_2/path_3/?test=1&test2=3";
* //string input_url = "https://127.0.0.1:40000/path_1/path_2/path_3/foo.git?test=&test2=3";
*
* Usage
* Just include header file.
*
* #include "../src/url_parser.h"
*
* URLParser::HTTP_URL http_url = URLParser::Parse(input_url);
*
* std::cout << "scheme:[" << http_url.scheme << "]" << std::endl;
* std::cout << "host:[" << http_url.host << "]" << std::endl;
* std::cout << "port:[" << http_url.port << "]" << std::endl;
*
* Return
* class URLParser
* {
* public:
* struct HTTP_URL
* {
* string scheme; // Defined porotocol on URL. (http, ssh, ftp... etc.)
* string host; // Host name or ip address.
* string port; // Port
* std::vector<string> path; // It contains path information that partitioned. (path_1, path_2...)
* string query_string; // Full of query string.
* std::unordered_map<string, string> query; // It conatains query information. That made up of key, value pair.
* };
* }
*
*/
namespace iflytop {
using namespace std;
class URLParserFunction {
public:
static bool FindKeyword(const string& input_url, size_t& st, size_t& before, const string& delim, string& result) {
char temp[1024] = {
0,
};
size_t temp_st = st;
memcpy(&temp_st, &st, sizeof(temp_st));
st = input_url.find(delim, before);
if (st == string::npos) {
st = temp_st;
return false;
}
memcpy(&temp[0], &input_url[before], st - before);
before = st + delim.length();
result = string(temp);
// if (result.empty()) return false;
return true;
};
static bool SplitQueryString(const string& str, const string& delim, string& key, string& value) {
char first[1024] = {
0,
};
char second[1024] = {
0,
};
size_t st = str.find(delim, 0);
memcpy(first, &str[0], st);
memcpy(second, &str[st + 1], str.length() - st);
key = string(first);
value = string(second);
return true;
};
};
class HTTP_URL {
public:
string raw;
string scheme;
string host;
string port;
std::vector<string> path;
string query_string;
std::unordered_map<string, string> query;
string getPath() {
string path;
for (auto& p : this->path) {
path += "/";
path += p;
}
return path;
}
void dump() {
printf("raw:%s\n", raw.c_str());
printf("scheme:%s\n", scheme.c_str());
printf("host:%s\n", host.c_str());
printf("port:%s\n", port.c_str());
printf("path:%s\n", getPath().c_str());
printf("query_string:%s\n", query_string.c_str());
for (auto& q : query) {
printf("query:%s=%s\n", q.first.c_str(), q.second.c_str());
}
printf("=\n");
}
};
class URLParser {
public:
static HTTP_URL Parse(const string& input_url) {
HTTP_URL http_url;
http_url.raw = input_url;
size_t st = 0;
size_t before = 0;
URLParserFunction::FindKeyword(input_url, st, before, "://", http_url.scheme);
URLParserFunction::FindKeyword(input_url, st, before, "/", http_url.host);
size_t temp_st = 0;
size_t temp_before = 0;
string temp_ip;
string temp_port;
if (true == URLParserFunction::FindKeyword(http_url.host, temp_st, temp_before, ":", temp_ip)) {
http_url.port = string(&http_url.host[temp_before]);
http_url.host = temp_ip;
}
while (true) {
string path;
if (false == URLParserFunction::FindKeyword(input_url, st, before, "/", path)) break;
http_url.path.push_back(path);
}
string path;
if (false == URLParserFunction::FindKeyword(input_url, st, before, "?", path)) {
path = string(&input_url[st + 1]);
http_url.path.push_back(path);
return http_url;
}
http_url.path.push_back(path);
if (st < input_url.length()) {
http_url.query_string = string(&input_url[st + 1]);
if (false == http_url.query_string.empty()) {
string query;
st = 0;
before = 0;
while (true) {
string key, value;
if (false == URLParserFunction::FindKeyword(http_url.query_string, st, before, "&", query)) {
URLParserFunction::SplitQueryString(string(&http_url.query_string[before]), "=", key, value);
http_url.query.insert(std::unordered_map<string, string>::value_type(key, value));
break;
}
URLParserFunction::SplitQueryString(query, "=", key, value);
http_url.query.insert(std::unordered_map<string, string>::value_type(key, value));
}
}
}
return http_url;
};
};
} // namespace iflytop
Loading…
Cancel
Save