RpcIfClient.cpp
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:13k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* RpcIfClient -- Encapsulates Remote Method Invocations */
  2. /* Copyright (c) 1999 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01t,17dec01,nel  Add include symbol for diab.
  7. 01s,10oct01,dbs  add AddKnownInterface() method to IOrpcClientChannel
  8. 01r,02oct01,nel  Move debug hooks into SockStream class.
  9. 01q,26sep01,nel  Modify hooks to pass IP and Port.
  10. 01p,21aug01,nel  Add hooks to optionally display decoded packet traffic.
  11. 01o,24jul01,dbs  take fix from SPR#68234
  12. 01n,13jul01,dbs  add pres ctx ID to request pdu
  13. 01m,29mar01,nel  SPR#35873. Add extra code to hold the client side context IDs
  14.                  for bound interfaces and modify the bindToIID method to send
  15.                  alter context for already bound interfaces rather than always
  16.                  sending bind.
  17. 01l,20jun00,dbs  fix client BIND/ALTER_CONTEXT handling
  18. 01k,24may00,dbs  add fault diagnostics
  19. 01j,04may00,nel  Add log output for client side requests.
  20. 01i,20aug99,aim  return SERVER_NOT_AVAILABLE when connect fails
  21. 01h,30jul99,aim  added S_INFO messages
  22. 01g,22jul99,dbs  enforce serialisation on method-calls
  23. 01f,19jul99,dbs  add client-side authn support
  24. 01e,13jul99,aim  syslog api changes
  25. 01d,06jul99,aim  new ctors
  26. 01c,02jul99,aim  added RpcInvocation functionality
  27. 01b,08jun99,aim  rework
  28. 01a,05jun99,aim  created
  29. */
  30. #include "RpcIfClient.h"
  31. #include "Reactor.h"
  32. #include "Syslog.h"
  33. #include "RpcPduFactory.h"
  34. #include "comErr.h"
  35. #include "SCM.h"
  36. #include "private/comSysLib.h"
  37. #include "private/DebugHooks.h"
  38. /* Include symbol for diab */
  39. extern "C" int include_vxdcom_RpcIfClient (void)
  40.     {
  41.     return 0;
  42.     }
  43. RpcIfClient::CALL_ID
  44. RpcIfClient::s_callId = 0;
  45. RpcIfClient::~RpcIfClient ()
  46.     {
  47.     TRACE_CALL;
  48.     // Remove records of this channel from NTLM authn service
  49.     NTLMSSP* ssp = SCM::ssp ();
  50.     if (ssp)
  51. ssp->channelRemove (channelId ());
  52.     }
  53. RpcIfClient::RpcIfClient (const INETSockAddr& peerAddr)
  54.   : m_peerAddr (peerAddr),
  55.     m_boundIIDs (),
  56.     m_stream (),
  57.     m_connector (),
  58.     m_connected (false),
  59.     m_dwRefCount (0)
  60.     {
  61.     }
  62. RpcIfClient::RpcIfClient (const RpcStringBinding& binding)
  63.   : m_peerAddr (),
  64.     m_boundIIDs (),
  65.     m_stream (),
  66.     m_connector (),
  67.     m_connected (false),
  68.     m_dwRefCount (0)
  69.     {
  70.     m_peerAddr = INETSockAddr (binding.ipAddress (),
  71.        binding.portNumber ());
  72.     }
  73. int RpcIfClient::connect (const INETSockAddr& peerAddr, HRESULT& hresult)
  74.     {
  75.     TRACE_CALL;
  76.     hresult = S_OK;
  77.     if (m_connected)
  78. return 0;
  79.     if (m_connector.connect (stream (), peerAddr) < 0)
  80. {
  81. S_ERR (LOG_RPC | LOG_ERRNO, "cannot connect to " << peerAddr);
  82. hresult = MAKE_HRESULT (SEVERITY_ERROR,
  83. FACILITY_WIN32,
  84. RPC_S_SERVER_UNAVAILABLE);
  85. }
  86.     else
  87. {
  88. INETSockAddr pa;
  89. if (stream().peerAddrGet (pa) < 0)
  90.     {
  91.     hresult = MAKE_HRESULT (SEVERITY_ERROR,
  92.     FACILITY_WIN32,
  93.     RPC_S_SERVER_UNAVAILABLE);
  94.     m_connected = false;
  95.     stream().close ();
  96.     }
  97. else
  98.     {
  99.     S_DEBUG (LOG_RPC, "connected to " << pa);
  100.     hresult = S_OK;
  101.     m_connected = true;
  102.     // Add this channel to SSP's records so we can perform
  103.     // authentication in future if required...
  104.     NTLMSSP* pssp = SCM::ssp ();
  105.     if (pssp)
  106. pssp->channelAdd (channelId ());
  107.     }
  108. }
  109.     return SUCCEEDED (hresult) ? 0 : -1;
  110.     }
  111. int RpcIfClient::connect ()
  112.     {
  113.     TRACE_CALL;
  114.     HRESULT hr;
  115.     connect (m_peerAddr, hr);
  116.     return hr;
  117.     }
  118. SockStream& RpcIfClient::stream ()
  119.     {
  120.     return m_stream;
  121.     }
  122. bool RpcIfClient::connected () const
  123.     {
  124.     return m_connected;
  125.     }
  126. int RpcIfClient::sendPdu (RpcPdu& pdu)
  127.     {
  128.     size_t len;
  129.     char *buf = 0;
  130.     int result = -1;
  131.     if (pdu.makeReplyBuffer (buf, len) < 0)
  132.         stream().close ();
  133.     else 
  134. {
  135. stream ().processDebugOutput (pRpcClientOutput, (BYTE *)buf, (DWORD)len);
  136. if (stream().send (buf, len) == len)
  137.     {
  138.     result = 0;
  139.     S_DEBUG (LOG_RPC, "sendPdu: " << pdu);
  140.     }
  141. }
  142.     if (buf != NULL)
  143. {
  144. delete [] buf;
  145. }
  146.     return result;
  147.     }
  148. RpcIfClient::CALL_ID RpcIfClient::nextCallId ()
  149.     {
  150.     return ++s_callId;
  151.     }
  152. int RpcIfClient::recvPdu (RpcPdu& pdu)
  153.     {
  154.     TRACE_CALL;
  155.     const int buflen = 1024;
  156.     DWORD totalLen = 0;
  157.     char buf[buflen];
  158.     while (1)
  159. {
  160. ssize_t n = stream().recv (buf, buflen);
  161. // no data or the peer closed the connection
  162. if (n <= 0)
  163.     return -1;
  164. totalLen += (DWORD)n;
  165. pdu.append (buf, n);
  166. if (pdu.complete ())
  167.     {
  168.     stream ().processDebugOutput (pRpcClientInput, (BYTE *)buf, (DWORD)buflen);
  169.     S_DEBUG (LOG_RPC, "recvPdu: " << pdu);
  170.     return 0;
  171.     }
  172. }
  173.     return -1;
  174.     }
  175. int RpcIfClient::channelId () const
  176.     {
  177.     return reinterpret_cast<int> (this);
  178.     }
  179. //////////////////////////////////////////////////////////////////////////
  180. //
  181. // RpcIfClient::interfaceIsBound - is the given IID already bound?
  182. //
  183. // This method tests if the interface ID <iid> is already bound,
  184. // i.e. we have at some point in the past, sent a BIND packet and
  185. // successfully allocated a presentation-context ID for it.
  186. //
  187. // If we have, then it returns 'true' and sets the value of
  188. // <presCtxId> appropriately. If not, then it returns 'false' and a
  189. // new presentation context ID will need to be generated.
  190. //
  191. bool RpcIfClient::interfaceIsBound (const IID& iid, USHORT& presCtxId)
  192.     {
  193.     // Search through the vector and if the interface ID is in the
  194.     // table, then set the presentation-context ID value and return
  195.     // true. If we reach the end of the table, and the IID is not
  196.     // present, return false (and do not set 'presCtxId' at all).
  197.     InterfaceVec::iterator i;
  198.     for (i = m_boundIIDs.begin (); i != m_boundIIDs.end (); i++)
  199.      {
  200.      if ((*i) == iid)
  201.       {
  202.     presCtxId = i - m_boundIIDs.begin ();
  203.     return true;
  204.     }
  205. }
  206.     return false;
  207.     }
  208. //////////////////////////////////////////////////////////////////////////
  209. //
  210. // RpcIfClient::bindToIID - bind this channel to the given IID
  211. //
  212. int RpcIfClient::bindToIID
  213.     (
  214.     const IID& iid,
  215.     const GUID* objid,
  216.     HRESULT& hresult,
  217.     USHORT&     presCtxId
  218.     )
  219.     {
  220.     // Check if we are already bound to this IID. If so, we can use
  221.     // that pres-ctx ID directly, and don't need to send either BIND
  222.     // or ALTER_CONTEXT first...
  223.     bool alreadyBound = interfaceIsBound (iid, presCtxId);
  224.     // If we have already bound to this IID, then we can possibly
  225.     // short-cut if its also the current IID (i.e. the last one we
  226.     // sent a BIND or ALTER_CONTEXT for)...
  227.     if (alreadyBound)
  228.         {
  229.         // If its the current IID, take the shortcut -- the
  230.         // presentation context ID will be set to the right value
  231.         // already...
  232.         if (iid == m_currentIID)
  233.             {
  234.             hresult = S_OK;
  235.             return 0;
  236.             }
  237.         // If its not the current IID, we need to fall through and do
  238.         // an ALTER_CONTEXT anyway...
  239.         }
  240.     else
  241.         {
  242.         // We need to generate a new presentation context ID...
  243.      presCtxId = m_boundIIDs.size ();
  244.         }
  245.     
  246.     // Locate default SSP for this machine
  247.     NTLMSSP* pssp = SCM::ssp ();
  248.     // Create BIND (or ALTER_CONTEXT) packet...
  249.     ULONG assocGroupId = 0;
  250.     RpcPdu bindPdu;
  251.     RpcPduFactory::formatBindPdu (bindPdu, 
  252.                                   iid, 
  253.                                   nextCallId (), 
  254.                                   assocGroupId, 
  255.                                   alreadyBound,
  256.                                   presCtxId);
  257.     // Add any required auth-trailer...
  258.     hresult = pssp->clientAuthnRequestAdd (channelId (), bindPdu);
  259.     if (FAILED (hresult))
  260. return -1;
  261.     // Send the PDU to the server...
  262.     if (sendPdu (bindPdu) < 0)
  263. {
  264. hresult = RPC_E_DISCONNECTED;
  265. return -1;
  266. }
  267.     // Receive reply (should be BIND-ACK or BIND-NAK)...
  268.     RpcPdu reply;
  269.     if (recvPdu (reply) < 0)
  270. {
  271. hresult = RPC_E_DISCONNECTED;
  272. return -1;
  273. }
  274.     // What kind of response did we get?
  275.     if (reply.isBindAck ())
  276. {
  277. // Process BIND-ACK packet, we may require to send an AUTH3 to
  278. // complete the authentication process. First record the bound
  279. // IID value...
  280.         AddKnownInterface (iid);
  281. m_currentIID = iid;
  282. // Now process the rest of the authentication steps...
  283. RpcPdu auth3Pdu;
  284. bool sendAuth3 = false;
  285. RpcPduFactory::formatAuth3Pdu (auth3Pdu, reply.callId ());
  286. // Generate the AUTH3 trailer, the NTLM object will decide
  287. // whether we need to send it or not...
  288. hresult = pssp->clientAuthnResponse (channelId (),
  289.      reply,
  290.      &sendAuth3,
  291.      auth3Pdu);
  292. if (SUCCEEDED (hresult) && sendAuth3)
  293.     {
  294.     if (sendPdu (auth3Pdu) < 0)
  295. hresult = RPC_E_DISCONNECTED;
  296.     }
  297. }
  298.     else if (reply.isAlterContextResp ())
  299. {
  300.         // We got an ALTER_CONTEXT_RESPONSE so just set the current
  301.         // IID to this IID...
  302. m_currentIID = iid;
  303. }
  304.     else if (reply.isBindNak ())
  305. {
  306.         // We got a BIND_NAK, that means the server end doesn't
  307.         // support the IID on this channel...
  308. hresult = MAKE_HRESULT (SEVERITY_ERROR,
  309. FACILITY_RPC,
  310. RPC_S_INTERFACE_NOT_FOUND);
  311. }
  312.     else
  313.         {
  314.         // Any other kind of packet is not what we can deal with...
  315. hresult = RPC_E_UNEXPECTED;
  316.         }
  317.     
  318.     return SUCCEEDED (hresult) ? 0 : -1;
  319.     }
  320. //////////////////////////////////////////////////////////////////////////
  321. //
  322. // RpcIfClient::sendMethod - send a REQUEST and get back a RESPONSE
  323. //
  324. //
  325. int RpcIfClient::sendMethod
  326.     (
  327.     RpcPdu& pdu,
  328.     RpcPdu& resultPdu,
  329.     HRESULT& hresult
  330.     )
  331.     {
  332.     // Send the REQUEST packet...
  333.     if (sendPdu (pdu) < 0)
  334. {
  335. hresult = RPC_E_DISCONNECTED;
  336. return -1;
  337. }
  338.     // Await the response...
  339.     if (recvPdu (resultPdu) < 0)
  340. {
  341. hresult = RPC_E_DISCONNECTED;
  342. return -1;
  343. }
  344.     // Is it the right kind of packet?
  345.     if (resultPdu.isResponse ())
  346. hresult = S_OK;
  347.     else if (resultPdu.isFault ())
  348. {
  349. S_ERR (LOG_RPC, "TxREQUEST:" << pdu);
  350. S_ERR (LOG_RPC, "RxFAULT:" << resultPdu);
  351. hresult = resultPdu.fault().status;
  352. }
  353.     else
  354. hresult = RPC_E_UNEXPECTED;
  355.     return SUCCEEDED (hresult) ? 0 : -1;
  356.     }
  357. //////////////////////////////////////////////////////////////////////////
  358. //
  359. // RpcIfClient::InvokeMethod - invoke a method on a remote machine
  360. //
  361. HRESULT RpcIfClient::InvokeMethod
  362.     (
  363.     const IID&         iid,
  364.     const GUID*         objid,
  365.     USHORT              opnum,
  366.     const MSHL_BUFFER*  pMshlBufIn,
  367.     MSHL_BUFFER*        pMshlBufOut
  368.     )
  369.     {
  370.     USHORT presCtxId;
  371.     HRESULT hr;
  372.     
  373.     // Wrap each method-invocation up in a critical-section, in case
  374.     // this object is being shared between tasks...
  375.     VxCritSec cs (m_mutex);
  376.     // Make sure we are connected to the remote server...
  377.     if (connect (m_peerAddr, hr) < 0)
  378.         return hr;
  379.                              
  380.     // Bind the channel to the right IID...
  381.     if (bindToIID (iid, objid, hr, presCtxId) < 0)
  382. return hr;
  383.     // Make a REQUEST PDU ready to send...
  384.     RpcPdu pdu;
  385.     
  386.     RpcPduFactory::formatRequestPdu (pdu,
  387.                                      nextCallId (),
  388.                                      opnum,
  389.                                      objid,
  390.                                      presCtxId);
  391.     
  392.     pdu.stubDataAppend (pMshlBufIn->buf, pMshlBufIn->len);
  393.     // Add any authentication data necessary...
  394.     NTLMSSP* pssp = SCM::ssp ();
  395.     if (pssp)
  396. pssp->clientAuthn (channelId (), pdu);
  397.     // Call the actual method, getting the resulting RESPONSE PDU back
  398.     // containing the result stub-data...
  399.     RpcPdu resultPdu;
  400.     
  401.     if (sendMethod (pdu, resultPdu, hr) < 0)
  402.         return hr;
  403.     // Copy the returned stub-data into the MSHL_BUFFER...
  404.     AllocBuffer (pMshlBufOut, resultPdu.stubDataLen ());
  405.     memcpy (pMshlBufOut->buf, resultPdu.stubData (), resultPdu.stubDataLen ());
  406.     pMshlBufOut->drep = resultPdu.drep ();
  407.     
  408.     return S_OK;
  409.     }
  410. //////////////////////////////////////////////////////////////////////////
  411. //
  412. // AllocBuffer - allocate a buffer for this channel
  413. //
  414. HRESULT RpcIfClient::AllocBuffer
  415.     (
  416.     MSHL_BUFFER*        pBuf,
  417.     DWORD               nBytes
  418.     )
  419.     {
  420.     void* pv = comSysAlloc (nBytes);
  421.     if (! pv)
  422.         return E_OUTOFMEMORY;
  423.     pBuf->buf = (byte*) pv;
  424.     pBuf->len = nBytes;
  425.     return S_OK;
  426.     }
  427. //////////////////////////////////////////////////////////////////////////
  428. //
  429. // FreeBuffer - free a previously-allocated channel buffer
  430. //
  431. HRESULT RpcIfClient::FreeBuffer
  432.     (
  433.     MSHL_BUFFER*        pBuf
  434.     )
  435.     {
  436.     comSysFree (pBuf->buf);
  437.     pBuf->buf = 0;
  438.     pBuf->len = 0;
  439.     return S_OK;
  440.     }
  441. //////////////////////////////////////////////////////////////////////////
  442. //
  443. ULONG RpcIfClient::AddRef ()
  444.     {
  445.     return comSafeInc (&m_dwRefCount);
  446.     }
  447. //////////////////////////////////////////////////////////////////////////
  448. //
  449. ULONG RpcIfClient::Release ()
  450.     {
  451.     DWORD n = comSafeDec (&m_dwRefCount);
  452.     if (n == 0)
  453. delete this;
  454.     return n;
  455.     }
  456. //////////////////////////////////////////////////////////////////////////
  457. //
  458. HRESULT RpcIfClient::QueryInterface (REFIID riid, void** ppv)
  459.     {
  460.     if ((riid == IID_IOrpcClientChannel) ||
  461.         (riid == IID_IUnknown))
  462.         {
  463.         *ppv = this;
  464.         AddRef ();
  465.         return S_OK;
  466.         }
  467.     return E_NOINTERFACE;
  468.     }
  469. //////////////////////////////////////////////////////////////////////////
  470. //
  471. HRESULT RpcIfClient::AddKnownInterface (REFIID iid)
  472.     {
  473.     // Add it to the list of 'bound' IIDs...
  474.     m_boundIIDs.push_back (iid);
  475.     return S_OK;
  476.     }