void dumpBuffer(unsigned char *buffer, size_t len) { if (buffer == NULL) { return; } // // We will print the buffer 16 characters at a time. For each group // of 16 characters will we build two strings. One we call the "hex" // string and the other the "ascii" string. They will be formatted // as follows: // // hex: "<hex pair> <hex pair> ..." // ascii: "<ascii value><ascii value>..." // // where each <hex pair> is a 4-character hex representation of // 2-bytes and each <ascii value> is 1 character. // const Int32 CHARS_PER_LINE = 16; const Int32 ASCII_BUF_LEN = CHARS_PER_LINE + 1; const Int32 HEX_BUF_LEN = (2 * CHARS_PER_LINE) // 2 hex characters per byte of input + (CHARS_PER_LINE / 2) // one space between each <hex pair> + 1; // null terminator // // The 100-byte pads in the following two buffers are only used as // safeguards to prevent corrupting the stack. The code should work // without the padding. // char hexBuf[HEX_BUF_LEN + 100]; char asciiBuf[ASCII_BUF_LEN + 100]; size_t i, j, hexOffset, asciiOffset; size_t startingOffset; Int32 nCharsWritten; // // This message will be used for buffer overflow assertion failures // const char *msg = "Buffer overflow in dumpBuffer() routine"; i = 0; while (i < len) { // // Initialize the two buffers with blank padding and null // terminators // memset(hexBuf, ' ', HEX_BUF_LEN); memset(asciiBuf, ' ', ASCII_BUF_LEN); hexBuf[HEX_BUF_LEN - 1] = '\0'; asciiBuf[ASCII_BUF_LEN - 1] = '\0'; hexOffset = 0; asciiOffset = 0; startingOffset = i; // // Inside the following for loop hexOffset should be incremented // by 2 or 3 and asciiOffset incremented by 1. // for (j = 0; j < CHARS_PER_LINE && i < len; j++, i++) { // // Write a 2-character hex value to the hex buffer. The %X // format expects an int value. // nCharsWritten = sprintf(&hexBuf[hexOffset], "%02X", (Int32) buffer[i]); UDR_ASSERT(nCharsWritten == 2, msg); hexOffset += 2; // // Add a space to the hex buffer following each pair of bytes // if (j % 2 == 1) { hexBuf[hexOffset++] = ' '; } // // Write one character to the ascii buffer // char c; if (!isprint(buffer[i])) { c = '.'; } else { c = buffer[i]; } asciiBuf[asciiOffset++] = c; } // for (j = 0; j < CHARSPERLINE && i < len; j++, i++) UDR_ASSERT(hexOffset < HEX_BUF_LEN, msg); UDR_ASSERT(asciiOffset < ASCII_BUF_LEN, msg); UDR_ASSERT(hexBuf[HEX_BUF_LEN - 1] == '\0', msg); UDR_ASSERT(asciiBuf[ASCII_BUF_LEN - 1] == '\0', msg); ServerDebug("%08X %-*s | %s", (Int32) startingOffset, (Int32) (HEX_BUF_LEN - 1), hexBuf, asciiBuf); } // while (i < len) ServerDebug(""); } // dumpBuffer
void UdrServerDataStream::actOnReceive(IpcConnection *conn) { const char *moduleName = "UdrServerDataStream::actOnReceive()"; IpcMessageObjType t; NABoolean somethingArrived = FALSE; // // A note about control flow in this method. It was originally // written under the assumption that only one message arrives at a // time. It would call getNextReceiveMsg() only once, then process // incoming objects, then return. It turns out this creates a memory // leak. Internally within the stream, the incoming message buffer // never moved from the "receive" list to the "in use" list and // never got cleaned up. Now this method calls getNextReceiveMsg() // until it returns FALSE. The result is that after the incoming // message has been processed, the next getNextReceiveMsg() call // will move the request buffer to the "in use" list where it later // gets cleaned up by a call to cleanupBuffers() or // releaseBuffers(). // while (getNextReceiveMsg(t)) { somethingArrived = TRUE; while (getNextObjType(t)) { switch (t) { case UDR_MSG_DATA_HEADER: { // Do nothing for now except extract the object from the stream UdrDataHeader *h = new (receiveMsgObj()) UdrDataHeader(this); } // case UDR_MSG_DATA_HEADER break; case UDR_MSG_CONTINUE_REQUEST: { // Extract the object from the stream and call SPInfo's work() UdrContinueMsg *m = new (receiveMsgObj()) UdrContinueMsg(this); if(spinfo_->getParamStyle() == COM_STYLE_TM) spinfo_->workTM(); else spinfo_->work(); } // case UDR_MSG_CONTINUE_REQUEST break; case UDR_MSG_DATA_REQUEST: { UdrDataBuffer *request = new (receiveMsgObj()) UdrDataBuffer(this); if (udrGlob_->verbose_ && udrGlob_->traceLevel_ >= TRACE_DETAILS && udrGlob_->showMain_) { ServerDebug( ""); ServerDebug("[UdrServ (%s)] Invoke Request has %ld tupps.", moduleName, request->getSqlBuffer()->getTotalTuppDescs()); ServerDebug("[UdrServ (%s)] Invoke Request SQL Buffer", moduleName); displaySqlBuffer(request->getSqlBuffer(), (Lng32) request->getSqlBufferLength()); } udrGlob_->numReqInvokeSP_++; // Let the SPInfo process the request spinfo_->setCurrentRequest(request); spinfo_->work(); } // case UDR_MSG_DATA_REQUEST break; case UDR_MSG_TMUDF_DATA_HEADER: { // Extract the object. UDR Handle and RS Handle are // interesting things in this message. UdrTmudfDataHeader *h = new (receiveMsgObj()) UdrTmudfDataHeader(this); UdrHandle udrHandle = h->getHandle(); NABoolean anyMore = getNextObjType(t); UDR_ASSERT(anyMore, "DATA_REQUEST must follow TMUDF DATA_HEADER"); UDR_ASSERT(t == UDR_MSG_DATA_REQUEST, "DATA_REQUEST must follow TMUDF DATA_HEADER"); UdrDataBuffer *request = new (receiveMsgObj()) UdrDataBuffer(this, FALSE); //Avoid unpack. // Let the SPInfo process the request spinfo_->setCurrentRequest(request); spinfo_->workTM(); } break; case UDR_MSG_RS_DATA_HEADER: { // Extract the object. UDR Handle and RS Handle are // interesting things in this message. UdrRSDataHeader *h = new (receiveMsgObj()) UdrRSDataHeader(this); UdrHandle udrHandle = h->getHandle(); RSHandle rsHandle = h->getRSHandle(); NABoolean anyMore = getNextObjType(t); UDR_ASSERT(anyMore, "DATA_REQUEST must follow RS_DATA_HEADER"); UDR_ASSERT(t == UDR_MSG_DATA_REQUEST, "DATA_REQUEST must follow RS_DATA_HEADER"); UdrDataBuffer *request = new (receiveMsgObj()) UdrDataBuffer(this); udrGlob_->numReqRSFetch_++; processAnRSFetchMessage(udrGlob_, *this, udrHandle, rsHandle, request); // We need the request buffer in a state where the stream // knows it can be freed. We call SqlBuffer::bufferFull() to // accomplish this even though the method name is a bit // misleading. SqlBuffer *sqlBuf = request->getSqlBuffer(); UDR_ASSERT(sqlBuf, "UDR request buffer is corrupt or contains no data"); sqlBuf->bufferFull(); } break; case UDR_MSG_RS_CONTINUE: { UdrRSContinueMsg *rsContinue = new (receiveMsgObj()) UdrRSContinueMsg(this); udrGlob_->numReqRSContinue_++; processAnRSContinueMessage(udrGlob_, *this, *rsContinue); } break; default: { UDR_ASSERT(FALSE, "Unknown message type arrived on UDR data stream"); } // default break; } // switch (t) } // while (getNextObjType(t)) } // while (getNextReceiveMsg(t)) // Make sure all reply buffers have been given to the connection. If // the only objects that arrived during this callback were continue // requests, then this action allows reply buffers associated with // those continue requests to propagate out of the stream and onto // the connection. // // If numOfInputBuffers() is > 0 then we do not need to do anything // at this point. This callback will be invoked again when the // incoming message is complete and ready to be processed. Lng32 numInputBuffers = numOfInputBuffers(); if (somethingArrived && numInputBuffers == 0 && spinfo_->getCurrentRequest() == NULL) { responseDone(); if (udrGlob_->verbose_ && udrGlob_->traceLevel_ >= TRACE_IPMS && udrGlob_->showMain_) { ServerDebug("[UdrServ (%s)] All messages marked as replied", moduleName); } // Cleanup any unpacked message buffers containing only objects // that are no longer in use, as determined by the virtual method // IpcMessageObj::msgObjIsFree() releaseBuffers(); // Do final garbage collection } } // UdrServerDataStream::actOnReceive()
NABoolean allocateReplyRow(UdrGlobals *UdrGlob, SqlBuffer &replyBuffer, // [IN] A reply buffer queue_index parentIndex, // [IN] Identifies the request queue entry Int32 replyRowLen, // [IN] Length of reply row char *&newReplyRow, // [OUT] The allocated reply row ControlInfo *&newControlInfo, // [OUT] The allocated ControlInfo entry ex_queue::up_status upStatus // [IN] Q_OK_MMORE, Q_NO_DATA, Q_SQLERROR ) { const char *moduleName = "allocateReplyRow"; doMessageBox(UdrGlob, TRACE_SHOW_DIALOGS, UdrGlob->showInvoke_, moduleName); NABoolean result = FALSE; SqlBufferBase::moveStatus status; up_state upState; upState.parentIndex = parentIndex; upState.downIndex = 0; upState.setMatchNo(0); upState.status = upStatus; tupp_descriptor *tdesc = NULL, **tuppDesc; ControlInfo **ctrlInfo; NABoolean moveCtrlInfo, moveDataInfo; switch (upStatus) { case ex_queue::Q_OK_MMORE : { ctrlInfo = &newControlInfo; moveCtrlInfo = TRUE; moveDataInfo = TRUE; tuppDesc = &tdesc; break; } case ex_queue::Q_SQLERROR : { ctrlInfo = &newControlInfo; moveCtrlInfo = TRUE; moveDataInfo = FALSE; tuppDesc = NULL; break; } case ex_queue::Q_NO_DATA : { ctrlInfo = NULL; moveCtrlInfo = TRUE; moveDataInfo = FALSE; tuppDesc = NULL; break; } default: { UDR_ASSERT(FALSE, "Unknown ex_queue::up_status value."); return FALSE; } } status = replyBuffer.moveInSendOrReplyData( FALSE, // [IN] sending? (vs. replying) moveCtrlInfo, // [IN] force move of ControlInfo? moveDataInfo, // [IN] move data? (void *) &upState, // [IN] queue state sizeof(ControlInfo), // [IN] length of ControlInfo ctrlInfo, // [OUT] new ControlInfo replyRowLen, // [IN] data row length tuppDesc, // [OUT] new data tupp_desc NULL, // [IN] diags area 0 // [OUT] new diags tupp_desc ); if (status == SqlBufferBase::MOVE_SUCCESS) { if (upStatus == ex_queue::Q_OK_MMORE) { newReplyRow = tdesc->getTupleAddress(); memset(newReplyRow, 0, replyRowLen); } result = TRUE; } else { result = FALSE; } return result; }