void HttpServer::setSessionCallback(HttpSession::PTR httpSession, HTTPPARSER_CALLBACK callback, CLOSE_CALLBACK closeCallback) { /*TODO::keep alive and timeout close */ TCPSession::PTR session = httpSession->getSession(); HTTPParser* httpParser = new HTTPParser(HTTP_BOTH); session->setUD((int64_t)httpParser); session->setCloseCallback([closeCallback, httpSession](TCPSession::PTR session){ HTTPParser* httpParser = (HTTPParser*)session->getUD(); delete httpParser; if (closeCallback != nullptr) { closeCallback(httpSession); } }); session->setDataCallback([this, callback, httpSession](TCPSession::PTR session, const char* buffer, size_t len){ int retlen = 0; HTTPParser* httpParser = (HTTPParser*)session->getUD(); if (httpParser->isWebSocket()) { std::string frame(buffer, len); std::string payload; uint8_t opcode; /*TODO::opcode是否回传给回调函数*/ if (WebSocketFormat::wsFrameExtract(frame, payload, opcode)) { callback(*httpParser, httpSession, payload.c_str(), payload.size()); retlen = len; } } else { retlen = httpParser->tryParse(buffer, len); if (httpParser->isCompleted()) { if (httpParser->isWebSocket()) { std::string response = WebSocketFormat::wsHandshake(httpParser->getValue("Sec-WebSocket-Key")); session->send(response.c_str(), response.size()); } else { callback(*httpParser, httpSession, nullptr, 0); if (httpParser->isKeepAlive()) { /*清除本次http报文数据,为下一次http报文准备*/ httpParser->clearParse(); } } } } return retlen; }); }
void WrapServer::addSession(int fd, SESSION_ENTER_CALLBACK userEnterCallback) { TCPSession::PTR tmpSession = std::make_shared<TCPSession>(); tmpSession->setService(mTCPService); auto enterCallback = [tmpSession, userEnterCallback](int64_t id, std::string ip){ tmpSession->setSocketID(id); tmpSession->setIP(ip); if (userEnterCallback != nullptr) { userEnterCallback(tmpSession); } }; auto closeCallback = [tmpSession](int64_t id){ auto& callback = tmpSession->getCloseCallback(); if (callback != nullptr) { callback(tmpSession); } }; auto msgCallback = [tmpSession](int64_t id, const char* buffer, int len){ auto& callback = tmpSession->getDataCallback(); if (callback != nullptr) { return callback(tmpSession, buffer, len); } else { return 0; } }; mTCPService->addDataSocket(fd, enterCallback, closeCallback, msgCallback); }
int main(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "Usage: <listen port> <backend ip> <backend port>"); exit(-1); } int bindPort = atoi(argv[1]); string backendIP = argv[2]; int backendPort = atoi(argv[3]); auto tcpService = std::make_shared<WrapTcpService>(); tcpService->startWorkThread(std::thread::hardware_concurrency()); auto asyncConnector = AsyncConnector::Create(); asyncConnector->startWorkerThread(); auto listenThread = ListenThread::Create(); // listen for front http client listenThread->startListen(false, "0.0.0.0", bindPort, [tcpService, asyncConnector, backendIP, backendPort](sock fd) { tcpService->addSession(fd, [tcpService, asyncConnector, backendIP, backendPort](const TCPSession::PTR& session) { session->setUD(static_cast<int64_t>(1)); std::shared_ptr<TCPSession::PTR> shareBackendSession = std::make_shared<TCPSession::PTR>(nullptr); std::shared_ptr<std::vector<string>> cachePacket = std::make_shared<std::vector<std::string>>(); /* new connect to backend server */ asyncConnector->asyncConnect(backendIP.c_str(), backendPort, std::chrono::seconds(10), [tcpService, session, shareBackendSession, cachePacket](sock fd) { if (true) { tcpService->addSession(fd, [=](const TCPSession::PTR& backendSession) { auto ud = brynet::net::cast<int64_t>(session->getUD()); if (*ud == -1) /*if http client already close*/ { backendSession->postDisConnect(); return; } *shareBackendSession = backendSession; for (auto& p : *cachePacket) { backendSession->send(p.c_str(), p.size()); } cachePacket->clear(); backendSession->setDisConnectCallback([=](const TCPSession::PTR& backendSession) { *shareBackendSession = nullptr; auto ud = brynet::net::cast<int64_t>(session->getUD()); if (*ud != -1) { session->postDisConnect(); } }); backendSession->setDataCallback([=](const TCPSession::PTR& backendSession, const char* buffer, size_t size) { /* recieve data from backend server, then send to http client */ session->send(buffer, size); return size; }); }, false, nullptr, 32 * 1024, false); } }, nullptr); session->setDataCallback([=](const TCPSession::PTR&, const char* buffer, size_t size) { TCPSession::PTR backendSession = *shareBackendSession; if (backendSession == nullptr) { /*cache it*/ cachePacket->push_back(std::string(buffer, size)); } else { /* receive data from http client, then send to backend server */ backendSession->send(buffer, size); } return size; }); session->setDisConnectCallback([=](const TCPSession::PTR& session) { /*if http client close, then close it's backend server */ TCPSession::PTR backendSession = *shareBackendSession; if (backendSession != nullptr) { backendSession->postDisConnect(); } session->setUD(-1); }); }, false, nullptr, 32 * 1024); }); std::cin.get(); }
int onSessionMsg(TCPSession::PTR session, const char* buffer, size_t len) { session->send(buffer, len); return len; }