Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

627 lines
18 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: serial.cxx
  4. //
  5. // Contents: serialization support
  6. //
  7. // Classes: Serializer
  8. //
  9. // Functions: Helper class for serialization which holds
  10. // serialization state like MES handles, position
  11. // in buffer, stream etc. Provides a virtual
  12. // buffer for operation but is created from and
  13. // commited back to an IStream object.
  14. //
  15. // History: 24-Jan-98 vinaykr Created
  16. // 17-Aug-98 vinaykr Made every method inline
  17. // and non-COM class.
  18. //
  19. //--------------------------------------------------------------------
  20. #ifndef __SERIAL_HXX
  21. #define __SERIAL_HXX
  22. #include <rpc.h>
  23. #include <midles.h>
  24. #include <actstrm.hxx>
  25. #include <buffer.h>
  26. #include <serializ.h>
  27. #include <ole2int.h>
  28. // Flag used to signal the in-proc case for Serialization header marshalling
  29. #define INTERNAL_SERIALIZATION_FLAG 0x487fabc
  30. extern GUID gProcessGuid;
  31. typedef struct _SSerializationHeader
  32. {
  33. DWORD dwSize;
  34. void* pvMarshalPtr;
  35. } SerializationHeader;
  36. class Serializer
  37. {
  38. public:
  39. enum
  40. {
  41. DIRECTION_READ = 0x1,
  42. DIRECTION_WRITE = 0x2
  43. };
  44. inline ~Serializer()
  45. {
  46. // Free MES handle
  47. if (_handle!=0)
  48. MesHandleFree(_handle);
  49. // If we have a stream free it
  50. if (_pStream)
  51. {
  52. _pIBuff->Release();
  53. _pStream->Release();
  54. }
  55. // If original stream is different free it
  56. if ((_pOriginalStream) && (_pOriginalStream != _pStream))
  57. _pOriginalStream->Release();
  58. }
  59. inline Serializer()
  60. {
  61. _bufSize=0;
  62. _operationSize=0;
  63. _buffer = 0;
  64. _nWritten = 0;
  65. _position = 0;
  66. _start = 0;
  67. _pStream = NULL;
  68. _pOriginalStream = NULL;
  69. _pIBuff = NULL;
  70. _handle = 0;
  71. _clRefs = 1;
  72. }
  73. inline Serializer(DWORD dwMaxDestCtx, DWORD dwCurrCtx, DWORD dwMarshalFlags)
  74. {
  75. this->Serializer::Serializer();
  76. _dwMaxDestCtx = dwMaxDestCtx;
  77. _dwCurrentDestCtx = dwCurrCtx;
  78. _dwMarshalFlags = dwMarshalFlags;
  79. }
  80. inline ULONG Serializer::Release(void)
  81. {
  82. Win4Assert((_clRefs != 0) && "Serializer::Release");
  83. ULONG ulRefs = InterlockedDecrement(&_clRefs);
  84. if (ulRefs == 0)
  85. {
  86. delete this;
  87. }
  88. return ulRefs;
  89. }
  90. /***************************************************************************/
  91. /** Initializes state based on stream for serialization **/
  92. /** Assumes that we know the limits of our operation before hand if we **/
  93. /** writing out to the stream. **/
  94. /** Note that it is the responsibility of the caller to ensure that the **/
  95. /** variable pMarshalPtr is only passed during in process marshalling **/
  96. /** otherwise undefined errors may result. **/
  97. /** Note that when writing pMarshalPtr and dwSize are input parameters **/
  98. /** and while reading they are output.
  99. /***************************************************************************/
  100. inline HRESULT InitStream(IStream *pStream,DWORD &dwSize, DWORD direction, void* &pMarshalPtr)
  101. {
  102. HRESULT hr;
  103. DWORD nRead;
  104. _direction = direction;
  105. _pOriginalStream = pStream;
  106. _pOriginalStream->AddRef();
  107. // Either read or write initial protocol header
  108. if (direction == DIRECTION_READ)
  109. {
  110. SerializationHeader hdr;
  111. DWORD dwFlag;
  112. // There was a slight security hole here, on both 32 and 64 bit,
  113. // because we could deference arbitrary pointers if we read them
  114. // out of a malicious objref.
  115. //
  116. // For the in-proc marshal case, we'll solve this by writing out the
  117. // in-proc serialization flag, followed by the process' secret guid
  118. // as 'authentication', followed by the actual CObjectContext pointer,
  119. //
  120. // -mfeingol 2/28/2002
  121. // Read the size
  122. if ((hr = _pOriginalStream->Read(&hdr.dwSize, sizeof (hdr.dwSize), &nRead)) != S_OK)
  123. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  124. // Read the flag
  125. if ((hr = _pOriginalStream->Read(&dwFlag, sizeof (dwFlag), &nRead)) != S_OK)
  126. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  127. // Determine if the stream comes from in-proc or out-of-proc
  128. if (dwFlag == INTERNAL_SERIALIZATION_FLAG)
  129. {
  130. // Inproc case: there's a guid, then a pointer in the stream
  131. GUID guidGuess = GUID_NULL;
  132. if ((hr = _pOriginalStream->Read(&guidGuess, sizeof (guidGuess), &nRead)) != S_OK)
  133. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  134. Win4Assert (gProcessGuid != GUID_NULL);
  135. if (guidGuess != gProcessGuid)
  136. return E_UNEXPECTED;
  137. // Now we know that there's a real pointer in the stream
  138. if ((hr = _pOriginalStream->Read(&hdr.pvMarshalPtr, sizeof (hdr.pvMarshalPtr), &nRead)) != S_OK)
  139. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  140. }
  141. else
  142. {
  143. // Out of proc case; the DWORD we read is just a NULL placeholder
  144. hdr.pvMarshalPtr = NULL;
  145. }
  146. pMarshalPtr = hdr.pvMarshalPtr;
  147. if (hdr.pvMarshalPtr)
  148. {
  149. _operationSize = hdr.dwSize;
  150. }
  151. else
  152. {
  153. BYTE *pSrc = (BYTE*) &hdr.dwSize;
  154. _operationSize = 0;
  155. for (int i = 0; i<(sizeof(DWORD)/sizeof(BYTE)); i++)
  156. {
  157. _operationSize |= ((((DWORD)(*pSrc++)) & 0xFF) << (i*8));
  158. }
  159. }
  160. dwSize = _operationSize;
  161. }
  162. else
  163. {
  164. _operationSize = dwSize;
  165. SerializationHeader hdr;
  166. hdr.pvMarshalPtr = pMarshalPtr;
  167. if (pMarshalPtr)
  168. {
  169. hdr.dwSize = dwSize;
  170. }
  171. else
  172. {
  173. BYTE *pDst = (BYTE*) &hdr.dwSize;
  174. for (int i = 0; i<(sizeof(DWORD)/sizeof(BYTE)); i++)
  175. {
  176. *pDst++ = (BYTE)((dwSize>>(i*8)) & 0xFF);
  177. }
  178. }
  179. if (pMarshalPtr)
  180. {
  181. // Inproc case: write the size DWORD, the flag, the process' secret guid GUID, then the ptr
  182. DWORD dwFlag = INTERNAL_SERIALIZATION_FLAG;
  183. if ((hr = _pOriginalStream->Write(&hdr.dwSize, sizeof (hdr.dwSize), &_nWritten)) != S_OK)
  184. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  185. if ((hr = _pOriginalStream->Write(&dwFlag, sizeof (dwFlag), &_nWritten)) != S_OK)
  186. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  187. if ((hr = _pOriginalStream->Write(&gProcessGuid, sizeof (gProcessGuid), &_nWritten)) != S_OK)
  188. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  189. if ((hr = _pOriginalStream->Write(&pMarshalPtr, sizeof (pMarshalPtr), &_nWritten)) != S_OK)
  190. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  191. }
  192. else
  193. {
  194. DWORD dwFlag = 0;
  195. // Out of proc case: write the DWORD and a blank DWORD for the NULL pointer
  196. if ((hr = _pOriginalStream->Write(&hdr.dwSize, sizeof (hdr.dwSize), &_nWritten)) != S_OK)
  197. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  198. if ((hr = _pOriginalStream->Write(&dwFlag, sizeof (dwFlag), &_nWritten)) != S_OK)
  199. return SUCCEEDED (hr) ? E_UNEXPECTED : hr;
  200. }
  201. }
  202. if (!_operationSize)
  203. {
  204. if (!pMarshalPtr)
  205. return E_UNEXPECTED;
  206. return S_OK;
  207. }
  208. // See if given stream supports IBuffer otherwise create one that does
  209. IBuffer *pibuff;
  210. if (_pOriginalStream->QueryInterface(IID_IBuffer, (void**)&pibuff)!=S_OK)
  211. {
  212. // allocate more in case alignment needed
  213. _bufSize = _operationSize + 8;
  214. _pStream = new ActivationStream(_bufSize);
  215. if (_pStream==NULL)
  216. return E_OUTOFMEMORY;
  217. hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
  218. ASSERT(hr==S_OK);
  219. pibuff = _pIBuff;
  220. }
  221. do // Loop until we get right buffer
  222. {
  223. // Invariant is that pibuff must exist by the time we get here
  224. ASSERT(pibuff != 0);
  225. // Set up our buffer appropriately
  226. if (direction == DIRECTION_READ)
  227. {
  228. if (pibuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
  229. return E_FAIL;
  230. if (_bufSize < _operationSize)
  231. return E_FAIL;
  232. }
  233. else
  234. if (direction == DIRECTION_WRITE)
  235. {
  236. if (pibuff->GetOrCreateBuffer(_operationSize+GetSize(),
  237. &_bufSize, &_buffer)!=S_OK)
  238. return E_FAIL;
  239. }
  240. if(((LONG_PTR)_buffer)&0x7)
  241. {
  242. // If buffer is not 8 byte aligned, do it
  243. if (pibuff != _pIBuff)
  244. {
  245. // Only get here if we are still using original
  246. ASSERT(_pIBuff == 0);
  247. // So release it and create a new aligned one
  248. pibuff->Release();
  249. _bufSize = _operationSize + 8;
  250. _pStream = new ActivationStream(_bufSize);
  251. if (_pStream==NULL)
  252. return E_OUTOFMEMORY;
  253. hr = _pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff);
  254. ASSERT(hr==S_OK);
  255. pibuff = _pIBuff; //Continue loop
  256. }
  257. else
  258. {
  259. // Got a buffer which we can align
  260. ASSERT(_pIBuff != 0);
  261. pibuff = 0; //Signal end of loop
  262. // Align buffer
  263. _start = (DWORD)(8-(((DWORD_PTR)_buffer)&7));
  264. }
  265. }
  266. else
  267. {
  268. // We have an original good one
  269. _pIBuff = pibuff;
  270. pibuff = 0;
  271. }
  272. }
  273. while (pibuff);
  274. ASSERT(_pIBuff!=0);
  275. // Set position for next operations and set up
  276. // internal state correctly
  277. hr = _pIBuff->SetPosition(_bufSize, _start);
  278. ASSERT(hr == S_OK);
  279. _bufSize -= _start;
  280. _buffer += _start;
  281. _position = 0;
  282. if (direction==DIRECTION_READ)
  283. {
  284. if ((_pStream) && (_pOriginalStream != _pStream))
  285. {
  286. //If what we have is not the original one then we
  287. //need to copy data into aligned address from original
  288. DWORD nOver=0;
  289. do {
  290. if ((hr=_pOriginalStream->Read(_buffer+nOver,
  291. _operationSize-nOver, &nRead))!= S_OK)
  292. return hr;
  293. nOver += nRead;
  294. }
  295. while (nOver<_operationSize);
  296. _pOriginalStream->Release();
  297. _pOriginalStream = 0; // Don't need original any longer
  298. }
  299. else
  300. _pStream = _pOriginalStream; // Set operating to original
  301. ASSERT(_pStream!=0);
  302. // Create decoding handle for MES operations
  303. MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
  304. if (_handle == NULL)
  305. return E_OUTOFMEMORY;
  306. }
  307. else
  308. {
  309. _nWritten = 0;
  310. // Check if we are still using the orignal stream
  311. if (_pStream == 0)
  312. _pStream = _pOriginalStream;
  313. // Create encoding handle for MES operations
  314. MesEncodeFixedBufferHandleCreate((char*)_buffer,
  315. _bufSize, &_nWritten, &_handle);
  316. if (_handle == NULL)
  317. return E_OUTOFMEMORY;
  318. }
  319. return S_OK;
  320. }
  321. /***************************************************************************/
  322. /** Sets stream and state for further serialization operations **/
  323. /** Assumes that a stream supporting IBuffer is provided. **/
  324. /***************************************************************************/
  325. inline HRESULT SetStream(IStream *pStream,DWORD dwOpSize,
  326. DWORD direction)
  327. {
  328. // Set up internal state
  329. _direction = direction;
  330. _pOriginalStream = 0;
  331. _pStream = pStream;
  332. _operationSize = dwOpSize;
  333. _pStream->AddRef();
  334. // Assume IBuffer exists otherwise fail
  335. if (_pStream->QueryInterface(IID_IBuffer, (void**)&_pIBuff)!=S_OK)
  336. return E_FAIL;
  337. if (_pIBuff->GetBuffer(&_bufSize, &_buffer)!=S_OK)
  338. return E_FAIL;
  339. if (_bufSize < _operationSize)
  340. return E_FAIL;
  341. // Set up MES handles
  342. if (direction==DIRECTION_READ)
  343. MesDecodeBufferHandleCreate((char*)_buffer, _bufSize, &_handle);
  344. else
  345. MesEncodeFixedBufferHandleCreate((char*)_buffer,
  346. _bufSize, &_nWritten, &_handle);
  347. if (_handle == NULL)
  348. return E_OUTOFMEMORY;
  349. return S_OK;
  350. }
  351. // Gets MES handle
  352. inline HRESULT GetSerializationHandle(void *pHandle)
  353. {
  354. *((handle_t*) pHandle) = _handle;
  355. return S_OK;
  356. }
  357. // Gets MES handle for sizing operations
  358. inline HRESULT GetSizingHandle(void *pHandle)
  359. {
  360. char dummy[30], *dummybuff;
  361. unsigned long encodedSize;
  362. handle_t handle;
  363. dummybuff = (char*)(((LONG_PTR)(&dummy[7])) & ~7);
  364. MesEncodeFixedBufferHandleCreate(dummybuff, 100, &encodedSize, (handle_t*)pHandle);
  365. if ( (*(handle_t*)pHandle) == NULL)
  366. return E_OUTOFMEMORY;
  367. return S_OK;
  368. }
  369. //Signals end of operations on this object and commits
  370. //operations to stream
  371. inline HRESULT Commit()
  372. {
  373. // If we are not using original and we are writing,
  374. // then we need to copy
  375. if ((_pOriginalStream) && (_pOriginalStream != _pStream))
  376. {
  377. ASSERT(_direction==DIRECTION_WRITE);
  378. HRESULT hr;
  379. do
  380. {
  381. _nWritten = 0;
  382. hr = _pOriginalStream->Write(_buffer,
  383. _operationSize, &_nWritten);
  384. if (hr != S_OK)
  385. break;
  386. _operationSize -= _nWritten;
  387. _buffer += _nWritten;
  388. }
  389. while (_operationSize);
  390. return hr;
  391. }
  392. else
  393. return _pIBuff->SetPosition(_bufSize, _operationSize);
  394. }
  395. inline HRESULT SetPosition(DWORD dwPos)
  396. {
  397. RPC_STATUS rpcStat;
  398. // Sets position in buffer and creates appropriate MES handle
  399. HRESULT hr = _pIBuff->SetPosition(_bufSize, dwPos);
  400. if (hr!=S_OK)
  401. return hr;
  402. MesHandleFree(_handle);
  403. _handle = NULL;
  404. if (_direction == DIRECTION_READ)
  405. rpcStat = MesDecodeBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_handle);
  406. else
  407. {
  408. _nWritten = 0;
  409. rpcStat = MesEncodeFixedBufferHandleCreate((char*)(_buffer+dwPos), _bufSize, &_nWritten, &_handle);
  410. }
  411. if (rpcStat != RPC_S_OK)
  412. {
  413. if ( HRESULT_FACILITY(rpcStat) == FACILITY_RPC )
  414. return rpcStat;
  415. else
  416. return HRESULT_FROM_WIN32(rpcStat);
  417. }
  418. if (_handle == NULL)
  419. return E_OUTOFMEMORY;
  420. _position = dwPos;
  421. return S_OK;
  422. }
  423. // Gets current position in buffer
  424. inline HRESULT GetPosition(DWORD *pdwPos)
  425. {
  426. *pdwPos = _position;
  427. return S_OK;
  428. }
  429. // Increment current position by specified amount in buffer
  430. inline HRESULT IncrementPosition(DWORD dwInc)
  431. {
  432. return SetPosition(_position+dwInc);
  433. }
  434. // Get buffers underlying stream object
  435. inline HRESULT GetStream(IStream **ppStream)
  436. {
  437. _pStream->AddRef();
  438. *ppStream = _pStream;
  439. return S_OK;
  440. }
  441. // Get a copy of this object
  442. inline HRESULT GetCopy(Serializer **ppSer)
  443. {
  444. HRESULT hr=E_FAIL;
  445. IStream *pNewStream;
  446. if (_pStream)
  447. {
  448. ASSERT(_direction==DIRECTION_READ); //No need for any other case right now
  449. hr = _pIBuff->SetPosition(_bufSize, 0);
  450. ASSERT(hr==S_OK);
  451. if (_pOriginalStream) // Still using original so clone
  452. {
  453. ASSERT(_start==0);
  454. ASSERT(_pStream==_pOriginalStream);
  455. hr = _pIBuff->SetCopyAlignment(8);
  456. ASSERT(hr==S_OK);
  457. hr = _pStream->Clone(&pNewStream);
  458. if (hr != S_OK)
  459. return hr;
  460. }
  461. else
  462. {
  463. pNewStream = _pStream;
  464. }
  465. Serializer *ser = new Serializer(_dwMaxDestCtx, _dwCurrentDestCtx, _dwMarshalFlags);
  466. if (ser==NULL)
  467. return E_OUTOFMEMORY;
  468. hr = ser->SetStream(pNewStream, _operationSize, _direction);
  469. if (FAILED(hr))
  470. goto exit_point;
  471. hr = ser->SetPosition(_position);
  472. if (FAILED(hr))
  473. goto exit_point;
  474. hr = _pIBuff->SetPosition(_bufSize, _position);
  475. if (FAILED(hr))
  476. goto exit_point;
  477. *ppSer = ser;
  478. exit_point:
  479. if (pNewStream != _pStream)
  480. pNewStream->Release();
  481. if (FAILED(hr))
  482. {
  483. ser->Release();
  484. *ppSer = NULL;
  485. }
  486. }
  487. return hr;
  488. }
  489. // Write provided buffer into our buffer at current position
  490. // and advance position
  491. inline HRESULT Write(BYTE *buff, DWORD nBytes)
  492. {
  493. if(nBytes > (_bufSize - _position))
  494. return E_FAIL;
  495. memcpy(_buffer+_position,buff, (size_t) nBytes);
  496. IncrementPosition(nBytes);
  497. return S_OK;
  498. }
  499. // Copy into provided Serializer our data at given position and length
  500. inline HRESULT CopyTo(Serializer *pSer, DWORD dwPos, DWORD nBytes)
  501. {
  502. if(nBytes > (_bufSize - dwPos) )
  503. return E_FAIL;
  504. return pSer->Write(_buffer+dwPos, nBytes);
  505. }
  506. // return buffer starting at current position
  507. inline HRESULT GetBufferAtCurrent(BYTE **ppBuff)
  508. {
  509. *ppBuff = _buffer+_position;
  510. return S_OK;
  511. }
  512. inline void GetMaxDestCtx(OUT DWORD *pdwDestCtx)
  513. {
  514. *pdwDestCtx = _dwMaxDestCtx;
  515. }
  516. inline void GetCurrDestCtx(OUT DWORD *pdwDestCtx)
  517. {
  518. *pdwDestCtx = _dwCurrentDestCtx;
  519. }
  520. inline void GetMarshalFlags(OUT DWORD *pdwMarshalFlags)
  521. {
  522. *pdwMarshalFlags = _dwMarshalFlags;
  523. }
  524. static inline DWORD GetSize()
  525. {
  526. // fixed initialization length
  527. return sizeof(SerializationHeader);
  528. }
  529. private:
  530. IStream *_pStream;
  531. IStream *_pOriginalStream;
  532. IBuffer *_pIBuff;
  533. BYTE *_buffer;
  534. DWORD _nWritten;
  535. DWORD _bufSize;
  536. DWORD _operationSize;
  537. handle_t _handle;
  538. LONG _clRefs;
  539. DWORD _direction;
  540. DWORD _position;
  541. DWORD _start;
  542. DWORD _dwMaxDestCtx;
  543. DWORD _dwCurrentDestCtx;
  544. DWORD _dwMarshalFlags;
  545. };
  546. #endif //__SERIAL_HXX__