예제 #1
0
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()
예제 #2
0
void EspNewIncomingConnectionStream::actOnReceive(IpcConnection *connection)
{
  // check for OS errors
  if (getState() == ERROR_STATE)
  {
    ex_assert(FALSE,"Error while receiving first message from client");
  }

  // check for protocol errors
  bool willPassTheAssertion = 
             (getType() == IPC_MSG_SQLESP_DATA_REQUEST OR
              getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND
              getVersion() == CurrEspRequestMessageVersion AND
              moreObjects();
  if (!willPassTheAssertion)
  {
    char *doCatchBugCRx = getenv("ESP_BUGCATCHER_CR_NONUMBER");
    if (!doCatchBugCRx ||
        *doCatchBugCRx != '0')
    {
      connection->dumpAndStopOtherEnd(true, false);
      environment_->getControlConnection()->
        castToGuaReceiveControlConnection()->
        getConnection()->dumpAndStopOtherEnd(true, false);
    }
  }

  ex_assert((getType() == IPC_MSG_SQLESP_DATA_REQUEST OR
             getType() == IPC_MSG_SQLESP_CANCEL_REQUEST) AND
	    getVersion() == CurrEspRequestMessageVersion AND
	    moreObjects(),
	    "Invalid first message from client");

  // take a look at the type of the first object in the message
  IpcMessageObjType nextObjType = getNextObjType();
  switch (nextObjType)
  {
    case ESP_OPEN_HDR:
    case ESP_LATE_CANCEL_HDR:
      {
        ExFragKey key;
        Lng32 remoteInstNum;
        NABoolean isParallelExtract = false; 

        // peek at the message header to see for whom it is
        if (nextObjType == ESP_OPEN_HDR)
        {
          ExEspOpenReqHeader reqHdr((NAMemory *) NULL);
	   
	  *this >> reqHdr;
	  key = reqHdr.key_;
	  remoteInstNum = reqHdr.myInstanceNum_;
	  if (reqHdr.getOpenType() == ExEspOpenReqHeader::PARALLEL_EXTRACT) 
          {
            isParallelExtract = true;
	  }
	}
        else
	{
          // note that the late cancel request may or may not
	  // arrive as the first request (only in the former case
	  // will we reach here)
	  ExEspLateCancelReqHeader reqHdr((NAMemory *) NULL);
	   
	  *this >> reqHdr;
	  key = reqHdr.key_;
	  remoteInstNum = reqHdr.myInstanceNum_;
	}

        if (!isParallelExtract) 
        {
          ExFragInstanceHandle handle =
	    espFragInstanceDir_->findHandle(key);

	  if (handle != NullFragInstanceHandle)
	  {
            // the send bottom node # myInstanceNum of this downloaded fragment
            // is the true recipient of this open request
            ex_split_bottom_tcb * receivingTcb =
              espFragInstanceDir_->getTopTcb(handle);
            ex_send_bottom_tcb *receivingSendTcb =
              receivingTcb->getSendNode(remoteInstNum);

            // Check the connection for a co-located client, and if so,
            // tell the split bottom, because it may prefer this send 
            // bottom when using skew buster uniform distribution.
            if (espFragInstanceDir_->
                  getEnvironment()->
                  getMyOwnProcessId(IPC_DOM_GUA_PHANDLE).match(
                    connection->getOtherEnd().getNodeName(),
                    connection->getOtherEnd().getCpuNum()))
              receivingTcb->setLocalSendBottom(remoteInstNum);

            // Portability note for the code above: we pass IPC_DOM_GUA_PHANDLE
            // for IpcEnvironment::getMyOwnProcessId, even though that method
            // can be called with the default param (IpcNetworkDomain 
            // IPC_DOM_INVALID).  In fact it would  probably be better 
            // to call the object without specifying the IpcNetworkDomain so
            // that it can decide for itself what domain it is using.
            // But there is a problem with the Windows implementation
            // of IpcEnvironment::getMyOwnProcessId, it seems to assume
            // that its domain is IPC_DOM_INTERNET and so this will 
            // cause the botch of an assertion that its control connection 
            // (which is type EspGuaControlConnection) can be cast to a 
            // SockControlConnection.  When this problem is fixed, the 
            // IPC_DOM_GUA_PHANDLE param above can be removed.  Also,
            // when this code is ported to run it a domain other than
            // "guardian", it will be necessary to fix this and to
            // fix IpcEnvironment::getMyOwnProcessId to work properly on
            // windows.

            receivingSendTcb->setClient(connection);
            receivingSendTcb->routeMsg(*this);
          }
	  else
	  {
            connection->dumpAndStopOtherEnd(true, false);
	    ex_assert(FALSE,"entry not found, set diagnostics area and reply");
	  }

        } // normal case, not parallel extract

        else 
        {
          // The OPEN request is from a parallel extract consumer. The
          // incoming request contains a user ID which we will compare
          // against the current user ID for this ESP.

          // NOTE: The user ID for the extract security check is
          // currently sent and compared as a C string. On Linux it is
          // possible to send and compare integers which would lead to
          // simpler code. The code to send/compare strings is still
          // used because it works on all platforms.

          char errorStr[150];

	  // check if next msg is of securityInfo type. 
          ex_assert(moreObjects(), "expected object not received");
          ex_assert(getNextObjType() == ESP_SECURITY_INFO,
	            "received message for unknown message type");
          
	  // unpack security info
	  ExMsgSecurityInfo secInfo(environment_->getHeap());
	  *this >> secInfo;

          // Get the auth ID of this ESP in text form and compare it
          // to the auth ID that arrived in the message. Skip this
          // step in the debug build if an environment variable is
          // set.
          NABoolean doAuthIdCheck = TRUE;
          Int32 status = 0;
#ifdef _DEBUG
          const char *envvar = getenv("NO_EXTRACT_AUTHID_CHECK");
          if (envvar && envvar[0])
            doAuthIdCheck = FALSE;
#endif
          if (doAuthIdCheck)
          {
            // Get user ID from ExMsgSecurityInfo -> (secUserID)
            // the user ID is the integer value made into a string
            // Convert it back into its integer value
            short userIDLen = (short) str_len(secInfo.getAuthID());
            Int32 secUserID = str_atoi(secInfo.getAuthID(), userIDLen);

            // Get the current user ID
            Int32 curUserID = ComUser::getSessionUser(); 

            // Report an error if the user ID is not valid
            if (curUserID == NA_UserIdDefault || secUserID == NA_UserIdDefault)
            {
              str_cpy_c(errorStr,
                        "Producer ESP could not authenticate the consumer, "
                        "no valid current user.");
              status = -1;
            }

            // Make sure user id passed in ExMsgSecurityInfo matches
            // the user id associated with the current session

#if defined(_DEBUG)
            NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
            if (doDebug)
              printf("[DBUSER:%d] ESP extract user ID: "
                     "local [%d], msg [%d]\n",
                     (int) getpid(), curUserID, secUserID);
#endif

              // Compare user ID, Report an error, if comparison fails
              if (curUserID != secUserID)
              {
                str_cpy_c(errorStr,
                          "Producer ESP could not authenticate the consumer, "
                          "user named passed in ExMsgSecurityInfo is not the "
                          "current user");
                status = -1;
              }

          } // if (doAuthIdCheck)
		   
          // get the split bottom TCB that matches the securityKey
          ex_split_bottom_tcb *receivingTcb = NULL;
          if (status == 0) 
          {
            receivingTcb = espFragInstanceDir_->getExtractTop(secInfo.getSecurityKey());
            if (receivingTcb == NULL) 
            {
              str_cpy_c(errorStr, "Producer ESP could not locate extract node");
              status = -1;
            }
          }

	  // get the sendBottom TCB if not already connected to a client
	  ex_send_bottom_tcb *receivingSendTcb = NULL;
	  if (status == 0)
	  {
	    receivingSendTcb = receivingTcb->getConsumerSendBottom();
	    if (receivingSendTcb == NULL) 
	    {
	      str_cpy_c(errorStr, "Producer ESP already connected to a client");
	      status = -1;
	    }
	  }

          // send the error message to the consumer 
	  if (status != 0) 
	  {
            clearAllObjects();
            setType(IPC_MSG_SQLESP_DATA_REPLY);

            NAMemory *heap = environment_->getHeap();

	    IpcMessageObj* baseObj =
	      new(heap)IpcMessageObj(IPC_SQL_DIAG_AREA, CurrEspReplyMessageVersion);
	    *this << *baseObj;

	    // prepare proper error message
	    char phandle[100];
	    MyGuaProcessHandle myHandle;
            myHandle.toAscii(phandle, 100);

	    ComDiagsArea *diags = ComDiagsArea::allocate(heap);
            *diags << DgSqlCode(-EXE_PARALLEL_EXTRACT_OPEN_ERROR)
                   << DgString0(phandle)
                   << DgString1(errorStr);
	    *this  << *diags;

	    diags->decrRefCount();

            send(TRUE /* TRUE indicates waited */);
          }

          // if everything okay, then make the connection
	  if (status == 0) 
          {
            receivingSendTcb->setClient(connection);
            receivingSendTcb->routeMsg(*this);
          }
        } // parallel extract case
      } // open or cancel header