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;
}
}