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.

1780 lines
47 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: obex.cxx
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "precomp.h"
  11. #include "iso8601.h"
  12. #include <irmonftp.h>
  13. #define OBEX_VERSION 0x10
  14. #define OBEX_OPCODE_FINALBIT 0x80
  15. #define OBEX_OPCODE_CONNECT ( 0x00 | OBEX_OPCODE_FINALBIT )
  16. #define OBEX_OPCODE_DISCONNECT ( 0x01 | OBEX_OPCODE_FINALBIT )
  17. #define OBEX_OPCODE_PUT 0x02
  18. #define OBEX_OPCODE_PUT_FINAL ( 0x02 | OBEX_OPCODE_FINALBIT )
  19. #define OBEX_OPCODE_SETPATH ( 0x05 | OBEX_OPCODE_FINALBIT )
  20. #define OBEX_OPCODE_ABORT 0xFF
  21. #define OBEX_OPCODE_LEN 1
  22. #define OBEX_OPCODE_VALID 1
  23. #define OBEX_OPCODE_NOTIMP 0
  24. #define OBEX_OPCODE_INVALID -1
  25. #define OBEX_REPLY_CONTINUE ( 0x10 | OBEX_OPCODE_FINALBIT )
  26. #define OBEX_REPLY_SUCCESS ( 0x20 | OBEX_OPCODE_FINALBIT )
  27. #define OBEX_REPLY_FAIL_BADREQUEST ( 0x40 | OBEX_OPCODE_FINALBIT )
  28. #define OBEX_REPLY_FAIL_FORBIDDEN ( 0x43 | OBEX_OPCODE_FINALBIT )
  29. #define OBEX_REPLY_FAIL_NOTFOUND ( 0x44 | OBEX_OPCODE_FINALBIT )
  30. #define OBEX_REPLY_FAIL_TOOBIG ( 0x4D | OBEX_OPCODE_FINALBIT )
  31. #define OBEX_REPLY_FAIL_NOTIMP ( 0x61 | OBEX_OPCODE_FINALBIT )
  32. #define OBEX_REPLY_FAIL_UNAVAILABLE ( 0x63 | OBEX_OPCODE_FINALBIT )
  33. #define CONNECT_PKTLEN 0x0007
  34. #define CONNECT_FLAGS 0x00
  35. #define DISCONNECT_PKTLEN 0x0003
  36. #define ABORT_PKTLEN 0x0008
  37. #define SETPATH_FLAGS 0x00
  38. #define SETPATH_CONSTANTS 0x00
  39. #define SETPATH_UPALEVEL 0x01
  40. #define REPLY_PKTLEN 0x0003
  41. #define REPLY_TIMEOUT TIMEOUT_INFINITE
  42. #define CONNECT_TIMEOUT 60000
  43. #define SETPATH_TIMEOUT 60000
  44. #define DISCONN_TIMEOUT 15000
  45. #define MAX_UPDATE_DELAY 5000
  46. #define dwBUFFER_INC 512L
  47. #define MIN_PACKET_SIZE 3 // 1 (opcode/status) + 2 (packet len)
  48. //#ifdef DBG
  49. #if 1
  50. LPSTR _szState[] = { "IDLE", "CONNECTED", "FILE" };
  51. #endif
  52. UUID DIALECT_ID_NT5 = /* b9c7fd98-e5f8-11d1-bfce-0000f8753890 */
  53. {
  54. 0xb9c7fd98,
  55. 0xe5f8,
  56. 0x11d1,
  57. {0xbf, 0xce, 0x00, 0x00, 0xf8, 0x75, 0x38, 0x90}
  58. };
  59. BOOL FILE_TRANSFER::Obex_Init( VOID )
  60. {
  61. //
  62. // initialize connection data structures
  63. //
  64. FillMemory( &_dataRecv, sizeof(_dataRecv), 0 );
  65. _SetState( &_dataRecv, osIDLE );
  66. _dataRecv.lpStore = Store_New( cbSTORE_SIZE_RECV );
  67. if( !_dataRecv.lpStore )
  68. goto lErr;
  69. return TRUE;
  70. lErr:
  71. if( _dataRecv.lpStore )
  72. Store_Delete( &_dataRecv.lpStore );
  73. return FALSE;
  74. }
  75. VOID FILE_TRANSFER::Obex_Reset( VOID )
  76. {
  77. _SetState( &_dataRecv, osIDLE );
  78. Store_Empty( _dataRecv.lpStore );
  79. }
  80. BOOL FILE_TRANSFER::Obex_ReceiveData( XFER_TYPE xferType, LPVOID lpvData, DWORD dwDataSize )
  81. {
  82. return Store_AddData( _dataRecv.lpStore, lpvData, dwDataSize );
  83. }
  84. error_status_t
  85. FILE_TRANSFER::Obex_Connect( __int64 dwTotalSize )
  86. {
  87. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  88. LPSTORE lpStore = Store_New( CONNECT_PKTLEN+30 );
  89. DbgLog2( SEV_FUNCTION, "Obex_Connect(0x%x): dwTotalSize: %d",
  90. OBEX_OPCODE_CONNECT, (ULONG) dwTotalSize );
  91. ExitOnFalse( _dataRecv.state == osIDLE );
  92. ExitOnNull( lpStore );
  93. if (_dialect == dialNt5)
  94. {
  95. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_OPCODE_CONNECT) );
  96. ExitOnFalse( Store_AddData2Byte(lpStore, CONNECT_PKTLEN+5) );
  97. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_VERSION) );
  98. ExitOnFalse( Store_AddData1Byte(lpStore, CONNECT_FLAGS) );
  99. ExitOnFalse( Store_AddData2Byte(lpStore, CONNECT_MAXPKT) );
  100. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_LENGTH) );
  101. ExitOnFalse( Store_AddData4Byte(lpStore, (ULONG) dwTotalSize) );
  102. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_WHO) );
  103. ExitOnFalse( Store_AddData2Byte(lpStore, sizeof(UUID)+3) );
  104. ExitOnFalse( Store_AddDataUuid(lpStore, &DIALECT_ID_NT5) );
  105. ExitOnFalse( _PokePacketSizeIntoStore(lpStore) );
  106. DbgLog1( SEV_INFO, "Connect (NT5) Packet Size: %d",
  107. Store_GetDataUsed( lpStore ) );
  108. status = _Request( lpStore, OBEX_REPLY_SUCCESS );
  109. ExitOnErr( status );
  110. status = _WaitForReply( CONNECT_TIMEOUT, OBEX_REPLY_SUCCESS );
  111. }
  112. else
  113. {
  114. DbgLog( SEV_INFO, "trying with Win9x Connect" );
  115. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_OPCODE_CONNECT) );
  116. ExitOnFalse( Store_AddData2Byte(lpStore, CONNECT_PKTLEN+5) );
  117. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_VERSION) );
  118. ExitOnFalse( Store_AddData1Byte(lpStore, CONNECT_FLAGS) );
  119. ExitOnFalse( Store_AddData2Byte(lpStore, CONNECT_MAXPKT) );
  120. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_LENGTH) );
  121. ExitOnFalse( Store_AddData4Byte(lpStore, (ULONG) dwTotalSize) );
  122. status = _Request( lpStore, OBEX_REPLY_SUCCESS );
  123. ExitOnErr( status );
  124. status = _WaitForReply( CONNECT_TIMEOUT, OBEX_REPLY_SUCCESS );
  125. }
  126. DbgLog1(SEV_INFO, "wait result was %d", status);
  127. if (ERROR_TIMEOUT == status)
  128. {
  129. DbgLog( SEV_FUNCTION, "Obex_Connect: no connect reply; assuming Win95 [%d]" );
  130. // Win95 doesn't reply;
  131. // manually fill in the values we would
  132. // have gotten in a connect response
  133. _dataRecv.b1Version = 0x10; // assume the lowest version, Obex 1.0
  134. _dataRecv.b1Flags = 0;
  135. _dataRecv.b2MaxPacket = 2000;
  136. status = 0;
  137. _dialect = dialWin95;
  138. }
  139. ExitOnErr( status );
  140. _SetState( &_dataRecv, osCONN );
  141. //
  142. // See Obex_PutBody for reasoning on the -16...
  143. // Make sure Acked <= Total; this is just an estimate, anyway.
  144. //
  145. _blockSize = _dataRecv.b2MaxPacket - 16;
  146. lExit:
  147. Store_Delete( &lpStore );
  148. DbgLog1( SEV_FUNCTION, "Obex_Connect leave [%d]", status );
  149. return status;
  150. }
  151. error_status_t
  152. FILE_TRANSFER::Obex_Disconnect(
  153. error_status_t error
  154. )
  155. {
  156. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  157. LPSTORE lpStore = Store_New( DISCONNECT_PKTLEN );
  158. DbgLog( SEV_FUNCTION, "Obex_Disconnect" );
  159. // if we are in the middle of sending a file, abort it before disconnecting.
  160. // this will set the state to osCONN.
  161. if( _dataRecv.state == osFILE )
  162. Obex_Abort(error);
  163. ExitOnFalse( _dataRecv.state == osCONN );
  164. ExitOnNull( lpStore );
  165. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_OPCODE_DISCONNECT) );
  166. ExitOnFalse( Store_AddData2Byte(lpStore, DISCONNECT_PKTLEN) );
  167. status = _Request( lpStore, OBEX_REPLY_SUCCESS );
  168. ExitOnErr( status );
  169. status = _WaitForReply( DISCONN_TIMEOUT, OBEX_REPLY_SUCCESS );
  170. lExit:
  171. _SetState( &_dataRecv, osIDLE );
  172. Store_Delete( &lpStore );
  173. DbgLog1( SEV_FUNCTION, "Obex_Disconnect leave [%d]", status );
  174. return status;
  175. }
  176. error_status_t
  177. FILE_TRANSFER::Obex_Abort(
  178. error_status_t error
  179. )
  180. {
  181. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  182. LPSTORE lpStore = Store_New( ABORT_PKTLEN );
  183. DbgLog( SEV_FUNCTION, "Obex_Abort" );
  184. ExitOnFalse( _dataRecv.state == osFILE );
  185. ExitOnNull( lpStore );
  186. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_OPCODE_ABORT) );
  187. ExitOnFalse( Store_AddData2Byte(lpStore, ABORT_PKTLEN) );
  188. if (status && _dialect != dialWin95)
  189. {
  190. ExitOnFalse( Store_AddData1Byte(lpStore, PRIVATE_PARAM_WIN32_ERROR) );
  191. ExitOnFalse( Store_AddData4Byte(lpStore, error) );
  192. }
  193. status = _Request( lpStore, OBEX_REPLY_SUCCESS );
  194. ExitOnErr( status );
  195. lExit:
  196. _SetState( &_dataRecv, osCONN );
  197. Store_Delete( &lpStore );
  198. DbgLog1( SEV_FUNCTION, "Obex_Abort leave [%d]", status );
  199. return status;
  200. }
  201. error_status_t
  202. FILE_TRANSFER::_Put(
  203. LPWSTR wszObj,
  204. __int64 dwObjSize,
  205. FILETIME * pFileTime,
  206. LPBYTE1 pb1Data,
  207. BYTE2 b2DataSize,
  208. BOOL fFinal
  209. )
  210. {
  211. DWORD msg;
  212. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  213. BYTE1 b1Opcode = ( fFinal ? OBEX_OPCODE_PUT_FINAL : OBEX_OPCODE_PUT );
  214. BYTE1 b1BodyParam = ( fFinal ? OBEX_PARAM_BODY_END : OBEX_PARAM_BODY );
  215. LPSTORE lpStore = Store_New( _dataRecv.b2MaxPacket );
  216. DbgLog1( SEV_FUNCTION, "_Put, fFinal = %s", SzBool(fFinal) );
  217. msg = MC_IRXFER_SEND_FAILED;
  218. ExitOnFalse( _dataRecv.state == osCONN || _dataRecv.state == osFILE );
  219. ExitOnNull( lpStore );
  220. ExitOnFalse( Store_AddData1Byte(lpStore, b1Opcode) );
  221. // add buffer space for the packet length
  222. ExitOnFalse( Store_AddData2Byte(lpStore, 0) );
  223. if( wszObj )
  224. {
  225. WCHAR wszNameOnly[MAX_PATH];
  226. //
  227. // strip the path from the full file name
  228. //
  229. StripPath(wszObj, wszNameOnly,sizeof(wszNameOnly)/sizeof(WCHAR) );
  230. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_NAME) );
  231. ExitOnFalse( Store_AddData2Byte(lpStore, 3+CbWsz(wszNameOnly)) );
  232. ExitOnFalse( Store_AddDataWsz(lpStore, wszNameOnly) );
  233. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_LENGTH) );
  234. ExitOnFalse( Store_AddData4Byte(lpStore, (ULONG) dwObjSize) );
  235. if (_dialect == dialWin95)
  236. {
  237. DWORD UnixTime;
  238. if( FileTimeToUnixTime(pFileTime, &UnixTime) )
  239. {
  240. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_UNIX_TIME) );
  241. ExitOnFalse( Store_AddData4Byte(lpStore, UnixTime) );
  242. }
  243. }
  244. else
  245. {
  246. char IsoTimeA[1+ISO_TIME_LENGTH];
  247. WCHAR IsoTimeW[1+ISO_TIME_LENGTH];
  248. status = FileTimeToiso8601(pFileTime, IsoTimeA);
  249. if (status)
  250. {
  251. goto lExit;
  252. }
  253. if (0 == MultiByteToWideChar(CP_ACP, 0L, IsoTimeA, -1, IsoTimeW, 1+ISO_TIME_LENGTH))
  254. {
  255. status = GetLastError();
  256. goto lExit;
  257. }
  258. DbgLog2(SEV_INFO, " ISO time: len %d '%S'", 3+CbWsz(IsoTimeW), IsoTimeW);
  259. ExitOnFalse( Store_AddData1Byte( lpStore, OBEX_PARAM_ISO_TIME ));
  260. ExitOnFalse( Store_AddData2Byte( lpStore, 3+CbWsz(IsoTimeW) ));
  261. ExitOnFalse( Store_AddDataWsz ( lpStore, IsoTimeW ));
  262. }
  263. }
  264. ExitOnFalse( Store_AddData1Byte(lpStore, b1BodyParam) );
  265. ExitOnFalse( Store_AddData2Byte(lpStore, b2DataSize+3) );
  266. ExitOnFalse( Store_AddData(lpStore, pb1Data, b2DataSize ) );
  267. DbgLog1(SEV_INFO, " data size %d", b2DataSize);
  268. ExitOnFalse( _PokePacketSizeIntoStore(lpStore) );
  269. status = _Request( lpStore, 0 );
  270. ExitOnErr( status );
  271. ++_blocksSent;
  272. msg = MC_IRXFER_SEND_WAIT_FAILED;
  273. if (fFinal) {
  274. //
  275. // final put
  276. //
  277. do {
  278. status = _WaitForReply( REPLY_TIMEOUT, OBEX_REPLY_SUCCESS );
  279. if (status != ERROR_TIMEOUT) {
  280. ++_blocksAcked;
  281. }
  282. DbgLog3(SEV_INFO, " blocks %d acks %d status %x",
  283. _blocksSent, _blocksAcked, status );
  284. } while ( !status && _blocksAcked < _blocksSent );
  285. } else {
  286. //
  287. // non-final put
  288. //
  289. #if 0
  290. if (GetTickCount() - _lastAckTime > MAX_UPDATE_DELAY) {
  291. #endif
  292. //
  293. // it has been more than 5 seconds since last ack
  294. //
  295. status = _WaitForReply( REPLY_TIMEOUT, OBEX_REPLY_SUCCESS );
  296. if (status != ERROR_TIMEOUT)
  297. {
  298. ++_blocksAcked;
  299. }
  300. DbgLog3(SEV_INFO, " blocks %d acks %d status %x",
  301. _blocksSent, _blocksAcked, status );
  302. #if 0
  303. } else {
  304. //
  305. // less than 5 seconds since last ack
  306. //
  307. status = _WaitForReply( 0, OBEX_REPLY_CONTINUE );
  308. if (status == ERROR_TIMEOUT)
  309. {
  310. status = 0;
  311. }
  312. else
  313. {
  314. ++_blocksAcked;
  315. }
  316. DbgLog3(SEV_INFO, " blocks %d acks %d status %x",
  317. _blocksSent, _blocksAcked, status );
  318. }
  319. #endif
  320. }
  321. ExitOnErr( status );
  322. _SetState( &_dataRecv, (fFinal ? osCONN : osFILE) );
  323. lExit:
  324. if (status)
  325. {
  326. ASSERT( msg );
  327. DWORD dwEventStatus = 0;
  328. EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
  329. if (!dwEventStatus)
  330. {
  331. ReportFileError( msg, _dataFileRecv.szFileName, status );
  332. }
  333. }
  334. Store_Delete( &lpStore );
  335. DbgLog1( SEV_FUNCTION, "_Put leave [%d]", status );
  336. return status;
  337. }
  338. error_status_t
  339. FILE_TRANSFER::_WaitForReply(
  340. DWORD dwTimeout,
  341. BYTE1 b1NeededReply
  342. )
  343. {
  344. BOOL fProcessed;
  345. long StartTime = GetTickCount();
  346. long EndTime = StartTime + dwTimeout;
  347. error_status_t status = 0;
  348. error_status_t ExpectedStatus = 0;
  349. DbgLog1( SEV_FUNCTION, "_WaitForReply( %d )", dwTimeout );
  350. ASSERT( b1NeededReply == OBEX_REPLY_SUCCESS ||
  351. b1NeededReply == OBEX_REPLY_CONTINUE );
  352. if (b1NeededReply == OBEX_REPLY_CONTINUE)
  353. {
  354. ExpectedStatus = ERROR_CONTINUE;
  355. }
  356. if (TRUE == Obex_ConsumePackets( xferSEND, &status ))
  357. {
  358. return status;
  359. }
  360. if (dwTimeout == TIMEOUT_INFINITE)
  361. {
  362. BOOL fProcessedPacket = FALSE;
  363. do
  364. {
  365. status = Sock_CheckForReply( TIMEOUT_INFINITE );
  366. if (status == WSAETIMEDOUT)
  367. {
  368. DbgLog(SEV_WARNING, " infinite wait returned WSAETIMEDOUT");
  369. status = 0;
  370. }
  371. if (!status)
  372. {
  373. fProcessedPacket = Obex_ConsumePackets( xferSEND, &status );
  374. }
  375. }
  376. while ( !fProcessedPacket && !status );
  377. }
  378. else
  379. {
  380. BOOL fProcessedPacket = FALSE;
  381. DbgLog1(SEV_INFO, " end time = %d", EndTime);
  382. do
  383. {
  384. status = Sock_CheckForReply( EndTime - GetTickCount() );
  385. if (status == WSAETIMEDOUT)
  386. {
  387. status = ERROR_TIMEOUT;
  388. }
  389. if (!status)
  390. {
  391. fProcessedPacket = Obex_ConsumePackets( xferSEND, &status );
  392. }
  393. }
  394. while ( !fProcessedPacket && !status && (EndTime - (long) GetTickCount() > 0) );
  395. if (!fProcessedPacket && !status)
  396. {
  397. status = ERROR_TIMEOUT;
  398. }
  399. }
  400. if ( status == ExpectedStatus )
  401. {
  402. status = 0;
  403. }
  404. DbgLog1( SEV_FUNCTION, "_WaitForReply leave [%d]", status );
  405. return status;
  406. }
  407. BOOL
  408. FILE_TRANSFER::Obex_ConsumePackets(
  409. XFER_TYPE xferType,
  410. error_status_t * pStatus
  411. )
  412. {
  413. BOOL fRet = FALSE;
  414. DWORD dwUsed;
  415. BYTE1 b1Opcode;
  416. BYTE2 b2Length;
  417. LPSTORE lpStore = _dataRecv.lpStore ;
  418. dwUsed = Store_GetDataUsed( lpStore );
  419. DbgLog1( SEV_FUNCTION, "Obex_ConsumePackets: dwUsed: %ld", dwUsed );
  420. // Must have at least MIN_PACKET_SIZE bytes to do anything
  421. if( dwUsed < MIN_PACKET_SIZE )
  422. {
  423. DbgLog( SEV_INFO, "not enough bytes");
  424. goto lExit;
  425. }
  426. // Get status/opcode
  427. if( !Store_GetData1Byte(lpStore, &b1Opcode) )
  428. {
  429. DbgLog( SEV_INFO, " can't get opcode");
  430. goto lExit;
  431. }
  432. // Get total packet length
  433. if( !Store_GetData2Byte(lpStore, &b2Length) )
  434. {
  435. DbgLog( SEV_INFO, " can't get packet length");
  436. goto lExit;
  437. }
  438. // We must have all of the packet to continue
  439. if (dwUsed < b2Length)
  440. {
  441. DbgLog2( SEV_INFO, " have: %d of %d",
  442. dwUsed, b2Length );
  443. // Put back the 3 bytes we just read
  444. Store_SkipData( lpStore, -3 );
  445. goto lExit;
  446. }
  447. DbgLog2( SEV_INFO, " b1Opcode: 0x%x b2Length: %d",
  448. b1Opcode, b2Length );
  449. // if we're waiting, this must be a response packet
  450. if( xferType == xferSEND )
  451. {
  452. *pStatus = _HandleResponse( b1Opcode, b2Length-3 );
  453. }
  454. else
  455. {
  456. *pStatus = _HandleRequest( b1Opcode, b2Length-3 ) ;
  457. }
  458. Store_RemoveData( lpStore, b2Length );
  459. _lastAckTime = GetTickCount();
  460. fRet = TRUE;
  461. lExit:
  462. DbgLog2( SEV_FUNCTION, "Obex_ConsumePackets leave [%s, %d]", SzBool(fRet), *pStatus );
  463. return fRet;
  464. }
  465. INT FILE_TRANSFER::_ValidOpcode( OBEXSTATE state, BYTE1 b1Opcode )
  466. {
  467. switch( b1Opcode )
  468. {
  469. case OBEX_OPCODE_CONNECT:
  470. if( state == osIDLE ) return OBEX_OPCODE_VALID;
  471. break;
  472. case OBEX_OPCODE_DISCONNECT:
  473. if( state == osCONN || state == osFILE ) return OBEX_OPCODE_VALID;
  474. break;
  475. case OBEX_OPCODE_PUT:
  476. case OBEX_OPCODE_PUT_FINAL:
  477. if( state == osCONN || state == osFILE ) return OBEX_OPCODE_VALID;
  478. break;
  479. case OBEX_OPCODE_SETPATH:
  480. if( state == osCONN ) return OBEX_OPCODE_VALID;
  481. break;
  482. case OBEX_OPCODE_ABORT:
  483. if( state == osFILE ) return OBEX_OPCODE_VALID;
  484. break;
  485. default:
  486. return OBEX_OPCODE_NOTIMP;
  487. }
  488. DbgLog1( SEV_FUNCTION, "_ValidOpcode: Invalid opcode: 0x%2.2x", b1Opcode);
  489. return OBEX_OPCODE_INVALID;
  490. }
  491. error_status_t
  492. FILE_TRANSFER::_HandleResponse(
  493. BYTE1 b1Opcode,
  494. BYTE2 b2Length
  495. )
  496. {
  497. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  498. DbgLog1( SEV_FUNCTION, "_HandleResponse b2Length[0x%x]", b2Length );
  499. if( _dataRecv.state == osIDLE )
  500. {
  501. BYTE2 RemoteMaxPacket;
  502. // this should be a connect response. get the conn data
  503. //
  504. ExitOnFalse( Store_GetData1Byte(_dataRecv.lpStore, &_dataRecv.b1Version) );
  505. DbgLog1( SEV_INFO, "_HandleResponse, b1Version[0x%x]", _dataRecv.b1Version );
  506. ExitOnFalse( Store_GetData1Byte(_dataRecv.lpStore, &_dataRecv.b1Flags) );
  507. DbgLog1( SEV_INFO, "_HandleResponse, b1Flags[0x%x]", _dataRecv.b1Flags );
  508. ExitOnFalse( Store_GetData2Byte(_dataRecv.lpStore, &RemoteMaxPacket) );
  509. DbgLog1( SEV_INFO, "_HandleResponse, b2MaxPacket[0x%x]", RemoteMaxPacket );
  510. _dataRecv.b2MaxPacket = min(RemoteMaxPacket, cbSTORE_SIZE_RECV);
  511. b2Length -= 4;
  512. status = _ParseParams( b1Opcode, b2Length );
  513. }
  514. else
  515. {
  516. status = _ParseParams( b1Opcode, b2Length );
  517. if (!status &&
  518. _dataRecv.state == osFILE &&
  519. (b1Opcode == OBEX_REPLY_SUCCESS || b1Opcode == OBEX_REPLY_CONTINUE))
  520. {
  521. if (_blocksAcked > 1)
  522. {
  523. __int64 currentFileBytesAcked = (_blocksAcked-1) * _blockSize;
  524. if (currentFileBytesAcked > _dataXferRecv.dwFileSize)
  525. {
  526. currentFileBytesAcked = _dataXferRecv.dwFileSize;
  527. }
  528. _UpdateSendProgress( rpcBinding,
  529. _cookie,
  530. _dataFileRecv.szFileName,
  531. _dataXferRecv.dwTotalSize,
  532. _completedFilesSize + currentFileBytesAcked,
  533. &status
  534. );
  535. if (status)
  536. {
  537. DbgLog1( SEV_WARNING, "_HandleResponse: UpdateSendProgress returned %d", status );
  538. }
  539. }
  540. }
  541. }
  542. if (!status && b1Opcode != OBEX_REPLY_SUCCESS && b1Opcode != OBEX_REPLY_CONTINUE)
  543. {
  544. status = ObexStatusToWin32( b1Opcode );
  545. DbgLog2( SEV_WARNING, "_HandleResponse: mapped OBEX 0x%x to Win32 %d", b1Opcode, status );
  546. }
  547. lExit:
  548. return status;
  549. }
  550. #ifdef DBG
  551. struct
  552. {
  553. BYTE1 opcode;
  554. char * name;
  555. }
  556. OpcodeNames[] =
  557. {
  558. { OBEX_OPCODE_CONNECT, "connect" },
  559. { OBEX_OPCODE_DISCONNECT, "disconnect" },
  560. { OBEX_OPCODE_PUT, "put" },
  561. { OBEX_OPCODE_ABORT, "abort" },
  562. { OBEX_OPCODE_SETPATH, "setpath" },
  563. { OBEX_OPCODE_PUT_FINAL, "putfinal" }
  564. };
  565. void
  566. LogOpcode(
  567. char * prefix,
  568. BYTE1 opcode,
  569. BYTE2 length
  570. )
  571. {
  572. unsigned i;
  573. for (i=0; i < sizeof(OpcodeNames)/sizeof(OpcodeNames[0]); ++i)
  574. {
  575. if (opcode == OpcodeNames[i].opcode)
  576. {
  577. DbgLog3( SEV_INFO, "%s: %s length %d", prefix, OpcodeNames[i].name, length );
  578. return;
  579. }
  580. }
  581. DbgLog3( SEV_ERROR, "%s: unknown opcode 0x%x, length %d", prefix, opcode, length );
  582. }
  583. #else
  584. inline void
  585. LogOpcode(
  586. char * prefix,
  587. BYTE1 opcode,
  588. BYTE2 length
  589. )
  590. {
  591. }
  592. #endif
  593. error_status_t
  594. FILE_TRANSFER::_HandleRequest(
  595. BYTE1 b1Opcode,
  596. BYTE2 b2Length
  597. )
  598. {
  599. INT nValid;
  600. BOOL fRet;
  601. LogOpcode( "_HandleRequest", b1Opcode, b2Length );
  602. // only accept valid opcodes, otherwise discard the packet and move on
  603. nValid = _ValidOpcode( _dataRecv.state, b1Opcode );
  604. if( nValid == OBEX_OPCODE_INVALID )
  605. {
  606. _HandleBadRequest( b1Opcode );
  607. return ERROR_INVALID_PARAMETER;
  608. }
  609. else if( nValid == OBEX_OPCODE_NOTIMP )
  610. {
  611. _HandleNotImplemented( b1Opcode );
  612. return ERROR_INVALID_PARAMETER;
  613. }
  614. // opcode is valid
  615. switch ( b1Opcode )
  616. {
  617. case OBEX_OPCODE_CONNECT:
  618. _HandleConnect( b1Opcode, b2Length );
  619. return 0;
  620. case OBEX_OPCODE_DISCONNECT:
  621. _HandleDisconnect( b1Opcode, b2Length );
  622. return 0xffffffff;
  623. case OBEX_OPCODE_PUT:
  624. return _HandlePut( b1Opcode, b2Length, FALSE );
  625. case OBEX_OPCODE_PUT_FINAL:
  626. return _HandlePut( b1Opcode, b2Length, TRUE );
  627. case OBEX_OPCODE_SETPATH:
  628. return _HandleSetPath( b1Opcode, b2Length );
  629. case OBEX_OPCODE_ABORT:
  630. _HandleAbort( b1Opcode, b2Length );
  631. return ERROR_CANCELLED;
  632. default:
  633. ASSERT( 0 && "IRMON: bad OBEX opcode" );
  634. return ERROR_INVALID_PARAMETER;
  635. }
  636. return 0;
  637. }
  638. BOOL FILE_TRANSFER::_HandleConnect( BYTE1 b1Opcode, BYTE2 b2Length )
  639. {
  640. BYTE1 ReplyCode;
  641. BYTE2 RemoteMaxPacket;
  642. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  643. LPSTORE lpStore = 0;
  644. DbgLog( SEV_FUNCTION, "_HandleConnect" );
  645. ExitOnFalse( Store_GetData1Byte(_dataRecv.lpStore, &_dataRecv.b1Version) );
  646. b2Length -= 1;
  647. ExitOnFalse( Store_GetData1Byte(_dataRecv.lpStore, &_dataRecv.b1Flags) );
  648. b2Length -= 1;
  649. ExitOnFalse( Store_GetData2Byte(_dataRecv.lpStore, &RemoteMaxPacket) );
  650. b2Length -= 2;
  651. _dataRecv.b2MaxPacket = min(RemoteMaxPacket, cbSTORE_SIZE_RECV);
  652. lpStore = Store_New( CONNECT_PKTLEN + 30);
  653. ExitOnNull( lpStore );
  654. status = Xfer_ConnStart();
  655. if (!status)
  656. {
  657. Xfer_FileInit();
  658. }
  659. //
  660. // Parse parms before checking login status so we can send richer error codes
  661. // to an NT client.
  662. //
  663. if (!status)
  664. {
  665. status = _ParseParams( b1Opcode, b2Length );
  666. }
  667. if (!status)
  668. {
  669. if (!g_fAllowReceives || g_fShutdown)
  670. {
  671. // We'd like to return ERROR_NOT_LOGGED_ON but the NT5 client can't handle this error.
  672. //
  673. status = ERROR_ACCESS_DENIED;
  674. }
  675. }
  676. DbgLog1(SEV_INFO, "status = %d", status);
  677. ReplyCode = StatusToReplyCode(b1Opcode, status);
  678. if (_dialect == dialNt5)
  679. {
  680. DbgLog(SEV_INFO, "using NT5 dialect");
  681. }
  682. ExitOnFalse( Store_AddData1Byte(lpStore, ReplyCode) );
  683. ExitOnFalse( Store_AddData2Byte(lpStore, 0) ); // placeholder for length
  684. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_VERSION) );
  685. ExitOnFalse( Store_AddData1Byte(lpStore, CONNECT_FLAGS) );
  686. ExitOnFalse( Store_AddData2Byte(lpStore, CONNECT_MAXPKT) );
  687. if (status && _dialect == dialNt5)
  688. {
  689. ExitOnFalse( Store_AddData1Byte(lpStore, PRIVATE_PARAM_WIN32_ERROR) );
  690. ExitOnFalse( Store_AddData4Byte(lpStore, status) );
  691. }
  692. else if (_dialect == dialNt5)
  693. {
  694. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_WHO) );
  695. ExitOnFalse( Store_AddData2Byte(lpStore, sizeof(UUID)+3) );
  696. ExitOnFalse( Store_AddDataUuid(lpStore, &DIALECT_ID_NT5) );
  697. }
  698. ExitOnFalse( _PokePacketSizeIntoStore(lpStore) );
  699. if (status)
  700. {
  701. _Respond( lpStore );
  702. }
  703. else
  704. {
  705. status = _Respond( lpStore );
  706. }
  707. ExitOnErr( status );
  708. _SetState( &_dataRecv, osCONN );
  709. status = _ReceiveInProgress(rpcBinding, _DeviceName, &_cookie, FALSE);
  710. DbgLog3( status ? SEV_ERROR : SEV_INFO, "ReceiveInProgress [%S] returned %d, cookie %p", _DeviceName, status, (void *) _cookie );
  711. ExitOnErr( status );
  712. _fInUiReceiveList = TRUE;
  713. lExit:
  714. if( status )
  715. Xfer_ConnEnd();
  716. if (lpStore)
  717. {
  718. Store_Delete( &lpStore );
  719. }
  720. DbgLog2( SEV_FUNCTION, "_HandleConnect leave [%s] %d", SzBool(_dataRecv.state == osCONN), status );
  721. return ( _dataRecv.state == osCONN );
  722. }
  723. #if 1
  724. error_status_t
  725. FILE_TRANSFER::ObexStatusToWin32(
  726. BYTE1 ObexStatus
  727. )
  728. {
  729. switch (ObexStatus)
  730. {
  731. case OBEX_REPLY_SUCCESS:
  732. return 0;
  733. case OBEX_REPLY_CONTINUE:
  734. return ERROR_CONTINUE;
  735. case OBEX_REPLY_FAIL_FORBIDDEN:
  736. return ERROR_ACCESS_DENIED;
  737. case OBEX_REPLY_FAIL_TOOBIG:
  738. return ERROR_DISK_FULL;
  739. case OBEX_REPLY_FAIL_UNAVAILABLE:
  740. return ERROR_NOT_ENOUGH_MEMORY;
  741. case OBEX_REPLY_FAIL_BADREQUEST:
  742. default:
  743. DbgLog1(SEV_ERROR, "obex error 0x%x", ObexStatus);
  744. return ERROR_INVALID_DATA;
  745. }
  746. }
  747. #endif
  748. BYTE1
  749. FILE_TRANSFER::StatusToReplyCode(
  750. BYTE1 b1Opcode,
  751. DWORD status
  752. )
  753. {
  754. if (status)
  755. {
  756. DbgLog1(SEV_ERROR, "win32 error 0x%x", status);
  757. }
  758. switch (status)
  759. {
  760. case 0:
  761. if (b1Opcode == OBEX_OPCODE_PUT) {
  762. return OBEX_REPLY_CONTINUE;
  763. }
  764. return OBEX_REPLY_SUCCESS;
  765. case ERROR_NOT_LOGGED_ON:
  766. case ERROR_ACCESS_DENIED:
  767. case ERROR_CANCELLED:
  768. return OBEX_REPLY_FAIL_FORBIDDEN;
  769. case ERROR_DISK_FULL:
  770. return OBEX_REPLY_FAIL_TOOBIG;
  771. case ERROR_INVALID_DATA:
  772. return OBEX_REPLY_FAIL_BADREQUEST;
  773. case ERROR_NOT_ENOUGH_MEMORY:
  774. return OBEX_REPLY_FAIL_UNAVAILABLE;
  775. default:
  776. DbgLog(SEV_WARNING, "error not mapped");
  777. return OBEX_REPLY_FAIL_UNAVAILABLE;
  778. }
  779. }
  780. BOOL
  781. FILE_TRANSFER::SendReplyWin32(
  782. BYTE1 b1Opcode,
  783. DWORD status
  784. )
  785. {
  786. LPSTORE lpStore;
  787. if (status)
  788. {
  789. DbgLog1( SEV_WARNING, "sending Win32 error [%d]", status );
  790. }
  791. lpStore = Store_New( REPLY_PKTLEN+5 );
  792. ExitOnNull( lpStore );
  793. ExitOnFalse( Store_AddData1Byte(lpStore, StatusToReplyCode(b1Opcode, status)) );
  794. ExitOnFalse( Store_AddData2Byte(lpStore, REPLY_PKTLEN) );
  795. if (status && _dialect != dialWin95)
  796. {
  797. DbgLog(SEV_INFO, "(including WIN32_ERROR parameter)");
  798. ExitOnFalse( Store_AddData1Byte(lpStore, PRIVATE_PARAM_WIN32_ERROR) );
  799. ExitOnFalse( Store_AddData4Byte(lpStore, status) );
  800. }
  801. status = _Respond( lpStore );
  802. lExit:
  803. Store_Delete( &lpStore );
  804. if (status)
  805. {
  806. Xfer_ConnEnd();
  807. _SetState( &_dataRecv, osIDLE );
  808. DbgLog1( SEV_FUNCTION, "SendReplyWin32 failed [%d]", status);
  809. return FALSE;
  810. }
  811. return TRUE;
  812. }
  813. BOOL
  814. FILE_TRANSFER::SendReplyObex(
  815. BYTE1 ObexCode
  816. )
  817. {
  818. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  819. LPSTORE lpStore = NULL;
  820. if (ObexCode != OBEX_REPLY_SUCCESS)
  821. {
  822. DbgLog1( SEV_WARNING, "sending OBEX error [0x%x]", ObexCode );
  823. }
  824. lpStore = Store_New( REPLY_PKTLEN );
  825. ExitOnNull( lpStore );
  826. ExitOnFalse( Store_AddData1Byte(lpStore, ObexCode) );
  827. ExitOnFalse( Store_AddData2Byte(lpStore, REPLY_PKTLEN) );
  828. status = _Respond( lpStore );
  829. lExit:
  830. Store_Delete( &lpStore );
  831. if (status)
  832. {
  833. Xfer_ConnEnd();
  834. _SetState( &_dataRecv, osIDLE );
  835. DbgLog1( SEV_FUNCTION, "SendReplyObex failed [%d]", status);
  836. return FALSE;
  837. }
  838. return TRUE;
  839. }
  840. BOOL FILE_TRANSFER::_HandleDisconnect( BYTE1 b1Opcode, BYTE2 b2Length )
  841. {
  842. DbgLog( SEV_FUNCTION, "_HandleDisconnect" );
  843. SendReplyObex( OBEX_REPLY_SUCCESS );
  844. Xfer_ConnEnd();
  845. _SetState( &_dataRecv, osIDLE );
  846. HandleClosure( 0 );
  847. DbgLog( SEV_FUNCTION, "_HandleDisconnect leave [TRUE]" );
  848. return TRUE;
  849. }
  850. error_status_t
  851. FILE_TRANSFER::_HandlePut(
  852. BYTE1 b1Opcode,
  853. BYTE2 b2Length,
  854. BOOL fFinal
  855. )
  856. {
  857. error_status_t status = 0;
  858. DbgLog1( SEV_FUNCTION, "_HandlePut%s", fFinal ? " (final)" : "" );
  859. status = _ParseParams( b1Opcode, b2Length );
  860. // if final put packet, write 0-length data packet to ensure the
  861. // file is closed (for 0-length files).
  862. // don't watch the error code - if the file is already closed, it
  863. // would return FALSE.
  864. if( fFinal )
  865. {
  866. if (!status)
  867. {
  868. status = Xfer_FileWriteBody( NULL, 0, TRUE );
  869. }
  870. else
  871. {
  872. Xfer_FileWriteBody( NULL, 0, TRUE );
  873. }
  874. }
  875. if (!SendReplyWin32(b1Opcode, status))
  876. {
  877. DbgLog1(SEV_WARNING, "_HandlePut leave [%d]", status);
  878. return status;
  879. }
  880. _SetState( &_dataRecv, (fFinal ? osCONN : osFILE) );
  881. DbgLog1( SEV_FUNCTION, "_HandlePut leave [%d]", status );
  882. // return ( _dataRecv.state == osCONN );
  883. return status;
  884. }
  885. error_status_t
  886. FILE_TRANSFER::_HandleSetPath(
  887. BYTE1 b1Opcode,
  888. BYTE2 b2Length
  889. )
  890. {
  891. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  892. DbgLog( SEV_FUNCTION, "_HandleSetPath" );
  893. // get the flags and constants
  894. ExitOnFalse( Store_GetData1Byte(_dataRecv.lpStore, &_dataPath.b1Flags) );
  895. b2Length -= 1;
  896. ExitOnFalse( Store_GetData1Byte(_dataRecv.lpStore, &_dataPath.b1Constants) );
  897. b2Length -= 1;
  898. status = 0;
  899. // pop up a level
  900. if( _dataPath.b1Flags & SETPATH_UPALEVEL )
  901. {
  902. status = Xfer_SetPath( szPREVDIR );
  903. }
  904. if (!status)
  905. {
  906. status = _ParseParams( b1Opcode, b2Length );
  907. }
  908. SendReplyWin32(b1Opcode, status);
  909. lExit:
  910. DbgLog1( SEV_FUNCTION, "_HandleSetPath leave [%d]", status);
  911. return status;
  912. }
  913. BOOL
  914. FILE_TRANSFER::_HandleAbort(
  915. BYTE1 b1Opcode,
  916. BYTE2 b2Length )
  917. {
  918. BOOL fRet = FALSE;
  919. LPSTORE lpStore = NULL;
  920. DbgLog( SEV_FUNCTION, "_HandleAbort" );
  921. Xfer_FileAbort();
  922. if (!SendReplyWin32(b1Opcode, 0))
  923. {
  924. return FALSE;
  925. }
  926. _SetState( &_dataRecv, osCONN );
  927. DbgLog( SEV_FUNCTION, "_HandleAbort leave" );
  928. return TRUE;
  929. }
  930. VOID FILE_TRANSFER::_SetState( LPDATA_CONN lpDataConn, OBEXSTATE os )
  931. {
  932. lpDataConn->state = os;
  933. DbgLog2( SEV_INFO, "_SetState[%s], %s", (lpDataConn == &_dataRecv ? "SEND":"RECV"), _szState[os] );
  934. }
  935. error_status_t
  936. FILE_TRANSFER::_ParseParams(
  937. BYTE1 b1Opcode,
  938. BYTE2 b2Length
  939. )
  940. {
  941. error_status_t status = 0;
  942. BOOL fHaveName = FALSE;
  943. BYTE1 b1Param;
  944. BYTE2 b2ParamLen;
  945. LPVOID lpvData;
  946. PSZ EndOfData = PSZ(Store_GetDataPtr( _dataRecv.lpStore )) + b2Length;
  947. DbgLog1( SEV_FUNCTION, "_ParseParams [0x%x]", b1Opcode );
  948. // get the data out of the buffer
  949. while( PSZ(Store_GetDataPtr( _dataRecv.lpStore )) < EndOfData )
  950. {
  951. if ( !Store_GetData1Byte(_dataRecv.lpStore, &b1Param))
  952. {
  953. status = ERROR_INVALID_DATA;
  954. goto lExit;
  955. }
  956. #ifdef DBG
  957. Store_DumpParameter( _dataRecv.lpStore, b1Param );
  958. #endif
  959. switch( b1Param )
  960. {
  961. case OBEX_PARAM_NAME:
  962. {
  963. WCHAR wszName[MAX_PATH];
  964. if ( !Store_GetData2Byte(_dataRecv.lpStore, &b2ParamLen) )
  965. {
  966. status = ERROR_NOT_ENOUGH_MEMORY;
  967. goto lExit;
  968. }
  969. if (b2ParamLen >= MAX_PATH)
  970. {
  971. status = ERROR_INVALID_DATA;
  972. goto lExit;
  973. }
  974. if ( !Store_GetDataWsz(_dataRecv.lpStore, wszName, sizeof(wszName)) )
  975. {
  976. status = ERROR_INVALID_DATA;
  977. goto lExit;
  978. }
  979. if( CchWsz(wszName) > 0 )
  980. {
  981. fHaveName = TRUE;
  982. if( b1Opcode == OBEX_OPCODE_SETPATH )
  983. status = Xfer_SetPath( wszName );
  984. if( b1Opcode == OBEX_OPCODE_PUT || b1Opcode == OBEX_OPCODE_PUT_FINAL )
  985. status = Xfer_FileSetName( wszName );
  986. if (status)
  987. {
  988. goto lExit;
  989. }
  990. }
  991. }
  992. break;
  993. case OBEX_PARAM_LENGTH:
  994. {
  995. BYTE4 b4Size;
  996. if ( !Store_GetData4Byte(_dataRecv.lpStore, &b4Size) )
  997. {
  998. status = ERROR_INVALID_DATA;
  999. goto lExit;
  1000. }
  1001. if( b1Opcode == OBEX_OPCODE_CONNECT )
  1002. {
  1003. Xfer_SetSize( b4Size );
  1004. }
  1005. else if( b1Opcode == OBEX_OPCODE_PUT || b1Opcode == OBEX_OPCODE_PUT_FINAL )
  1006. {
  1007. if( !Xfer_FileSetSize(b4Size) )
  1008. {
  1009. DWORD dwEventStatus = 0;
  1010. EVENT_LOG EventLog(WS_EVENT_SOURCE,&dwEventStatus);
  1011. if (!dwEventStatus)
  1012. {
  1013. EventLog.ReportError(CAT_IRXFER, MC_IRXFER_DISK_FULL);
  1014. }
  1015. status = ERROR_DISK_FULL;
  1016. goto lExit;
  1017. }
  1018. }
  1019. break;
  1020. }
  1021. case OBEX_PARAM_UNIX_TIME:
  1022. {
  1023. DWORD UnixTime;
  1024. if ( !Store_GetData4Byte(_dataRecv.lpStore, &UnixTime) )
  1025. {
  1026. status = ERROR_INVALID_DATA;
  1027. goto lExit;
  1028. }
  1029. if( b1Opcode == OBEX_OPCODE_PUT || b1Opcode == OBEX_OPCODE_PUT_FINAL )
  1030. {
  1031. if (!UnixTimeToFileTime( UnixTime, &_dataFileRecv.filetime))
  1032. {
  1033. DbgLog1(SEV_ERROR, "UnixTimeToFileTime() failed on 0x%x", UnixTime);
  1034. status = ERROR_INVALID_DATA;
  1035. goto lExit;
  1036. }
  1037. }
  1038. break;
  1039. }
  1040. case OBEX_PARAM_ISO_TIME:
  1041. {
  1042. char IsoTimeA[1+ISO_TIME_LENGTH];
  1043. WCHAR IsoTimeW[1+ISO_TIME_LENGTH];
  1044. if ( !Store_GetData2Byte(_dataRecv.lpStore, &b2ParamLen) )
  1045. {
  1046. status = ERROR_INVALID_DATA;
  1047. goto lExit;
  1048. }
  1049. if (b2ParamLen > 3+(1+ISO_TIME_LENGTH)*sizeof(WCHAR))
  1050. {
  1051. DbgLog2(SEV_ERROR, "ISO time length is %d, string is '%S'", b2ParamLen, Store_GetDataPtr( _dataRecv.lpStore ));
  1052. status = ERROR_INVALID_DATA;
  1053. goto lExit;
  1054. }
  1055. ExitOnFalse( Store_GetDataWsz( _dataRecv.lpStore, IsoTimeW, sizeof(IsoTimeW)));
  1056. if( b1Opcode == OBEX_OPCODE_PUT || b1Opcode == OBEX_OPCODE_PUT_FINAL )
  1057. {
  1058. if (0 == WideCharToMultiByte(CP_ACP, 0L, IsoTimeW, -1, IsoTimeA, 1+ISO_TIME_LENGTH, NULL, NULL))
  1059. {
  1060. DbgLog2(SEV_ERROR, "WideCharToMultiByte failed %d on '%S'", GetLastError(), IsoTimeW);
  1061. status = ERROR_INVALID_DATA;
  1062. goto lExit;
  1063. }
  1064. if (0 != iso8601ToFileTime( IsoTimeA, &_dataFileRecv.filetime, TRUE, TRUE))
  1065. {
  1066. DbgLog1(SEV_ERROR, "iso8601ToFileTime() failed on '%s'", IsoTimeA);
  1067. status = ERROR_INVALID_DATA;
  1068. goto lExit;
  1069. }
  1070. }
  1071. break;
  1072. }
  1073. case OBEX_PARAM_BODY:
  1074. case OBEX_PARAM_BODY_END:
  1075. {
  1076. if ( !Store_GetData2Byte(_dataRecv.lpStore, &b2ParamLen) )
  1077. {
  1078. status = ERROR_INVALID_DATA;
  1079. goto lExit;
  1080. }
  1081. lpvData = Store_GetDataPtr( _dataRecv.lpStore );
  1082. if( b1Opcode == OBEX_OPCODE_PUT || b1Opcode == OBEX_OPCODE_PUT_FINAL )
  1083. {
  1084. status = Xfer_FileWriteBody(lpvData, b2ParamLen-3, FALSE);
  1085. if (status)
  1086. {
  1087. goto lExit;
  1088. }
  1089. }
  1090. Store_SkipData( _dataRecv.lpStore, b2ParamLen-3 ); // -3 for HI and HI len
  1091. break;
  1092. }
  1093. case OBEX_PARAM_WHO:
  1094. {
  1095. BYTE2 Left;
  1096. if ( !Store_GetData2Byte(_dataRecv.lpStore, &b2ParamLen) )
  1097. {
  1098. status = ERROR_INVALID_DATA;
  1099. goto lExit;
  1100. }
  1101. Left = b2ParamLen;
  1102. Left -= 3; // -3 for HI and HI len
  1103. while (Left >= sizeof(UUID))
  1104. {
  1105. UUID dialect;
  1106. if ( !Store_GetDataUuid(_dataRecv.lpStore, &dialect) )
  1107. {
  1108. status = ERROR_INVALID_DATA;
  1109. goto lExit;
  1110. }
  1111. Left -= sizeof(UUID);
  1112. if (0 == memcmp(&dialect, &DIALECT_ID_NT5, sizeof(UUID)))
  1113. {
  1114. _dialect = dialNt5;
  1115. break;
  1116. }
  1117. }
  1118. //
  1119. // Skip over uninterpreted parameter data.
  1120. //
  1121. Store_SkipData( _dataRecv.lpStore, Left );
  1122. break;
  1123. }
  1124. case PRIVATE_PARAM_WIN32_ERROR:
  1125. {
  1126. if ( !Store_GetData4Byte( _dataRecv.lpStore, &status ))
  1127. {
  1128. status = ERROR_INVALID_DATA;
  1129. goto lExit;
  1130. }
  1131. if (status)
  1132. {
  1133. goto lExit;
  1134. }
  1135. break;
  1136. }
  1137. default:
  1138. _SkipHeader( b1Param, _dataRecv.lpStore );
  1139. break;
  1140. }
  1141. }
  1142. if( b1Opcode == OBEX_OPCODE_SETPATH )
  1143. {
  1144. if( !(_dataPath.b1Flags & SETPATH_UPALEVEL) && !fHaveName )
  1145. {
  1146. // go back to receive folder root
  1147. status = Xfer_SetPath( NULL );
  1148. }
  1149. }
  1150. lExit:
  1151. DbgLog1( SEV_FUNCTION, "_ParseParams leave [%d]", status );
  1152. return status;
  1153. }
  1154. BYTE2 FILE_TRANSFER::_SkipHeader( BYTE1 b1Param, LPSTORE lpStore )
  1155. {
  1156. BYTE2 b2Ret = 0;
  1157. // if it's 1 or 4 byte value, read it in and ignore, otherwise
  1158. // read the length and skip ahead the appropriate number of bytes
  1159. // NOTE: Win95 and Win98 have a bug in this routine. Their test looks like
  1160. //
  1161. // if( b1Param & OBEX_PARAM_1BYTE )
  1162. // {
  1163. // treat as 1-byte;
  1164. // }
  1165. // else if( b1Param & OBEX_PARAM_4BYTE )
  1166. // {
  1167. // treat as 4-byte;
  1168. // }
  1169. // else
  1170. // {
  1171. // treat as 2-byte length-prefixed header;
  1172. // }
  1173. //
  1174. // which, if I read it correctly, treats 1- and 4-byte headers as 1-byte,
  1175. // byte-stream headers as 4-byte, and Unicode headers as Unicode.
  1176. if( (b1Param & OBEX_PARAM_TYPE_MASK) == OBEX_PARAM_1BYTE )
  1177. {
  1178. BYTE1 b1;
  1179. ExitOnFalse( Store_GetData1Byte(lpStore, &b1) );
  1180. b2Ret = 2;
  1181. }
  1182. else if( (b1Param & OBEX_PARAM_TYPE_MASK) == OBEX_PARAM_4BYTE )
  1183. {
  1184. BYTE4 b4;
  1185. ExitOnFalse( Store_GetData4Byte(lpStore, &b4) );
  1186. b2Ret = 5;
  1187. }
  1188. else
  1189. {
  1190. ExitOnFalse( Store_GetData2Byte(lpStore, &b2Ret) );
  1191. Store_SkipData( lpStore, b2Ret-3 ); // -3 for HI and HI len
  1192. }
  1193. lExit:
  1194. return b2Ret;
  1195. }
  1196. BOOL FILE_TRANSFER::_PokePacketSizeIntoStore( LPSTORE lpStore )
  1197. {
  1198. // NOTE: cast assumes store sizes to fit into 2 bytes
  1199. BYTE2 b2PktSize = (BYTE2)Store_GetDataUsed( lpStore );
  1200. // packet size is always the 2nd and 3rd bytes in the buffer
  1201. return Store_PokeData( lpStore, 1, &b2PktSize, sizeof(b2PktSize) );
  1202. }
  1203. error_status_t
  1204. FILE_TRANSFER::_Request(
  1205. LPSTORE lpStore,
  1206. BYTE1 b1NeededReply
  1207. )
  1208. {
  1209. error_status_t status = 0;
  1210. LPBYTE1 pb1Data = (LPBYTE1) Store_GetDataPtr(lpStore);
  1211. DWORD dwUsed = Store_GetDataUsed(lpStore);
  1212. DWORD dwOffset = 0;
  1213. DbgLog( SEV_FUNCTION, "_Request" );
  1214. status = Sock_Request( pb1Data + dwOffset, dwUsed - dwOffset );
  1215. ExitOnErr( status );
  1216. #if 0
  1217. status = _WaitForReply( REPLY_TIMEOUT, b1NeededReply );
  1218. if (status == ERROR_TIMEOUT)
  1219. {
  1220. status = 0;
  1221. }
  1222. ExitOnErr( status );
  1223. #endif
  1224. lExit:
  1225. DbgLog1( SEV_FUNCTION, "_Request leave [%d]", status );
  1226. return status;
  1227. }
  1228. error_status_t
  1229. FILE_TRANSFER::_Respond(
  1230. LPSTORE lpStore
  1231. )
  1232. {
  1233. error_status_t status = 0;
  1234. LPBYTE1 pb1Data = (LPBYTE1) Store_GetDataPtr(lpStore);
  1235. DWORD dwUsed = Store_GetDataUsed(lpStore);
  1236. DWORD dwOffset = 0;
  1237. DbgLog( SEV_FUNCTION, "_Respond" );
  1238. status = Sock_Respond( pb1Data + dwOffset, dwUsed - dwOffset );
  1239. ExitOnErr( status );
  1240. lExit:
  1241. DbgLog1( SEV_FUNCTION, "_Respond leave [%d]", status );
  1242. return status;
  1243. }
  1244. error_status_t
  1245. FILE_TRANSFER::Obex_PutBegin(
  1246. LPWSTR wszObj,
  1247. __int64 dwObjSize,
  1248. FILETIME * pFileTime
  1249. )
  1250. {
  1251. _blocksSent = 0;
  1252. _blocksAcked = 0;
  1253. _lastAckTime = GetTickCount();
  1254. return _Put( wszObj, dwObjSize, pFileTime, NULL, 0, dwObjSize == 0 );
  1255. }
  1256. error_status_t
  1257. FILE_TRANSFER::Obex_PutBody(
  1258. wchar_t FileName[],
  1259. LPBYTE1 pb1Data,
  1260. BYTE2 b2DataSize,
  1261. BOOL fFinal
  1262. )
  1263. {
  1264. error_status_t status = 0;
  1265. BYTE2 b2Sent = 0;
  1266. BYTE2 b2MaxBodySize = _dataRecv.b2MaxPacket - 16; // 16 = 3 (opcode+pktlen) + 3 (param+len param) + 10 (for good measure)
  1267. // send in packets no larger than what the receiving side requested
  1268. while( b2Sent < b2DataSize )
  1269. {
  1270. BYTE2 b2SendSize = min( b2DataSize - b2Sent, b2MaxBodySize );
  1271. BOOL fLastPacket = fFinal && (b2Sent + b2SendSize == b2DataSize);
  1272. DbgLog4(SEV_INFO, " b2DataSize %d, b2Sent %d, b2MaxBodySize %d, b2MaxPacket %d",
  1273. _dataRecv.b2MaxPacket, b2DataSize, b2Sent, b2MaxBodySize );
  1274. if( _fCancelled )
  1275. {
  1276. Obex_Abort(ERROR_CANCELLED);
  1277. return ERROR_CANCELLED;
  1278. }
  1279. status = _Put( NULL, 0, 0, pb1Data + b2Sent, b2SendSize, fLastPacket );
  1280. if( status )
  1281. break;
  1282. status = 0;
  1283. b2Sent += b2SendSize;
  1284. }
  1285. return status;
  1286. }
  1287. error_status_t
  1288. FILE_TRANSFER::Obex_SetPath(
  1289. LPWSTR wszPath
  1290. )
  1291. {
  1292. error_status_t status = ERROR_NOT_ENOUGH_MEMORY;
  1293. BOOL fUpALevel = ( !wszPath || CchWsz(wszPath) == 0 );
  1294. BYTE1 b1Flags = SETPATH_FLAGS;
  1295. WCHAR wsz[MAX_PATH];
  1296. LPSTORE lpStore = Store_New( MAX_PATH+10 );
  1297. DbgLog1( SEV_FUNCTION, "Obex_SetPath '%S'", wszPath );
  1298. if( !fUpALevel ) {
  1299. WCHAR TempPath[MAX_PATH];
  1300. StringCbCopy(TempPath, sizeof(TempPath), wszPath);
  1301. //
  1302. // strip off all but the last directory
  1303. //
  1304. if ( TempPath[CchWsz(TempPath)-1] == cBACKSLASH ) {
  1305. TempPath[CchWsz(TempPath)-1] = (WCHAR)cNIL;
  1306. }
  1307. StripPath( TempPath, wsz, sizeof(wsz)/sizeof(WCHAR) );
  1308. }
  1309. if ( _dataRecv.state != osCONN )
  1310. {
  1311. status = ERROR_NOT_CONNECTED;
  1312. goto lExit;
  1313. }
  1314. ExitOnNull( lpStore );
  1315. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_OPCODE_SETPATH) );
  1316. // add buffer space for the packet length
  1317. ExitOnFalse( Store_AddData2Byte(lpStore, 0) );
  1318. if( fUpALevel )
  1319. b1Flags |= SETPATH_UPALEVEL;
  1320. ExitOnFalse( Store_AddData1Byte(lpStore, b1Flags) );
  1321. ExitOnFalse( Store_AddData1Byte(lpStore, SETPATH_CONSTANTS) );
  1322. if( !fUpALevel )
  1323. {
  1324. ExitOnFalse( Store_AddData1Byte(lpStore, OBEX_PARAM_NAME) );
  1325. ExitOnFalse( Store_AddData2Byte(lpStore, 3+CbWsz(wsz)) );
  1326. ExitOnFalse( Store_AddDataWsz(lpStore, wsz) );
  1327. }
  1328. ExitOnFalse( _PokePacketSizeIntoStore(lpStore) );
  1329. status = _Request( lpStore, OBEX_REPLY_SUCCESS );
  1330. ExitOnErr( status );
  1331. status = _WaitForReply( SETPATH_TIMEOUT, OBEX_REPLY_SUCCESS );
  1332. ExitOnErr( status );
  1333. status = 0;
  1334. lExit:
  1335. Store_Delete( &lpStore );
  1336. DbgLog1( SEV_FUNCTION, "Obex_SetPath leave [%d]", status );
  1337. return status;
  1338. }
  1339. BOOL FILE_TRANSFER::_HandleNotImplemented( BYTE1 b1Opcode )
  1340. {
  1341. return SendReplyObex( OBEX_REPLY_FAIL_NOTIMP );
  1342. }
  1343. BOOL FILE_TRANSFER::_HandleBadRequest( BYTE1 b1Opcode )
  1344. {
  1345. return SendReplyObex( OBEX_REPLY_FAIL_BADREQUEST );
  1346. }