diff options
Diffstat (limited to 'SDL_Core/src/components/TransportManager/src')
21 files changed, 5716 insertions, 0 deletions
diff --git a/SDL_Core/src/components/TransportManager/src/CBluetoothAdapter.cpp b/SDL_Core/src/components/TransportManager/src/CBluetoothAdapter.cpp new file mode 100644 index 000000000..c914fee94 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CBluetoothAdapter.cpp @@ -0,0 +1,573 @@ +/** + * \file CBluetoothAdapter.cpp + * \brief Class CBluetoothAdapter. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <errno.h> +#include <iomanip> +#include <set> +#include <unistd.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> +#include <bluetooth/rfcomm.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "IDeviceAdapterListener.hpp" +#include "IHandleGenerator.hpp" +#include "CBluetoothAdapter.hpp" + +NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::SBluetoothDevice::SBluetoothDevice(const bdaddr_t & Address, const char * Name, const NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::tRFCOMMChannelVector & SmartDeviceLinkRFCOMMChannels): +SDevice(Name), +mAddress(Address), +mSmartDeviceLinkRFCOMMChannels(SmartDeviceLinkRFCOMMChannels) +{ + mUniqueDeviceId = getUniqueDeviceId(Address); +} + +bool NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::SBluetoothDevice::isSameAs(const NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SDevice * OtherDevice) const +{ + bool result = false; + + if (true == SDevice::isSameAs(OtherDevice)) + { + const SBluetoothDevice * otherBluetoothDevice = dynamic_cast<const SBluetoothDevice *>(OtherDevice); + + if (0 != otherBluetoothDevice) + { + result = (0 == memcmp(&mAddress, &otherBluetoothDevice->mAddress, sizeof(bdaddr_t))); + } + } + + return result; +} + +NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::SRFCOMMConnection::SRFCOMMConnection(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle, const uint8_t RFCOMMChannel): +SConnection(DeviceHandle), +mRFCOMMChannel(RFCOMMChannel) +{ +} + +bool NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::SRFCOMMConnection::isSameAs(const NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection * OtherConnection) const +{ + bool result = false; + + if (true == SConnection::isSameAs(OtherConnection)) + { + const SRFCOMMConnection * otherRFCOMMConnection = dynamic_cast<const SRFCOMMConnection *>(OtherConnection); + + if (0 != otherRFCOMMConnection) + { + result = (mRFCOMMChannel == otherRFCOMMConnection->mRFCOMMChannel); + } + } + + return result; +} + +NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::CBluetoothAdapter(NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener & Listener, IHandleGenerator & HandleGenerator): +CDeviceAdapter(Listener, HandleGenerator), +mSmartDeviceLinkServiceUUID() +{ + LOG4CPLUS_INFO(mLogger, "BluetoothAdapter constructed"); + + uint8_t SmartDeviceLinkServiceUUIDData[] = {0x93, 0x6D, 0xA0, 0x1F, 0x9A, 0xBD, 0x4D, 0x9D, 0x80, 0xC7, 0x02, 0xAF, 0x85, 0xC8, 0x22, 0xA8}; + sdp_uuid128_create(&mSmartDeviceLinkServiceUUID, SmartDeviceLinkServiceUUIDData); +} + +NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::~CBluetoothAdapter(void) +{ + LOG4CPLUS_INFO(mLogger, "BluetoothAdapter destructor"); + + waitForThreadsTermination(); +} + +NsSmartDeviceLink::NsTransportManager::EDeviceType NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::getDeviceType(void) const +{ + return DeviceBluetooth; +} + +void NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::createConnectionsListForDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle, std::vector< NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection* >& ConnectionsList) +{ + bdaddr_t deviceAddress; + tRFCOMMChannelVector rfcommChannels; + bool isDeviceValid = false; + + ConnectionsList.clear(); + + pthread_mutex_lock(&mDevicesMutex); + + tDeviceMap::iterator deviceIterator = mDevices.find(DeviceHandle); + + if (mDevices.end() != deviceIterator) + { + SBluetoothDevice * device = dynamic_cast<SBluetoothDevice*>(deviceIterator->second); + + if (0 != device) + { + memcpy(&deviceAddress, &device->mAddress, sizeof(bdaddr_t)); + rfcommChannels = device->mSmartDeviceLinkRFCOMMChannels; + isDeviceValid = true; + } + else + { + LOG4CPLUS_WARN(mLogger, "Device " << DeviceHandle << " is invalid"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device handle " << DeviceHandle << " is invalid"); + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (true == isDeviceValid) + { + if (false == rfcommChannels.empty()) + { + pthread_mutex_lock(&mConnectionsMutex); + + for (tConnectionMap::const_iterator connectionIterator = mConnections.begin(); connectionIterator != mConnections.end(); ++connectionIterator) + { + const SRFCOMMConnection * connection = dynamic_cast<SRFCOMMConnection*>(connectionIterator->second); + + if (0 != connection) + { + rfcommChannels.erase(std::remove_if(rfcommChannels.begin(), + rfcommChannels.end(), + [&DeviceHandle, &connection] (const uint8_t & Channel) + { + return (connection->mDeviceHandle == DeviceHandle) && + (connection->mRFCOMMChannel == Channel); + } + ), + rfcommChannels.end()); + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + + for (tRFCOMMChannelVector::const_iterator channelIterator = rfcommChannels.begin(); channelIterator != rfcommChannels.end(); ++channelIterator) + { + ConnectionsList.push_back(new SRFCOMMConnection(DeviceHandle, *channelIterator)); + } + } + else + { + LOG4CPLUS_WARN(mLogger, "SmartDeviceLink service was not discovered on device " << DeviceHandle); + } + } +} + +void NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::mainThread(void) +{ + LOG4CPLUS_INFO(mLogger, "Bluetooth adapter main thread initialized"); + + const size_t maxDevices = 256u; + inquiry_info * inquiryInfoList = new inquiry_info[maxDevices]; + + while (false == mShutdownFlag) + { + tDeviceMap newDevices; + tDeviceVector discoveredDevices; + + bool deviceScanRequested = waitForDeviceScanRequest(0); + + if (true == deviceScanRequested) + { + int deviceID = hci_get_route(0); + + if (deviceID >= 0) + { + int deviceHandle = hci_open_dev(deviceID); + + if (deviceHandle >= 0) + { + const uint8_t inquiryTime = 8u; // Time unit is 1.28 seconds + + LOG4CPLUS_INFO(mLogger, "Starting hci_inquiry on device " << deviceID); + + int numberOfDevices = hci_inquiry(deviceID, inquiryTime, maxDevices, 0, &inquiryInfoList, IREQ_CACHE_FLUSH); + + if (numberOfDevices >= 0) + { + LOG4CPLUS_INFO(mLogger, "hci_inquiry: found " << numberOfDevices << " devices"); + + for (int i = 0; i < numberOfDevices; ++i) + { + tRFCOMMChannelVector SmartDeviceLinkRFCOMMChannels; + discoverSmartDeviceLinkRFCOMMChannels(inquiryInfoList[i].bdaddr, SmartDeviceLinkRFCOMMChannels); + + if (false == SmartDeviceLinkRFCOMMChannels.empty()) + { + char deviceName[256]; + + if (0 != hci_read_remote_name(deviceHandle, &inquiryInfoList[i].bdaddr, sizeof(deviceName) / sizeof(deviceName[0]), deviceName, 0)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "hci_read_remote_name failed"); + strncpy(deviceName, getUniqueDeviceId(inquiryInfoList[i].bdaddr).c_str(), sizeof(deviceName) / sizeof(deviceName[0])); + } + + discoveredDevices.push_back(new SBluetoothDevice(inquiryInfoList[i].bdaddr, deviceName, SmartDeviceLinkRFCOMMChannels)); + } + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "hci_inquiry failed"); + } + + close(deviceHandle); + } + } + + for (tDeviceVector::iterator discoveredDeviceIterator = discoveredDevices.begin(); discoveredDeviceIterator != discoveredDevices.end(); ++discoveredDeviceIterator) + { + SDevice * discoveredDevice = *discoveredDeviceIterator; + + if (0 != discoveredDevice) + { + tDeviceHandle deviceHandle = InvalidDeviceHandle; + + pthread_mutex_lock(&mDevicesMutex); + + for (tDeviceMap::iterator deviceIterator = mDevices.begin(); deviceIterator != mDevices.end(); ++deviceIterator) + { + SDevice * exisingDevice = deviceIterator->second; + + if (true == discoveredDevice->isSameAs(exisingDevice)) + { + deviceHandle = deviceIterator->first; + break; + } + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (InvalidDeviceHandle == deviceHandle) + { + deviceHandle = mHandleGenerator.generateNewDeviceHandle(); + + LOG4CPLUS_INFO(mLogger, "Adding new device " << deviceHandle << " (\"" << discoveredDevice->mName << "\")"); + } + + newDevices[deviceHandle] = discoveredDevice; + } + } + + pthread_mutex_lock(&mConnectionsMutex); + + std::set<tDeviceHandle> connectedDevices; + + for (tConnectionMap::const_iterator connectionIterator = mConnections.begin(); connectionIterator != mConnections.end(); ++connectionIterator) + { + const SConnection * connection = connectionIterator->second; + + if (0 != connection) + { + if (connectedDevices.end() == connectedDevices.find(connection->mDeviceHandle)) + { + connectedDevices.insert(connection->mDeviceHandle); + } + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + + pthread_mutex_lock(&mDevicesMutex); + + for (tDeviceMap::iterator deviceIterator = mDevices.begin(); deviceIterator != mDevices.end(); ++deviceIterator) + { + SDevice * device = deviceIterator->second; + + if (0 != device) + { + if (newDevices.end() == newDevices.find(deviceIterator->first)) + { + if (connectedDevices.end() != connectedDevices.find(deviceIterator->first)) + { + newDevices[deviceIterator->first] = device; + device = 0; + } + } + + if (0 != device) + { + delete device; + } + } + } + + mDevices = newDevices; + + pthread_mutex_unlock(&mDevicesMutex); + + LOG4CPLUS_INFO(mLogger, "Discovered " << newDevices.size() << " device" << ((1u == newDevices.size()) ? "" : "s") << " with SmartDeviceLink service. New devices map:"); + + for (tDeviceMap::iterator deviceIterator = newDevices.begin(); deviceIterator != newDevices.end(); ++deviceIterator) + { + SDevice * device = deviceIterator->second; + + if (0 != device) + { + LOG4CPLUS_INFO(mLogger, std::setw(10) << deviceIterator->first << std::setw(0) << ": " << device->mUniqueDeviceId << ", " << device->mName.c_str()); + } + else + { + LOG4CPLUS_ERROR(mLogger, std::setw(10) << deviceIterator->first << std::setw(0) << ": Device is null"); + } + } + + mDeviceScanRequested = false; + + updateClientDeviceList(); + } + } + + delete [] inquiryInfoList; + + LOG4CPLUS_INFO(mLogger, "Bluetooth adapter main thread finished"); +} + +void NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::connectionThread(const NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle) +{ + LOG4CPLUS_INFO(mLogger, "Connection thread started for connection " << ConnectionHandle); + + tDeviceHandle deviceHandle = InvalidDeviceHandle; + struct sockaddr_rc remoteSocketAddress = {0}; + remoteSocketAddress.rc_family = AF_BLUETOOTH; + + pthread_mutex_lock(&mConnectionsMutex); + + SRFCOMMConnection * connection = 0; + tConnectionMap::const_iterator connectionIterator = mConnections.find(ConnectionHandle); + + if (connectionIterator != mConnections.end()) + { + connection = dynamic_cast<SRFCOMMConnection*>(connectionIterator->second); + + if (0 != connection) + { + deviceHandle = connection->mDeviceHandle; + remoteSocketAddress.rc_channel = connection->mRFCOMMChannel; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " is not valid"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " does not exist"); + } + + pthread_mutex_unlock(&mConnectionsMutex); + + if (0 != connection) + { + if (InvalidDeviceHandle != deviceHandle) + { + bool isDeviceValid = false; + + pthread_mutex_lock(&mDevicesMutex); + + tDeviceMap::const_iterator deviceIterator = mDevices.find(deviceHandle); + + if (deviceIterator != mDevices.end()) + { + const SBluetoothDevice * device = dynamic_cast<const SBluetoothDevice*>(deviceIterator->second); + + if (0 != device) + { + isDeviceValid = true; + memcpy(&remoteSocketAddress.rc_bdaddr, &device->mAddress, sizeof(bdaddr_t)); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device " << deviceHandle << " is not valid"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device " << deviceHandle << " does not exist"); + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (true == isDeviceValid) + { + int rfcommSocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + + if (-1 != rfcommSocket) + { + if (0 == connect(rfcommSocket, (struct sockaddr *)&remoteSocketAddress, sizeof(remoteSocketAddress))) + { + connection->mConnectionSocket = rfcommSocket; + handleCommunication(ConnectionHandle); + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to connect to remote device " << getUniqueDeviceId(remoteSocketAddress.rc_bdaddr) << " for connection " << ConnectionHandle); + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to create RFCOMM socket for connection " << ConnectionHandle); + } + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device handle for connection " << ConnectionHandle << " is invalid"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " is null"); + } + + LOG4CPLUS_INFO(mLogger, "Removing connection " << ConnectionHandle << " from connection map"); + + pthread_mutex_lock(&mConnectionsMutex); + mConnections.erase(ConnectionHandle); + pthread_mutex_unlock(&mConnectionsMutex); + + delete connection; + + LOG4CPLUS_INFO(mLogger, "Connection thread finished for connection " << ConnectionHandle); +} + +std::string NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::getUniqueDeviceId(const bdaddr_t & DeviceAddress) +{ + char deviceAddressString[32]; + + ba2str(&DeviceAddress, deviceAddressString); + + return std::string("BT-") + deviceAddressString; +} + +void NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::discoverSmartDeviceLinkRFCOMMChannels(const bdaddr_t & DeviceAddress, NsSmartDeviceLink::NsTransportManager::CBluetoothAdapter::tRFCOMMChannelVector & SmartDeviceLinkRFCOMMChannels) +{ + SmartDeviceLinkRFCOMMChannels.clear(); + + static bdaddr_t anyAddress = {{0, 0, 0, 0, 0, 0}}; + + sdp_session_t * sdpSession = sdp_connect(&anyAddress, &DeviceAddress, SDP_RETRY_IF_BUSY); + + if (0 != sdpSession) + { + sdp_list_t * searchList = sdp_list_append(0, &mSmartDeviceLinkServiceUUID); + uint32_t range = 0x0000ffff; + sdp_list_t * attrList = sdp_list_append(0, &range); + sdp_list_t * responseList = 0; + + if (0 == sdp_service_search_attr_req(sdpSession, searchList, SDP_ATTR_REQ_RANGE, attrList, &responseList)) + { + for (sdp_list_t * r = responseList; 0 != r; r = r->next) + { + sdp_record_t * sdpRecord = static_cast<sdp_record_t*>(r->data); + sdp_list_t * protoList = 0; + + if (0 == sdp_get_access_protos(sdpRecord, &protoList)) + { + for (sdp_list_t * p = protoList; 0 != p; p = p->next) + { + sdp_list_t * pdsList = static_cast<sdp_list_t*>(p->data); + + for (sdp_list_t * pds = pdsList; 0 != pds; pds = pds->next) + { + sdp_data_t * sdpData = static_cast<sdp_data_t*>(pds->data); + int proto = 0; + + for (sdp_data_t * d = sdpData; 0 != d; d = d->next) + { + switch (d->dtd) + { + case SDP_UUID16: + case SDP_UUID32: + case SDP_UUID128: + proto = sdp_uuid_to_proto(&d->val.uuid); + break; + + case SDP_UINT8: + if (RFCOMM_UUID == proto) + { + SmartDeviceLinkRFCOMMChannels.push_back(d->val.uint8); + } + break; + } + } + } + + sdp_list_free(pdsList, 0); + } + + sdp_list_free(protoList, 0); + } + } + } + + sdp_list_free(searchList, 0); + sdp_list_free(attrList, 0); + sdp_list_free(responseList, 0); + sdp_close(sdpSession); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Service discovery failed for " << getUniqueDeviceId(DeviceAddress)); + } + + if (false == SmartDeviceLinkRFCOMMChannels.empty()) + { + std::stringstream rfcommChannelsString; + + for (tRFCOMMChannelVector::const_iterator channelIterator = SmartDeviceLinkRFCOMMChannels.begin(); channelIterator != SmartDeviceLinkRFCOMMChannels.end(); ++channelIterator) + { + if (channelIterator != SmartDeviceLinkRFCOMMChannels.begin()) + { + rfcommChannelsString << ", "; + } + + rfcommChannelsString << static_cast<uint32_t>(*channelIterator); + } + + LOG4CPLUS_INFO(mLogger, "SmartDeviceLink service was discovered on device " << getUniqueDeviceId(DeviceAddress) << " at channel(s): " << rfcommChannelsString.str().c_str()); + } + else + { + LOG4CPLUS_INFO(mLogger, "SmartDeviceLink service was not discovered on device " << getUniqueDeviceId(DeviceAddress)); + } +} diff --git a/SDL_Core/src/components/TransportManager/src/CBluetoothAdapter.hpp b/SDL_Core/src/components/TransportManager/src/CBluetoothAdapter.hpp new file mode 100644 index 000000000..43f0b96ef --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CBluetoothAdapter.hpp @@ -0,0 +1,225 @@ +/** + * \file CBluetoothAdapter.hpp + * \brief Class CBluetoothAdapter header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_CBLUETOOTHADAPTER_HPP__ +#define __TRANSPORTMANAGER_CBLUETOOTHADAPTER_HPP__ + +#include <bluetooth/bluetooth.h> +#include <bluetooth/sdp.h> +#include <time.h> + +#include "Logger.hpp" + +#include "TransportManager/SDeviceInfo.hpp" + +#include "CDeviceAdapter.hpp" + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + /** + * @brief Bluetooth device adapter. + * + * @see @ref components_transportmanager_internal_design_device_adapters_bluetooth_adapter + **/ + class CBluetoothAdapter: public CDeviceAdapter + { + public: + /** + * @brief Constructor. + * + * @param Listener Listener for device adapter notifications. + * @param HandleGenerator Handle generator implementation. + **/ + CBluetoothAdapter(IDeviceAdapterListener & Listener, IHandleGenerator & HandleGenerator); + + /** + * @brief Destructor. + **/ + virtual ~CBluetoothAdapter(void); + + /** + * @brief Get type of devices handled by this device adapter. + * + * @return Device type. + **/ + virtual EDeviceType getDeviceType(void) const; + + private: + /** + * @brief Vector of RFCOMM channels. + **/ + typedef std::vector<uint8_t> tRFCOMMChannelVector; + + /** + * @brief Internal structure describing bluetooth device. + **/ + struct SBluetoothDevice: public SDevice + { + /** + * @brief Constructor. + * + * @param Address Bluetooth address. + * @param Name User-friendly device name. + * @param SmartDeviceLinkRFCOMMChannels List of RFCOMM channels where SmartDeviceLink service has been discovered. + **/ + SBluetoothDevice(const bdaddr_t & Address, const char * Name, const tRFCOMMChannelVector & SmartDeviceLinkRFCOMMChannels); + + /** + * @brief Compare devices. + * + * This method checks whether two SBluetoothDevice structures + * refer to the same device. + * + * @param OtherDevice Device to compare with. + * + * @return true if devices are equal, false otherwise. + **/ + virtual bool isSameAs(const SDevice * OtherDevice) const; + + /** + * @brief Device bluetooth address. + **/ + bdaddr_t mAddress; + + /** + * @brief List of RFCOMM channels where SmartDeviceLink service has been discovered. + **/ + tRFCOMMChannelVector mSmartDeviceLinkRFCOMMChannels; + }; + + /** + * @brief RFCOMM connection. + **/ + struct SRFCOMMConnection: public SConnection + { + /** + * @brief Constructor. + * + * @param DeviceHandle Device handle. + * @param RFCOMMChannel RFCOMM channel of SmartDeviceLink service on remote device. + **/ + SRFCOMMConnection(const tDeviceHandle DeviceHandle, const uint8_t RFCOMMChannel); + + /** + * @brief Compare connections. + * + * This method compares whether two SRFCOMMConnection structures + * refer to the same connection. + * + * @param OtherConnection Connection to compare with. + * + * @return true if connections are equal, false otherwise. + **/ + virtual bool isSameAs(const SConnection * OtherConnection) const; + + /** + * @brief RFCOMM channel of remote device. + **/ + const uint8_t mRFCOMMChannel; + }; + + /** + * @brief Create list of connections possible for specified device. + * + * This method is called from connectDevice(). This implementation will + * perform service discovery and create connection structures for all + * RFCOMM channels where SmartDeviceLink service is discovered. + * + * @param DeviceHandle Device handle. + * @param ConnectionsList Reference to connections list that must be filled. + * + * @see @ref components_transportmanager_internal_design_device_adapters_bluetooth_adapter_connecting_devices + **/ + virtual void createConnectionsListForDevice(const tDeviceHandle DeviceHandle, std::vector<SConnection*> & ConnectionsList); + + /** + * @brief Device discovery thread. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_main_thread + * @see @ref components_transportmanager_internal_design_device_adapters_bluetooth_adapter_discovery + **/ + virtual void mainThread(void); + + /** + * @brief Connection thread. + * + * This method is responsible for establishing connection and communicating + * with remote device via specified connection. It must remove itself from + * connection map when connection is terminated before terminating connection thread. + * + * @param ConnectionHandle Connection handle. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connection_thread + **/ + virtual void connectionThread(const tConnectionHandle ConnectionHandle); + + /** + * @brief Get unique device ID. + * + * Get TransportManager-unique identifier of + * bluetooth device based on its bluetooth address. + * + * @param DeviceAddress Address of device. + * + * @return Unique device identifier. + **/ + static std::string getUniqueDeviceId(const bdaddr_t & DeviceAddress); + + /** + * @brief Discover SmartDeviceLink RFCOMM channels. + * + * Run service discovery for specified remote bluetooth device + * and discover RFCOMM channels with SmartDeviceLink service. + * + * @param DeviceAddress Address of device. + * @param SmartDeviceLinkRFCOMMChannels Reference to variable that will + * receive list of RFCOMM channels + * with SmartDeviceLink service discovered. + * + * @see @ref components_transportmanager_internal_design_device_adapters_bluetooth_adapter_discovery + * @see @ref components_transportmanager_internal_design_device_adapters_bluetooth_adapter_connecting_devices + **/ + void discoverSmartDeviceLinkRFCOMMChannels(const bdaddr_t & DeviceAddress, tRFCOMMChannelVector & SmartDeviceLinkRFCOMMChannels); + + /** + * @brief UUID of SmartDeviceLink service. + **/ + uuid_t mSmartDeviceLinkServiceUUID; + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/CDeviceAdapter.cpp b/SDL_Core/src/components/TransportManager/src/CDeviceAdapter.cpp new file mode 100644 index 000000000..32b9e6e88 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CDeviceAdapter.cpp @@ -0,0 +1,866 @@ +/** + * \file CDeviceAdapter.cpp + * \brief Class CDeviceAdapter. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fcntl.h> +#include <memory.h> +#include <poll.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "IDeviceAdapterListener.hpp" +#include "IHandleGenerator.hpp" +#include "CDeviceAdapter.hpp" + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SFrame::SFrame(int UserData, const uint8_t* Data, const size_t DataSize): +mUserData(UserData), +mData(0), +mDataSize(0) +{ + if ((0 != Data) && + (0u != DataSize)) + { + mData = new uint8_t[DataSize]; + + if (0 != mData) + { + mDataSize = DataSize; + memcpy(mData, Data, DataSize); + } + } +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SFrame::~SFrame(void) +{ + if (0 != mData) + { + delete [] mData; + } +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SDevice::SDevice(const char * Name): +mName(Name), +mUniqueDeviceId() +{ +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SDevice::~SDevice(void) +{ +} + +bool NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SDevice::isSameAs(const NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SDevice * OtherDevice) const +{ + return true; +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection::SConnection(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle): +mDeviceHandle(DeviceHandle), +mConnectionThread(), +mNotificationPipeFds(), +mConnectionSocket(-1), +mFramesToSend(), +mTerminateFlag(false) +{ +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection::~SConnection(void) +{ + while (false == mFramesToSend.empty()) + { + delete mFramesToSend.front(); + mFramesToSend.pop(); + } +} + +bool NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection::isSameAs(const NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection * OtherConnection) const +{ + bool result = false; + + if (0 != OtherConnection) + { + result = (mDeviceHandle == OtherConnection->mDeviceHandle); + } + + return result; +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnectionThreadParameters::SConnectionThreadParameters(NsSmartDeviceLink::NsTransportManager::CDeviceAdapter & DeviceAdapter, NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle): +mDeviceAdapter(DeviceAdapter), +mConnectionHandle(ConnectionHandle) +{ +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::CDeviceAdapter(NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener& Listener, IHandleGenerator& HandleGenerator): +mLogger(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TransportManager"))), +mListener(Listener), +mHandleGenerator(HandleGenerator), +mDeviceScanRequested(false), +mDeviceScanRequestedMutex(), +mDeviceScanRequestedCond(), +mDevices(), +mDevicesMutex(), +mConnections(), +mConnectionsMutex(), +mShutdownFlag(false), +mMainThread(), +mMainThreadStarted(false) +{ + pthread_cond_init(&mDeviceScanRequestedCond, 0); + pthread_mutex_init(&mDeviceScanRequestedMutex, 0); + pthread_mutex_init(&mDevicesMutex, 0); + pthread_mutex_init(&mConnectionsMutex, 0); +} + +NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::~CDeviceAdapter(void) +{ + pthread_mutex_destroy(&mConnectionsMutex); + pthread_mutex_destroy(&mDevicesMutex); + pthread_mutex_destroy(&mDeviceScanRequestedMutex); + pthread_cond_destroy(&mDeviceScanRequestedCond); +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::run(void) +{ + LOG4CPLUS_INFO(mLogger, "Initializing device adapter"); + + int errorCode = pthread_create(&mMainThread, 0, &mainThreadStartRoutine, this); + + if (0 == errorCode) + { + mMainThreadStarted = true; + LOG4CPLUS_INFO(mLogger, "Device adapter main thread started"); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device adapter main thread start failed, error code " << errorCode); + } +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::scanForNewDevices(void) +{ + pthread_mutex_lock(&mDeviceScanRequestedMutex); + + if (false == mDeviceScanRequested) + { + LOG4CPLUS_INFO(mLogger, "Requesting device scan"); + + mDeviceScanRequested = true; + pthread_cond_signal(&mDeviceScanRequestedCond); + } + else + { + LOG4CPLUS_INFO(mLogger, "Device scan is currently in progress"); + } + + pthread_mutex_unlock(&mDeviceScanRequestedMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::connectDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle) +{ + bool isDeviceValid = false; + + pthread_mutex_lock(&mDevicesMutex); + + if (mDevices.end() != mDevices.find(DeviceHandle)) + { + isDeviceValid = true; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device handle " << DeviceHandle << " is invalid"); + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (true == isDeviceValid) + { + std::vector<SConnection*> connections; + createConnectionsListForDevice(DeviceHandle, connections); + + if (false == connections.empty()) + { + LOG4CPLUS_INFO(mLogger, "Connecting device " << DeviceHandle); + + for (std::vector<SConnection*>::iterator connectionIterator = connections.begin(); connectionIterator != connections.end(); ++connectionIterator) + { + startConnection(*connectionIterator); + } + } + else + { + LOG4CPLUS_WARN(mLogger, "No connections to establish on device " << DeviceHandle); + } + } +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::disconnectDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle) +{ + bool isDeviceValid = false; + + pthread_mutex_lock(&mDevicesMutex); + + if (mDevices.end() != mDevices.find(DeviceHandle)) + { + isDeviceValid = true; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device handle " << DeviceHandle << " is invalid"); + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (true == isDeviceValid) + { + std::vector<tConnectionHandle> connectionsToTerminate; + + pthread_mutex_lock(&mConnectionsMutex); + + for (tConnectionMap::const_iterator connectionIterator = mConnections.begin(); connectionIterator != mConnections.end(); ++connectionIterator) + { + SConnection * connection = connectionIterator->second; + + if (0 != connection) + { + if (connection->mDeviceHandle == DeviceHandle) + { + connectionsToTerminate.push_back(connectionIterator->first); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << connectionIterator->first << " is null"); + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + + for (std::vector<tConnectionHandle>::const_iterator connectionHandleIterator = connectionsToTerminate.begin(); connectionHandleIterator != connectionsToTerminate.end(); ++connectionHandleIterator) + { + stopConnection(*connectionHandleIterator); + } + } +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::sendFrame(NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize, int UserData) +{ + if (0u == DataSize) + { + LOG4CPLUS_WARN(mLogger, "DataSize=0"); + } + else if (0 == Data) + { + LOG4CPLUS_WARN(mLogger, "Data is null"); + } + else + { + pthread_mutex_lock(&mConnectionsMutex); + + tConnectionMap::iterator connectionIterator = mConnections.find(ConnectionHandle); + + if (mConnections.end() == connectionIterator) + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " does not exist"); + } + else + { + SConnection * connection = connectionIterator->second; + + if (0 != connection) + { + connection->mFramesToSend.push(new SFrame(UserData, Data, DataSize)); + + if (-1 != connection->mNotificationPipeFds[1]) + { + uint8_t c = 0; + if (1 != write(connection->mNotificationPipeFds[1], &c, 1)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to wake up connection thread for connection " << connectionIterator->first); + } + } + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + } +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::waitForThreadsTermination(void) +{ + mShutdownFlag = true; + + if (true == mMainThreadStarted) + { + LOG4CPLUS_INFO(mLogger, "Waiting for device adapter main thread termination"); + pthread_join(mMainThread, 0); + LOG4CPLUS_INFO(mLogger, "Device adapter main thread terminated"); + } + + std::vector<pthread_t> connectionThreads; + + pthread_mutex_lock(&mConnectionsMutex); + + for (tConnectionMap::iterator connectionIterator = mConnections.begin(); connectionIterator != mConnections.end(); ++connectionIterator) + { + SConnection * connection = connectionIterator->second; + + if (0 != connection) + { + connection->mTerminateFlag = true; + if (-1 != connection->mNotificationPipeFds[1]) + { + uint8_t c = 0; + if (1 != write(connection->mNotificationPipeFds[1], &c, 1)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to wake up connection thread for connection " << connectionIterator->first); + } + } + connectionThreads.push_back(connection->mConnectionThread); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << connectionIterator->first << " is null"); + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + + LOG4CPLUS_INFO(mLogger, "Waiting for connection threads termination"); + + for (std::vector<pthread_t>::iterator connectionThreadIterator = connectionThreads.begin(); connectionThreadIterator != connectionThreads.end(); ++connectionThreadIterator) + { + pthread_join(*connectionThreadIterator, 0); + } + + LOG4CPLUS_INFO(mLogger, "Connection threads terminated"); +} + +bool NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::startConnection(NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection * Connection) +{ + bool isConnectionThreadStarted = false; + + if (0 != Connection) + { + tConnectionHandle newConnectionHandle = mHandleGenerator.generateNewConnectionHandle(); + + pthread_mutex_lock(&mConnectionsMutex); + + if (false == mShutdownFlag) + { + tConnectionMap::const_iterator connectionIterator; + for (connectionIterator = mConnections.begin(); connectionIterator != mConnections.end(); ++connectionIterator) + { + const SConnection * existingConnection = connectionIterator->second; + + if (0 != existingConnection) + { + if (existingConnection->isSameAs(Connection)) + { + LOG4CPLUS_WARN(mLogger, "Connection is already opened (" << connectionIterator->first << ")"); + + break; + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << connectionIterator->first << " is null"); + } + } + + if (mConnections.end() == connectionIterator) + { + std::pair<tConnectionMap::iterator, bool> insertResult = mConnections.insert(std::make_pair(newConnectionHandle, Connection)); + + if (true == insertResult.second) + { + SConnection * newConnection = insertResult.first->second; + + if (0 != newConnection) + { + SConnectionThreadParameters * connectionThreadParameters = new SConnectionThreadParameters(*this, newConnectionHandle); + + int errorCode = pthread_create(&newConnection->mConnectionThread, 0, &CDeviceAdapter::connectionThreadStartRoutine, static_cast<void*>(connectionThreadParameters)); + + if (0 == errorCode) + { + LOG4CPLUS_INFO(mLogger, "Connection thread started for connection " << newConnectionHandle << " (device " << newConnection->mDeviceHandle << ")"); + + isConnectionThreadStarted = true; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection thread start failed for connection " << newConnectionHandle << " (device " << newConnection->mDeviceHandle << ")"); + + delete connectionThreadParameters; + mConnections.erase(insertResult.first); + delete newConnection; + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Failed to allocate connection " << newConnectionHandle); + + mConnections.erase(newConnectionHandle); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection handle " << newConnectionHandle << " already exists"); + } + } + else + { + delete Connection; + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection is null"); + } + + return isConnectionThreadStarted; +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::stopConnection(NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle) +{ + pthread_mutex_lock(&mConnectionsMutex); + + tConnectionMap::iterator connectionIterator = mConnections.find(ConnectionHandle); + + if (mConnections.end() != connectionIterator) + { + SConnection * connection = connectionIterator->second; + + if (0 != connection) + { + if (false == connection->mTerminateFlag) + { + connection->mTerminateFlag = true; + if (-1 != connection->mNotificationPipeFds[1]) + { + uint8_t c = 0; + if (1 != write(connection->mNotificationPipeFds[1], &c, 1)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to wake up connection thread for connection " << connectionIterator->first); + } + } + + LOG4CPLUS_INFO(mLogger, "Connection " << ConnectionHandle << "(device " << connection->mDeviceHandle << ") has been marked for termination"); + } + else + { + LOG4CPLUS_WARN(mLogger, "Connection " << ConnectionHandle << " is already terminating"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " is null"); + } + } + else + { + LOG4CPLUS_WARN(mLogger, "Connection " << ConnectionHandle << " does not exist"); + } + + pthread_mutex_unlock(&mConnectionsMutex); +} + +bool NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::waitForDeviceScanRequest(const time_t Timeout) +{ + bool deviceScanRequested = false; + + pthread_mutex_lock(&mDeviceScanRequestedMutex); + + if (false == mDeviceScanRequested) + { + if (0 == Timeout) + { + if (0 != pthread_cond_wait(&mDeviceScanRequestedCond, &mDeviceScanRequestedMutex)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "pthread_cond_wait failed"); + } + } + else + { + timespec timeoutTime; + + if (0 == clock_gettime(CLOCK_REALTIME, &timeoutTime)) + { + timeoutTime.tv_sec += Timeout; + + while (0 == pthread_cond_timedwait(&mDeviceScanRequestedCond, &mDeviceScanRequestedMutex, &timeoutTime)) + { + if (true == mDeviceScanRequested) + { + break; + } + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "clock_gettime failed"); + + sleep(Timeout); + } + } + } + + deviceScanRequested = mDeviceScanRequested; + + pthread_mutex_unlock(&mDeviceScanRequestedMutex); + + return deviceScanRequested; +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::handleCommunication(const NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle) +{ + SConnection * connection = 0; + bool isPipeCreated = false; + int notificationPipeReadFd = -1; + int connectionSocket = -1; + tDeviceHandle deviceHandle = InvalidDeviceHandle; + + pthread_mutex_lock(&mConnectionsMutex); + + tConnectionMap::iterator connectionIterator = mConnections.find(ConnectionHandle); + + if (mConnections.end() != connectionIterator) + { + connection = connectionIterator->second; + + if (0 != connection) + { + isPipeCreated = (0 == pipe(connection->mNotificationPipeFds)); + notificationPipeReadFd = connection->mNotificationPipeFds[0]; + connectionSocket = connection->mConnectionSocket; + deviceHandle = connection->mDeviceHandle; + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + + if (0 != connection) + { + if (-1 != connectionSocket) + { + if (InvalidDeviceHandle != deviceHandle) + { + bool isDeviceValid = false; + SDeviceInfo clientDeviceInfo; + + pthread_mutex_lock(&mDevicesMutex); + + tDeviceMap::const_iterator deviceIterator = mDevices.find(deviceHandle); + + if (deviceIterator != mDevices.end()) + { + const SDevice * device = deviceIterator->second; + + if (0 != device) + { + isDeviceValid = true; + + clientDeviceInfo.mDeviceHandle = deviceHandle; + clientDeviceInfo.mDeviceType = getDeviceType(); + clientDeviceInfo.mUserFriendlyName = device->mName; + clientDeviceInfo.mUniqueDeviceId = device->mUniqueDeviceId; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device " << deviceHandle << " is not valid"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device " << deviceHandle << " does not exist"); + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (true == isDeviceValid) + { + if (true == isPipeCreated) + { + if (0 == fcntl(notificationPipeReadFd, F_SETFL, fcntl(notificationPipeReadFd, F_GETFL) | O_NONBLOCK)) + { + LOG4CPLUS_INFO(mLogger, "Connection " << ConnectionHandle << " to remote device " << clientDeviceInfo.mUniqueDeviceId << " established"); + + mListener.onApplicationConnected(this, clientDeviceInfo, ConnectionHandle); + + pollfd pollFds[2]; + pollFds[0].fd = connectionSocket; + pollFds[0].events = POLLIN | POLLPRI; + pollFds[1].fd = connection->mNotificationPipeFds[0]; + pollFds[1].events = POLLIN | POLLPRI; + + while (false == connection->mTerminateFlag) + { + if (-1 != poll(pollFds, sizeof(pollFds) / sizeof(pollFds[0]), -1)) + { + if (0 != (pollFds[0].revents & (POLLERR | POLLHUP | POLLNVAL))) + { + LOG4CPLUS_INFO(mLogger, "Connection " << ConnectionHandle << " terminated"); + + connection->mTerminateFlag = true; + } + else if (0 != (pollFds[1].revents & (POLLERR | POLLHUP | POLLNVAL))) + { + LOG4CPLUS_ERROR(mLogger, "Notification pipe for connection " << ConnectionHandle << " terminated"); + + connection->mTerminateFlag = true; + } + else + { + uint8_t buffer[4096]; + ssize_t bytesRead = -1; + + if (0 != pollFds[0].revents) + { + do + { + bytesRead = recv(connectionSocket, buffer, sizeof(buffer), MSG_DONTWAIT); + + if (bytesRead > 0) + { + LOG4CPLUS_INFO(mLogger, "Received " << bytesRead << " bytes for connection " << ConnectionHandle); + + mListener.onFrameReceived(this, ConnectionHandle, buffer, static_cast<size_t>(bytesRead)); + } + else if (bytesRead < 0) + { + if ((EAGAIN != errno) && + (EWOULDBLOCK != errno)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "recv() failed for connection " << ConnectionHandle); + + connection->mTerminateFlag = true; + } + } + else + { + LOG4CPLUS_INFO(mLogger, "Connection " << ConnectionHandle << " closed by remote peer"); + + connection->mTerminateFlag = true; + } + } while (bytesRead > 0); + } + + if ((false == connection->mTerminateFlag) && + (0 != pollFds[1].revents)) + { + do + { + bytesRead = read(notificationPipeReadFd, buffer, sizeof(buffer)); + } while (bytesRead > 0); + + if ((bytesRead < 0) && + (EAGAIN != errno)) + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to clear notification pipe for connection " << ConnectionHandle); + + connection->mTerminateFlag = true; + } + + tFrameQueue framesToSend; + + pthread_mutex_lock(&mConnectionsMutex); + framesToSend.swap(connection->mFramesToSend); + pthread_mutex_unlock(&mConnectionsMutex); + + for (; false == framesToSend.empty(); framesToSend.pop()) + { + SFrame * frame = framesToSend.front(); + ESendStatus frameSendStatus = SendStatusUnknownError; + + if (0 != frame) + { + if ((0 != frame->mData) && + (0u != frame->mDataSize)) + { + ssize_t bytesSent = send(connectionSocket, frame->mData, frame->mDataSize, 0); + + if (static_cast<size_t>(bytesSent) == frame->mDataSize) + { + frameSendStatus = SendStatusOK; + } + else + { + if (bytesSent >= 0) + { + LOG4CPLUS_ERROR(mLogger, "Sent " << bytesSent << " bytes while " << frame->mDataSize << " had been requested for connection " << ConnectionHandle); + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Send failed for connection " << ConnectionHandle); + } + + frameSendStatus = SendStatusFailed; + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Frame data is invalid for connection " << ConnectionHandle); + + frameSendStatus = SendStatusInternalError; + } + + delete frame; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Frame data is null for connection " << ConnectionHandle); + + frameSendStatus = SendStatusInternalError; + } + + mListener.onFrameSendCompleted(this, ConnectionHandle, frame->mUserData, frameSendStatus); + } + } + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "poll() failed for connection " << ConnectionHandle); + + connection->mTerminateFlag = true; + } + } + + mListener.onApplicationDisconnected(this, clientDeviceInfo, ConnectionHandle); + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to set O_NONBLOCK for notification pipe for connection " << ConnectionHandle); + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to create notification pipe for connection " << ConnectionHandle); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device for connection " << ConnectionHandle << " is invalid"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device handle for connection " << ConnectionHandle << " is invalid"); + } + + close(connectionSocket); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Socket is invalid for connection " << ConnectionHandle); + } + + if (true == isPipeCreated) + { + pthread_mutex_lock(&mConnectionsMutex); + + close(connection->mNotificationPipeFds[0]); + close(connection->mNotificationPipeFds[1]); + + connection->mNotificationPipeFds[0] = connection->mNotificationPipeFds[1] = -1; + + pthread_mutex_unlock(&mConnectionsMutex); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " is not valid"); + } +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::updateClientDeviceList(void ) +{ + LOG4CPLUS_INFO(mLogger, "Updating client device list"); + + tInternalDeviceList clientDeviceList; + + pthread_mutex_lock(&mDevicesMutex); + + for (tDeviceMap::const_iterator di = mDevices.begin(); di != mDevices.end(); ++di) + { + const SDevice * device = di->second; + + if (0 != device) + { + clientDeviceList.push_back(SInternalDeviceInfo(di->first, device->mName, device->mUniqueDeviceId)); + } + } + + pthread_mutex_unlock(&mDevicesMutex); + + mListener.onDeviceListUpdated(this, clientDeviceList); +} + +void NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::createConnectionsListForDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle, std::vector<NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection *> & ConnectionsList) +{ + ConnectionsList.clear(); +} + +void * NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::mainThreadStartRoutine(void * Data) +{ + CDeviceAdapter * deviceAdapter = static_cast<CDeviceAdapter*>(Data); + + if (0 != deviceAdapter) + { + deviceAdapter->mainThread(); + } + + return 0; +} + +void * NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::connectionThreadStartRoutine(void * Data) +{ + SConnectionThreadParameters * connectionThreadParameters = static_cast<SConnectionThreadParameters*>(Data); + + if (0 != connectionThreadParameters) + { + CDeviceAdapter & deviceAdapter(connectionThreadParameters->mDeviceAdapter); + tConnectionHandle connectionHandle(connectionThreadParameters->mConnectionHandle); + + delete connectionThreadParameters; + connectionThreadParameters = 0; + + deviceAdapter.connectionThread(connectionHandle); + } + + return 0; +} diff --git a/SDL_Core/src/components/TransportManager/src/CDeviceAdapter.hpp b/SDL_Core/src/components/TransportManager/src/CDeviceAdapter.hpp new file mode 100644 index 000000000..299197a36 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CDeviceAdapter.hpp @@ -0,0 +1,555 @@ +/** + * \file CDeviceAdapter.hpp + * \brief Class CDeviceAdapter header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_CDEVICEADAPTER_HPP__ +#define __TRANSPORTMANAGER_CDEVICEADAPTER_HPP__ + +#include <pthread.h> +#include <queue> +#include <time.h> + +#include "Logger.hpp" + +#include "IDeviceAdapter.hpp" + +#define LOG4CPLUS_ERROR_WITH_ERRNO(logger, message) LOG4CPLUS_ERROR(logger, message << ", error code " << errno << " (" << strerror(errno) << ")") + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + class IDeviceAdapterListener; + class IHandleGenerator; + + /** + * @brief Base class for @link components_transportmanager_internal_design_device_adapters device adapters @endlink. + **/ + class CDeviceAdapter: public IDeviceAdapter + { + public: + /** + * @brief Constructor. + * + * @param Listener Listener for device adapter notifications. + * @param HandleGenerator Handle generator implementation. + **/ + CDeviceAdapter(IDeviceAdapterListener & Listener, IHandleGenerator & HandleGenerator); + + /** + * @brief Destructor. + **/ + virtual ~CDeviceAdapter(void); + + /** + * @brief Run device adapter. + * + * Called from transport manager to start device adapter. + **/ + virtual void run(void); + + /** + * @brief Start scanning for new devices. + * + * List of new devices will be supplied in onDeviceListUpdated callback. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_device_scan + **/ + virtual void scanForNewDevices(void); + + /** + * @brief Connect to all applications discovered on device. + * + * @param DeviceHandle Handle of device to connect to. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connecting_devices + **/ + virtual void connectDevice(const tDeviceHandle DeviceHandle); + + /** + * @brief Disconnect from all applications connected on device. + * + * @param DeviceHandle Handle of device to disconnect from. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_disconnecting_devices + **/ + virtual void disconnectDevice(const tDeviceHandle DeviceHandle); + + /** + * @brief Send frame. + * + * @param ConnectionHandle Connection handle. + * @param Data Frame payload data. + * @param DataSize Size of data in bytes. + * @param UserData Any user data. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_handling_communication + **/ + virtual void sendFrame(tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize, int UserData); + + protected: + /** + * @brief Frame. + * + * Used to store data frames that must be sent to remote device. + **/ + struct SFrame + { + /** + * @brief Constructor. + * + * @param UserData User data + * @param Data Frame data. SFrame stores a copy of this data, + * i.e. data may be freed after SFrame object is constructed. + * @param DataSize Size of frame data in bytes. + **/ + SFrame(int UserData, const uint8_t * Data, const size_t DataSize); + + /** + * @brief Destructor. + * + * Frees stored frame data. + **/ + ~SFrame(void); + + /** + * @brief User data + **/ + int mUserData; + + /** + * @brief Frame data. + **/ + uint8_t * mData; + + /** + * @brief Frame data size in bytes. + **/ + size_t mDataSize; + }; + + /** + * @brief Frame queue. + **/ + typedef std::queue<SFrame*> tFrameQueue; + + /** + * @brief Internal structure describing device. + **/ + struct SDevice + { + /** + * @brief Constructor. + * + * @param Name User-friendly device name. + **/ + SDevice(const char * Name); + + /** + * @brief Destructor. + **/ + virtual ~SDevice(void); + + /** + * @brief Compare devices. + * + * This method checks whether two SDevice structures + * refer to the same device. + * + * @param OtherDevice Device to compare with. + * + * @return true if devices are equal, false otherwise. + **/ + virtual bool isSameAs(const SDevice * OtherDevice) const; + + /** + * @brief Device user-friendly name. + **/ + std::string mName; + + /** + * @brief Unique device identifier across all devices. + **/ + std::string mUniqueDeviceId; + }; + + /** + * @brief Vector of devices. + **/ + typedef std::vector<SDevice *> tDeviceVector; + + /** + * @brief Devices map. + **/ + typedef std::map<tDeviceHandle, SDevice *> tDeviceMap; + + /** + * @brief Application connection. + **/ + struct SConnection + { + /** + * @brief Constructor. + * + * @param DeviceHandle Device handle. + **/ + SConnection(const tDeviceHandle DeviceHandle); + + /** + * @brief Destructor. + * + * Clears map of frames to send. + **/ + virtual ~SConnection(void); + + /** + * @brief Compare connections. + * + * This method checks whether two SConnection structures + * refer to the same connection. + * + * @param OtherConnection Connection to compare with. + * + * @return true if connections are equal, false otherwise. + **/ + virtual bool isSameAs(const SConnection * OtherConnection) const; + + /** + * @brief Device handle. + **/ + const tDeviceHandle mDeviceHandle; + + /** + * @brief Thread that handles connection. + **/ + pthread_t mConnectionThread; + + /** + * @brief File descriptors of notification pipe. + * + * Notification pipe is used to wake up connection thread + * on external event (e.g. new data is available to send or + * connection is requested to be terminated). + * + * mNotificationPipeFds[0] is a descriptor of the read end of the pipe + * (the one that is used in poll() by connection thread) and + * mNotificationPipeFds[1] is a descriptor of the write end of the pipe + * (the one that is used in methods exposed to transport manager to + * wake up connection thread when necessary). + * + * @note eventfd cannot be used instead of a pipe because it does not + * conform to POSIX (eventfd is Linux-specific). + **/ + int mNotificationPipeFds[2]; + + /** + * @brief Descriptor of connection socket. + **/ + int mConnectionSocket; + + /** + * @brief Frames that must be sent to remote device. + **/ + tFrameQueue mFramesToSend; + + /** + * @brief Terminate flag. + * + * This flag is set to notify connection thread that connection + * must be closed and connection thread must be terminated. + **/ + bool mTerminateFlag; + }; + + /** + * @brief Parameters for starting connection thread. + **/ + struct SConnectionThreadParameters + { + /** + * @brief Constructor. + * + * @param DeviceAdapter Reference to device adapter. + * @param ConnectionHandle Connection handle. + **/ + SConnectionThreadParameters(CDeviceAdapter & DeviceAdapter, tConnectionHandle ConnectionHandle); + + /** + * @brief Reference to device adapter. + **/ + CDeviceAdapter & mDeviceAdapter; + + /** + * @brief Connection handle. + **/ + tConnectionHandle mConnectionHandle; + }; + + /** + * @brief Wait until all device adapter threads are terminated. + * + * Every device adapter must call this method in destructor to wait + * for other threads to terminate before destroying device adapter. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_threads_termination + **/ + void waitForThreadsTermination(void); + + /** + * @brief Start connection. + * + * Check if connection is not in connection map + * and if it's not, add it to map and start connection thread. + * + * @param Connection Connection to start. + * + * @return true if connection thread has been started, false otherwise. + **/ + bool startConnection(SConnection * Connection); + + /** + * @brief Stop connection. + * + * This method only initiates connection termination. It returns immediately + * without waiting for actual termination of the connection. + * + * @param ConnectionHandle Handle of connection to stop. + **/ + void stopConnection(tConnectionHandle ConnectionHandle); + + /** + * @brief Wait for device scan request. + * + * Wait until scanForNewDevices() is called or timeout + * expires. + * + * @param Timeout Timeout value in seconds. 0 means no + * timeout. + * + * @return true if scanForNewDevices() has been called, + * false if timeout expired. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_device_scan + **/ + bool waitForDeviceScanRequest(const time_t Timeout); + + /** + * @brief Handle communication. + * + * Handle communication for specified connection (send/receive data + * to/from connection socket). + * + * This method must be called from connection thread implementation + * when connection is established and connection socket descriptor + * is set for the connection. + * + * This methods returns when connection is terminated. + * + * @param ConnectionHandle Connection handle. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_handling_communication + **/ + void handleCommunication(const tConnectionHandle ConnectionHandle); + + /** + * @brief Update client device list. + * + * This method is called when list of devices is changed to + * notify device adapter listener about new list of devices. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_update_client_device_list + **/ + void updateClientDeviceList(void); + + /** + * @brief Create list of connections possible for specified device. + * + * This method is called from connectDevice(). Device adapter may implement + * this method to provide list of connections that must be running on + * connected device. + * + * @param DeviceHandle Device handle. + * @param ConnectionsList Reference to connections list that must be filled. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connecting_devices + **/ + virtual void createConnectionsListForDevice(const tDeviceHandle DeviceHandle, std::vector<SConnection*> & ConnectionsList); + + /** + * @brief Device adapter main thread. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_main_thread + **/ + virtual void mainThread(void) = 0; + + /** + * @brief Connection thread. + * + * This method is responsible for establishing connection and communicating + * with remote device via specified connection. It must remove itself from + * connection map when connection is terminated before terminating connection thread. + * + * @param ConnectionHandle Connection handle. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connection_thread + **/ + virtual void connectionThread(const tConnectionHandle ConnectionHandle) = 0; + + /** + * @brief Connections map. + **/ + typedef std::map<tConnectionHandle, SConnection *> tConnectionMap; + + /** + * @brief Logger. + **/ + const log4cplus::Logger mLogger; + + /** + * @brief Listener for device adapter notifications. + **/ + IDeviceAdapterListener & mListener; + + /** + * @brief Handle generator implementation. + **/ + IHandleGenerator & mHandleGenerator; + + /** + * @brief Flag indicating that device scan was requested. + * + * This flag is set in scanForNewDevices and reset after requested + * device scan is completed. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_device_scan + **/ + bool mDeviceScanRequested; + + /** + * @brief Mutex restricting access to DeviceScanRequested flag. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_device_scan + **/ + pthread_mutex_t mDeviceScanRequestedMutex; + + /** + * @brief Conditional variable for signaling discovery thread about requested device scan. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_device_scan + **/ + pthread_cond_t mDeviceScanRequestedCond; + + /** + * @brief Map of device handle to device. + * + * This map contains all currently available bluetooth devices. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_devices_map + **/ + tDeviceMap mDevices; + + /** + * @brief Mutex restricting access to device map. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_devices_map + **/ + mutable pthread_mutex_t mDevicesMutex; + + /** + * @brief Map of connections. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connections_map + **/ + tConnectionMap mConnections; + + /** + * @brief Mutex restricting access to connections map. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connections_map + **/ + mutable pthread_mutex_t mConnectionsMutex; + + /** + * @brief Shutdown flag. + * + * This flag is set to true on shutdown to inform all device adapter + * threads that device adapter shutdown is in progress. After setting + * this flag device adapter waits until all its threads are terminated. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_threads_termination + **/ + bool mShutdownFlag; + + private: + /** + * @brief Start routine for device adapter main thread. + * + * @param Data Must be pointer to CDeviceAdapter instance. + * + * @return Thread return value. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_main_thread + **/ + static void * mainThreadStartRoutine(void * Data); + + /** + * @brief Connection thread start routine. + * + * @param Data Must be pointer to SConnectionThreadParameters. Ownership + * of connection thread parameters is passed to connection thread, i.e. + * connection thread is responsible for freeing this object. + * + * @return Thread return value. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_connection_thread + **/ + static void * connectionThreadStartRoutine(void * Data); + + /** + * @brief ID of device adapter main thread. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_main_thread + **/ + pthread_t mMainThread; + + /** + * @brief Flag indicating whether the device adapter main thread has been started successfully. + * + * @see @ref components_transportmanager_internal_design_device_adapters_common_main_thread + **/ + bool mMainThreadStarted; + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/CTCPAdapter.cpp b/SDL_Core/src/components/TransportManager/src/CTCPAdapter.cpp new file mode 100644 index 000000000..4f545356e --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CTCPAdapter.cpp @@ -0,0 +1,317 @@ +/** + * \file CTCPAdapter.cpp + * \brief Class CTCPAdapter. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <memory.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "CTCPAdapter.hpp" +#include "IHandleGenerator.hpp" + +NsSmartDeviceLink::NsTransportManager::CTCPAdapter::STCPDevice::STCPDevice(const char* Name, const in_addr_t & Address): +SDevice(Name), +mAddress(Address) +{ +} + +NsSmartDeviceLink::NsTransportManager::CTCPAdapter::STCPDevice::~STCPDevice(void) +{ +} + +bool NsSmartDeviceLink::NsTransportManager::CTCPAdapter::STCPDevice::isSameAs(const NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SDevice * OtherDevice) const +{ + bool result = false; + + if (true == SDevice::isSameAs(OtherDevice)) + { + const STCPDevice * otherTCPDevice = dynamic_cast<const STCPDevice*>(OtherDevice); + + if (0 != otherTCPDevice) + { + result = (mAddress == otherTCPDevice->mAddress); + } + } + + return result; +} + +NsSmartDeviceLink::NsTransportManager::CTCPAdapter::STCPConnection::STCPConnection(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle, int ConnectionSocket, const in_port_t Port): +SConnection(DeviceHandle), +mPort(Port) +{ + mConnectionSocket = ConnectionSocket; +} + +NsSmartDeviceLink::NsTransportManager::CTCPAdapter::STCPConnection::~STCPConnection(void) +{ +} + +bool NsSmartDeviceLink::NsTransportManager::CTCPAdapter::STCPConnection::isSameAs(const NsSmartDeviceLink::NsTransportManager::CDeviceAdapter::SConnection* OtherConnection) const +{ + bool result = false; + + if (true == SConnection::isSameAs(OtherConnection)) + { + const STCPConnection * otherTCPConnection = dynamic_cast<const STCPConnection*>(OtherConnection); + + if (0 != otherTCPConnection) + { + result = (mPort == otherTCPConnection->mPort); + } + } + + return result; +} + +NsSmartDeviceLink::NsTransportManager::CTCPAdapter::CTCPAdapter(NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener & Listener, NsSmartDeviceLink::NsTransportManager::IHandleGenerator & HandleGenerator): +CDeviceAdapter(Listener, HandleGenerator) +{ +} + +NsSmartDeviceLink::NsTransportManager::CTCPAdapter::~CTCPAdapter(void) +{ + waitForThreadsTermination(); +} + +NsSmartDeviceLink::NsTransportManager::EDeviceType NsSmartDeviceLink::NsTransportManager::CTCPAdapter::getDeviceType(void) const +{ + return DeviceWiFi; +} + +void NsSmartDeviceLink::NsTransportManager::CTCPAdapter::mainThread(void) +{ + LOG4CPLUS_INFO(mLogger, "Main thread initialized"); + + int socketFd = socket(AF_INET, SOCK_STREAM, 0); + + if (-1 != socketFd) + { + sockaddr_in serverAddress; + + memset(&serverAddress, 0, sizeof(serverAddress)); + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(cTCPAdapterPort); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + if (0 == bind(socketFd, (struct sockaddr*)&serverAddress, sizeof(serverAddress))) + { + if (0 == listen(socketFd, 128)) + { + while (false == mShutdownFlag) + { + sockaddr_in clientAddress; + socklen_t clientAddressSize = sizeof(clientAddress); + + int connectionFd = accept(socketFd, (struct sockaddr*)&clientAddress, &clientAddressSize); + + if (connectionFd >= 0) + { + bool isConnectionThreadStarted = false; + + if ((AF_INET == clientAddress.sin_family) && + (sizeof(clientAddress) == clientAddressSize)) + { + char deviceName[32]; + + strncpy(deviceName, inet_ntoa(clientAddress.sin_addr), sizeof(deviceName) / sizeof(deviceName[0])); + + LOG4CPLUS_INFO(mLogger, "Connected client " << deviceName); + + tDeviceHandle deviceHandle = InvalidDeviceHandle; + + pthread_mutex_lock(&mDevicesMutex); + + for (tDeviceMap::const_iterator deviceIterator = mDevices.begin(); deviceIterator != mDevices.end(); ++deviceIterator) + { + const STCPDevice * device = dynamic_cast<const STCPDevice *>(deviceIterator->second); + + if (0 != device) + { + if (clientAddress.sin_addr.s_addr == device->mAddress) + { + deviceHandle = deviceIterator->first; + break; + } + } + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (InvalidDeviceHandle == deviceHandle) + { + deviceHandle = mHandleGenerator.generateNewDeviceHandle(); + STCPDevice * device = new STCPDevice(deviceName, clientAddress.sin_addr.s_addr); + + pthread_mutex_lock(&mDevicesMutex); + + if (true == mDevices.insert(std::make_pair(deviceHandle, device)).second) + { + device->mUniqueDeviceId = std::string("TCP-") + deviceName; + + LOG4CPLUS_INFO(mLogger, "Added new device " << deviceHandle << ": " << device->mName << " (" << device->mUniqueDeviceId << ")"); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device handle " << deviceHandle << " is already present in devices map"); + + deviceHandle = InvalidDeviceHandle; + delete device; + device = 0; + } + + pthread_mutex_unlock(&mDevicesMutex); + + if (0 != device) + { + updateClientDeviceList(); + } + } + + if (InvalidDeviceHandle != deviceHandle) + { + isConnectionThreadStarted = startConnection(new STCPConnection(deviceHandle, connectionFd, clientAddress.sin_port)); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Failed to insert new device into devices map"); + } + } + else + { + LOG4CPLUS_ERROR(mLogger, "Address of connected client is invalid"); + } + + if (false == isConnectionThreadStarted) + { + close(connectionFd); + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "accept() failed"); + } + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "listen() failed"); + } + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "bind() failed"); + } + + close(socketFd); + } + else + { + LOG4CPLUS_ERROR_WITH_ERRNO(mLogger, "Failed to create socket"); + } + + LOG4CPLUS_INFO(mLogger, "Main thread finished"); +} + +void NsSmartDeviceLink::NsTransportManager::CTCPAdapter::connectionThread(const NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle) +{ + handleCommunication(ConnectionHandle); + + tDeviceHandle deviceHandle = InvalidDeviceHandle; + + pthread_mutex_lock(&mConnectionsMutex); + + tConnectionMap::iterator connectionIterator = mConnections.find(ConnectionHandle); + + if (mConnections.end() != connectionIterator) + { + STCPConnection * connection = dynamic_cast<STCPConnection*>(connectionIterator->second); + + if (0 != connection) + { + deviceHandle = connection->mDeviceHandle; + + delete connection; + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " is invalid"); + } + + mConnections.erase(connectionIterator); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Connection " << ConnectionHandle << " was not found in connections map"); + } + + for (connectionIterator = mConnections.begin(); connectionIterator != mConnections.end(); ++connectionIterator) + { + SConnection * connection = connectionIterator->second; + + if (0 != connection) + { + if (deviceHandle == connection->mDeviceHandle) + { + deviceHandle = InvalidDeviceHandle; + break; + } + } + } + + pthread_mutex_unlock(&mConnectionsMutex); + + if (InvalidDeviceHandle != deviceHandle) + { + LOG4CPLUS_INFO(mLogger, "No connections left for device " << deviceHandle << ". Deleting device"); + + pthread_mutex_lock(&mDevicesMutex); + + tDeviceMap::iterator deviceIterator = mDevices.find(deviceHandle); + + if (mDevices.end() != deviceIterator) + { + delete deviceIterator->second; + + mDevices.erase(deviceIterator); + } + + pthread_mutex_unlock(&mDevicesMutex); + + updateClientDeviceList(); + } +} diff --git a/SDL_Core/src/components/TransportManager/src/CTCPAdapter.hpp b/SDL_Core/src/components/TransportManager/src/CTCPAdapter.hpp new file mode 100644 index 000000000..14af2be24 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CTCPAdapter.hpp @@ -0,0 +1,181 @@ +/** + * \file CTCPAdapter.hpp + * \brief Class CTCPAdapter header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_CTCPADAPTER_HPP__ +#define __TRANSPORTMANAGER_CTCPADAPTER_HPP__ + +#include <netinet/in.h> + +#include "CDeviceAdapter.hpp" + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + /** + * @brief Device adapter for TCP/IP connections. + * + * @see @ref components_transportmanager_internal_design_device_adapters_tcp_adapter + **/ + class CTCPAdapter: public CDeviceAdapter + { + public: + /** + * @brief Constructor. + * + * @param Listener Listener for device adapter notifications. + * @param HandleGenerator Handle generator implementation. + **/ + CTCPAdapter(IDeviceAdapterListener & Listener, IHandleGenerator & HandleGenerator); + + /** + * @brief Destructor. + **/ + virtual ~CTCPAdapter(void); + + /** + * @brief Get type of devices handled by this device adapter. + * + * @return Device type. + **/ + virtual EDeviceType getDeviceType(void) const; + + private: + /** + * @brief TCP port for listening for incoming connections. + * + * @see @ref components_transportmanager_internal_design_device_adapters_tcp_adapter_listen + **/ + static const uint16_t cTCPAdapterPort = 12345u; + + /** + * @brief Internal structure describing TCP device. + **/ + struct STCPDevice: public SDevice + { + /** + * @brief Constructor. + * + * @param Name User-friendly device name. + * @param Address Device IP address. + **/ + STCPDevice(const char * Name, const in_addr_t & Address); + + /** + * @brief Destructor. + **/ + virtual ~STCPDevice(void); + + /** + * @brief Compare devices. + * + * This method checks whether two STCPDevice structures + * refer to the same device. + * + * @param OtherDevice Device to compare with. + * + * @return true if devices are equal, false otherwise. + **/ + virtual bool isSameAs(const SDevice * OtherDevice) const; + + /** + * @brief Device IP address. + **/ + in_addr_t mAddress; + }; + + /** + * @brief TCP connection. + **/ + struct STCPConnection: public SConnection + { + /** + * @brief Constructor. + * + * @param DeviceHandle Device handle. + * @param ConnectionSocket Connection socket. + * @param Port TCP port. + **/ + STCPConnection(const tDeviceHandle DeviceHandle, int ConnectionSocket, const in_port_t Port); + + /** + * @brief Destructor. + **/ + virtual ~STCPConnection(void); + + /** + * @brief Compare connections. + * + * This method compares whether two STCPConnection structures + * refer to the same connection. + * + * @param OtherConnection Connection to compare with. + * + * @return true if connections are equal, false otherwise. + **/ + virtual bool isSameAs(const SConnection * OtherConnection) const; + + /** + * @brief TCP port of remote device. + **/ + const in_port_t mPort; + }; + + /** + * @brief Device adapter main thread. + * + * @see @ref components_transportmanager_internal_design_device_adapters_tcp_adapter_listen + * @see @ref components_transportmanager_internal_design_device_adapters_tcp_adapter_accept + * @see @ref components_transportmanager_internal_design_device_adapters_common_main_thread + **/ + virtual void mainThread(void); + + /** + * @brief Connection thread. + * + * This method is responsible for establishing connection and communicating + * with remote device via specified connection. It must remove itself from + * connection map when connection is terminated before terminating connection thread. + * + * @param ConnectionHandle Connection handle. + * + * @see @ref components_transportmanager_internal_design_device_adapters_tcp_adapter_disconnecting + * @see @ref components_transportmanager_internal_design_device_adapters_common_connection_thread + **/ + virtual void connectionThread(const tConnectionHandle ConnectionHandle); + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/CTransportManager.cpp b/SDL_Core/src/components/TransportManager/src/CTransportManager.cpp new file mode 100644 index 000000000..c9c30332d --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CTransportManager.cpp @@ -0,0 +1,1311 @@ +/** + * \file CTransportManager.cpp + * \brief Class CTransportManager. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "LoggerHelper.hpp" + +#include "CTransportManager.hpp" +#include "CBluetoothAdapter.hpp" +#include "CTCPAdapter.hpp" +#include "TransportManagerLoggerHelpers.hpp" + +#include <algorithm> + +using namespace NsSmartDeviceLink::NsTransportManager; + +NsSmartDeviceLink::NsTransportManager::CTransportManager::CTransportManager(void): +mDeviceAdapters(), +mLogger(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TransportManager"))), +mDataListenersMutex(), +mDeviceListenersMutex(), +mDeviceHandleGenerationMutex(), +mConnectionHandleGenerationMutex(), +mDataListeners(), +mDeviceListeners(), +mLastUsedDeviceHandle(0), +mLastUsedConnectionHandle(0), +mApplicationCallbacksThread(), +mDeviceListenersConditionVar(), +mDeviceListenersCallbacks(), +mTerminateFlag(false), +mDevicesByAdapter(), +mDevicesByAdapterMutex(), +mConnections(), +mClientInterfaceMutex() +{ + pthread_mutex_init(&mDataListenersMutex, 0); + pthread_mutex_init(&mDeviceListenersMutex, 0); + pthread_mutex_init(&mDeviceHandleGenerationMutex, 0); + pthread_mutex_init(&mConnectionHandleGenerationMutex, 0); + pthread_mutex_init(&mClientInterfaceMutex, 0); + + pthread_cond_init(&mDeviceListenersConditionVar, NULL); + + LOG4CPLUS_INFO(mLogger, "TransportManager constructed"); +} + +NsSmartDeviceLink::NsTransportManager::CTransportManager::~CTransportManager(void) +{ + LOG4CPLUS_INFO(mLogger, "TransportManager destructor"); + + mTerminateFlag = true; + + // Terminating all threads + stopApplicationCallbacksThread(); + LOG4CPLUS_INFO(mLogger, "Waiting for application callbacks thread termination"); + pthread_join(mApplicationCallbacksThread, 0); + LOG4CPLUS_INFO(mLogger, "Application callbacks thread terminated"); + + pthread_mutex_lock(&mDataListenersMutex); + std::map<tConnectionHandle, pthread_t> dataThreads; + for (tConnectionsMap::iterator ConnectionsIterator = mConnections.begin(); ConnectionsIterator != mConnections.end(); ++ConnectionsIterator) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionsIterator->first, "Stopping connection"); + dataThreads[ConnectionsIterator->first] = ConnectionsIterator->second->mConnectionThread; + stopConnection(ConnectionsIterator->second->mConnectionHandle); + } + pthread_mutex_unlock(&mDataListenersMutex); + + for (std::map<tConnectionHandle, pthread_t>::iterator threadsIterator = dataThreads.begin(); threadsIterator != dataThreads.end(); ++threadsIterator) + { + TM_CH_LOG4CPLUS_INFO(mLogger, threadsIterator->first, "Waiting for thread stoping"); + pthread_join(threadsIterator->second, 0); + TM_CH_LOG4CPLUS_INFO(mLogger, threadsIterator->first, "Thread terminated"); + } + + LOG4CPLUS_INFO(mLogger, "All data callbacks threads terminated. Terminating device adapters"); + + for (std::vector<IDeviceAdapter*>::iterator di = mDeviceAdapters.begin(); di != mDeviceAdapters.end(); ++di) + { + removeDeviceAdapter((*di)); + delete (*di); + } + + LOG4CPLUS_INFO(mLogger, "All device adapters removed"); + + pthread_mutex_destroy(&mDataListenersMutex); + pthread_mutex_destroy(&mDeviceListenersMutex); + pthread_mutex_destroy(&mDeviceHandleGenerationMutex); + pthread_mutex_destroy(&mConnectionHandleGenerationMutex); + pthread_mutex_destroy(&mClientInterfaceMutex); + + pthread_cond_destroy(&mDeviceListenersConditionVar); + + LOG4CPLUS_INFO(mLogger, "Component terminated"); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::run(void) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + initializeDeviceAdapters(); + + LOG4CPLUS_INFO(mLogger, "Starting device adapters"); + for (std::vector<IDeviceAdapter*>::iterator di = mDeviceAdapters.begin(); di != mDeviceAdapters.end(); ++di) + { + (*di)->run(); + } + + startApplicationCallbacksThread(); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::scanForNewDevices(void) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + LOG4CPLUS_INFO(mLogger, "Scanning new devices on all registered device adapters"); + for (std::vector<IDeviceAdapter*>::iterator di = mDeviceAdapters.begin(); di != mDeviceAdapters.end(); ++di) + { + LOG4CPLUS_INFO(mLogger, "Initiating scanning of new devices on adapter: " <<(*di)->getDeviceType()); + (*di)->scanForNewDevices(); + LOG4CPLUS_INFO(mLogger, "Scanning of new devices initiated on adapter: " <<(*di)->getDeviceType()); + } + LOG4CPLUS_INFO(mLogger, "Scanning of new devices initiated"); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::connectDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + connectDisconnectDevice(DeviceHandle, true); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::disconnectDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + connectDisconnectDevice(DeviceHandle, false); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::addDataListener(NsSmartDeviceLink::NsTransportManager::ITransportManagerDataListener * Listener) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + mDataListeners.push_back(Listener); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::removeDataListener(NsSmartDeviceLink::NsTransportManager::ITransportManagerDataListener * Listener) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + mDataListeners.erase(std::remove(mDataListeners.begin(), mDataListeners.end(), Listener), mDataListeners.end()); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::addDeviceListener(NsSmartDeviceLink::NsTransportManager::ITransportManagerDeviceListener * Listener) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + mDeviceListeners.push_back(Listener); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::removeDeviceListener(NsSmartDeviceLink::NsTransportManager::ITransportManagerDeviceListener * Listener) +{ + pthread_mutex_lock(&mClientInterfaceMutex); + mDeviceListeners.erase(std::remove(mDeviceListeners.begin(), mDeviceListeners.end(), Listener), mDeviceListeners.end()); + pthread_mutex_unlock(&mClientInterfaceMutex); +} + +void NsSmartDeviceLink::NsTransportManager::CTransportManager::sendFrame(tConnectionHandle ConnectionHandle, const uint8_t* Data, size_t DataSize, const int UserData) +{ + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "sendFrame called. DataSize: "<<DataSize); + + if(InvalidConnectionHandle == ConnectionHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "sendFrame received with invalid connection handle"); + return; + } + + bool bIncomingParamsValid = true; + if(0 == Data) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "sendFrame with empty data"); + bIncomingParamsValid = false; + } + + if(0 == DataSize) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "sendFrame with DataSize=0"); + bIncomingParamsValid = false; + } + + if(false == bIncomingParamsValid) + { + SDataListenerCallback newCallback(CTransportManager::DataListenerCallbackType_FrameSendCompleted, ConnectionHandle, UserData, SendStatusInvalidParametersError); + + pthread_mutex_lock(&mDataListenersMutex); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Sending callback"); + sendDataCallback(newCallback); + pthread_mutex_unlock(&mDataListenersMutex); + return; + } + + // Searching device adapter + pthread_mutex_lock(&mDataListenersMutex); + SConnectionInfo* connectionInfo = getConnection(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + + if(0 != connectionInfo) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Device adapter found (type: "<<connectionInfo->mpDeviceAdapter.getDeviceType()<<"). Sending frame to it"); + connectionInfo->mpDeviceAdapter.sendFrame(ConnectionHandle, Data, DataSize, UserData); + } + else + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Device adapter that handles Connection Handle was not found"); + } +} + +NsSmartDeviceLink::NsTransportManager::tDeviceHandle NsSmartDeviceLink::NsTransportManager::CTransportManager::generateNewDeviceHandle(void) +{ + tDeviceHandle outputDeviceHandle; + + pthread_mutex_lock(&mDeviceHandleGenerationMutex); + ++mLastUsedDeviceHandle; + outputDeviceHandle = mLastUsedDeviceHandle; + pthread_mutex_unlock(&mDeviceHandleGenerationMutex); + + return outputDeviceHandle; +} + +NsSmartDeviceLink::NsTransportManager::tConnectionHandle NsSmartDeviceLink::NsTransportManager::CTransportManager::generateNewConnectionHandle(void) +{ + tConnectionHandle outputConnectionHandle; + + pthread_mutex_lock(&mConnectionHandleGenerationMutex); + ++mLastUsedConnectionHandle; + outputConnectionHandle = mLastUsedConnectionHandle; + pthread_mutex_unlock(&mConnectionHandleGenerationMutex); + + return outputConnectionHandle; +} + +void CTransportManager::onDeviceListUpdated(IDeviceAdapter * DeviceAdapter, const tInternalDeviceList & DeviceList) +{ + if(0 == DeviceAdapter) + { + LOG4CPLUS_WARN(mLogger, "DeviceAdapter=0"); + } + else + { + LOG4CPLUS_INFO(mLogger, "Device adapter type is: "<<DeviceAdapter->getDeviceType() << ", number of devices is: "<<DeviceList.size()); + pthread_mutex_lock(&mDevicesByAdapterMutex); + + tDevicesByAdapterMap::iterator devicesIterator = mDevicesByAdapter.find(DeviceAdapter); + if(devicesIterator == mDevicesByAdapter.end()) + { + LOG4CPLUS_WARN(mLogger, "Invalid adapter initialization. No devices vector available for adapter: "<<DeviceAdapter->getDeviceType()); + pthread_mutex_unlock(&mDevicesByAdapterMutex); + } + else + { + // Updating devices for adapter + tInternalDeviceList *pDevices = devicesIterator->second; + pDevices->clear(); + std::copy(DeviceList.begin(), DeviceList.end(), std::back_inserter(*pDevices)); + + LOG4CPLUS_INFO(mLogger, "Devices list for adapter is updated. Adapter type is: "<<DeviceAdapter->getDeviceType()); + + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + // Calling callback with new device list to subscribers + sendDeviceListUpdatedCallback(); + } + } +} + +void CTransportManager::onApplicationConnected(IDeviceAdapter * DeviceAdapter, const SDeviceInfo & ConnectedDevice, const tConnectionHandle ConnectionHandle) +{ + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "onApplicationConnected"); + + if(0 == DeviceAdapter) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "ApplicationConnected received from invalid device adapter"); + return; + } + + if(InvalidConnectionHandle == ConnectionHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "ApplicationConnected received with invalid connection handle"); + return; + } + + if(InvalidDeviceHandle == ConnectedDevice.mDeviceHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "ApplicationConnected received with invalid device handle: "<<ConnectedDevice.mDeviceHandle); + return; + } + + if(DeviceAdapter->getDeviceType() != ConnectedDevice.mDeviceType) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "ApplicationConnected received but connected device type("<<ConnectedDevice.mDeviceType<<") differs from device adapters type: "<<DeviceAdapter->getDeviceType()); + return; + } + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Before mDevicesByAdapterMutex mutex lock"); + + pthread_mutex_lock(&mDevicesByAdapterMutex); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Right after mDevicesByAdapterMutex mutex lock"); + tDevicesByAdapterMap::iterator devicesIterator = mDevicesByAdapter.find(DeviceAdapter); + if(devicesIterator == mDevicesByAdapter.end()) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Invalid device adapter initialization. No devices vector available for adapter: "<<DeviceAdapter->getDeviceType()); + pthread_mutex_unlock(&mDevicesByAdapterMutex); + return; + } + + tInternalDeviceList *pDevices = devicesIterator->second; + bool connectionHandleFound = false; + for(tInternalDeviceList::const_iterator deviceIterator = pDevices->begin(); deviceIterator != pDevices->end(); ++deviceIterator) + { + if(deviceIterator->mDeviceHandle == ConnectedDevice.mDeviceHandle) + { + connectionHandleFound = true; + } + } + + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "After mDevicesByAdapterMutex mutex unlock"); + + if(false == connectionHandleFound) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Connected device handle ("<<ConnectedDevice.mDeviceHandle<<") was not found in devices list for adapter of type: "<<DeviceAdapter->getDeviceType()); + return; + } + + startConnection(ConnectionHandle, *DeviceAdapter); + + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "Sending callback"); + + // Sending callback + SDeviceListenerCallback cb(CTransportManager::DeviceListenerCallbackType_ApplicationConnected, ConnectedDevice, ConnectionHandle); + sendDeviceCallback(cb); + + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "END of onApplicationConnected"); +} + +void CTransportManager::onApplicationDisconnected(IDeviceAdapter* DeviceAdapter, const SDeviceInfo& DisconnectedDevice, const tConnectionHandle ConnectionHandle) +{ + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "onApplicationDisconnected"); + + if(0 == DeviceAdapter) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "ApplicationDisconnected received from invalid device adapter"); + return; + } + + if(InvalidConnectionHandle == ConnectionHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "ApplicationDisconnected received with invalid connection handle"); + return; + } + + if(InvalidDeviceHandle == DisconnectedDevice.mDeviceHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "ApplicationDisconnected received with invalid device handle: "<<DisconnectedDevice.mDeviceHandle); + return; + } + + if(DeviceAdapter->getDeviceType() != DisconnectedDevice.mDeviceType) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "ApplicationDisconnected received but disconnected device type("<<DisconnectedDevice.mDeviceType<<") differs from device adapters type: "<<DeviceAdapter->getDeviceType()); + return; + } + + pthread_mutex_lock(&mDevicesByAdapterMutex); + tDevicesByAdapterMap::iterator devicesIterator = mDevicesByAdapter.find(DeviceAdapter); + if(devicesIterator == mDevicesByAdapter.end()) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Invalid device adapter initialization. No devices vector available for adapter: "<<DeviceAdapter->getDeviceType()); + pthread_mutex_unlock(&mDevicesByAdapterMutex); + return; + } + + tInternalDeviceList *pDevices = devicesIterator->second; + bool connectionHandleFound = false; + for(tInternalDeviceList::const_iterator deviceIterator = pDevices->begin(); deviceIterator != pDevices->end(); ++deviceIterator) + { + if(deviceIterator->mDeviceHandle == DisconnectedDevice.mDeviceHandle) + { + connectionHandleFound = true; + } + } + + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + if(false == connectionHandleFound) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Disconnected device handle ("<<DisconnectedDevice.mDeviceHandle<<") was not found in devices list for adapter of type: "<<DeviceAdapter->getDeviceType()); + return; + } + + pthread_mutex_lock(&mDataListenersMutex); + SConnectionInfo* pConnection = getConnection(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + + if(0 == pConnection) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Thread for connection does not exist"); + return; + } + + pthread_mutex_lock(&mDataListenersMutex); + if(true == pConnection->mTerminateFlag) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Connection is already in shutdown state."); + pthread_mutex_unlock(&mDataListenersMutex); + } + else + { + stopConnection(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + + // Sending callback + SDeviceListenerCallback cb(CTransportManager::DeviceListenerCallbackType_ApplicationDisconnected, DisconnectedDevice, ConnectionHandle); + sendDeviceCallback(cb); + } + + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "END of onApplicationDisconnected"); +} + +void CTransportManager::onFrameReceived(IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize) +{ + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "onFrameReceived called. DA: "<<DeviceAdapter<<", DataSize: "<<DataSize); + + if(0 == DeviceAdapter) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "onFrameReceived received from invalid device adapter"); + return; + } + + if(0 == Data) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "onFrameReceived with empty data"); + return; + } + + if(0 == DataSize) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "onFrameReceived with DataSize=0"); + return; + } + + if(InvalidConnectionHandle == ConnectionHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "onFrameReceived received with invalid connection handle"); + return; + } + + pthread_mutex_lock(&mDevicesByAdapterMutex); + tDevicesByAdapterMap::iterator devicesIterator = mDevicesByAdapter.find(DeviceAdapter); + if(devicesIterator == mDevicesByAdapter.end()) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "onFrameReceived. Invalid device adapter initialization. No devices vector available for adapter: "<<DeviceAdapter->getDeviceType()); + pthread_mutex_unlock(&mDevicesByAdapterMutex); + return; + } + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + pthread_mutex_lock(&mDataListenersMutex); + SConnectionInfo* connectionInfo = getConnection(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + + if(0 == connectionInfo) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "onFrameReceived. Connection information for connection does not exist"); + return; + } + + pthread_mutex_lock(&mDataListenersMutex); + connectionInfo->mFrameData.appendFrameData(Data, DataSize); + + uint8_t *pFramePacketData = 0; + size_t FramePacketSize = 0; + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Starting frame extraction"); + while(true == connectionInfo->mFrameData.extractFrame(pFramePacketData, FramePacketSize)) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Frame extracted. Size is: "<< FramePacketSize); + SDataListenerCallback newCallback(CTransportManager::DataListenerCallbackType_FrameReceived, ConnectionHandle, pFramePacketData, FramePacketSize); + sendDataCallback(newCallback); + delete pFramePacketData; + FramePacketSize = 0; + } + + pthread_mutex_unlock(&mDataListenersMutex); + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "onFrameReceived processed"); +} + +void CTransportManager::onFrameSendCompleted(IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, int UserData, ESendStatus SendStatus) +{ + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "onFrameSendCompleted called. DA: "<<DeviceAdapter<<", UserData: "<<UserData <<", SendStatus: " <<SendStatus); + + if(0 == DeviceAdapter) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "onFrameSendCompleted received from invalid device adapter"); + return; + } + + if(InvalidConnectionHandle == ConnectionHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "onFrameSendCompleted received with invalid connection handle"); + return; + } + + pthread_mutex_lock(&mDevicesByAdapterMutex); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "searching for devices for adapter"); + tDevicesByAdapterMap::iterator devicesIterator = mDevicesByAdapter.find(DeviceAdapter); + if(devicesIterator == mDevicesByAdapter.end()) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "onFrameSendCompleted. Invalid device adapter initialization. No devices vector available for adapter: "<<DeviceAdapter->getDeviceType()); + pthread_mutex_unlock(&mDevicesByAdapterMutex); + return; + } + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Checking connection information availability"); + + pthread_mutex_lock(&mDataListenersMutex); + bool bThreadExist = isConnectionAvailable(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + + if(false == bThreadExist) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "onFrameSendCompleted. Connection is not available"); + return; + } + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Connection is available. Preparing callback"); + + SDataListenerCallback newCallback(CTransportManager::DataListenerCallbackType_FrameSendCompleted, ConnectionHandle, UserData, SendStatus); + + pthread_mutex_lock(&mDataListenersMutex); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Sending callback"); + sendDataCallback(newCallback); + pthread_mutex_unlock(&mDataListenersMutex); +} + +CTransportManager::SDeviceListenerCallback::SDeviceListenerCallback(CTransportManager::EDeviceListenerCallbackType CallbackType, const tDeviceList& DeviceList) +: mCallbackType(CallbackType) +, mDeviceList(DeviceList) +, mDeviceInfo() +, mConnectionHandle() +{ +} + +CTransportManager::SDeviceListenerCallback::SDeviceListenerCallback(CTransportManager::EDeviceListenerCallbackType CallbackType, const SDeviceInfo& DeviceInfo, const tConnectionHandle& ConnectionHandle) +: mCallbackType(CallbackType) +, mDeviceList() +, mDeviceInfo(DeviceInfo) +, mConnectionHandle(ConnectionHandle) +{ +} + +CTransportManager::SDeviceListenerCallback::SDeviceListenerCallback(const SDeviceListenerCallback& other) +: mCallbackType(other.mCallbackType) +, mDeviceList(other.mDeviceList) +, mDeviceInfo(other.mDeviceInfo) +, mConnectionHandle(other.mConnectionHandle) +{ +} + +bool CTransportManager::SDeviceListenerCallback::operator==( const SDeviceListenerCallback& i_other ) const +{ + return ( (mCallbackType == i_other.mCallbackType) + && (mDeviceList == i_other.mDeviceList) + && (mDeviceInfo == i_other.mDeviceInfo) + && (mConnectionHandle == i_other.mConnectionHandle)); +} + +CTransportManager::SDeviceListenerCallback::~SDeviceListenerCallback(void ) +{ +} + +CTransportManager::SDataListenerCallback::SDataListenerCallback(CTransportManager::EDataListenerCallbackType CallbackType, tConnectionHandle ConnectionHandle, const uint8_t* Data, size_t DataSize) +: mCallbackType(CallbackType) +, mConnectionHandle(ConnectionHandle) +, mData(0) +, mDataSize(DataSize) +, mUserData() +, mSendStatus(NsSmartDeviceLink::NsTransportManager::SendStatusUnknownError) +{ + if ((0 != Data) && + (0u != DataSize)) + { + mData = new uint8_t[DataSize]; + + if (0 != mData) + { + memcpy(mData, Data, DataSize); + } + } +} + +CTransportManager::SDataListenerCallback::SDataListenerCallback(CTransportManager::EDataListenerCallbackType CallbackType, tConnectionHandle ConnectionHandle, int UserData, ESendStatus SendStatus) +: mCallbackType(CallbackType) +, mConnectionHandle(ConnectionHandle) +, mData(0) +, mDataSize(0) +, mUserData(UserData) +, mSendStatus(SendStatus) +{ + +} + +NsSmartDeviceLink::NsTransportManager::CTransportManager::SDataListenerCallback::SDataListenerCallback(const SDataListenerCallback& other) +: mCallbackType(other.mCallbackType) +, mConnectionHandle(other.mConnectionHandle) +, mData(0) +, mDataSize(other.mDataSize) +, mUserData(other.mUserData) +, mSendStatus(other.mSendStatus) +{ + if ((0 != other.mData) && + (0u != other.mDataSize)) + { + mData = new uint8_t[other.mDataSize]; + + if (0 != mData) + { + mDataSize = other.mDataSize; + memcpy(mData, other.mData, mDataSize); + } + } +} + +bool NsSmartDeviceLink::NsTransportManager::CTransportManager::SDataListenerCallback::operator==( const SDataListenerCallback& i_other ) const +{ + return ( (mCallbackType == i_other.mCallbackType) + && (mConnectionHandle == i_other.mConnectionHandle) + && (mDataSize == i_other.mDataSize) + && (mUserData == i_other.mUserData) + && (mSendStatus == i_other.mSendStatus) + && (0 == memcmp(mData, i_other.mData, i_other.mDataSize))); +} + +CTransportManager::SDataListenerCallback::~SDataListenerCallback(void ) +{ + if (0 != mData) + { + delete[] mData; + } +} + +CTransportManager::SDataThreadStartupParams::SDataThreadStartupParams(CTransportManager* TransportManager, tConnectionHandle ConnectionHandle) +: mTransportManager(TransportManager) +, mConnectionHandle(ConnectionHandle) +{ +} + + +void CTransportManager::applicationCallbacksThread() +{ + LOG4CPLUS_INFO(mLogger, "Started application callbacks thread"); + + while(false == mTerminateFlag) + { + pthread_mutex_lock(&mDeviceListenersMutex); + + while(mDeviceListenersCallbacks.empty() && (false == mTerminateFlag)) + { + LOG4CPLUS_INFO(mLogger, "No callbacks to process. Waiting"); + pthread_cond_wait(&mDeviceListenersConditionVar, &mDeviceListenersMutex); + LOG4CPLUS_INFO(mLogger, "Callbacks processing triggered"); + } + + if(mTerminateFlag) + { + LOG4CPLUS_INFO(mLogger, "Shutdown is on progress. Skipping callback processing."); + pthread_mutex_unlock(&mDeviceListenersMutex); + break; + } + + LOG4CPLUS_INFO(mLogger, "Copying callbacks and device listeners to process"); + + std::vector<SDeviceListenerCallback> callbacksToProcess(mDeviceListenersCallbacks); + mDeviceListenersCallbacks.clear(); + + std::vector<ITransportManagerDeviceListener*> deviceListenersToSend(mDeviceListeners); + + pthread_mutex_unlock(&mDeviceListenersMutex); + + LOG4CPLUS_INFO(mLogger, "Starting callbacks processing. Number of callbacks: " << callbacksToProcess.size()); + + std::vector<SDeviceListenerCallback>::const_iterator callbackIterator; + + for(callbackIterator = callbacksToProcess.begin(); callbackIterator != callbacksToProcess.end(); ++callbackIterator) + { + LOG4CPLUS_INFO(mLogger, "Processing callback of type: " << (*callbackIterator).mCallbackType); + + std::vector<ITransportManagerDeviceListener*>::const_iterator deviceListenersIterator; + int deviceListenerIndex = 0; + + for (deviceListenersIterator = deviceListenersToSend.begin(), deviceListenerIndex=0; deviceListenersIterator != deviceListenersToSend.end(); ++deviceListenersIterator, ++deviceListenerIndex) + { + LOG4CPLUS_INFO(mLogger, "Calling callback on listener #" << deviceListenerIndex); + + switch((*callbackIterator).mCallbackType) + { + case CTransportManager::DeviceListenerCallbackType_DeviceListUpdated: + (*deviceListenersIterator)->onDeviceListUpdated((*callbackIterator).mDeviceList); + break; + case CTransportManager::DeviceListenerCallbackType_ApplicationConnected: + (*deviceListenersIterator)->onApplicationConnected((*callbackIterator).mDeviceInfo, (*callbackIterator).mConnectionHandle); + break; + case CTransportManager::DeviceListenerCallbackType_ApplicationDisconnected: + (*deviceListenersIterator)->onApplicationDisconnected((*callbackIterator).mDeviceInfo, (*callbackIterator).mConnectionHandle); + break; + default: + LOG4CPLUS_ERROR(mLogger, "Unknown callback type: " << (*callbackIterator).mCallbackType); + break; + } + + LOG4CPLUS_INFO(mLogger, "Callback on listener #" << deviceListenerIndex <<" called"); + } + } + + LOG4CPLUS_INFO(mLogger, "All callbacks processed. Starting next callbacks processing iteration"); + } + + LOG4CPLUS_INFO(mLogger, "ApplicationsCallback thread terminated"); +} + +void* CTransportManager::applicationCallbacksThreadStartRoutine(void* Data) +{ + if (0 != Data) + { + static_cast<CTransportManager*>(Data)->applicationCallbacksThread(); + } + + return 0; +} + +void CTransportManager::dataCallbacksThread(const tConnectionHandle ConnectionHandle) +{ + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Started data callbacks thread"); + + pthread_mutex_lock(&mDataListenersMutex); + SConnectionInfo* connectionInfo = getConnection(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + + if(0 == connectionInfo) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "Connection information was not found"); + return; + } + + while(false == connectionInfo->mTerminateFlag) + { + pthread_mutex_lock(&mDataListenersMutex); + + while(connectionInfo->mDataCallbacksVector.empty() && (false == connectionInfo->mTerminateFlag)) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "No callbacks to process. Waiting"); + pthread_cond_wait(&connectionInfo->mConditionVar, &mDataListenersMutex); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Callbacks processing triggered"); + } + + if(connectionInfo->mTerminateFlag) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Shutdown is on progress. Skipping callback processing."); + pthread_mutex_unlock(&mDataListenersMutex); + break; + } + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Copying callbacks and device listeners to process"); + + tDataCallbacksVector callbacksToProcess(connectionInfo->mDataCallbacksVector); + connectionInfo->mDataCallbacksVector.clear(); + + std::vector<ITransportManagerDataListener*> dataListenersToSend(mDataListeners); + + pthread_mutex_unlock(&mDataListenersMutex); + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Starting callbacks processing. Number of callbacks: " << callbacksToProcess.size()); + + tDataCallbacksVector::const_iterator callbackIterator; + for(callbackIterator = callbacksToProcess.begin(); callbackIterator != callbacksToProcess.end(); ++callbackIterator) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Processing callback of type: " << (*callbackIterator).mCallbackType); + + if(ConnectionHandle != callbackIterator->mConnectionHandle) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "Possible error. Thread connection handle ("<<ConnectionHandle<<") differs from callback connection handle ("<<callbackIterator->mConnectionHandle<<")"); + } + + std::vector<ITransportManagerDataListener*>::const_iterator dataListenersIterator; + int dataListenerIndex = 0; + + for (dataListenersIterator = dataListenersToSend.begin(), dataListenerIndex=0; dataListenersIterator != dataListenersToSend.end(); ++dataListenersIterator, ++dataListenerIndex) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Calling callback on listener #" << dataListenerIndex); + + switch((*callbackIterator).mCallbackType) + { + case CTransportManager::DataListenerCallbackType_FrameReceived: + (*dataListenersIterator)->onFrameReceived(callbackIterator->mConnectionHandle, callbackIterator->mData, callbackIterator->mDataSize); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Callback onFrameReceived on listener #" << dataListenerIndex << " was called. DataSize: " << callbackIterator->mDataSize); + break; + case CTransportManager::DataListenerCallbackType_FrameSendCompleted: + (*dataListenersIterator)->onFrameSendCompleted(callbackIterator->mConnectionHandle, callbackIterator->mUserData, callbackIterator->mSendStatus); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Callback onFrameReceived on listener #" << dataListenerIndex << " was called. UserData: " << callbackIterator->mUserData<<", SendStatus: "<<callbackIterator->mSendStatus); + break; + default: + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "Unknown callback type: " << (*callbackIterator).mCallbackType); + break; + } + + LOG4CPLUS_INFO(mLogger, "Callback on listener #" << dataListenerIndex <<" called"<<", ConnectionHandle: "<<ConnectionHandle); + } + } + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "All callbacks processed. Starting next callbacks processing iteration"); + } + + pthread_mutex_lock(&mDataListenersMutex); + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Terminating connection thread"); + + // Deleting data associated with connection handle + delete connectionInfo; + mConnections.erase(ConnectionHandle); + pthread_mutex_unlock(&mDataListenersMutex); + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Connection thread terminated"); +} + +void* CTransportManager::dataCallbacksThreadStartRoutine(void* Data) +{ + SDataThreadStartupParams * parameters = static_cast<SDataThreadStartupParams*>(Data); + + if (0 != parameters) + { + CTransportManager *pTransportManager = parameters->mTransportManager; + tConnectionHandle connectionHandle(parameters->mConnectionHandle); + + delete parameters; + parameters = 0; + + pTransportManager->dataCallbacksThread(connectionHandle); + } + + return 0; +} + +void CTransportManager::startApplicationCallbacksThread() +{ + LOG4CPLUS_INFO(mLogger, "Starting device listeners thread"); + + int errorCode = pthread_create(&mApplicationCallbacksThread, 0, &applicationCallbacksThreadStartRoutine, this); + + if (0 == errorCode) + { + LOG4CPLUS_INFO(mLogger, "Device listeners thread started"); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Device listeners thread cannot be started, error code " << errorCode); + } +} + +void CTransportManager::stopApplicationCallbacksThread() +{ + LOG4CPLUS_TRACE(mLogger, "Stopping application-callbacks thread"); + + pthread_mutex_lock(&mDeviceListenersMutex); + pthread_cond_signal(&mDeviceListenersConditionVar); + pthread_mutex_unlock(&mDeviceListenersMutex); +} + +void CTransportManager::startConnection(const tConnectionHandle ConnectionHandle, IDeviceAdapter & DeviceAdapter) +{ + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "Starting data-callbacks thread"); + + pthread_mutex_lock(&mDataListenersMutex); + + if(isConnectionAvailable(ConnectionHandle)) + { + TM_CH_LOG4CPLUS_ERROR(mLogger, ConnectionHandle, "Connection with this handle already available. Possible error."); + } + else + { + SConnectionInfo *connection = new SConnectionInfo(ConnectionHandle, DeviceAdapter); + SDataThreadStartupParams *connectionThreadParams = new SDataThreadStartupParams(this, ConnectionHandle); + + int errorCode = pthread_create(&connection->mConnectionThread, 0, &dataCallbacksThreadStartRoutine, connectionThreadParams); + + if (0 == errorCode) + { + mConnections[ConnectionHandle] = connection; + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Connection started."); + } + else + { + LOG4CPLUS_ERROR(mLogger, "Thread start for connection handle (" << ConnectionHandle << ") failed, error code " << errorCode); + delete connection; + delete connectionThreadParams; + } + } + + pthread_mutex_unlock(&mDataListenersMutex); +} + +void CTransportManager::stopConnection(const tConnectionHandle ConnectionHandle) +{ + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "Stopping data-callbacks thread"); + + SConnectionInfo* connectionInfo = getConnection(ConnectionHandle); + if(0 == connectionInfo) + { + //pthread_mutex_unlock(&mDataListenersMutex); + return; + } + else + { + connectionInfo->mTerminateFlag = true; + pthread_cond_signal(&connectionInfo->mConditionVar); + } +} + + +bool CTransportManager::isConnectionAvailable(const tConnectionHandle ConnectionHandle) +{ + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "Checking connection availability"); + + bool bConnectionExist = (mConnections.find(ConnectionHandle) != mConnections.end()); + + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "Result of checking is: " << bConnectionExist); + + return bConnectionExist; +} + +CTransportManager::SConnectionInfo* CTransportManager::getConnection(const tConnectionHandle ConnectionHandle) +{ + TM_CH_LOG4CPLUS_TRACE(mLogger, ConnectionHandle, "Checking connection availability"); + + if(ConnectionHandle == InvalidConnectionHandle) + { + TM_CH_LOG4CPLUS_WARN(mLogger, ConnectionHandle, "Trying to get connection for invalid handle."); + return 0; + } + + tConnectionsMap::iterator ConnectionIterator = mConnections.find(ConnectionHandle); + if(ConnectionIterator == mConnections.end()) + { + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Connection info was not found"); + return 0; + } + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Connection info was found"); + return ConnectionIterator->second; +} + + +void CTransportManager::addDeviceAdapter(IDeviceAdapter* DeviceAdapter) +{ + mDeviceAdapters.push_back(DeviceAdapter); + mDevicesByAdapter.insert(std::make_pair(DeviceAdapter, new tInternalDeviceList())); +} + +void CTransportManager::removeDeviceAdapter(IDeviceAdapter* DeviceAdapter) +{ + tDevicesByAdapterMap::iterator devicesIterator = mDevicesByAdapter.find(DeviceAdapter); + if(devicesIterator != mDevicesByAdapter.end()) + { + delete devicesIterator->second; + mDevicesByAdapter.erase(DeviceAdapter); + } +} + +void CTransportManager::initializeDeviceAdapters() +{ + addDeviceAdapter(new CBluetoothAdapter(*this, *this)); + addDeviceAdapter(new CTCPAdapter(*this, *this)); + LOG4CPLUS_INFO(mLogger, "Device adapters initialized"); +} + +void CTransportManager::sendDeviceListUpdatedCallback() +{ + LOG4CPLUS_INFO(mLogger, "Preparing complete device list from all adapters"); + + // Preparing complete device list + tDeviceList devices; + + tDevicesByAdapterMap::const_iterator deviceAdaptersIterator; + + pthread_mutex_lock(&mDevicesByAdapterMutex); + + for(deviceAdaptersIterator = mDevicesByAdapter.begin(); deviceAdaptersIterator != mDevicesByAdapter.end(); ++deviceAdaptersIterator) + { + IDeviceAdapter* pDeviceAdapter = deviceAdaptersIterator->first; + tInternalDeviceList *pDevices = deviceAdaptersIterator->second; + + LOG4CPLUS_INFO(mLogger, "Processing adapter with type: "<<pDeviceAdapter->getDeviceType()); + + tInternalDeviceList::const_iterator devicesInAdapterIterator; + for(devicesInAdapterIterator = pDevices->begin(); devicesInAdapterIterator != pDevices->end(); ++devicesInAdapterIterator) + { + SDeviceInfo deviceInfo; + + deviceInfo.mDeviceHandle = devicesInAdapterIterator->mDeviceHandle; + deviceInfo.mDeviceType = pDeviceAdapter->getDeviceType(); + deviceInfo.mUniqueDeviceId = devicesInAdapterIterator->mUniqueDeviceId; + deviceInfo.mUserFriendlyName = devicesInAdapterIterator->mUserFriendlyName; + + devices.push_back(deviceInfo); + + LOG4CPLUS_INFO(mLogger, "Processed device with unique Id: "<<devicesInAdapterIterator->mUniqueDeviceId << ", friendlyName: "<<devicesInAdapterIterator->mUserFriendlyName); + } + } + + LOG4CPLUS_INFO(mLogger, "Complete device list from all adapters was prepared. Preparing callback OnDeviceListUpdated for sending"); + + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + // Sending DeviceListUpdatedCallback + SDeviceListenerCallback cb(CTransportManager::DeviceListenerCallbackType_DeviceListUpdated, devices); + sendDeviceCallback(cb); + + LOG4CPLUS_INFO(mLogger, "Callback OnDeviceListUpdated was prepared for sending"); +} + +void CTransportManager::connectDisconnectDevice(const tDeviceHandle DeviceHandle, bool Connect) +{ + LOG4CPLUS_INFO(mLogger, "Performing "<<(Connect?"CONNECT":"DISCONNECT")<<" for device with handle: " << DeviceHandle); + LOG4CPLUS_INFO(mLogger, "Searching for device adapter for handling DeviceHandle: " << DeviceHandle); + + tDevicesByAdapterMap::const_iterator deviceAdaptersIterator; + + pthread_mutex_lock(&mDevicesByAdapterMutex); + + IDeviceAdapter* pDeviceAdapterToCall = 0; + + for(deviceAdaptersIterator = mDevicesByAdapter.begin(); deviceAdaptersIterator != mDevicesByAdapter.end(); ++deviceAdaptersIterator) + { + IDeviceAdapter* pDeviceAdapter = deviceAdaptersIterator->first; + tInternalDeviceList *pDevices = deviceAdaptersIterator->second; + + LOG4CPLUS_INFO(mLogger, "Processing adapter with type: "<<pDeviceAdapter->getDeviceType()); + + tInternalDeviceList::const_iterator devicesInAdapterIterator; + for(devicesInAdapterIterator = pDevices->begin(); devicesInAdapterIterator != pDevices->end(); ++devicesInAdapterIterator) + { + LOG4CPLUS_INFO(mLogger, "Processing device with unique Id: "<<devicesInAdapterIterator->mUniqueDeviceId << ", DeviceHandle: "<<devicesInAdapterIterator->mDeviceHandle); + if(devicesInAdapterIterator->mDeviceHandle == DeviceHandle) + { + LOG4CPLUS_INFO(mLogger, "DeviceHandle relates to adapter: "<<pDeviceAdapter->getDeviceType()); + pDeviceAdapterToCall = pDeviceAdapter; + } + } + } + + pthread_mutex_unlock(&mDevicesByAdapterMutex); + + if(0 != pDeviceAdapterToCall) + { + if(Connect) + { + pDeviceAdapterToCall->connectDevice(DeviceHandle); + } + else + { + pDeviceAdapterToCall->disconnectDevice(DeviceHandle); + } + LOG4CPLUS_INFO(mLogger, (Connect?"CONNECT":"DISCONNECT")<<" operation performed on device with handle: " << DeviceHandle); + } + else + { + LOG4CPLUS_WARN(mLogger, (Connect?"CONNECT":"DISCONNECT")<<" operation was not performed. Device handle was not found on any device: " << DeviceHandle); + } +} + +void CTransportManager::sendDataCallback(const CTransportManager::SDataListenerCallback& callback) +{ + TM_CH_LOG4CPLUS_INFO(mLogger, callback.mConnectionHandle, "Preparing callback of type: "<<callback.mCallbackType<<", to send"); + + SConnectionInfo* connectionInfo = getConnection(callback.mConnectionHandle); + if(0 == connectionInfo) + { + TM_CH_LOG4CPLUS_WARN(mLogger, callback.mConnectionHandle, "Connection information was not found"); + } + else + { + connectionInfo->mDataCallbacksVector.push_back(callback); + pthread_cond_signal(&connectionInfo->mConditionVar); + } +} + +void CTransportManager::sendDeviceCallback(const CTransportManager::SDeviceListenerCallback& callback) +{ + LOG4CPLUS_INFO(mLogger, "Sending new device callback. Type: " << callback.mCallbackType); + pthread_mutex_lock(&mDeviceListenersMutex); + + mDeviceListenersCallbacks.push_back(callback); + LOG4CPLUS_INFO(mLogger, "Device callback was added to pool"); + + pthread_cond_signal(&mDeviceListenersConditionVar); + + pthread_mutex_unlock(&mDeviceListenersMutex); + LOG4CPLUS_INFO(mLogger, "Triggering device callback processing"); +} + +CTransportManager::SFrameDataForConnection::SFrameDataForConnection(tConnectionHandle ConnectionHandle) +: mDataSize(0) +, mConnectionHandle(ConnectionHandle) +, mLogger(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TransportManager"))) +{ + mBufferSize = 1536; + mpDataBuffer = new uint8_t[mBufferSize]; + + TM_CH_LOG4CPLUS_INFO(mLogger, ConnectionHandle, "Initialized frame data for connection container"); +} + +CTransportManager::SFrameDataForConnection::~SFrameDataForConnection() +{ + if(0 != mpDataBuffer) + { + delete mpDataBuffer; + mpDataBuffer = 0; + } + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "Frame data for connection container destroyed"); +} + +void CTransportManager::SFrameDataForConnection::appendFrameData(const uint8_t* Data, size_t DataSize) +{ + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "Appending data to container. DataSize: " << DataSize); + + // Checking that data can be added to existing buffer + if( (mDataSize+DataSize) <= mBufferSize) + { + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "Data can be appended to existing buffer. Buffer size: "<<mBufferSize<<", Existing data size: "<<mDataSize<<", DataSize: " << DataSize); + memcpy(&mpDataBuffer[mDataSize], Data, DataSize); + mDataSize += DataSize; + } + else + { + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "Data cannot be appended to existing buffer. Buffer size: "<<mBufferSize<<", Existing data size: "<<mDataSize<<", DataSize: " << DataSize); + + // Currently memory for incoming data is allocated as sum of existing memory size and incoming data size. + // In the future depending of type and sizes of incoming data this algorithm can be changed + size_t newSize = mBufferSize + DataSize; + uint8_t *newBuffer = new uint8_t[newSize]; + + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "New buffer allocated. Buffer size: "<<newSize<<", was: "<<mBufferSize); + + memcpy(newBuffer, mpDataBuffer, mDataSize); + memcpy(&newBuffer[mDataSize], Data, DataSize); + delete mpDataBuffer; + mpDataBuffer = 0; // Paranoid mode on + + mpDataBuffer = newBuffer; + mDataSize = mDataSize+DataSize; + mBufferSize = newSize; + } + + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "Data appended. Buffer size: "<<mBufferSize<<", Existing data size: "<<mDataSize); +} + +bool CTransportManager::SFrameDataForConnection::extractFrame(uint8_t *& Data, size_t & DataSize) +{ + if(mDataSize < PROTOCOL_HEADER_V1_SIZE) + { + TM_CH_LOG4CPLUS_WARN(mLogger, mConnectionHandle, "Not enough data for version in the buffer. No changes was made. mDataSize: "<<mDataSize); + return false; + } + + // Extracting version + uint8_t firstByte = mpDataBuffer[0]; + uint8_t version = firstByte >> 4; + + uint8_t offset = sizeof(uint32_t); + uint32_t frameDataSize = mpDataBuffer[offset++] << 24; + frameDataSize |= mpDataBuffer[offset++] << 16; + frameDataSize |= mpDataBuffer[offset++] << 8; + frameDataSize |= mpDataBuffer[offset++]; + + size_t requiredDataSize = 0; + + if(version == PROTOCOL_VERSION_1) + { + requiredDataSize = (PROTOCOL_HEADER_V1_SIZE + frameDataSize); + } + else if(version == PROTOCOL_VERSION_2) + { + requiredDataSize = (PROTOCOL_HEADER_V2_SIZE + frameDataSize); + } + else + { + TM_CH_LOG4CPLUS_WARN(mLogger, mConnectionHandle, "Unsupported version received: " << (int)version); + return false; + } + + if(mDataSize < requiredDataSize) + { + TM_CH_LOG4CPLUS_WARN(mLogger, mConnectionHandle, "Frame canot be extracted. Its size: " << requiredDataSize << ", Available data size: "<<mDataSize); + return false; + } + + // Extracting frame from buffer + Data = new uint8_t[requiredDataSize]; + memcpy(Data, mpDataBuffer, requiredDataSize); + DataSize = requiredDataSize; + + // Shifting buffer + mDataSize -= requiredDataSize; + memmove(mpDataBuffer, &mpDataBuffer[requiredDataSize], mDataSize); + + return true; +} + + +NsSmartDeviceLink::NsTransportManager::CTransportManager::SFrameDataForConnection::SFrameDataForConnection(const SFrameDataForConnection& other) +: mDataSize(other.mDataSize) +, mBufferSize(other.mBufferSize) +, mConnectionHandle(other.mConnectionHandle) +, mLogger(log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("TransportManager"))) +{ + mpDataBuffer = new uint8_t[other.mBufferSize]; + memcpy(mpDataBuffer, other.mpDataBuffer, other.mBufferSize); + + TM_CH_LOG4CPLUS_INFO(mLogger, mConnectionHandle, "Initialized frame data for connection container"); +} + +bool NsSmartDeviceLink::NsTransportManager::CTransportManager::SFrameDataForConnection::operator==( const SFrameDataForConnection& i_other ) const +{ + return ( (mDataSize == i_other.mDataSize) + && (mBufferSize == i_other.mBufferSize) + && (mConnectionHandle == i_other.mConnectionHandle) + && (0 == memcmp(mpDataBuffer, i_other.mpDataBuffer, mBufferSize)) + ); +} + +CTransportManager::SConnectionInfo::SConnectionInfo(const tConnectionHandle ConnectionHandle, IDeviceAdapter & DeviceAdapter) +: mConnectionHandle(ConnectionHandle) +, mTerminateFlag(false) +, mDataCallbacksVector() +, mConnectionThread() +, mConditionVar() +, mpDeviceAdapter(DeviceAdapter) +, mFrameData(ConnectionHandle) +{ + pthread_cond_init(&mConditionVar, NULL); +} + +CTransportManager::SConnectionInfo::SConnectionInfo(const CTransportManager::SConnectionInfo& other) +: mConnectionHandle(other.mConnectionHandle) +, mTerminateFlag(other.mTerminateFlag) +, mDataCallbacksVector(other.mDataCallbacksVector) +, mConnectionThread(other.mConnectionThread) +, mConditionVar(other.mConditionVar) +, mpDeviceAdapter(other.mpDeviceAdapter) +, mFrameData(other.mFrameData) +{ + +} + +bool CTransportManager::SConnectionInfo::operator==(const CTransportManager::SConnectionInfo& i_other) const +{ + return ( (mConnectionHandle == i_other.mConnectionHandle) +// && (mTerminateFlag == i_other.mTerminateFlag) +// && (mDataCallbacksVector == i_other.mDataCallbacksVector) +// && (mConnectionThread == i_other.mConnectionThread) +// && (mConditionVar == i_other.mConditionVar) +// && (mpDeviceAdapter == i_other.mpDeviceAdapter) +// && (mFrameData == i_other.mFrameData) + ); +} + +CTransportManager::SConnectionInfo::~SConnectionInfo() +{ + pthread_cond_destroy(&mConditionVar); +} diff --git a/SDL_Core/src/components/TransportManager/src/CTransportManager.hpp b/SDL_Core/src/components/TransportManager/src/CTransportManager.hpp new file mode 100644 index 000000000..ec4062136 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/CTransportManager.hpp @@ -0,0 +1,837 @@ +/** + * \file CTransportManager.hpp + * \brief Class CTransportManager header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_CTRANSPORTMANAGER_HPP__ +#define __TRANSPORTMANAGER_CTRANSPORTMANAGER_HPP__ + +#include "TransportManager/ITransportManager.hpp" +#include "IDeviceAdapterListener.hpp" +#include "IHandleGenerator.hpp" +#include "Logger.hpp" + +#include <pthread.h> +#include <vector> + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + class IDeviceAdapter; + + // Some constants + + const uint8_t PROTOCOL_HEADER_V1_SIZE = 8; + const uint8_t PROTOCOL_HEADER_V2_SIZE = 12; + + const uint8_t PROTOCOL_VERSION_1 = 1; + const uint8_t PROTOCOL_VERSION_2 = 2; + + // Class definition + + /** + * @brief Transport manager implementation. + * + * Potential future optimizations: + * + * @todo Potential future optimization: Add shutdown flag checking inside client interface function calls + * @todo Potential future optimization: Implement more thread-safe processing of shutdown flag + * @todo Potential future optimization: Move ITransportManagerDeviceListener::onApplicationConnected and + * ITransportManagerDeviceListener::onApplicationDisconnected callbacks calling to corresponded connection thread + * + * @todo Potential future optimization: Currently all frames processed in one thread. In the future processing of them + * can be moved to the thread, which sent callbacks for corresponded connection. + * + * @todo Potential future optimization: Currently it is not possible to validate incoming frame data. Some kind of data + * validation can be implemented and if incoming data is invalid one of the possible solutions is to close + * corresponded connection + **/ + class CTransportManager: public ITransportManager, + public IDeviceAdapterListener, + public IHandleGenerator + { + public: + /** + * @brief Constructor. + **/ + CTransportManager(void); + + /** + * @brief Destructor. + **/ + virtual ~CTransportManager(void); + + /** + * @brief Run transport manager. + * + * Must be called from startup after all references to + * external components are initialized to start trasport manager. + **/ + virtual void run(void); + + /** + * @brief Start scanning for new devices. + * + * List of new devices will be supplied in onDeviceListUpdated callback. + **/ + virtual void scanForNewDevices(void); + + /** + * @brief Connect to all applications discovered on device. + * + * @param DeviceHandle Handle of device to connect to. + **/ + virtual void connectDevice(const tDeviceHandle DeviceHandle); + + /** + * @brief Disconnect from all applications connected on device. + * + * @param DeviceHandle Handle of device to disconnect from. + **/ + virtual void disconnectDevice(const tDeviceHandle DeviceHandle); + + /** + * @brief Add listener to the data-related events + * + * @param Listener Pointer to listener. + **/ + virtual void addDataListener(ITransportManagerDataListener * Listener); + + /** + * @brief Remove listener to the data-related events. + * + * @param Listener Pointer to listener. + **/ + virtual void removeDataListener(ITransportManagerDataListener * Listener); + + /** + * @brief Add listener to the device-related events. + * + * @param Listener Pointer to listener. + **/ + virtual void addDeviceListener(ITransportManagerDeviceListener * Listener); + + /** + * @brief Remove listenerto the device-related events. + * + * @param Listener Pointer to listener. + **/ + virtual void removeDeviceListener(ITransportManagerDeviceListener * Listener); + + /** + * @brief Send frame. + * + * @param ConnectionHandle Connection handle. + * @param Data Frame payload data. + * @param DataSize Size of data in bytes. + * @param UserData Any user data. Will be returned as is in ITransportManagerDataListener::onFrameSendCompleted + **/ + virtual void sendFrame(tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize, const int UserData); + + /** + * @brief Generate new device handle. + * + * Internal method used for generation of unique device handle + * for device adapters. + * + * @return New device handle. + **/ + virtual tDeviceHandle generateNewDeviceHandle(void); + + /** + * @brief Generate new connection handle. + * + * Internal method used for generation of unique connection handle + * for device adapters. + * + * @return New connection handle. + **/ + virtual tConnectionHandle generateNewConnectionHandle(void); + + // Handling Device Adapters callbacks + + /** + * @brief Available devices list updated callback. + * + * @param DeviceAdapter Calling device adapter. + * @param DeviceList New list of available devices. + **/ + virtual void onDeviceListUpdated(IDeviceAdapter * DeviceAdapter, const tInternalDeviceList & DeviceList); + + /** + * @brief Application connected callback. + * + * @param ConnectedDevice DeviceInfo of device with connected application. + * @param Connection Connection handle. + **/ + virtual void onApplicationConnected(IDeviceAdapter * DeviceAdapter, const SDeviceInfo & ConnectedDevice, const tConnectionHandle ConnectionHandle); + + /** + * @brief Application disconnected callback. + * + * @param ConnectedDevice DeviceInfo of device with connected application. + * @param Connection Connection handle. + **/ + virtual void onApplicationDisconnected(IDeviceAdapter * DeviceAdapter, const SDeviceInfo & DisconnectedDevice, const tConnectionHandle ConnectionHandle); + + /** + * @brief Frame received callback. + * + * @param DeviceAdapter Calling device adapter. + * @param ConnectionHandle Connection handle. + * @param Data Received frame data. + * @param DataSize Size of received data in bytes. + * + * @note %Data pointed by parameter Data is valid only until + * this callback returns control to the caller. Callback + * handler is responsible to copy this data to its own + * location if it needs the data after return. + **/ + virtual void onFrameReceived(IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize); + + /** + * @brief Frame send completed callback. + * + * @param DeviceAdapter Calling device adapter. + * @param ConnectionHandle Connection handle. + * @param UserData User data that was previously passed to ITransportManager::sendFrame. + * @param SendStatus Result status. + **/ + virtual void onFrameSendCompleted(IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, int UserData, ESendStatus SendStatus); + + protected: + + /** + * @brief Enumeration that represents type of the device listener callback + * that must be called + **/ + enum EDeviceListenerCallbackType + { + DeviceListenerCallbackType_DeviceListUpdated = 0, + DeviceListenerCallbackType_ApplicationConnected = 1, + DeviceListenerCallbackType_ApplicationDisconnected = 2 + }; + + /** + * @brief Enumeration that represents type of the data listener callback + * that must be called + **/ + enum EDataListenerCallbackType + { + DataListenerCallbackType_FrameReceived = 0, + DataListenerCallbackType_FrameSendCompleted = 1 + }; + + /** + * @brief Device listener callback information + * + * Used to store data for calling device listeners + **/ + struct SDeviceListenerCallback + { + /** + * @brief Constructor for creating DeviceListUpdated callback. + * + * @param CallbackType Type of the callback + * @param DeviceList Device list + **/ + SDeviceListenerCallback(EDeviceListenerCallbackType CallbackType, const tDeviceList & DeviceList); + + /** + * @brief Constructor for creating ApplicationConnected and ApplicationDisconnected callbacks + * + * @param CallbackType Type of the callback + * @param DeviceInfo Device information + * @param ConnectionHandle Connection handle + **/ + SDeviceListenerCallback(EDeviceListenerCallbackType CallbackType, const SDeviceInfo & DeviceInfo, const tConnectionHandle & ConnectionHandle); + + /** + * @brief Copy constructor + * + * @param other Reference to object to be copied + **/ + SDeviceListenerCallback(const SDeviceListenerCallback& other); + + /** + * @brief Comparison operator. + * + * @param i_other Reference to the object to be compared with + * @return bool + **/ + bool operator==( const SDeviceListenerCallback& i_other ) const; + + /** + * @brief Destructor. + * + **/ + ~SDeviceListenerCallback(void); + + /** + * @brief Type of the callback that must be called + **/ + EDeviceListenerCallbackType mCallbackType; + + /** + * @brief Device list (will be sent in the DeviceListUpdated callback) + **/ + tDeviceList mDeviceList; + + /** + * @brief Device information (will be sent in the ApplicationConnected and ApplicationDisconnected callbacks) + **/ + SDeviceInfo mDeviceInfo; + + /** + * @brief Connection handle (will be sent in the ApplicationConnected and ApplicationDisconnected callbacks) + **/ + tConnectionHandle mConnectionHandle; + }; + + /** + * @brief Data listener callback information + * + * Used to store data for calling data listeners + **/ + struct SDataListenerCallback + { + /** + * @brief Constructor for creating FrameReceived callback. + * + * @param CallbackType Type of the callback + * @param ConnectionHandle Connection handle + * @param Data Data + * @param DataSize Size of the data + **/ + SDataListenerCallback(NsSmartDeviceLink::NsTransportManager::CTransportManager::EDataListenerCallbackType CallbackType, NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle, const uint8_t* Data, size_t DataSize); + + /** + * @brief Constructor for creating FrameSendCompleted callback + * + * @param CallbackType Type of the callback + * @param ConnectionHandle Connection handle + * @param UserData User data + * @param SendStatus Status of operation + **/ + SDataListenerCallback(EDataListenerCallbackType CallbackType, tConnectionHandle ConnectionHandle, int UserData, ESendStatus SendStatus); + + /** + * @brief Copy constructor + * + * @param other Reference to object to be copied + **/ + SDataListenerCallback(const SDataListenerCallback& other); + + /** + * @brief Comparison operator. + * + * @param i_other Reference to the object to be compared with + * @return bool + **/ + bool operator==( const SDataListenerCallback& i_other ) const; + + /** + * @brief Destructor. + * + **/ + ~SDataListenerCallback(void); + + /** + * @brief Type of the callback that must be called + **/ + EDataListenerCallbackType mCallbackType; + + /** + * @brief Connection handle (will be sent in the ApplicationConnected and ApplicationDisconnected callbacks) + **/ + tConnectionHandle mConnectionHandle; + + /** + * @brief Data to send + **/ + uint8_t * mData; + + /** + * @brief Size of the data + **/ + size_t mDataSize; + + /** + * @brief User data + **/ + int mUserData; + + /** + * @brief Operation status + **/ + ESendStatus mSendStatus; + }; + + /** + * @brief Struct that contains startup params for data-threads + **/ + struct SDataThreadStartupParams + { + /** + * @brief Constructor + * + * @param TransportManager Pointer to the Transport Manager + * @param ConnectionHandle Connection Handle + **/ + SDataThreadStartupParams(NsSmartDeviceLink::NsTransportManager::CTransportManager* TransportManager, NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle); + + /** + * @brief Pointer to Transport Manager + **/ + CTransportManager * mTransportManager; + + /** + * @brief Connection Handle + **/ + tConnectionHandle mConnectionHandle; + }; + + /** + * @brief Incapsulates frame data for each connection + * + **/ + struct SFrameDataForConnection + { + /** + * @brief Constructor + * + **/ + SFrameDataForConnection(tConnectionHandle ConnectionHandle); + + /** + * @brief Destructor + * + **/ + ~SFrameDataForConnection(); + + /** + * @brief Copy constructor + * + * @param other Reference to object to be copied + **/ + SFrameDataForConnection(const SFrameDataForConnection& other); + + /** + * @brief Comparison operator. + * + * @param i_other Reference to the object to be compared with + * @return bool + **/ + bool operator==( const SFrameDataForConnection& i_other ) const; + + /** + * @brief Appends new data to the buffer + * + * @param Data Data to append + * @param DataSize Size of data + * @return void + **/ + void appendFrameData(const uint8_t * Data, size_t DataSize); + + /** + * @brief Extracts single frame and returns it + * + * @param[out] Data Pointer to the frame data + * @param[out] size_t Size of the returned frame. + * + * @return bool Result of extract operation + * + * @warning Memory for this buffer is allocated in the method call but must be freed + * when it does not needed by caller component ONLY if method returns true + **/ + bool extractFrame(uint8_t *& Data, size_t & DataSize); + + /** + * @brief Pointer to the data buffer + **/ + uint8_t *mpDataBuffer; + + /** + * @brief Size of the data in the buffer + **/ + size_t mDataSize; + + /** + * @brief Size of the data buffer + **/ + size_t mBufferSize; + + /** + * @brief Handle of the connection + * + * @note Used only for debugging purposes + **/ + tConnectionHandle mConnectionHandle; + + /** + * @brief Logger + **/ + Logger mLogger; + }; + + /** + * @brief Vector for storing Data Callbacks. + **/ + typedef std::vector<SDataListenerCallback> tDataCallbacksVector; + + /** + * @brief Struct for storing information, related to single connection + **/ + struct SConnectionInfo + { + /** + * @brief Constructor. + * + * @param ConnectionHandle Connection handle. + * @param DeviceAdapter Device adapter + **/ + SConnectionInfo(const tConnectionHandle ConnectionHandle, IDeviceAdapter & DeviceAdapter); + + /** + * @brief Copy constructor + * + * @param other Reference to object to be copied + **/ + SConnectionInfo(const SConnectionInfo& other); + + /** + * @brief Comparison operator. + * + * @param i_other Reference to the object to be compared with + * @return bool + **/ + bool operator==( const SConnectionInfo& i_other ) const; + + /** + * @brief Destructor + * + **/ + virtual ~SConnectionInfo(); + + /** + * @brief Connection handle, associated with connection information + **/ + const tConnectionHandle mConnectionHandle; + + /** + * @brief Terminate flag. + * + * This flag is set to notify connection thread that connection + * must be closed and connection thread must be terminated. + **/ + bool mTerminateFlag; + + /** + * @brief Callbacks for sending + **/ + tDataCallbacksVector mDataCallbacksVector; + + /** + * @brief Thread handle + **/ + pthread_t mConnectionThread; + + /** + * @brief Condition variable. Used for waiting for callbacks data + **/ + pthread_cond_t mConditionVar; + + /** + * @brief Device adapter, which opened connection + **/ + IDeviceAdapter& mpDeviceAdapter; + + /** + * @brief Frame data + **/ + SFrameDataForConnection mFrameData; + }; + + /** + * @brief Connections map + **/ + typedef std::map<tConnectionHandle, SConnectionInfo*> tConnectionsMap; + + /** + * @brief Map for storing available devices for each device adapter + **/ + typedef std::map<IDeviceAdapter*, tInternalDeviceList*> tDevicesByAdapterMap; + + /** + * @brief Start routine for Application-related callbacks. + * + * @param Data Must be pointer to CTransportManager instance. + * + * @return Thread return value. + **/ + static void * applicationCallbacksThreadStartRoutine(void * Data); + + /** + * @brief Application-related callbacks thread. + * + * From this thread all application-related callbacks are called + * + **/ + void applicationCallbacksThread(); + + /** + * @brief Start routine for Data-related callbacks. + * + * @param Data Must be pointer to CTransportManager instance. + * + * @return Thread return value. + **/ + static void * dataCallbacksThreadStartRoutine(void * Data); + + /** + * @brief Data-related callbacks thread. + * + * From this thread all data-related callbacks related to given connection handle are called + * + * @param ConnectionHandle Connection handle + **/ + void dataCallbacksThread(const tConnectionHandle ConnectionHandle); + + /** + * @brief Starts thread for application-related callbacks + * + **/ + void startApplicationCallbacksThread(); + + /** + * @brief Stops thread for application-related callbacks + * + * @return void + * @warning terminate flag must be set to true before calling this function + **/ + void stopApplicationCallbacksThread(); + + /** + * @brief Starts thread for data-related callbacks for given connection handle + * + * @param ConnectionHandle Connection Handle + * @return bool + **/ + void startConnection(const tConnectionHandle ConnectionHandle, IDeviceAdapter& DeviceAdapter); + + /** + * @brief Stops thread for data-related callbacks for given connection handle + * + * @param ConnectionHandle Connection Handle + * @return void + * @warning terminate flag must be set to true before calling this function + **/ + void stopConnection(const tConnectionHandle ConnectionHandle); + + /** + * @brief Check thread existence for given ConnectionHandle + * + * @param ConnectionHandle Connection Handle + * @return bool + * + * @attention This function is not thread safe + **/ + bool isConnectionAvailable(const tConnectionHandle ConnectionHandle); + + /** + * @brief Returns connection information by Connection Handle + * + * @param ConnectionHandle Connection handle + * @return SConnectionInfo* + **/ + SConnectionInfo* getConnection(const tConnectionHandle ConnectionHandle); + + /** + * @brief Adds new device adapter + * + * @param DeviceAdapter Device adapter to add + * @return void + **/ + void addDeviceAdapter(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter* DeviceAdapter); + + /** + * @brief Removes device adapter + * + * @note This function does not deletes DeviceAdapter pointer + * + * @param DeviceAdapter Device adapter to remove + * @return void + **/ + void removeDeviceAdapter(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter* DeviceAdapter); + + /** + * @brief All device adapters initialized here + * + * @return void + **/ + virtual void initializeDeviceAdapters(); + + /** + * @brief Sends callback DeviceListUpdated to subscribers + * + * @return void + * @attention This function is not thread safe + **/ + void sendDeviceListUpdatedCallback(); + + /** + * @brief Connects and disconnects device by its handle + * + * @param DeviceHandle Handle of the device to connect or disconnect + * @param Connect Flag of device operation: true for connect, false for disconnect. Defaults to true. + * @return void + **/ + void connectDisconnectDevice(const NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle, bool Connect = true); + + /** + * @brief Sends data callback + * + * @attention This function is not thread-safe + * @param callback Callback to send + * @return void + **/ + void sendDataCallback(const SDataListenerCallback& callback); + + /** + * @brief Sends device callback + * + * @param callback Callback to send + * @return void + **/ + void sendDeviceCallback(const SDeviceListenerCallback& callback); + + /** + * @brief Device adapters. + **/ + std::vector<IDeviceAdapter*> mDeviceAdapters; + + /** + * @brief Logger. + **/ + const log4cplus::Logger mLogger; + + /** + * @brief Mutex restricting access to data listeners. + **/ + mutable pthread_mutex_t mDataListenersMutex; + + /** + * @brief Mutex restricting access to device listeners. + **/ + mutable pthread_mutex_t mDeviceListenersMutex; + + /** + * @brief Mutex restricting access to new device handle generation + **/ + mutable pthread_mutex_t mDeviceHandleGenerationMutex; + + /** + * @brief Mutex restricting access to new conenction handle generation + **/ + mutable pthread_mutex_t mConnectionHandleGenerationMutex; + + /** + * @brief Data listeners + **/ + std::vector<ITransportManagerDataListener*> mDataListeners; + + /** + * @brief Device listeners + **/ + std::vector<ITransportManagerDeviceListener*> mDeviceListeners; + + /** + * @brief Last used device handle + * + * Used during device handle generation + **/ + tDeviceHandle mLastUsedDeviceHandle; + + /** + * @brief Last used connection handle + * + * Used during connection handle generation + **/ + tConnectionHandle mLastUsedConnectionHandle; + + /** + * @brief ID of thread, which sends Application-related callbacks + **/ + pthread_t mApplicationCallbacksThread; + + /** + * @brief Condition variable used for device listeners callbacks synchronization + **/ + pthread_cond_t mDeviceListenersConditionVar; + + /** + * @brief Vector of the device listeners callbacks to call + **/ + std::vector<SDeviceListenerCallback> mDeviceListenersCallbacks; + + /** + * @brief Terminate flag. + * + * This flag is set to notify threads that they must be terminated. + **/ + bool mTerminateFlag; + + /** + * @brief Devices for each adapter + **/ + tDevicesByAdapterMap mDevicesByAdapter; + + /** + * @brief Mutex restricting access to devices information for each adapter + **/ + mutable pthread_mutex_t mDevicesByAdapterMutex; + + /** + * @brief Connections + **/ + tConnectionsMap mConnections; + + /** + * @brief Mutex restricting access to client interface + **/ + mutable pthread_mutex_t mClientInterfaceMutex; + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/IDeviceAdapter.cpp b/SDL_Core/src/components/TransportManager/src/IDeviceAdapter.cpp new file mode 100644 index 000000000..3d45feecd --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/IDeviceAdapter.cpp @@ -0,0 +1,39 @@ +/** + * \file IDeviceAdapter.cpp + * \brief Class IDeviceAdapter. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IDeviceAdapter.hpp" + +NsSmartDeviceLink::NsTransportManager::IDeviceAdapter::~IDeviceAdapter(void) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/IDeviceAdapter.hpp b/SDL_Core/src/components/TransportManager/src/IDeviceAdapter.hpp new file mode 100644 index 000000000..ec27f7c0a --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/IDeviceAdapter.hpp @@ -0,0 +1,109 @@ +/** + * \file IDeviceAdapter.hpp + * \brief Class IDeviceAdapter header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_IDEVICEADAPTER_HPP__ +#define __TRANSPORTMANAGER_IDEVICEADAPTER_HPP__ + +#include <stdint.h> +#include <sys/types.h> +#include <vector> + +#include "TransportManager/ITransportManager.hpp" +#include "SInternalDeviceInfo.hpp" + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + /** + * @brief Interface for device adapter. + * @interface IDeviceAdapter + **/ + class IDeviceAdapter + { + public: + /** + * @brief Destructor. + **/ + virtual ~IDeviceAdapter(void); + + /** + * @brief Run device adapter. + * + * Called from transport manager to start device adapter. + **/ + virtual void run(void) = 0; + + /** + * @brief Start scanning for new devices. + * + * List of new devices will be supplied in onDeviceListUpdated callback. + **/ + virtual void scanForNewDevices(void) = 0; + + /** + * @brief Connect to all applications discovered on device. + * + * @param DeviceHandle Handle of device to connect to. + **/ + virtual void connectDevice(const tDeviceHandle DeviceHandle) = 0; + + /** + * @brief Disconnect from all applications connected on device. + * + * @param DeviceHandle Handle of device to disconnect from. + **/ + virtual void disconnectDevice(const tDeviceHandle DeviceHandle) = 0; + + /** + * @brief Get type of devices handled by this device adapter. + * + * @return Device type. + **/ + virtual EDeviceType getDeviceType(void) const = 0; + + /** + * @brief Send frame. + * + * @param ConnectionHandle Connection handle. + * @param Data Frame payload data. + * @param DataSize Size of data in bytes. + * @param UserData Any user data. Will be returned as is in ITransportManagerDataListener::onFrameSendCompleted + **/ + virtual void sendFrame(tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize, int UserData) = 0; + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/IDeviceAdapterListener.cpp b/SDL_Core/src/components/TransportManager/src/IDeviceAdapterListener.cpp new file mode 100644 index 000000000..d6bc0cce3 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/IDeviceAdapterListener.cpp @@ -0,0 +1,59 @@ +/** + * \file IDeviceAdapterListener.cpp + * \brief Class IDeviceAdapterListener. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IDeviceAdapterListener.hpp" + +NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener::~IDeviceAdapterListener(void ) +{ +} + +void NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener::onDeviceListUpdated(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter * DeviceAdapter, const NsSmartDeviceLink::NsTransportManager::tInternalDeviceList & DeviceList) +{ +} + +void NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener::onApplicationConnected(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter * DeviceAdapter, const NsSmartDeviceLink::NsTransportManager::SDeviceInfo & ConnectedDevice, const NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle) +{ +} + +void NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener::onApplicationDisconnected(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter * DeviceAdapter, const NsSmartDeviceLink::NsTransportManager::SDeviceInfo & DisconnectedDevice, const NsSmartDeviceLink::NsTransportManager::tConnectionHandle ConnectionHandle) +{ +} + +void NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener::onFrameReceived(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize) +{ +} + +void NsSmartDeviceLink::NsTransportManager::IDeviceAdapterListener::onFrameSendCompleted(NsSmartDeviceLink::NsTransportManager::IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, int FrameSequenceNumber, ESendStatus SendStatus) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/IDeviceAdapterListener.hpp b/SDL_Core/src/components/TransportManager/src/IDeviceAdapterListener.hpp new file mode 100644 index 000000000..be16bc847 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/IDeviceAdapterListener.hpp @@ -0,0 +1,126 @@ +/** + * \file IDeviceAdapterListener.hpp + * \brief Class IDeviceAdapterListener. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_IDEVICEADAPTERLISTENER_HPP__ +#define __TRANSPORTMANAGER_IDEVICEADAPTERLISTENER_HPP__ + +#include <stdint.h> +#include <sys/types.h> +#include <vector> + +#include "TransportManager/ITransportManager.hpp" +#include "TransportManager/ITransportManagerDataListener.hpp" +#include "TransportManager/ITransportManagerDeviceListener.hpp" + +#include "SInternalDeviceInfo.hpp" + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + class IDeviceAdapter; + + /** + * @brief Interface of device adapter listener. + * + * Used to notify transport manager about events in + * device adapters. + * @interface IDeviceAdapterListener + **/ + class IDeviceAdapterListener + { + public: + /** + * @brief Destructor. + **/ + virtual ~IDeviceAdapterListener(void); + + /** + * @brief Available devices list updated callback. + * + * Called when device scanning initiated with scanForNewDevices + * is completed. + * + * @param DeviceAdapter Calling device adapter. + * @param DeviceList New list of available devices. + **/ + virtual void onDeviceListUpdated(IDeviceAdapter * DeviceAdapter, const tInternalDeviceList & DeviceList); + + /** + * @brief Application connected callback. + * + * @param DeviceAdapter Device adapter + * @param ConnectedDevice DeviceInfo of device with connected application. + * @param Connection Connection handle. + **/ + virtual void onApplicationConnected(IDeviceAdapter * DeviceAdapter, const SDeviceInfo & ConnectedDevice, const tConnectionHandle ConnectionHandle); + + /** + * @brief Application disconnected callback. + * + * @param DeviceAdapter Device adapter + * @param ConnectedDevice DeviceInfo of device with connected application. + * @param Connection Connection handle. + **/ + virtual void onApplicationDisconnected(IDeviceAdapter * DeviceAdapter, const SDeviceInfo & DisconnectedDevice, const tConnectionHandle ConnectionHandle); + + /** + * @brief Frame received callback. + * + * @param DeviceAdapter Calling device adapter. + * @param ConnectionHandle Connection handle. + * @param Data Received frame data. + * @param DataSize Size of received data in bytes. + * + * @note %Data pointed by parameter Data is valid only until + * this callback returns control to the caller. Callback + * handler is responsible to copy this data to its own + * location if it needs the data after return. + **/ + virtual void onFrameReceived(IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize); + + /** + * @brief Frame send completed callback. + * + * @param DeviceAdapter Calling device adapter. + * @param ConnectionHandle Connection handle. + * @param FrameSequenceNumber Sequence numbere of frame that was previously returned by ITransportManager::sendFrame. + * @param SendStatus Result status. + **/ + virtual void onFrameSendCompleted(IDeviceAdapter * DeviceAdapter, tConnectionHandle ConnectionHandle, int FrameSequenceNumber, ESendStatus SendStatus); + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/IHandleGenerator.cpp b/SDL_Core/src/components/TransportManager/src/IHandleGenerator.cpp new file mode 100644 index 000000000..9b4dce66c --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/IHandleGenerator.cpp @@ -0,0 +1,39 @@ +/** + * \file IHandleGenerator.cpp + * \brief Class IHandleGenerator. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IHandleGenerator.hpp" + +NsSmartDeviceLink::NsTransportManager::IHandleGenerator::~IHandleGenerator(void) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/IHandleGenerator.hpp b/SDL_Core/src/components/TransportManager/src/IHandleGenerator.hpp new file mode 100644 index 000000000..a820c6e4a --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/IHandleGenerator.hpp @@ -0,0 +1,79 @@ +/** + * \file IHandleGenerator.hpp + * \brief Class IHandleGenerator. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_IHANDLEGENERATOR_HPP__ +#define __TRANSPORTMANAGER_IHANDLEGENERATOR_HPP__ + +#include "TransportManager/ITransportManager.hpp" + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + /** + * @brief Interface for handle generator. + * @interface IHandleGenerator + **/ + class IHandleGenerator + { + public: + /** + * @brief Destructor. + **/ + virtual ~IHandleGenerator(void); + + /** + * @brief Generate new device handle. + * + * Internal method used for generation of unique device handle + * for device adapters. + * + * @return New device handle. + **/ + virtual tDeviceHandle generateNewDeviceHandle(void) = 0; + + /** + * @brief Generate new connection handle. + * + * Internal method used for generation of unique connection handle + * for device adapters. + * + * @return New connection handle. + **/ + virtual tConnectionHandle generateNewConnectionHandle(void) = 0; + }; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/ITransportManager.cpp b/SDL_Core/src/components/TransportManager/src/ITransportManager.cpp new file mode 100644 index 000000000..5406265fc --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/ITransportManager.cpp @@ -0,0 +1,44 @@ +/** + * \file ITransportManager.cpp + * \brief Class ITransportManager. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CTransportManager.hpp" + +NsSmartDeviceLink::NsTransportManager::ITransportManager * NsSmartDeviceLink::NsTransportManager::ITransportManager::create(void) +{ + return new CTransportManager(); +} + +NsSmartDeviceLink::NsTransportManager::ITransportManager::~ITransportManager(void) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/ITransportManagerDataListener.cpp b/SDL_Core/src/components/TransportManager/src/ITransportManagerDataListener.cpp new file mode 100644 index 000000000..3ed2a9aa9 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/ITransportManagerDataListener.cpp @@ -0,0 +1,47 @@ +/** + * \file ITransportManagerDataListener.cpp + * \brief Class ITransportManagerDataListener. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TransportManager/ITransportManagerDataListener.hpp" + +NsSmartDeviceLink::NsTransportManager::ITransportManagerDataListener::~ITransportManagerDataListener() +{ +} + +void NsSmartDeviceLink::NsTransportManager::ITransportManagerDataListener::onFrameReceived(tConnectionHandle ConnectionHandle, const uint8_t * Data, size_t DataSize) +{ +} + +void NsSmartDeviceLink::NsTransportManager::ITransportManagerDataListener::onFrameSendCompleted(tConnectionHandle ConnectionHandle, int FrameSequenceNumber, ESendStatus SendStatus) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/ITransportManagerDeviceListener.cpp b/SDL_Core/src/components/TransportManager/src/ITransportManagerDeviceListener.cpp new file mode 100644 index 000000000..abdacb781 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/ITransportManagerDeviceListener.cpp @@ -0,0 +1,52 @@ +/** + * \file ITransportManagerDeviceListener.cpp + * \brief Class ITransportManagerDeviceListener. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TransportManager/ITransportManagerDeviceListener.hpp" + +NsSmartDeviceLink::NsTransportManager::ITransportManagerDeviceListener::~ITransportManagerDeviceListener() +{ + +} + +void NsSmartDeviceLink::NsTransportManager::ITransportManagerDeviceListener::onDeviceListUpdated(const tDeviceList & DeviceList) +{ +} + +void NsSmartDeviceLink::NsTransportManager::ITransportManagerDeviceListener::onApplicationConnected(const SDeviceInfo & ConnectedDevice, const tConnectionHandle Connection) +{ +} + +void NsSmartDeviceLink::NsTransportManager::ITransportManagerDeviceListener::onApplicationDisconnected(const SDeviceInfo & DisconnectedDevice, const tConnectionHandle Connection) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/SDeviceInfo.cpp b/SDL_Core/src/components/TransportManager/src/SDeviceInfo.cpp new file mode 100644 index 000000000..6fda35517 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/SDeviceInfo.cpp @@ -0,0 +1,67 @@ +/** + * \file SDeviceInfo.cpp + * \brief Class SDeviceInfo. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TransportManager/SDeviceInfo.hpp" + +NsSmartDeviceLink::NsTransportManager::SDeviceInfo::SDeviceInfo() +: mDeviceHandle() +, mDeviceType() +, mUserFriendlyName() +, mUniqueDeviceId() +{ +} + +NsSmartDeviceLink::NsTransportManager::SDeviceInfo::SDeviceInfo(tDeviceHandle DeviceHandle, EDeviceType DeviceType, std::string UserFriendlyName, std::string UniqueDeviceId) +: mDeviceHandle(DeviceHandle) +, mDeviceType(DeviceType) +, mUserFriendlyName(UserFriendlyName) +, mUniqueDeviceId(UniqueDeviceId) +{ +} + +NsSmartDeviceLink::NsTransportManager::SDeviceInfo::SDeviceInfo(const SDeviceInfo& other) +: mDeviceHandle(other.mDeviceHandle) +, mDeviceType(other.mDeviceType) +, mUserFriendlyName(other.mUserFriendlyName) +, mUniqueDeviceId(other.mUniqueDeviceId) +{ +} + +bool NsSmartDeviceLink::NsTransportManager::SDeviceInfo::operator==( const SDeviceInfo& i_other ) const +{ + return ( (mDeviceHandle == i_other.mDeviceHandle) + && (mDeviceType == i_other.mDeviceType) + && (mUserFriendlyName == i_other.mUserFriendlyName) + && (mUniqueDeviceId == i_other.mUniqueDeviceId)); +} diff --git a/SDL_Core/src/components/TransportManager/src/SInternalDeviceInfo.cpp b/SDL_Core/src/components/TransportManager/src/SInternalDeviceInfo.cpp new file mode 100644 index 000000000..4b7d8753f --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/SInternalDeviceInfo.cpp @@ -0,0 +1,49 @@ +/** + * \file SInternalDeviceInfo.cpp + * \brief Class SInternalDeviceInfo. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SInternalDeviceInfo.hpp" + +NsSmartDeviceLink::NsTransportManager::SInternalDeviceInfo::SInternalDeviceInfo(void): +mDeviceHandle(NsSmartDeviceLink::NsTransportManager::InvalidDeviceHandle), +mUserFriendlyName(), +mUniqueDeviceId() +{ +} + +NsSmartDeviceLink::NsTransportManager::SInternalDeviceInfo::SInternalDeviceInfo(NsSmartDeviceLink::NsTransportManager::tDeviceHandle DeviceHandle, const std::string & UserFriendlyName, const std::string & UniqueDeviceId): +mDeviceHandle(DeviceHandle), +mUserFriendlyName(UserFriendlyName), +mUniqueDeviceId(UniqueDeviceId) +{ +} diff --git a/SDL_Core/src/components/TransportManager/src/SInternalDeviceInfo.hpp b/SDL_Core/src/components/TransportManager/src/SInternalDeviceInfo.hpp new file mode 100644 index 000000000..ee95588be --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/SInternalDeviceInfo.hpp @@ -0,0 +1,88 @@ +/** + * \file SInternalDeviceInfo.hpp + * \brief Class SInternalDeviceInfo header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_SINTERNALDEVICEINFO_HPP__ +#define __TRANSPORTMANAGER_SINTERNALDEVICEINFO_HPP__ + +#include <vector> + +#include "TransportManager/SDeviceInfo.hpp" + +namespace NsSmartDeviceLink +{ + namespace NsTransportManager + { + /** + * @brief Internal device information. + **/ + struct SInternalDeviceInfo + { + /** + * @brief Default constructor. + **/ + SInternalDeviceInfo(void); + + /** + * @brief Constructor. + * + * @param DeviceHandle Device handle. + * @param UserFriendlyName User-friendly device name. + * @param UniqueDeviceId Unique device identifier across all devices. + **/ + SInternalDeviceInfo(tDeviceHandle DeviceHandle, const std::string & UserFriendlyName, const std::string & UniqueDeviceId); + + /** + * @brief Device handle. + **/ + tDeviceHandle mDeviceHandle; + + /** + * @brief User-friendly device name. + **/ + std::string mUserFriendlyName; + + /** + * @brief Unique device identifier across all devices. + **/ + std::string mUniqueDeviceId; + }; + + /** + * @brief List of internal devices. + **/ + typedef std::vector<SInternalDeviceInfo> tInternalDeviceList; + } +} + +#endif diff --git a/SDL_Core/src/components/TransportManager/src/TransportManagerLoggerHelpers.hpp b/SDL_Core/src/components/TransportManager/src/TransportManagerLoggerHelpers.hpp new file mode 100644 index 000000000..b9578b292 --- /dev/null +++ b/SDL_Core/src/components/TransportManager/src/TransportManagerLoggerHelpers.hpp @@ -0,0 +1,53 @@ +/** + * \file TransportManagerLoggerHelpers.hpp + * \brief Class TransportManagerLoggerHelpers header. + * Copyright (c) 2013, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TRANSPORTMANAGER_TRANSPORTMANAGERLOGGERHELPERS_HPP__ +#define __TRANSPORTMANAGER_TRANSPORTMANAGERLOGGERHELPERS_HPP__ + +// Log helpers for logs related to Connection Handle +#define TM_CH_LOG4CPLUS_INFO(logger, ConnectionHandle, logEvent) LOG4CPLUS_INFO(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_INFO_STR(logger, ConnectionHandle, logEvent) LOG4CPLUS_INFO_STR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_TRACE_METHOD(logger, ConnectionHandle, logEvent) LOG4CPLUS_TRACE_METHOD(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_TRACE(logger, ConnectionHandle, logEvent) LOG4CPLUS_TRACE(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_TRACE_STR(logger, ConnectionHandle, logEvent) LOG4CPLUS_TRACE_STR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_DEBUG(logger, ConnectionHandle, logEvent) LOG4CPLUS_DEBUG(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_DEBUG_STR(logger, ConnectionHandle, logEvent) LOG4CPLUS_DEBUG_STR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_WARN(logger, ConnectionHandle, logEvent) LOG4CPLUS_WARN(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_WARN_STR(logger, ConnectionHandle, logEvent) LOG4CPLUS_WARN_STR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_ERROR(logger, ConnectionHandle, logEvent) LOG4CPLUS_ERROR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_ERROR_STR(logger, ConnectionHandle, logEvent) LOG4CPLUS_ERROR_STR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_FATAL(logger, ConnectionHandle, logEvent) LOG4CPLUS_FATAL(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) +#define TM_CH_LOG4CPLUS_FATAL_STR(logger, ConnectionHandle, logEvent) LOG4CPLUS_FATAL_STR(logger, "[ConnectionHandle: " << ConnectionHandle << "]: " << logEvent) + +#endif //__TRANSPORTMANAGER_TRANSPORTMANAGERLOGGERHELPERS_HPP__ |