michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_dom_bluetooth_bluetoothoppmanager_h__ michael@0: #define mozilla_dom_bluetooth_bluetoothoppmanager_h__ michael@0: michael@0: #include "BluetoothCommon.h" michael@0: #include "BluetoothProfileManagerBase.h" michael@0: #include "BluetoothSocketObserver.h" michael@0: #include "DeviceStorage.h" michael@0: #include "mozilla/dom/ipc/Blob.h" michael@0: #include "mozilla/ipc/UnixSocket.h" michael@0: #include "nsCOMArray.h" michael@0: michael@0: class nsIOutputStream; michael@0: class nsIInputStream; michael@0: class nsIVolumeMountLock; michael@0: michael@0: BEGIN_BLUETOOTH_NAMESPACE michael@0: michael@0: class BluetoothSocket; michael@0: class ObexHeaderSet; michael@0: class SendFileBatch; michael@0: michael@0: class BluetoothOppManager : public BluetoothSocketObserver michael@0: , public BluetoothProfileManagerBase michael@0: { michael@0: public: michael@0: BT_DECL_PROFILE_MGR_BASE michael@0: virtual void GetName(nsACString& aName) michael@0: { michael@0: aName.AssignLiteral("OPP"); michael@0: } michael@0: michael@0: static const int MAX_PACKET_LENGTH = 0xFFFE; michael@0: michael@0: virtual ~BluetoothOppManager(); michael@0: static BluetoothOppManager* Get(); michael@0: void ClientDataHandler(mozilla::ipc::UnixSocketRawData* aMessage); michael@0: void ServerDataHandler(mozilla::ipc::UnixSocketRawData* aMessage); michael@0: michael@0: bool Listen(); michael@0: michael@0: bool SendFile(const nsAString& aDeviceAddress, BlobParent* aActor); michael@0: bool SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob); michael@0: bool StopSendingFile(); michael@0: bool ConfirmReceivingFile(bool aConfirm); michael@0: michael@0: void SendConnectRequest(); michael@0: void SendPutHeaderRequest(const nsAString& aFileName, int aFileSize); michael@0: void SendPutRequest(uint8_t* aFileBody, int aFileBodyLength); michael@0: void SendPutFinalRequest(); michael@0: void SendDisconnectRequest(); michael@0: michael@0: void ExtractPacketHeaders(const ObexHeaderSet& aHeader); michael@0: bool ExtractBlobHeaders(); michael@0: void CheckPutFinal(uint32_t aNumRead); michael@0: michael@0: // The following functions are inherited from BluetoothSocketObserver michael@0: void ReceiveSocketData( michael@0: BluetoothSocket* aSocket, michael@0: nsAutoPtr& aMessage) MOZ_OVERRIDE; michael@0: virtual void OnSocketConnectSuccess(BluetoothSocket* aSocket) MOZ_OVERRIDE; michael@0: virtual void OnSocketConnectError(BluetoothSocket* aSocket) MOZ_OVERRIDE; michael@0: virtual void OnSocketDisconnect(BluetoothSocket* aSocket) MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: BluetoothOppManager(); michael@0: bool Init(); michael@0: void HandleShutdown(); michael@0: michael@0: void StartFileTransfer(); michael@0: void StartSendingNextFile(); michael@0: void FileTransferComplete(); michael@0: void UpdateProgress(); michael@0: void ReceivingFileConfirmation(); michael@0: bool CreateFile(); michael@0: bool WriteToFile(const uint8_t* aData, int aDataLength); michael@0: void DeleteReceivedFile(); michael@0: void ReplyToConnect(); michael@0: void ReplyToDisconnectOrAbort(); michael@0: void ReplyToPut(bool aFinal, bool aContinue); michael@0: void ReplyError(uint8_t aError); michael@0: void AfterOppConnected(); michael@0: void AfterFirstPut(); michael@0: void AfterOppDisconnected(); michael@0: void ValidateFileName(); michael@0: bool IsReservedChar(char16_t c); michael@0: void ClearQueue(); michael@0: void RetrieveSentFileName(); michael@0: void NotifyAboutFileChange(); michael@0: bool AcquireSdcardMountLock(); michael@0: void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize); michael@0: void AppendBlobToSend(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob); michael@0: void DiscardBlobsToSend(); michael@0: bool ProcessNextBatch(); michael@0: void ConnectInternal(const nsAString& aDeviceAddress); michael@0: michael@0: /** michael@0: * Usually we won't get a full PUT packet in one operation, which means that michael@0: * a packet may be devided into several parts and BluetoothOppManager should michael@0: * be in charge of assembling. michael@0: * michael@0: * @return true if a packet has been fully received. michael@0: * false if the received length exceeds/not reaches the expected michael@0: * length. michael@0: */ michael@0: bool ComposePacket(uint8_t aOpCode, michael@0: mozilla::ipc::UnixSocketRawData* aMessage); michael@0: michael@0: /** michael@0: * OBEX session status. michael@0: * Set when OBEX session is established. michael@0: */ michael@0: bool mConnected; michael@0: nsString mConnectedDeviceAddress; michael@0: michael@0: /** michael@0: * Remote information michael@0: */ michael@0: uint8_t mRemoteObexVersion; michael@0: uint8_t mRemoteConnectionFlags; michael@0: int mRemoteMaxPacketLength; michael@0: michael@0: /** michael@0: * For sending files, we decide our next action based on current command and michael@0: * previous one. michael@0: * For receiving files, we don't need previous command and it is set to 0 michael@0: * as a default value. michael@0: */ michael@0: int mLastCommand; michael@0: michael@0: int mPacketLength; michael@0: int mPutPacketReceivedLength; michael@0: int mBodySegmentLength; michael@0: int mUpdateProgressCounter; michael@0: michael@0: /** michael@0: * When it is true and the target service on target device couldn't be found, michael@0: * refreshing SDP records is necessary. michael@0: */ michael@0: bool mNeedsUpdatingSdpRecords; michael@0: michael@0: /** michael@0: * Set when StopSendingFile() is called. michael@0: */ michael@0: bool mAbortFlag; michael@0: michael@0: /** michael@0: * Set when receiving the first PUT packet of a new file michael@0: */ michael@0: bool mNewFileFlag; michael@0: michael@0: /** michael@0: * Set when receiving a PutFinal packet michael@0: */ michael@0: bool mPutFinalFlag; michael@0: michael@0: /** michael@0: * Set when FileTransferComplete() is called michael@0: */ michael@0: bool mSendTransferCompleteFlag; michael@0: michael@0: /** michael@0: * Set when a transfer is successfully completed. michael@0: */ michael@0: bool mSuccessFlag; michael@0: michael@0: /** michael@0: * True: Receive file (Server) michael@0: * False: Send file (Client) michael@0: */ michael@0: bool mIsServer; michael@0: michael@0: /** michael@0: * Set when receiving the first PUT packet and wait for michael@0: * ConfirmReceivingFile() to be called. michael@0: */ michael@0: bool mWaitingForConfirmationFlag; michael@0: michael@0: nsString mFileName; michael@0: nsString mContentType; michael@0: uint32_t mFileLength; michael@0: uint32_t mSentFileLength; michael@0: bool mWaitingToSendPutFinal; michael@0: michael@0: nsAutoArrayPtr mBodySegment; michael@0: nsAutoArrayPtr mReceivedDataBuffer; michael@0: michael@0: int mCurrentBlobIndex; michael@0: nsCOMPtr mBlob; michael@0: nsTArray mBatches; michael@0: michael@0: /** michael@0: * A seperate member thread is required because our read calls can block michael@0: * execution, which is not allowed to happen on the IOThread. michael@0: */ michael@0: nsCOMPtr mReadFileThread; michael@0: nsCOMPtr mOutputStream; michael@0: nsCOMPtr mInputStream; michael@0: nsCOMPtr mMountLock; michael@0: nsRefPtr mDsFile; michael@0: michael@0: // If a connection has been established, mSocket will be the socket michael@0: // communicating with the remote socket. We maintain the invariant that if michael@0: // mSocket is non-null, mRfcommSocket and mL2capSocket must be null (and vice michael@0: // versa). michael@0: nsRefPtr mSocket; michael@0: michael@0: // Server sockets. Once an inbound connection is established, it will hand michael@0: // over the ownership to mSocket, and get a new server socket while Listen() michael@0: // is called. michael@0: nsRefPtr mRfcommSocket; michael@0: nsRefPtr mL2capSocket; michael@0: }; michael@0: michael@0: END_BLUETOOTH_NAMESPACE michael@0: michael@0: #endif