void SessionHandler::start()

in src/dxapi/native/tickdb/session_handler.cpp [888:995]


void SessionHandler::start()
{
    try {
        // Allocate buffer (currently using constant size)
        byte * allocPtr = (byte *)malloc(BASIC_WRITER_BUFFER_SIZE + 0x1000);
        
        if (NULL == allocPtr) {
            DBGLOGERR((std::string*)NULL, LOGHDR ".open(): Not enough memory for session handler output buffer", ID);
            throw std::bad_alloc();
        }

        bufferAllocPtr_ = allocPtr;

        // Align to 4k page boundary and add 8-byte front guard area
        byte * bufPtr = (byte *)DX_POINTER_ALIGN_UP(allocPtr, 0x1000);
        assert(NULL != bufPtr);

        writer_.setBuffer(allocPtr, bufPtr, bufPtr + BASIC_WRITER_BUFFER_SIZE);

        IOStream * ioStream = db_.createConnectionStream(TCP::NO_DELAY, false);
        this->ioStream_ = ioStream;

        auto & o = writer_;
        o.resetPointer();

        DBGLOG_VERBOSE(LOGHDR ".open(): Opening Timebase session..", ID);

        // TODO: refactor common code
        o.writeByte(PROTOCOL_INIT);
        o.writeInt16(PROTOCOL_VERSION);
        flushOutput();

        serverVersion_ = read<int16>();
        if (serverVersion_ < MIN_SERVER_VERSION) {
            THROW_DBGLOG(LOGHDR ".open(): Incompatible HTTP-TB protocol version %d. Minimum expected version is %d", ID, serverVersion_, MIN_SERVER_VERSION);
        }


        // Transmit credentials
        {
            auto &db = db_;
            secure_string data = db.username();
            scramble(data);
            if (!data.size()) {
                o.writeByte(false);
            }
            else {
                o.writeByte(true);
                o.writeUTF8(data);
                data = db.encodedPass();
                scramble(data);
                o.writeUTF8(data);
            }
        }

        flushOutput();
        int handshake = read<int32>();

        if (RESP_ERROR == handshake) {
            closeConnection();
            // No need to remove from loader, because it is not yet added
            std::string out;
            DBGLOGERR(&out, LOGHDR ".open(): Handshake failed: Wrong username or password", ID);
            throw XmlErrorResponseException(401, out);
        }

        DBGLOG_VERBOSE(LOGHDR ".open(): Handshake succeeded. Initializing session, reading session id", ID);

        o.writeByte(REQ_CREATE_SESSION);
        o.writeByte(0);                     // useCompression = false
        o.writeByte(1);                     // isBigEndian = true (requesting LE stream won't give us noticeable perf. improvement)
        flushOutput();

        // A little hack to force the server to confirm it is working properly by sending a message right away
        requestGetDummyStream();

        // But expect session Id first. If the server is too old, it will send reply to the stream request instead, causing exception
        if (SESSION_STARTED != read<int32_t>()) {
            // TODO: Change exception type?
            THROW_DBGLOG(LOGHDR ".open(): ERR: SESSION_STARTED marker is expected!", ID);
        }

        if (!readUTF8(db_.sessionId_) || 0 == db_.sessionId_.length()) {
            THROW_DBGLOG(LOGHDR ".open(): ERR: Session Id string is expected!", ID);
        }

        DBGLOG_VERBOSE(LOGHDR ".open(): Session id read. Starting worker thread", ID);
        
        // Ok, start worker thread
        thread_ = new std::thread(threadProcStatic, std::ref(*this));
        while (!isRunning_ && !isStopped_) {
            this_thread::yield();
        }
    }

    catch (const IOStreamDisconnectException &) {
        // If was disconnected while still reading response from server, return error
        // If just empty response, set isAtEnd (TODO: KLUDGE: not compatible with realtime mode?)
        DBGLOG(LOGHDR ".open(): ERR: disconnected while connecting", ID);
        cleanup();
        throw;
    }

    catch (...) {
        cleanup();
        throw;
    }
}