Source code of Windows XP (NT5)
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.

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