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);
}
Example #3
0
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;
}