summaryrefslogtreecommitdiff
path: root/src/components/transport_manager/src
diff options
context:
space:
mode:
authorJustin Dickow <jjdickow@gmail.com>2014-10-20 17:44:41 -0400
committerJustin Dickow <jjdickow@gmail.com>2014-10-20 17:44:41 -0400
commit34e7256493ff0e6594029b9857d7e2aa31f5dbeb (patch)
tree367306b507c52d3af211533810adbc22004e0192 /src/components/transport_manager/src
parent2eef966e9b5fd4d94dd98820095eb765e200c64b (diff)
downloadsdl_core-34e7256493ff0e6594029b9857d7e2aa31f5dbeb.tar.gz
SDL 3.8!
Signed-off-by: Justin Dickow <jjdickow@gmail.com>
Diffstat (limited to 'src/components/transport_manager/src')
-rw-r--r--src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc82
-rw-r--r--src/components/transport_manager/src/bluetooth/bluetooth_device.cc112
-rw-r--r--src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc497
-rw-r--r--src/components/transport_manager/src/bluetooth/bluetooth_socket_connection.cc132
-rw-r--r--src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc161
-rw-r--r--src/components/transport_manager/src/tcp/dnssd_service_browser.cc381
-rw-r--r--src/components/transport_manager/src/tcp/tcp_client_listener.cc286
-rw-r--r--src/components/transport_manager/src/tcp/tcp_connection_factory.cc79
-rw-r--r--src/components/transport_manager/src/tcp/tcp_device.cc153
-rw-r--r--src/components/transport_manager/src/tcp/tcp_socket_connection.cc121
-rw-r--r--src/components/transport_manager/src/tcp/tcp_transport_adapter.cc158
-rw-r--r--src/components/transport_manager/src/transport_adapter/threaded_socket_connection.cc357
-rw-r--r--src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc845
-rw-r--r--src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc277
-rw-r--r--src/components/transport_manager/src/transport_manager_default.cc107
-rw-r--r--src/components/transport_manager/src/transport_manager_impl.cc987
-rw-r--r--src/components/transport_manager/src/usb/libusb/platform_usb_device.cc85
-rw-r--r--src/components/transport_manager/src/usb/libusb/usb_connection.cc348
-rw-r--r--src/components/transport_manager/src/usb/libusb/usb_handler.cc474
-rw-r--r--src/components/transport_manager/src/usb/qnx/platform_usb_device.cc79
-rw-r--r--src/components/transport_manager/src/usb/qnx/usb_connection.cc404
-rw-r--r--src/components/transport_manager/src/usb/qnx/usb_handler.cc302
-rw-r--r--src/components/transport_manager/src/usb/usb_aoa_adapter.cc90
-rw-r--r--src/components/transport_manager/src/usb/usb_connection_factory.cc100
-rw-r--r--src/components/transport_manager/src/usb/usb_device_scanner.cc258
25 files changed, 6875 insertions, 0 deletions
diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc b/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc
new file mode 100644
index 0000000000..421104422b
--- /dev/null
+++ b/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc
@@ -0,0 +1,82 @@
+/**
+ * \file bluetooth_connection_factory.cc
+ * \brief BluetoothConnectionFactory class source file.
+ *
+ * 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 "transport_manager/bluetooth/bluetooth_connection_factory.h"
+#include "transport_manager/transport_adapter/transport_adapter_controller.h"
+#include "transport_manager/bluetooth/bluetooth_socket_connection.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+BluetoothConnectionFactory::BluetoothConnectionFactory(
+ TransportAdapterController* controller)
+ : controller_(controller) {
+}
+
+TransportAdapter::Error BluetoothConnectionFactory::Init() {
+ return TransportAdapter::OK;
+}
+
+TransportAdapter::Error BluetoothConnectionFactory::CreateConnection(
+ const DeviceUID& device_uid, const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. device_uid: " << &device_uid << ", app_handle: " <<
+ &app_handle);
+ BluetoothSocketConnection* connection(
+ new BluetoothSocketConnection(device_uid, app_handle, controller_));
+ TransportAdapter::Error error = connection->Start();
+ if (TransportAdapter::OK != error) {
+ LOG4CXX_ERROR(logger_, "connection::Start() failed");
+ delete connection;
+ }
+ LOG4CXX_TRACE(logger_, "exit with error: " << error);
+ return error;
+}
+
+void BluetoothConnectionFactory::Terminate() {
+}
+
+bool BluetoothConnectionFactory::IsInitialised() const {
+ return true;
+}
+
+BluetoothConnectionFactory::~BluetoothConnectionFactory() {
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_device.cc b/src/components/transport_manager/src/bluetooth/bluetooth_device.cc
new file mode 100644
index 0000000000..1a47f6c7ff
--- /dev/null
+++ b/src/components/transport_manager/src/bluetooth/bluetooth_device.cc
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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 "transport_manager/bluetooth/bluetooth_device.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <algorithm>
+#include <limits>
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+bool BluetoothDevice::GetRfcommChannel(const ApplicationHandle app_handle,
+ uint8_t* channel_out) {
+ LOG4CXX_TRACE(logger_, "enter. app_handle: " << app_handle << ", channel_out: " <<
+ channel_out);
+ if (app_handle < 0 || app_handle > std::numeric_limits<uint8_t>::max()) {
+ LOG4CXX_TRACE(logger_,
+ "exit with FALSE. Condition: app_handle < 0 || app_handle > numeric_limits::max()");
+ return false;
+ }
+ const uint8_t channel = static_cast<uint8_t>(app_handle);
+ RfcommChannelVector::const_iterator it = std::find(rfcomm_channels_.begin(),
+ rfcomm_channels_.end(),
+ channel);
+ if (it == rfcomm_channels_.end()) {
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: channel not found in RfcommChannelVector");
+ return false;
+ }
+ *channel_out = channel;
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+std::string BluetoothDevice::GetUniqueDeviceId(const bdaddr_t& device_address) {
+ LOG4CXX_TRACE(logger_, "enter. device_adress: " << &device_address);
+ char device_address_string[32];
+ ba2str(&device_address, device_address_string);
+ LOG4CXX_TRACE(logger_, "exit with BT-" << device_address_string);
+ return std::string("BT-") + device_address_string;
+}
+
+BluetoothDevice::BluetoothDevice(const bdaddr_t& device_address, const char* device_name,
+ const RfcommChannelVector& rfcomm_channels)
+ : Device(device_name, GetUniqueDeviceId(device_address)),
+ address_(device_address),
+ rfcomm_channels_(rfcomm_channels) {
+}
+
+bool BluetoothDevice::IsSameAs(const Device* other) const {
+ LOG4CXX_TRACE(logger_, "enter. device: " << other);
+ bool result = false;
+
+ const BluetoothDevice* other_bluetooth_device =
+ dynamic_cast<const BluetoothDevice*>(other);
+
+ if (0 != other_bluetooth_device) {
+ if (0
+ == memcmp(&address_, &other_bluetooth_device->address_,
+ sizeof(bdaddr_t))) {
+ result = true;
+ }
+ }
+ if (result) {
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ }
+ return result;
+}
+
+ApplicationList BluetoothDevice::GetApplicationList() const {
+ return ApplicationList(rfcomm_channels_.begin(), rfcomm_channels_.end());
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc b/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc
new file mode 100644
index 0000000000..e440ccb830
--- /dev/null
+++ b/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc
@@ -0,0 +1,497 @@
+/**
+ * \file bluetooth_device_scanner.cc
+ * \brief BluetoothDeviceScanner class header file.
+ *
+ * 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 "transport_manager/bluetooth/bluetooth_device_scanner.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 <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <vector>
+#include <sstream>
+#include "transport_manager/bluetooth/bluetooth_transport_adapter.h"
+#include "transport_manager/bluetooth/bluetooth_device.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+namespace {
+char* SplitToAddr(char* dev_list_entry) {
+ char* bl_address = strtok(dev_list_entry, "()");
+ if (bl_address != NULL) {
+ bl_address = strtok(NULL, "()");
+ return bl_address;
+ } else {
+ return NULL;
+ }
+}
+
+int FindPairedDevs(std::vector<bdaddr_t>* result) {
+ LOG4CXX_TRACE(logger_, "enter. result adress: " << result);
+ DCHECK(result != NULL);
+
+ const char* cmd = "bt-device -l";
+
+ FILE* pipe = popen(cmd, "r");
+ if (!pipe) {
+ LOG4CXX_TRACE(logger_, "exit -1. Condition: !pipe");
+ return -1;
+ }
+ char* buffer = new char[1028];
+ size_t counter = 0;
+ while (fgets(buffer, 1028, pipe) != NULL) {
+ if (0 < counter++) { // skip first line
+ char* bt_address = SplitToAddr(buffer);
+ if (bt_address) {
+ bdaddr_t address;
+ str2ba(bt_address, &address);
+ result->push_back(address);
+ }
+ }
+ delete [] buffer;
+ buffer = new char[1028];
+ }
+ pclose(pipe);
+ LOG4CXX_TRACE(logger_, "exit with 0");
+ return 0;
+}
+} // namespace
+
+BluetoothDeviceScanner::BluetoothDeviceScanner(
+ TransportAdapterController* controller, bool auto_repeat_search,
+ int auto_repeat_pause_sec)
+ : controller_(controller),
+ thread_(NULL),
+ shutdown_requested_(false),
+ ready_(true),
+ device_scan_requested_(false),
+ device_scan_requested_lock_(),
+ device_scan_requested_cv_(),
+ auto_repeat_search_(auto_repeat_search),
+ auto_repeat_pause_sec_(auto_repeat_pause_sec) {
+ uint8_t smart_device_link_service_uuid_data[] = { 0x93, 0x6D, 0xA0, 0x1F,
+ 0x9A, 0xBD, 0x4D, 0x9D, 0x80, 0xC7, 0x02, 0xAF, 0x85, 0xC8, 0x22, 0xA8
+ };
+ sdp_uuid128_create(&smart_device_link_service_uuid_,
+ smart_device_link_service_uuid_data);
+ thread_ = new threads::Thread("BT Device Scaner", new BluetoothDeviceScannerDelegate(this));
+}
+
+BluetoothDeviceScanner::~BluetoothDeviceScanner() {
+}
+
+
+bool BluetoothDeviceScanner::IsInitialised() const {
+ return thread_->is_running();
+}
+
+void BluetoothDeviceScanner::UpdateTotalDeviceList() {
+ LOG4CXX_TRACE(logger_, "enter");
+ DeviceVector devices;
+ devices.insert(devices.end(), paired_devices_with_sdl_.begin(),
+ paired_devices_with_sdl_.end());
+ devices.insert(devices.end(), found_devices_with_sdl_.begin(),
+ found_devices_with_sdl_.end());
+ controller_->SearchDeviceDone(devices);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void BluetoothDeviceScanner::DoInquiry() {
+ LOG4CXX_TRACE(logger_, "enter");
+
+ const int device_id = hci_get_route(0);
+ if (device_id < 0) {
+ LOG4CXX_INFO(logger_, "HCI device is not available");
+ shutdown_requested_ = true;
+ controller_->SearchDeviceFailed(SearchDeviceError());
+ LOG4CXX_TRACE(logger_, "exit. Condition: device_id < 0");
+ return;
+ }
+
+ int device_handle = hci_open_dev(device_id);
+ if (device_handle < 0) {
+ controller_->SearchDeviceFailed(SearchDeviceError());
+ LOG4CXX_TRACE(logger_, "exit. Condition: device_handle < 0");
+ return;
+ }
+
+ if (paired_devices_.empty()) {
+ LOG4CXX_INFO(logger_, "Searching for paired devices.");
+ if (-1 == FindPairedDevs(&paired_devices_)) {
+ LOG4CXX_ERROR(logger_, "Failed to retrieve list of paired devices.");
+ controller_->SearchDeviceFailed(SearchDeviceError());
+ }
+ }
+
+ LOG4CXX_INFO(logger_, "Check rfcomm channel on "
+ << paired_devices_.size() << " paired devices.");
+
+ paired_devices_with_sdl_.clear();
+ CheckSDLServiceOnDevices(paired_devices_, device_handle,
+ &paired_devices_with_sdl_);
+ UpdateTotalDeviceList();
+
+ LOG4CXX_INFO(logger_, "Starting hci_inquiry on device " << device_id);
+ const uint8_t inquiry_time = 8u; // Time unit is 1.28 seconds
+ const size_t max_devices = 256u;
+ inquiry_info* inquiry_info_list = new inquiry_info[max_devices];
+
+ const int number_of_devices = hci_inquiry(device_id, inquiry_time,
+ max_devices, 0, &inquiry_info_list,
+ IREQ_CACHE_FLUSH);
+
+ if (number_of_devices >= 0) {
+ LOG4CXX_INFO(logger_,
+ "hci_inquiry: found " << number_of_devices << " devices");
+ std::vector < bdaddr_t > found_devices(number_of_devices);
+ for (int i = 0; i < number_of_devices; ++i) {
+ found_devices[i] = inquiry_info_list[i].bdaddr;
+ }
+ found_devices_with_sdl_.clear();
+ CheckSDLServiceOnDevices(found_devices, device_handle,
+ &found_devices_with_sdl_);
+ }
+ UpdateTotalDeviceList();
+
+ close(device_handle);
+ delete[] inquiry_info_list;
+
+ if (number_of_devices < 0) {
+ LOG4CXX_DEBUG(logger_, "number_of_devices < 0");
+ controller_->SearchDeviceFailed(SearchDeviceError());
+ }
+
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void BluetoothDeviceScanner::CheckSDLServiceOnDevices(
+ const std::vector<bdaddr_t>& bd_addresses, int device_handle,
+ DeviceVector* discovered_devices) {
+ LOG4CXX_TRACE(logger_, "enter. bd_addresses: " << &bd_addresses << ", device_handle: " <<
+ device_handle << ", discovered_devices: " << discovered_devices);
+ std::vector<RfcommChannelVector> sdl_rfcomm_channels =
+ DiscoverSmartDeviceLinkRFCOMMChannels(bd_addresses);
+
+ for (size_t i = 0; i < bd_addresses.size(); ++i) {
+ if (sdl_rfcomm_channels[i].empty()) {
+ continue;
+ }
+
+ const bdaddr_t& bd_address = bd_addresses[i];
+ char deviceName[256];
+ int hci_read_remote_name_ret = hci_read_remote_name(
+ device_handle, &bd_address, sizeof(deviceName) / sizeof(deviceName[0]),
+ deviceName, 0);
+
+ if (hci_read_remote_name_ret != 0) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "hci_read_remote_name failed");
+ strncpy(deviceName,
+ BluetoothDevice::GetUniqueDeviceId(bd_address).c_str(),
+ sizeof(deviceName) / sizeof(deviceName[0]));
+ }
+
+ Device* bluetooth_device = new BluetoothDevice(bd_address, deviceName,
+ sdl_rfcomm_channels[i]);
+ if (bluetooth_device) {
+ LOG4CXX_INFO(logger_, "Bluetooth device created successfully");
+ discovered_devices->push_back(bluetooth_device);
+ } else {
+ LOG4CXX_WARN(logger_, "Can't create bluetooth device " << deviceName);
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+std::vector<BluetoothDeviceScanner::RfcommChannelVector>
+BluetoothDeviceScanner::DiscoverSmartDeviceLinkRFCOMMChannels(
+ const std::vector<bdaddr_t>& device_addresses) {
+ LOG4CXX_TRACE(logger_, "enter device_addresses: " << &device_addresses);
+ const size_t size = device_addresses.size();
+ std::vector<RfcommChannelVector> result(size);
+
+ static const int attempts = 4;
+ static const int attempt_timeout = 5;
+ std::vector<bool> processed(size, false);
+ unsigned processed_count = 0;
+ for (int nattempt = 0; nattempt < attempts; ++nattempt) {
+ for (size_t i = 0; i < size; ++i) {
+ if (processed[i]) {
+ continue;
+ }
+ const bool final = DiscoverSmartDeviceLinkRFCOMMChannels(
+ device_addresses[i], &result[i]);
+ if (final) {
+ processed[i] = true;
+ ++processed_count;
+ }
+ }
+ if (++processed_count >= size) {
+ break;
+ }
+ sleep(attempt_timeout);
+ }
+ LOG4CXX_TRACE(logger_, "exit with vector<RfcommChannelVector>: size = " << result.size());
+ return result;
+}
+
+bool BluetoothDeviceScanner::DiscoverSmartDeviceLinkRFCOMMChannels(
+ const bdaddr_t& device_address, RfcommChannelVector* channels) {
+ LOG4CXX_TRACE(logger_, "enter. device_address: " << &device_address << ", channels: " <<
+ channels);
+ static bdaddr_t any_address = { { 0, 0, 0, 0, 0, 0 } };
+
+ sdp_session_t* sdp_session = sdp_connect(
+ &any_address, &device_address, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE);
+ if (sdp_session == 0) {
+ bool result = !(errno == 31 || errno == 16 || errno == 117 || errno == 114);
+ if (result) {
+ LOG4CXX_TRACE(logger_, "exit with TRUE. Condition: sdp_session == 0");
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: sdp_session == 0");
+ }
+ return result;
+ }
+
+ sdp_list_t* search_list = sdp_list_append(0,
+ &smart_device_link_service_uuid_);
+ uint32_t range = 0x0000ffff;
+ sdp_list_t* attr_list = sdp_list_append(0, &range);
+ sdp_list_t* response_list = 0;
+
+ if (0 == sdp_service_search_attr_req(sdp_session, search_list,
+ SDP_ATTR_REQ_RANGE, attr_list,
+ &response_list)) {
+ for (sdp_list_t* r = response_list; 0 != r; r = r->next) {
+ sdp_record_t* sdp_record = static_cast<sdp_record_t*>(r->data);
+ sdp_list_t* proto_list = 0;
+
+ if (0 == sdp_get_access_protos(sdp_record, &proto_list)) {
+ for (sdp_list_t* p = proto_list; 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) {
+ channels->push_back(d->val.uint8);
+ }
+ break;
+ }
+ }
+ }
+
+ sdp_list_free(pdsList, 0);
+ }
+
+ sdp_list_free(proto_list, 0);
+ }
+ }
+ }
+ sdp_list_free(search_list, 0);
+ sdp_list_free(attr_list, 0);
+ sdp_list_free(response_list, 0);
+ sdp_close(sdp_session);
+
+ if (!channels->empty()) {
+ LOG4CXX_INFO(logger_, "channels not empty");
+ std::stringstream rfcomm_channels_string;
+
+ for (RfcommChannelVector::const_iterator it = channels->begin();
+ it != channels->end(); ++it) {
+ if (it != channels->begin()) {
+ rfcomm_channels_string << ", ";
+ }
+ rfcomm_channels_string << static_cast<uint32_t>(*it);
+ }
+
+ LOG4CXX_INFO(logger_,
+ "SmartDeviceLink service was discovered on device "
+ << BluetoothDevice::GetUniqueDeviceId(device_address)
+ << " at channel(s): " << rfcomm_channels_string.str().c_str());
+ } else {
+ LOG4CXX_INFO(logger_,
+ "SmartDeviceLink service was not discovered on device "
+ << BluetoothDevice::GetUniqueDeviceId(device_address));
+ }
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+void BluetoothDeviceScanner::Thread() {
+ LOG4CXX_TRACE(logger_, "enter");
+ ready_ = true;
+ if (auto_repeat_search_) {
+ while (!shutdown_requested_) {
+ DoInquiry();
+ device_scan_requested_ = false;
+ TimedWaitForDeviceScanRequest();
+ }
+ } else { // search only on demand
+ while (true) {
+ {
+ sync_primitives::AutoLock auto_lock(device_scan_requested_lock_);
+ while (!(device_scan_requested_ || shutdown_requested_)) {
+ device_scan_requested_cv_.Wait(auto_lock);
+ }
+ }
+ if (shutdown_requested_) {
+ break;
+ }
+ DoInquiry();
+ device_scan_requested_ = false;
+ }
+ }
+
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void BluetoothDeviceScanner::TimedWaitForDeviceScanRequest() {
+ LOG4CXX_TRACE(logger_, "enter");
+
+ if (auto_repeat_pause_sec_ == 0) {
+ LOG4CXX_TRACE(logger_, "exit. Condition: auto_repeat_pause_sec_ == 0");
+ return;
+ }
+
+ {
+ sync_primitives::AutoLock auto_lock(device_scan_requested_lock_);
+ while (!(device_scan_requested_ || shutdown_requested_)) {
+ const sync_primitives::ConditionalVariable::WaitStatus wait_status =
+ device_scan_requested_cv_.WaitFor(auto_lock, auto_repeat_pause_sec_ * 1000);
+ if (wait_status == sync_primitives::ConditionalVariable::kTimeout) {
+ LOG4CXX_INFO(logger_, "Bluetooth scanner timeout, performing scan");
+ device_scan_requested_ = true;
+ }
+ }
+ }
+
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error BluetoothDeviceScanner::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if(!thread_->start()) {
+ LOG4CXX_ERROR(logger_, "Bluetooth device scanner thread start failed");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter:Fail");
+ return TransportAdapter::FAIL;
+ }
+ LOG4CXX_INFO(logger_, "Bluetooth device scanner thread started");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter:OK");
+ return TransportAdapter::OK;
+}
+
+void BluetoothDeviceScanner::Terminate() {
+ LOG4CXX_TRACE(logger_, "enter");
+ shutdown_requested_ = true;
+ if (thread_->is_running()) {
+ {
+ sync_primitives::AutoLock auto_lock(device_scan_requested_lock_);
+ device_scan_requested_ = false;
+ device_scan_requested_cv_.NotifyOne();
+ }
+ LOG4CXX_INFO(logger_,
+ "Waiting for bluetooth device scanner thread termination");
+ thread_->join();
+ LOG4CXX_INFO(logger_, "PASA Bluetooth device scanner thread joined");
+ }
+ delete thread_;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error BluetoothDeviceScanner::Scan() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if ((!IsInitialised()) || shutdown_requested_) {
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::BAD_STATE");
+ return TransportAdapter::BAD_STATE;
+ }
+ if (auto_repeat_pause_sec_ == 0) {
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+ }
+ TransportAdapter::Error ret = TransportAdapter::OK;
+
+ {
+ sync_primitives::AutoLock auto_lock(device_scan_requested_lock_);
+ if (false == device_scan_requested_) {
+ LOG4CXX_INFO(logger_, "Requesting device Scan");
+ device_scan_requested_ = true;
+ device_scan_requested_cv_.NotifyOne();
+ } else {
+ ret = TransportAdapter::BAD_STATE;
+ LOG4CXX_INFO(logger_, "Device Scan is currently in progress");
+ }
+ }
+
+ LOG4CXX_TRACE(logger_, "exit with Error: " << ret);
+ return ret;
+}
+
+BluetoothDeviceScanner::BluetoothDeviceScannerDelegate::BluetoothDeviceScannerDelegate(
+ BluetoothDeviceScanner* scanner)
+ : scanner_(scanner) {
+}
+
+void BluetoothDeviceScanner::BluetoothDeviceScannerDelegate::threadMain()
+{
+ LOG4CXX_TRACE_ENTER(logger_);
+ DCHECK(scanner_);
+ scanner_->Thread();
+ LOG4CXX_TRACE_EXIT(logger_);
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
+
diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_socket_connection.cc b/src/components/transport_manager/src/bluetooth/bluetooth_socket_connection.cc
new file mode 100644
index 0000000000..ac1ccecfb5
--- /dev/null
+++ b/src/components/transport_manager/src/bluetooth/bluetooth_socket_connection.cc
@@ -0,0 +1,132 @@
+/**
+ *
+ * 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 "transport_manager/bluetooth/bluetooth_socket_connection.h"
+
+#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 "transport_manager/bluetooth/bluetooth_device.h"
+#include "transport_manager/transport_adapter/transport_adapter_controller.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+BluetoothSocketConnection::BluetoothSocketConnection(
+ const DeviceUID& device_uid, const ApplicationHandle& app_handle,
+ TransportAdapterController* controller)
+ : ThreadedSocketConnection(device_uid, app_handle, controller) {
+}
+
+BluetoothSocketConnection::~BluetoothSocketConnection() {
+}
+
+bool BluetoothSocketConnection::Establish(ConnectError** error) {
+ LOG4CXX_TRACE(logger_, "enter. (#" << pthread_self() << "), error: " << error);
+ DeviceSptr device = controller()->FindDevice(device_handle());
+
+ BluetoothDevice* bluetooth_device =
+ static_cast<BluetoothDevice*>(device.get());
+
+ uint8_t rfcomm_channel;
+ if (!bluetooth_device->GetRfcommChannel(application_handle(),
+ &rfcomm_channel)) {
+ LOG4CXX_DEBUG(logger_,
+ "Application " << application_handle() << " not found");
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ return false;
+ }
+
+ struct sockaddr_rc remoteSocketAddress = { 0 };
+ remoteSocketAddress.rc_family = AF_BLUETOOTH;
+ memcpy(&remoteSocketAddress.rc_bdaddr, &bluetooth_device->address(),
+ sizeof(bdaddr_t));
+ remoteSocketAddress.rc_channel = rfcomm_channel;
+
+ int rfcomm_socket;
+
+ int attempts = 4;
+ int connect_status = 0;
+ LOG4CXX_DEBUG(logger_, "start rfcomm Connect attempts");
+ do {
+ rfcomm_socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (-1 == rfcomm_socket) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_,
+ "Failed to create RFCOMM socket for device " << device_handle());
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ return false;
+ }
+ connect_status = ::connect(rfcomm_socket,
+ (struct sockaddr*) &remoteSocketAddress,
+ sizeof(remoteSocketAddress));
+ if (0 == connect_status) {
+ LOG4CXX_DEBUG(logger_, "rfcomm Connect ok");
+ break;
+ }
+ if (errno != 111 && errno != 104) {
+ LOG4CXX_DEBUG(logger_, "rfcomm Connect errno " << errno);
+ break;
+ }
+ if (errno) {
+ LOG4CXX_DEBUG(logger_, "rfcomm Connect errno " << errno);
+ close(rfcomm_socket);
+ }
+ sleep(2);
+ } while (--attempts > 0);
+ LOG4CXX_INFO(logger_, "rfcomm Connect attempts finished");
+ if (0 != connect_status) {
+ LOG4CXX_DEBUG(logger_,
+ "Failed to Connect to remote device " << BluetoothDevice::GetUniqueDeviceId(
+ remoteSocketAddress.rc_bdaddr) << " for session " << this);
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ return false;
+ }
+
+ set_socket(rfcomm_socket);
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc b/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc
new file mode 100644
index 0000000000..7d60213b01
--- /dev/null
+++ b/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc
@@ -0,0 +1,161 @@
+/**
+ * \file bluetooth_transport_adapter.cc
+ * \brief BluetoothTransportAdapter class source file.
+ *
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <iomanip>
+#include <set>
+#include <bluetooth/bluetooth.h>
+
+#include "resumption/last_state.h"
+
+#include "transport_manager/bluetooth/bluetooth_transport_adapter.h"
+#include "transport_manager/bluetooth/bluetooth_device_scanner.h"
+#include "transport_manager/bluetooth/bluetooth_connection_factory.h"
+#include "transport_manager/bluetooth/bluetooth_device.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+BluetoothTransportAdapter::~BluetoothTransportAdapter() {
+}
+
+BluetoothTransportAdapter::BluetoothTransportAdapter()
+ : TransportAdapterImpl(new BluetoothDeviceScanner(this, true, 0),
+ new BluetoothConnectionFactory(this), 0) {
+}
+
+DeviceType BluetoothTransportAdapter::GetDeviceType() const {
+ return "sdl-bluetooth";
+}
+
+void BluetoothTransportAdapter::Store() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ Json::Value bluetooth_adapter_dictionary;
+ Json::Value devices_dictionary;
+ DeviceList device_ids = GetDeviceList();
+ for (DeviceList::const_iterator i = device_ids.begin(); i != device_ids.end(); ++i) {
+ DeviceUID device_id = *i;
+ DeviceSptr device = FindDevice(device_id);
+ if (!device) { // device could have been disconnected
+ continue;
+ }
+ utils::SharedPtr<BluetoothDevice> bluetooth_device =
+ DeviceSptr::static_pointer_cast<BluetoothDevice>(device);
+ Json::Value device_dictionary;
+ device_dictionary["name"] = bluetooth_device->name();
+ char address[18];
+ ba2str(&bluetooth_device->address(), address);
+ device_dictionary["address"] = std::string(address);
+ Json::Value applications_dictionary;
+ ApplicationList app_ids = bluetooth_device->GetApplicationList();
+ for (ApplicationList::const_iterator j = app_ids.begin(); j != app_ids.end(); ++j) {
+ ApplicationHandle app_handle = *j;
+ if (FindEstablishedConnection(bluetooth_device->unique_device_id(), app_handle)) {
+ uint8_t rfcomm_channel;
+ bluetooth_device->GetRfcommChannel(app_handle, &rfcomm_channel);
+ Json::Value application_dictionary;
+ char rfcomm_channel_record[4];
+ sprintf(rfcomm_channel_record, "%u", rfcomm_channel);
+ application_dictionary["rfcomm_channel"] = std::string(rfcomm_channel_record);
+ applications_dictionary.append(application_dictionary);
+ }
+ }
+ if (!applications_dictionary.empty()) {
+ device_dictionary["applications"] = applications_dictionary;
+ devices_dictionary.append(device_dictionary);
+ }
+ }
+ bluetooth_adapter_dictionary["devices"] = devices_dictionary;
+ resumption::LastState::instance()->dictionary["TransportManager"]["BluetoothAdapter"] =
+ bluetooth_adapter_dictionary;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool BluetoothTransportAdapter::Restore() {
+ LOG4CXX_TRACE(logger_, "enter");
+ bool errors_occured = false;
+ const Json::Value bluetooth_adapter_dictionary =
+ resumption::LastState::instance()->dictionary["TransportManager"]["BluetoothAdapter"];
+ const Json::Value devices_dictionary = bluetooth_adapter_dictionary["devices"];
+ for (Json::Value::const_iterator i = devices_dictionary.begin();
+ i != devices_dictionary.end(); ++i) {
+ const Json::Value device_dictionary = *i;
+ std::string name = device_dictionary["name"].asString();
+ std::string address_record = device_dictionary["address"].asString();
+ bdaddr_t address;
+ str2ba(address_record.c_str(), &address);
+ RfcommChannelVector rfcomm_channels;
+ const Json::Value applications_dictionary = device_dictionary["applications"];
+ for (Json::Value::const_iterator j = applications_dictionary.begin();
+ j != applications_dictionary.end(); ++j) {
+ const Json::Value application_dictionary = *j;
+ std::string rfcomm_channel_record =
+ application_dictionary["rfcomm_channel"].asString();
+ uint8_t rfcomm_channel =
+ static_cast<uint8_t>(atoi(rfcomm_channel_record.c_str()));
+ rfcomm_channels.push_back(rfcomm_channel);
+ }
+ BluetoothDevice* bluetooth_device =
+ new BluetoothDevice(address, name.c_str(), rfcomm_channels);
+ DeviceSptr device(bluetooth_device);
+ AddDevice(device);
+ for (RfcommChannelVector::const_iterator j =
+ rfcomm_channels.begin(); j != rfcomm_channels.end(); ++j) {
+ ApplicationHandle app_handle =
+ *j; // for Bluetooth device app_handle is just RFCOMM channel
+ if (Error::OK != Connect(device->unique_device_id(), app_handle)) {
+ errors_occured = true;
+ }
+ }
+ }
+ bool result = !errors_occured;
+ if (result) {
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ }
+ return result;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/tcp/dnssd_service_browser.cc b/src/components/transport_manager/src/tcp/dnssd_service_browser.cc
new file mode 100644
index 0000000000..5580585766
--- /dev/null
+++ b/src/components/transport_manager/src/tcp/dnssd_service_browser.cc
@@ -0,0 +1,381 @@
+/**
+ *
+ * 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 <algorithm>
+#include <map>
+
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+#include "transport_manager/tcp/tcp_device.h"
+#include "transport_manager/tcp/dnssd_service_browser.h"
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+bool operator==(const DnssdServiceRecord& a, const DnssdServiceRecord& b) {
+ return a.name == b.name && a.type == b.type && a.interface == b.interface
+ && a.protocol == b.protocol && a.domain_name == b.domain_name;
+}
+
+void DnssdServiceBrowser::Terminate() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (0 != avahi_threaded_poll_) {
+ avahi_threaded_poll_stop(avahi_threaded_poll_);
+ }
+ if (0 != avahi_service_browser_) {
+ avahi_service_browser_free(avahi_service_browser_);
+ }
+ if (0 != avahi_client_) {
+ avahi_client_free(avahi_client_);
+ }
+ if (0 != avahi_threaded_poll_) {
+ avahi_threaded_poll_free(avahi_threaded_poll_);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool DnssdServiceBrowser::IsInitialised() const {
+ return initialised_;
+}
+
+DnssdServiceBrowser::DnssdServiceBrowser(TransportAdapterController* controller)
+ : controller_(controller),
+ avahi_service_browser_(0),
+ avahi_threaded_poll_(0),
+ avahi_client_(0),
+ service_records_(),
+ mutex_(),
+ initialised_(false) {
+ pthread_mutex_init(&mutex_, 0);
+}
+
+DnssdServiceBrowser::~DnssdServiceBrowser() {
+ pthread_mutex_destroy(&mutex_);
+}
+
+void DnssdServiceBrowser::OnClientConnected() {
+ initialised_ = true;
+ LOG4CXX_INFO(logger_, "AvahiClient ready");
+}
+
+void DnssdServiceBrowser::OnClientFailure() {
+ LOG4CXX_TRACE(logger_, "enter");
+ const int avahi_errno = avahi_client_errno(avahi_client_);
+ if (avahi_errno == AVAHI_ERR_DISCONNECTED) {
+ LOG4CXX_DEBUG(logger_, "AvahiClient disconnected");
+ CreateAvahiClientAndBrowser();
+ } else {
+ LOG4CXX_ERROR(logger_,
+ "AvahiClient failure: " << avahi_strerror(avahi_errno));
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void AvahiClientCallback(AvahiClient* avahi_client,
+ AvahiClientState avahi_client_state, void* data) {
+ LOG4CXX_TRACE(logger_,
+ "enter. avahi_client " << avahi_client << "avahi_client_state " <<
+ avahi_client_state << "data " << data);
+ DnssdServiceBrowser* dnssd_service_browser =
+ static_cast<DnssdServiceBrowser*>(data);
+
+ switch (avahi_client_state) {
+ case AVAHI_CLIENT_S_RUNNING:
+ dnssd_service_browser->OnClientConnected();
+ LOG4CXX_DEBUG(logger_, "avahi_client_state: AVAHI_CLIENT_S_RUNNING");
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ dnssd_service_browser->OnClientFailure();
+ LOG4CXX_DEBUG(logger_, "avahi_client_state: AVAHI_CLIENT_FAILURE");
+ break;
+ default: {
+ LOG4CXX_ERROR(logger_, "Unknown avahi_client_state: " << avahi_client_state);
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void AvahiServiceBrowserCallback(AvahiServiceBrowser* avahi_service_browser,
+ AvahiIfIndex interface, AvahiProtocol protocol,
+ AvahiBrowserEvent event, const char* name,
+ const char* type, const char* domain,
+ AvahiLookupResultFlags flags, void* data) {
+ LOG4CXX_TRACE(logger_, "enter. avahi_service_browser " << avahi_service_browser <<
+ " interface " << interface << " protocol " << protocol <<
+ " event " << event << " name " << name << " type " << type << " domain " << domain <<
+ " flags " << flags << " data " << data);
+ DnssdServiceBrowser* dnssd_service_browser =
+ static_cast<DnssdServiceBrowser*>(data);
+
+ switch (event) {
+ case AVAHI_BROWSER_FAILURE:
+ LOG4CXX_ERROR(
+ logger_,
+ "AvahiServiceBrowser failure: " << avahi_strerror(
+ avahi_client_errno(
+ avahi_service_browser_get_client(
+ avahi_service_browser))));
+ break;
+
+ case AVAHI_BROWSER_NEW:
+ dnssd_service_browser->AddService(interface, protocol, name, type,
+ domain);
+ LOG4CXX_DEBUG(logger_, "event: AVAHI_BROWSER_NEW");
+ break;
+
+ case AVAHI_BROWSER_REMOVE:
+ dnssd_service_browser->RemoveService(interface, protocol, name, type,
+ domain);
+ LOG4CXX_DEBUG(logger_, "event: AVAHI_BROWSER_REMOVE");
+ break;
+
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ LOG4CXX_DEBUG(logger_, "event: AVAHI_BROWSER_ALL_FOR_NOW");
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ LOG4CXX_DEBUG(logger_, "event: AVAHI_BROWSER_CACHE_EXHAUSTED");
+ break;
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void DnssdServiceBrowser::ServiceResolved(
+ const DnssdServiceRecord& service_record) {
+ LOG4CXX_TRACE(logger_, "enter");
+ pthread_mutex_lock(&mutex_);
+ ServiceRecords::iterator service_record_it = std::find(
+ service_records_.begin(), service_records_.end(), service_record);
+ if (service_record_it != service_records_.end()) {
+ *service_record_it = service_record;
+ }
+ DeviceVector device_vector = PrepareDeviceVector();
+ controller_->SearchDeviceDone(device_vector);
+ pthread_mutex_unlock(&mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void DnssdServiceBrowser::ServiceResolveFailed(
+ const DnssdServiceRecord& service_record) {
+ LOG4CXX_TRACE(logger_, "enter");
+ LOG4CXX_ERROR(logger_,
+ "AvahiServiceResolver failure for: " << service_record.name);
+ pthread_mutex_lock(&mutex_);
+ ServiceRecords::iterator service_record_it = std::find(
+ service_records_.begin(), service_records_.end(), service_record);
+ if (service_record_it != service_records_.end()) {
+ service_records_.erase(service_record_it);
+ }
+ pthread_mutex_unlock(&mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void AvahiServiceResolverCallback(AvahiServiceResolver* avahi_service_resolver,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiResolverEvent event, const char* name,
+ const char* type, const char* domain,
+ const char* host_name,
+ const AvahiAddress* avahi_address,
+ uint16_t port, AvahiStringList* txt,
+ AvahiLookupResultFlags flags, void* data) {
+ LOG4CXX_TRACE(logger_, "enter. avahi_service_resolver " << avahi_service_resolver <<
+ " interface " << interface <<
+ " protocol " << protocol << " event " << event << " name " << name << " type " << type <<
+ " domain " << domain << " host_name " << host_name <<
+ " avahi_address " << avahi_address << " port " << port << " txt " << txt << " flags " <<
+ flags << " data " << data);
+ DnssdServiceBrowser* dnssd_service_browser =
+ static_cast<DnssdServiceBrowser*>(data);
+
+ DnssdServiceRecord service_record;
+ service_record.interface = interface;
+ service_record.protocol = protocol;
+ service_record.domain_name = domain;
+ service_record.host_name = host_name;
+ service_record.name = name;
+ service_record.type = type;
+ switch (event) {
+ case AVAHI_RESOLVER_FOUND:
+ service_record.addr = avahi_address->data.ipv4.address;
+ service_record.port = port;
+ dnssd_service_browser->ServiceResolved(service_record);
+ LOG4CXX_DEBUG(logger_, "event: AVAHI_RESOLVER_FOUND");
+ break;
+ case AVAHI_RESOLVER_FAILURE:
+ dnssd_service_browser->ServiceResolveFailed(service_record);
+ LOG4CXX_DEBUG(logger_, "event: AVAHI_RESOLVER_FAILURE");
+ break;
+ }
+
+ avahi_service_resolver_free(avahi_service_resolver);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error DnssdServiceBrowser::CreateAvahiClientAndBrowser() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (0 != avahi_service_browser_) {
+ avahi_service_browser_free(avahi_service_browser_);
+ }
+ if (0 != avahi_client_) {
+ avahi_client_free(avahi_client_);
+ }
+
+ int avahi_error;
+ avahi_client_ = avahi_client_new(
+ avahi_threaded_poll_get(avahi_threaded_poll_), AVAHI_CLIENT_NO_FAIL,
+ AvahiClientCallback, this, &avahi_error);
+ if (0 == avahi_client_) {
+ LOG4CXX_ERROR(logger_, "Failed to create AvahiClient: " << avahi_strerror(avahi_error));
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL");
+ return TransportAdapter::FAIL;
+ }
+
+ pthread_mutex_lock(&mutex_);
+ service_records_.clear();
+ pthread_mutex_unlock(&mutex_);
+
+ avahi_service_browser_ = avahi_service_browser_new(
+ avahi_client_, AVAHI_IF_UNSPEC, /* TODO use only required iface */
+ AVAHI_PROTO_INET, DNSSD_DEFAULT_SERVICE_TYPE, NULL, /* use default domain */
+ static_cast<AvahiLookupFlags>(0), AvahiServiceBrowserCallback, this);
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+}
+
+TransportAdapter::Error DnssdServiceBrowser::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ avahi_threaded_poll_ = avahi_threaded_poll_new();
+ if (0 == avahi_threaded_poll_) {
+ LOG4CXX_ERROR(logger_, "Failed to create AvahiThreadedPoll");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL");
+ return TransportAdapter::FAIL;
+ }
+
+ const TransportAdapter::Error err = CreateAvahiClientAndBrowser();
+ if (err != TransportAdapter::OK) {
+ LOG4CXX_TRACE(logger_, "exit with error " << err);
+ return err;
+ }
+
+ const int poll_start_status = avahi_threaded_poll_start(avahi_threaded_poll_);
+ if (0 != poll_start_status) {
+ LOG4CXX_ERROR(logger_, "Failed to start AvahiThreadedPoll");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL. Condition: 0 != poll_start_status");
+ return TransportAdapter::FAIL;
+ }
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+}
+
+TransportAdapter::Error DnssdServiceBrowser::Scan() {
+ return TransportAdapter::NOT_SUPPORTED;
+}
+
+void DnssdServiceBrowser::AddService(AvahiIfIndex interface,
+ AvahiProtocol protocol, const char* name,
+ const char* type, const char* domain) {
+ LOG4CXX_TRACE(logger_, "enter: interface " << interface << " protocol " << protocol <<
+ " name " << name << " type " << type << " domain " << domain);
+ DnssdServiceRecord record;
+ record.interface = interface;
+ record.protocol = protocol;
+ record.domain_name = domain;
+ record.name = name;
+ record.type = type;
+
+ pthread_mutex_lock(&mutex_);
+ if (service_records_.end()
+ == std::find(service_records_.begin(), service_records_.end(), record)) {
+ service_records_.push_back(record);
+ avahi_service_resolver_new(
+ avahi_client_, interface, protocol, name, type, domain,
+ AVAHI_PROTO_INET, static_cast<AvahiLookupFlags>(0),
+ AvahiServiceResolverCallback, this);
+ }
+ pthread_mutex_unlock(&mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void DnssdServiceBrowser::RemoveService(AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ const char* name, const char* type,
+ const char* domain) {
+ LOG4CXX_TRACE(logger_, "enter: interface " << interface << " protocol " << protocol <<
+ " name " << name << " type " << type << " domain " << domain);
+ DnssdServiceRecord record;
+ record.interface = interface;
+ record.protocol = protocol;
+ record.name = name;
+ record.type = type;
+ record.domain_name = domain;
+
+ pthread_mutex_lock(&mutex_);
+ service_records_.erase(
+ std::remove(service_records_.begin(), service_records_.end(), record),
+ service_records_.end());
+ pthread_mutex_unlock(&mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+DeviceVector DnssdServiceBrowser::PrepareDeviceVector() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ std::map<uint32_t, TcpDevice*> devices;
+ for (ServiceRecords::const_iterator it = service_records_.begin();
+ it != service_records_.end(); ++it) {
+ const DnssdServiceRecord& service_record = *it;
+ if (service_record.host_name.empty()) {
+ continue;
+ }
+ if (devices[service_record.addr] == 0) {
+ devices[service_record.addr] = new TcpDevice(service_record.addr,
+ service_record.host_name);
+ }
+ if (devices[service_record.addr] != 0) {
+ devices[service_record.addr]->AddDiscoveredApplication(
+ service_record.port);
+ }
+ }
+ DeviceVector device_vector;
+ device_vector.reserve(devices.size());
+ for (std::map<uint32_t, TcpDevice*>::const_iterator it = devices.begin();
+ it != devices.end(); ++it) {
+ device_vector.push_back(DeviceSptr(it->second));
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+ return device_vector;
+}
+
+} // namespace
+} // namespace
+
diff --git a/src/components/transport_manager/src/tcp/tcp_client_listener.cc b/src/components/transport_manager/src/tcp/tcp_client_listener.cc
new file mode 100644
index 0000000000..514fbe66eb
--- /dev/null
+++ b/src/components/transport_manager/src/tcp/tcp_client_listener.cc
@@ -0,0 +1,286 @@
+/**
+ *
+ * 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 "transport_manager/tcp/tcp_client_listener.h"
+
+#include <memory.h>
+#include <signal.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#ifdef __linux__
+# include <linux/tcp.h>
+#else // __linux__
+# include <sys/time.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <netinet/tcp_var.h>
+#endif // __linux__
+
+#include "utils/logger.h"
+
+#include "transport_manager/transport_adapter/transport_adapter_controller.h"
+#include "transport_manager/tcp/tcp_device.h"
+#include "transport_manager/tcp/tcp_socket_connection.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+TcpClientListener::TcpClientListener(TransportAdapterController* controller,
+ const uint16_t port,
+ const bool enable_keepalive)
+ : port_(port),
+ enable_keepalive_(enable_keepalive),
+ controller_(controller),
+ thread_(),
+ socket_(-1),
+ thread_started_(false),
+ shutdown_requested_(false),
+ thread_stop_requested_(false) {}
+
+void* tcpClientListenerThread(void* data) {
+ LOG4CXX_TRACE(logger_, "enter. data " << data);
+ TcpClientListener* tcpClientListener = static_cast<TcpClientListener*>(data);
+ assert(tcpClientListener != 0);
+ tcpClientListener->Thread();
+ LOG4CXX_TRACE(logger_, "exit");
+ return 0;
+}
+
+TransportAdapter::Error TcpClientListener::Init() {
+ return TransportAdapter::OK;
+}
+
+void TcpClientListener::Terminate() {
+ LOG4CXX_TRACE(logger_, "enter");
+ shutdown_requested_ = true;
+ if (TransportAdapter::OK != StopListening()) {
+ LOG4CXX_ERROR(logger_, "Cannot stop listening TCP");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool TcpClientListener::IsInitialised() const {
+ return true;
+}
+
+TcpClientListener::~TcpClientListener() {
+ LOG4CXX_INFO(logger_, "destructor");
+}
+
+void SetKeepaliveOptions(const int fd) {
+ LOG4CXX_TRACE(logger_, "enter. fd: " << fd);
+ int yes = 1;
+ int keepidle = 3; // 3 seconds to disconnection detecting
+ int keepcnt = 5;
+ int keepintvl = 1;
+#ifdef __linux__
+ int user_timeout = 7000; // milliseconds
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
+ setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
+ setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
+ setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
+ setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout,
+ sizeof(user_timeout));
+#elif __QNX__ // __linux__
+ // TODO (KKolodiy): Out of order!
+ const int kMidLength = 4;
+ int mib[kMidLength];
+ timeval tval;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_INET;
+ mib[2] = IPPROTO_TCP;
+ mib[3] = TCPCTL_KEEPIDLE;
+ sysctl(mib, kMidLength, NULL, NULL, &keepidle, sizeof(keepidle));
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_INET;
+ mib[2] = IPPROTO_TCP;
+ mib[3] = TCPCTL_KEEPCNT;
+ sysctl(mib, kMidLength, NULL, NULL, &keepcnt, sizeof(keepcnt));
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_INET;
+ mib[2] = IPPROTO_TCP;
+ mib[3] = TCPCTL_KEEPINTVL;
+ sysctl(mib, kMidLength, NULL, NULL, &keepintvl, sizeof(keepintvl));
+
+ memset(&tval, sizeof(tval), 0);
+ tval.tv_sec = keepidle;
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
+ setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tval, sizeof(tval));
+#endif // __QNX__
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TcpClientListener::Thread() {
+ LOG4CXX_TRACE(logger_, "enter");
+ while (false == thread_stop_requested_) {
+ sockaddr_in client_address;
+ socklen_t client_address_size = sizeof(client_address);
+ const int connection_fd = accept(socket_, (struct sockaddr*)&client_address,
+ &client_address_size);
+ if (thread_stop_requested_) {
+ LOG4CXX_DEBUG(logger_, "thread_stop_requested_");
+ break;
+ }
+
+ if (connection_fd < 0) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "accept() failed");
+ continue;
+ }
+
+ if (AF_INET != client_address.sin_family) {
+ LOG4CXX_DEBUG(logger_, "Address of connected client is invalid");
+ continue;
+ }
+
+ char device_name[32];
+ strncpy(device_name, inet_ntoa(client_address.sin_addr),
+ sizeof(device_name) / sizeof(device_name[0]));
+ LOG4CXX_INFO(logger_, "Connected client " << device_name);
+
+ if (enable_keepalive_) {
+ SetKeepaliveOptions(connection_fd);
+ }
+
+ TcpDevice* tcp_device = new TcpDevice(client_address.sin_addr.s_addr, device_name);
+ DeviceSptr device = controller_->AddDevice(tcp_device);
+ tcp_device = static_cast<TcpDevice*>(device.get());
+ const ApplicationHandle app_handle = tcp_device->AddIncomingApplication(
+ connection_fd);
+
+ TcpSocketConnection* connection(
+ new TcpSocketConnection(device->unique_device_id(), app_handle,
+ controller_));
+ connection->set_socket(connection_fd);
+ const TransportAdapter::Error error = connection->Start();
+ if (error != TransportAdapter::OK) {
+ delete connection;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error TcpClientListener::StartListening() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (thread_started_) {
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::BAD_STATE. Condition: thread_started_");
+ return TransportAdapter::BAD_STATE;
+ }
+
+ socket_ = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (-1 == socket_) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create socket");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL. Condition: -1 == socket_");
+ return TransportAdapter::FAIL;
+ }
+
+ sockaddr_in server_address;
+ memset(&server_address, 0, sizeof(server_address));
+ server_address.sin_family = AF_INET;
+ server_address.sin_port = htons(port_);
+ server_address.sin_addr.s_addr = INADDR_ANY;
+
+ int optval = 1;
+ setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+
+ if (0 != bind(socket_, (sockaddr*) &server_address, sizeof(server_address))) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "bind() failed");
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: 0 != bind(socket_, (sockaddr*) &server_address, sizeof(server_address))");
+ return TransportAdapter::FAIL;
+ }
+
+ if (0 != listen(socket_, 128)) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "listen() failed");
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: 0 != listen(socket_, 128)");
+ return TransportAdapter::FAIL;
+ }
+
+ const int thread_start_error = pthread_create(&thread_, 0,
+ &tcpClientListenerThread, this);
+ if (0 == thread_start_error) {
+ thread_started_ = true;
+ LOG4CXX_DEBUG(logger_, "Tcp client listener thread started");
+ pthread_setname_np(thread_, "TCP listener");
+ } else {
+ LOG4CXX_ERROR(logger_, "Tcp client listener thread start failed, error code "
+ << thread_start_error);
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: 0 !== thread_start_error");
+ return TransportAdapter::FAIL;
+ }
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+}
+
+TransportAdapter::Error TcpClientListener::StopListening() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (!thread_started_) {
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::BAD_STATE. Condition !thread_started_");
+ return TransportAdapter::BAD_STATE;
+ }
+
+ thread_stop_requested_ = true;
+ int byebyesocket = socket(AF_INET, SOCK_STREAM, 0);
+ sockaddr_in server_address;
+ memset(&server_address, 0, sizeof(server_address));
+ server_address.sin_family = AF_INET;
+ server_address.sin_port = htons(port_);
+ server_address.sin_addr.s_addr = INADDR_ANY;
+ connect(byebyesocket, (sockaddr*)&server_address, sizeof(server_address));
+ shutdown(byebyesocket, SHUT_RDWR);
+ close(byebyesocket);
+ pthread_join(thread_, 0);
+ LOG4CXX_DEBUG(logger_, "Tcp client listener thread terminated");
+ close(socket_);
+ socket_ = -1;
+ thread_started_ = false;
+ thread_stop_requested_ = false;
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/tcp/tcp_connection_factory.cc b/src/components/transport_manager/src/tcp/tcp_connection_factory.cc
new file mode 100644
index 0000000000..69173a0e06
--- /dev/null
+++ b/src/components/transport_manager/src/tcp/tcp_connection_factory.cc
@@ -0,0 +1,79 @@
+/**
+ *
+ * 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 "transport_manager/tcp/tcp_connection_factory.h"
+#include "transport_manager/tcp/tcp_socket_connection.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+TcpConnectionFactory::TcpConnectionFactory(TransportAdapterController* controller)
+ : controller_(controller) {
+}
+
+TransportAdapter::Error TcpConnectionFactory::Init() {
+ return TransportAdapter::OK;
+}
+
+TransportAdapter::Error TcpConnectionFactory::CreateConnection(
+ const DeviceUID& device_uid, const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. DeviceUID: " << &device_uid << ", ApplicationHandle: " <<
+ &app_handle);
+ TcpServerOiginatedSocketConnection* connection(
+ new TcpServerOiginatedSocketConnection(device_uid, app_handle,
+ controller_));
+ TransportAdapter::Error error = connection->Start();
+ if (TransportAdapter::OK != error) {
+ LOG4CXX_ERROR(logger_, "Transport adapter error " << error);
+ delete connection;
+ }
+ LOG4CXX_TRACE(logger_, "exit with error " << error);
+ return error;
+}
+
+void TcpConnectionFactory::Terminate() {
+}
+
+bool TcpConnectionFactory::IsInitialised() const {
+ return true;
+}
+
+TcpConnectionFactory::~TcpConnectionFactory() {
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/tcp/tcp_device.cc b/src/components/transport_manager/src/tcp/tcp_device.cc
new file mode 100644
index 0000000000..2540c26ed0
--- /dev/null
+++ b/src/components/transport_manager/src/tcp/tcp_device.cc
@@ -0,0 +1,153 @@
+/**
+ *
+ * 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 "transport_manager/tcp/tcp_device.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+TcpDevice::TcpDevice(const in_addr_t& in_addr, const std::string& name)
+ :
+ Device(name, name),
+ in_addr_(in_addr),
+ last_handle_(0) {
+ pthread_mutex_init(&applications_mutex_, 0);
+}
+
+bool TcpDevice::IsSameAs(const Device* other) const {
+ LOG4CXX_TRACE(logger_, "enter. Device: " << other);
+ const TcpDevice* other_tcp_device = static_cast<const TcpDevice*>(other);
+
+ if (other_tcp_device->in_addr_ == in_addr_) {
+ LOG4CXX_TRACE(logger_,
+ "exit with TRUE. Condition: other_tcp_device->in_addr_ == in_addr_");
+ return true;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ return false;
+ }
+}
+
+ApplicationList TcpDevice::GetApplicationList() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ pthread_mutex_lock(&applications_mutex_);
+ ApplicationList app_list;
+ for (std::map<ApplicationHandle, Application>::const_iterator it =
+ applications_.begin(); it != applications_.end(); ++it) {
+ app_list.push_back(it->first);
+ }
+ pthread_mutex_unlock(&applications_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with app_list. It's size = " << app_list.size());
+ return app_list;
+}
+
+ApplicationHandle TcpDevice::AddIncomingApplication(int socket_fd) {
+ LOG4CXX_TRACE(logger_, "enter. Socket_fd: " << socket_fd);
+ Application app;
+ app.incoming = true;
+ app.socket = socket_fd;
+ app.port = 0; // this line removes compiler warning
+ pthread_mutex_lock(&applications_mutex_);
+ const ApplicationHandle app_handle = ++last_handle_;
+ applications_[app_handle] = app;
+ pthread_mutex_unlock(&applications_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with app_handle " << app_handle);
+ return app_handle;
+}
+
+ApplicationHandle TcpDevice::AddDiscoveredApplication(int port) {
+ LOG4CXX_TRACE(logger_, "enter. port " << port);
+ Application app;
+ app.incoming = false;
+ app.socket = 0; // this line removes compiler warning
+ app.port = port;
+ pthread_mutex_lock(&applications_mutex_);
+ const ApplicationHandle app_handle = ++last_handle_;
+ applications_[app_handle] = app;
+ pthread_mutex_unlock(&applications_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with app_handle " << app_handle);
+ return app_handle;
+}
+
+
+void TcpDevice::RemoveApplication(const ApplicationHandle app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. ApplicationHandle: " << app_handle);
+ pthread_mutex_lock(&applications_mutex_);
+ applications_.erase(app_handle);
+ pthread_mutex_unlock(&applications_mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TcpDevice::~TcpDevice() {
+ pthread_mutex_destroy(&applications_mutex_);
+}
+
+int TcpDevice::GetApplicationSocket(const ApplicationHandle app_handle) const {
+ LOG4CXX_TRACE(logger_, "enter. ApplicationHandle: " << app_handle);
+ std::map<ApplicationHandle, Application>::const_iterator it = applications_.find(
+ app_handle);
+ if (applications_.end() == it) {
+ LOG4CXX_TRACE(logger_, "exit with -1. Condition: applications_.end() == it");
+ return -1;
+ }
+ if (!it->second.incoming) {
+ LOG4CXX_TRACE(logger_, "exit with -1. Condition: !it->second.incoming");
+ return -1;
+ }
+ LOG4CXX_TRACE(logger_, "exit with socket " << it->second.socket);
+ return it->second.socket;
+}
+
+int TcpDevice::GetApplicationPort(const ApplicationHandle app_handle) const {
+ LOG4CXX_TRACE(logger_, "enter. ApplicationHandle: " << app_handle);
+ std::map<ApplicationHandle, Application>::const_iterator it = applications_.find(
+ app_handle);
+ if (applications_.end() == it) {
+ LOG4CXX_TRACE(logger_, "exit with -1. Condition: applications_.end() == it");
+ return -1;
+ }
+ if (it->second.incoming) {
+ LOG4CXX_TRACE(logger_, "exit with -1. Condition: it->second.incoming");
+ return -1;
+ }
+ LOG4CXX_TRACE(logger_, "exit with port " << it->second.port);
+ return it->second.port;
+}
+
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/tcp/tcp_socket_connection.cc b/src/components/transport_manager/src/tcp/tcp_socket_connection.cc
new file mode 100644
index 0000000000..cea5805348
--- /dev/null
+++ b/src/components/transport_manager/src/tcp/tcp_socket_connection.cc
@@ -0,0 +1,121 @@
+/**
+ *
+ * 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 "transport_manager/transport_adapter/transport_adapter_controller.h"
+#include "transport_manager/tcp/tcp_socket_connection.h"
+#include "transport_manager/tcp/tcp_device.h"
+#include "utils/logger.h"
+
+#include <memory.h>
+#include <signal.h>
+#include <errno.h>
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+
+TcpSocketConnection::TcpSocketConnection(const DeviceUID& device_uid,
+ const ApplicationHandle& app_handle,
+ TransportAdapterController* controller)
+ : ThreadedSocketConnection(device_uid, app_handle, controller) {
+}
+
+TcpSocketConnection::~TcpSocketConnection() {
+}
+
+bool TcpSocketConnection::Establish(ConnectError** error) {
+ return true;
+}
+
+TcpServerOiginatedSocketConnection::TcpServerOiginatedSocketConnection(
+ const DeviceUID& device_uid, const ApplicationHandle& app_handle,
+ TransportAdapterController* controller)
+ : ThreadedSocketConnection(device_uid, app_handle, controller) {
+}
+
+TcpServerOiginatedSocketConnection::~TcpServerOiginatedSocketConnection() {
+}
+
+bool TcpServerOiginatedSocketConnection::Establish(ConnectError** error) {
+ LOG4CXX_TRACE(logger_, "enter. error " << error);
+ DeviceSptr device = controller()->FindDevice(device_handle());
+ if (!device.valid()) {
+ LOG4CXX_ERROR(logger_, "Device " << device_handle() << " not found");
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !device.valid()");
+ return false;
+ }
+ TcpDevice* tcp_device = static_cast<TcpDevice*>(device.get());
+
+ int port;
+ if (-1 == (port = tcp_device->GetApplicationPort(application_handle()))) {
+ LOG4CXX_ERROR(logger_, "Application port for " << application_handle() << " not found");
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: port not found");
+ return false;
+ }
+
+ const int socket = ::socket(AF_INET, SOCK_STREAM, 0);
+ if (socket < 0) {
+ LOG4CXX_ERROR(logger_, "Failed to create socket");
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: failed to create socket");
+ return false;
+ }
+
+ struct sockaddr_in addr;
+ memset((char*) &addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = tcp_device->in_addr();
+ addr.sin_port = htons(port);
+
+ LOG4CXX_INFO(logger_, "Connecting " << inet_ntoa(addr.sin_addr) << ":"
+ << port);
+ if (::connect(socket, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
+ LOG4CXX_ERROR(logger_, "Failed to connect for application "
+ << application_handle() << ", error " << errno);
+ *error = new ConnectError();
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: failed to connect to application");
+ return false;
+ }
+
+ set_socket(socket);
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
+
diff --git a/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc b/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc
new file mode 100644
index 0000000000..6067def111
--- /dev/null
+++ b/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc
@@ -0,0 +1,158 @@
+/**
+ *
+ * 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 <signal.h>
+#include <errno.h>
+#include <sstream>
+#include <cstdlib>
+
+#include "resumption/last_state.h"
+
+#include "utils/logger.h"
+
+#include "transport_manager/tcp/tcp_transport_adapter.h"
+#include "transport_manager/tcp/tcp_client_listener.h"
+#include "transport_manager/tcp/tcp_connection_factory.h"
+#include "transport_manager/tcp/tcp_device.h"
+
+#ifdef AVAHI_SUPPORT
+#include "transport_manager/tcp/dnssd_service_browser.h"
+#endif
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportAdapterImpl")
+
+TcpTransportAdapter::TcpTransportAdapter(const uint16_t port)
+ : TransportAdapterImpl(
+#ifdef AVAHI_SUPPORT
+ new DnssdServiceBrowser(this),
+#else
+ NULL,
+#endif
+ new TcpConnectionFactory(this),
+ new TcpClientListener(this, port, false)) {
+}
+
+TcpTransportAdapter::~TcpTransportAdapter() {
+}
+
+DeviceType TcpTransportAdapter::GetDeviceType() const {
+ return "sdl-tcp";
+}
+
+void TcpTransportAdapter::Store() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ Json::Value tcp_adapter_dictionary;
+ Json::Value devices_dictionary;
+ DeviceList device_ids = GetDeviceList();
+ for (DeviceList::const_iterator i = device_ids.begin(); i != device_ids.end(); ++i) {
+ DeviceUID device_id = *i;
+ DeviceSptr device = FindDevice(device_id);
+ if (!device) { // device could have been disconnected
+ continue;
+ }
+ utils::SharedPtr<TcpDevice> tcp_device =
+ DeviceSptr::static_pointer_cast<TcpDevice>(device);
+ Json::Value device_dictionary;
+ device_dictionary["name"] = tcp_device->name();
+ struct in_addr address;
+ address.s_addr = tcp_device->in_addr();
+ device_dictionary["address"] = std::string(inet_ntoa(address));
+ Json::Value applications_dictionary;
+ ApplicationList app_ids = tcp_device->GetApplicationList();
+ for (ApplicationList::const_iterator j = app_ids.begin(); j != app_ids.end(); ++j) {
+ ApplicationHandle app_handle = *j;
+ if (FindEstablishedConnection(tcp_device->unique_device_id(), app_handle)) {
+ int port = tcp_device->GetApplicationPort(app_handle);
+ if (port != -1) { // don't want to store incoming applications
+ Json::Value application_dictionary;
+ char port_record[12];
+ sprintf(port_record, "%d", port);
+ application_dictionary["port"] = std::string(port_record);
+ applications_dictionary.append(application_dictionary);
+ }
+ }
+ }
+ if (!applications_dictionary.empty()) {
+ device_dictionary["applications"] = applications_dictionary;
+ devices_dictionary.append(device_dictionary);
+ }
+ }
+ tcp_adapter_dictionary["devices"] = devices_dictionary;
+ resumption::LastState::instance()->dictionary["TransportManager"]["TcpAdapter"] =
+ tcp_adapter_dictionary;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool TcpTransportAdapter::Restore() {
+ LOG4CXX_TRACE(logger_, "enter");
+ bool errors_occurred = false;
+ const Json::Value tcp_adapter_dictionary =
+ resumption::LastState::instance()->dictionary["TransportManager"]["TcpAdapter"];
+ const Json::Value devices_dictionary = tcp_adapter_dictionary["devices"];
+ for (Json::Value::const_iterator i = devices_dictionary.begin();
+ i != devices_dictionary.end(); ++i) {
+ const Json::Value device_dictionary = *i;
+ std::string name = device_dictionary["name"].asString();
+ std::string address_record = device_dictionary["address"].asString();
+ in_addr_t address = inet_addr(address_record.c_str());
+ TcpDevice* tcp_device = new TcpDevice(address, name);
+ DeviceSptr device(tcp_device);
+ AddDevice(device);
+ const Json::Value applications_dictionary = device_dictionary["applications"];
+ for (Json::Value::const_iterator j = applications_dictionary.begin();
+ j != applications_dictionary.end(); ++j) {
+ const Json::Value application_dictionary = *j;
+ std::string port_record = application_dictionary["port"].asString();
+ int port = atoi(port_record.c_str());
+ ApplicationHandle app_handle = tcp_device->AddDiscoveredApplication(port);
+ if (Error::OK != Connect(device->unique_device_id(), app_handle)) {
+ errors_occurred = true;
+ }
+ }
+ }
+ bool result = !errors_occurred;
+ if (result) {
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with FALSE");
+ }
+ return result;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
+
diff --git a/src/components/transport_manager/src/transport_adapter/threaded_socket_connection.cc b/src/components/transport_manager/src/transport_adapter/threaded_socket_connection.cc
new file mode 100644
index 0000000000..2c365ca405
--- /dev/null
+++ b/src/components/transport_manager/src/transport_adapter/threaded_socket_connection.cc
@@ -0,0 +1,357 @@
+/**
+ * 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 <fcntl.h>
+#include <memory.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "utils/logger.h"
+
+#include "transport_manager/transport_adapter/threaded_socket_connection.h"
+#include "transport_manager/transport_adapter/transport_adapter_controller.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+ThreadedSocketConnection::ThreadedSocketConnection(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle,
+ TransportAdapterController* controller)
+ : read_fd_(-1), write_fd_(-1), controller_(controller),
+ frames_to_send_(),
+ frames_to_send_mutex_(),
+ thread_(),
+ socket_(-1),
+ terminate_flag_(false),
+ unexpected_disconnect_(false),
+ device_uid_(device_id),
+ app_handle_(app_handle) {
+ pthread_mutex_init(&frames_to_send_mutex_, 0);
+}
+
+ThreadedSocketConnection::~ThreadedSocketConnection() {
+ terminate_flag_ = true;
+ Notify();
+ pthread_join(thread_, 0);
+ pthread_mutex_destroy(&frames_to_send_mutex_);
+
+ if (-1 != read_fd_) {
+ close(read_fd_);
+ }
+ if (-1 != write_fd_) {
+ close(write_fd_);
+ }
+}
+
+void ThreadedSocketConnection::Abort() {
+ LOG4CXX_TRACE(logger_, "enter");
+ unexpected_disconnect_ = true;
+ terminate_flag_ = true;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void* StartThreadedSocketConnection(void* v) {
+ LOG4CXX_TRACE(logger_, "enter");
+ ThreadedSocketConnection* connection =
+ static_cast<ThreadedSocketConnection*>(v);
+ connection->Thread();
+ LOG4CXX_TRACE(logger_, "exit with 0");
+ return 0;
+}
+
+TransportAdapter::Error ThreadedSocketConnection::Start() {
+ LOG4CXX_TRACE(logger_, "enter");
+ int fds[2];
+ const int pipe_ret = pipe(fds);
+ if (0 == pipe_ret) {
+ LOG4CXX_DEBUG(logger_, "pipe created(#" << pthread_self() << ")");
+ read_fd_ = fds[0];
+ write_fd_ = fds[1];
+ } else {
+ LOG4CXX_WARN(logger_, "pipe creation failed (#" << pthread_self() << ")");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL");
+ return TransportAdapter::FAIL;
+ }
+ const int fcntl_ret = fcntl(read_fd_, F_SETFL,
+ fcntl(read_fd_, F_GETFL) | O_NONBLOCK);
+ if (0 != fcntl_ret) {
+ LOG4CXX_WARN(logger_, "fcntl failed (#" << pthread_self() << ")");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL");
+ return TransportAdapter::FAIL;
+ }
+
+ if (0 != pthread_create(&thread_, 0, &StartThreadedSocketConnection, this)) {
+ LOG4CXX_WARN(logger_, "thread creation failed (#" << pthread_self() << ")");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL");
+ return TransportAdapter::FAIL;
+ }
+ LOG4CXX_DEBUG(logger_, "thread created (#" << pthread_self() << ")");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ const std::string thread_name = std::string("Socket ") + device_handle();
+ pthread_setname_np(thread_, thread_name.c_str());
+ return TransportAdapter::OK;
+}
+
+void ThreadedSocketConnection::Finalize() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (unexpected_disconnect_) {
+ LOG4CXX_DEBUG(logger_, "unexpected_disconnect (#" << pthread_self() << ")");
+ controller_->ConnectionAborted(device_handle(), application_handle(),
+ CommunicationError());
+ } else {
+ LOG4CXX_DEBUG(logger_, "not unexpected_disconnect (#" << pthread_self() << ")");
+ controller_->ConnectionFinished(device_handle(), application_handle());
+ }
+ close(socket_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error ThreadedSocketConnection::Notify() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (-1 == write_fd_) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_,
+ "Failed to wake up connection thread for connection " << this);
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::BAD_STATE");
+ return TransportAdapter::BAD_STATE;
+ }
+ uint8_t c = 0;
+ if (1 == write(write_fd_, &c, 1)) {
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+ } else {
+ LOG4CXX_ERROR_WITH_ERRNO(
+ logger_, "Failed to wake up connection thread for connection " << this);
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL");
+ return TransportAdapter::FAIL;
+ }
+}
+
+TransportAdapter::Error ThreadedSocketConnection::SendData(
+ RawMessagePtr message) {
+ LOG4CXX_TRACE(logger_, "enter");
+ pthread_mutex_lock(&frames_to_send_mutex_);
+ frames_to_send_.push(message);
+ pthread_mutex_unlock(&frames_to_send_mutex_);
+ TransportAdapter::Error error = Notify();
+ LOG4CXX_TRACE(logger_, "exit with error" << error);
+ return error;
+}
+
+TransportAdapter::Error ThreadedSocketConnection::Disconnect() {
+ LOG4CXX_TRACE(logger_, "enter");
+ terminate_flag_ = true;
+ TransportAdapter::Error error = Notify();
+ LOG4CXX_TRACE(logger_, "exit with error" << error);
+ return error;
+}
+
+void ThreadedSocketConnection::Thread() {
+ LOG4CXX_TRACE(logger_, "enter");
+ controller_->ConnectionCreated(this, device_uid_, app_handle_);
+ ConnectError* connect_error = NULL;
+ if (Establish(&connect_error)) {
+ LOG4CXX_DEBUG(logger_, "Connection established (#" << pthread_self() << ")");
+ controller_->ConnectDone(device_handle(), application_handle());
+ while (!terminate_flag_) {
+ Transmit();
+ }
+ LOG4CXX_DEBUG(logger_, "Connection is to finalize (#" << pthread_self() << ")");
+ Finalize();
+ while (!frames_to_send_.empty()) {
+ LOG4CXX_INFO(logger_, "removing message (#" << pthread_self() << ")");
+ RawMessagePtr message = frames_to_send_.front();
+ frames_to_send_.pop();
+ controller_->DataSendFailed(device_handle(), application_handle(),
+ message, DataSendError());
+ }
+ controller_->DisconnectDone(device_handle(), application_handle());
+ } else {
+ LOG4CXX_ERROR(logger_, "Connection Establish failed (#" << pthread_self() << ")");
+ controller_->ConnectFailed(device_handle(), application_handle(),
+ *connect_error);
+ delete connect_error;
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void ThreadedSocketConnection::Transmit() {
+ LOG4CXX_TRACE(logger_, "enter");
+
+ const nfds_t poll_fds_size = 2;
+ pollfd poll_fds[poll_fds_size];
+ poll_fds[0].fd = socket_;
+ poll_fds[0].events = POLLIN | POLLPRI | (frames_to_send_.empty() ? 0 : POLLOUT);
+ poll_fds[1].fd = read_fd_;
+ poll_fds[1].events = POLLIN | POLLPRI;
+
+ LOG4CXX_DEBUG(logger_, "poll (#" << pthread_self() << ") " << this);
+ if (-1 == poll(poll_fds, poll_fds_size, -1)) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "poll failed for connection " << this);
+ Abort();
+ LOG4CXX_TRACE(logger_, "exit. Condition: -1 == poll(poll_fds, poll_fds_size, -1)");
+ return;
+ }
+ LOG4CXX_DEBUG(logger_, "poll is ok (#" << pthread_self() << ") " << this << " revents0:"
+ <<
+ std::hex << poll_fds[0].revents << " revents1:" << std::hex << poll_fds[1].revents);
+ // error check
+ if (0 != (poll_fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))) {
+ LOG4CXX_ERROR(logger_,
+ "Notification pipe for connection " << this << " terminated");
+ Abort();
+ LOG4CXX_TRACE(logger_,
+ "exit. Condition: 0 != (poll_fds[1].revents & (POLLERR | POLLHUP | POLLNVAL))");
+ return;
+ }
+
+ if (poll_fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ LOG4CXX_WARN(logger_, "Connection " << this << " terminated");
+ Abort();
+ LOG4CXX_TRACE(logger_,
+ "exit. Condition: poll_fds[0].revents & (POLLERR | POLLHUP | POLLNVAL");
+ return;
+ }
+
+ // clear notifications
+ char buffer[256];
+ ssize_t bytes_read = -1;
+ do {
+ bytes_read = read(read_fd_, buffer, sizeof(buffer));
+ } while (bytes_read > 0);
+ if ((bytes_read < 0) && (EAGAIN != errno)) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to clear notification pipe");
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "poll failed for connection " << this);
+ Abort();
+ LOG4CXX_TRACE(logger_, "exit. Condition: (bytes_read < 0) && (EAGAIN != errno)");
+ return;
+ }
+
+ // send data if possible
+ if (!frames_to_send_.empty() && (poll_fds[0].revents | POLLOUT)) {
+ LOG4CXX_DEBUG(logger_, "frames_to_send_ not empty() (#" << pthread_self() << ")");
+
+ // send data
+ const bool send_ok = Send();
+ if (!send_ok) {
+ LOG4CXX_ERROR(logger_, "Send() failed (#" << pthread_self() << ")");
+ Abort();
+ LOG4CXX_TRACE(logger_, "exit. Condition: !send_ok");
+ return;
+ }
+ }
+
+ // receive data
+ if (poll_fds[0].revents & (POLLIN | POLLPRI)) {
+ const bool receive_ok = Receive();
+ if (!receive_ok) {
+ LOG4CXX_ERROR(logger_, "Receive() failed (#" << pthread_self() << ")");
+ Abort();
+ LOG4CXX_TRACE(logger_, "exit. Condition: !receive_ok");
+ return;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool ThreadedSocketConnection::Receive() {
+ LOG4CXX_TRACE(logger_, "enter");
+ uint8_t buffer[4096];
+ ssize_t bytes_read = -1;
+
+ do {
+ bytes_read = recv(socket_, buffer, sizeof(buffer), MSG_DONTWAIT);
+
+ if (bytes_read > 0) {
+ LOG4CXX_DEBUG(
+ logger_,
+ "Received " << bytes_read << " bytes for connection " << this);
+ RawMessagePtr frame(
+ new protocol_handler::RawMessage(0, 0, buffer, bytes_read));
+ controller_->DataReceiveDone(device_handle(), application_handle(),
+ frame);
+ } else if (bytes_read < 0) {
+ if (EAGAIN != errno && EWOULDBLOCK != errno) {
+ LOG4CXX_ERROR_WITH_ERRNO(logger_,
+ "recv() failed for connection " << this);
+ LOG4CXX_TRACE(logger_,
+ "exit with FALSE. Condition: EAGAIN != errno && EWOULDBLOCK != errno");
+ return false;
+ }
+ } else {
+ LOG4CXX_WARN(logger_, "Connection " << this << " closed by remote peer");
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: bytes_read >= 0");
+ return false;
+ }
+ } while (bytes_read > 0);
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+bool ThreadedSocketConnection::Send() {
+ LOG4CXX_TRACE(logger_, "enter");
+ FrameQueue frames_to_send;
+ pthread_mutex_lock(&frames_to_send_mutex_);
+ std::swap(frames_to_send, frames_to_send_);
+ pthread_mutex_unlock(&frames_to_send_mutex_);
+
+ size_t offset = 0;
+ while (!frames_to_send.empty()) {
+ LOG4CXX_INFO(logger_, "frames_to_send is not empty" << pthread_self() << ")");
+ RawMessagePtr frame = frames_to_send.front();
+ const ssize_t bytes_sent = ::send(socket_, frame->data() + offset,
+ frame->data_size() - offset, 0);
+
+ if (bytes_sent >= 0) {
+ LOG4CXX_DEBUG(logger_, "bytes_sent >= 0" << pthread_self() << ")");
+ offset += bytes_sent;
+ if (offset == frame->data_size()) {
+ frames_to_send.pop();
+ offset = 0;
+ controller_->DataSendDone(device_handle(), application_handle(), frame);
+ }
+ } else {
+ LOG4CXX_DEBUG(logger_, "bytes_sent < 0" << pthread_self() << ")");
+ LOG4CXX_ERROR_WITH_ERRNO(logger_, "Send failed for connection " << this);
+ frames_to_send.pop();
+ offset = 0;
+ controller_->DataSendFailed(device_handle(), application_handle(), frame,
+ DataSendError());
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+} // namespace
+} // namespace
diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc
new file mode 100644
index 0000000000..e1d6197072
--- /dev/null
+++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 2014, 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 "config_profile/profile.h"
+#include "utils/logger.h"
+
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+#include "transport_manager/transport_adapter/transport_adapter_listener.h"
+#include "transport_manager/transport_adapter/device_scanner.h"
+#include "transport_manager/transport_adapter/server_connection_factory.h"
+#include "transport_manager/transport_adapter/client_connection_listener.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+TransportAdapterImpl::TransportAdapterImpl(
+ DeviceScanner* device_scanner,
+ ServerConnectionFactory* server_connection_factory,
+ ClientConnectionListener* client_connection_listener)
+ : listeners_(),
+ initialised_(0),
+ devices_(),
+ devices_mutex_(),
+ connections_(),
+ connections_mutex_(),
+ device_scanner_(device_scanner),
+ server_connection_factory_(server_connection_factory),
+ client_connection_listener_(client_connection_listener)
+#ifdef TIME_TESTER
+ , metric_observer_(NULL)
+#endif // TIME_TESTER
+{
+ pthread_mutex_init(&devices_mutex_, 0);
+ pthread_mutex_init(&connections_mutex_, 0);
+}
+
+TransportAdapterImpl::~TransportAdapterImpl() {
+ if (device_scanner_) {
+ device_scanner_->Terminate();
+ LOG4CXX_DEBUG(logger_, "device_scanner_ " << device_scanner_ << " terminated.");
+ delete device_scanner_;
+ LOG4CXX_DEBUG(logger_, "device_scanner_ " << device_scanner_ << " deleted.");
+ }
+ if (server_connection_factory_) {
+ server_connection_factory_->Terminate();
+ LOG4CXX_DEBUG(logger_, "server_connection_factory " << server_connection_factory_ << " terminated.");
+ delete server_connection_factory_;
+ LOG4CXX_DEBUG(logger_, "server_connection_factory " << server_connection_factory_ << " deleted.");
+ }
+ if (client_connection_listener_) {
+ client_connection_listener_->Terminate();
+ LOG4CXX_DEBUG(logger_, "client_connection_listener_ " << client_connection_listener_ << " terminated.");
+ delete client_connection_listener_;
+ LOG4CXX_DEBUG(logger_, "client_connection_listener_ " << client_connection_listener_ << " deleted.");
+ }
+
+ pthread_mutex_lock(&connections_mutex_);
+ ConnectionMap connections;
+ std::swap(connections, connections_);
+ pthread_mutex_unlock(&connections_mutex_);
+ connections.clear();
+
+ LOG4CXX_DEBUG(logger_, "Connections deleted");
+
+ pthread_mutex_lock(&devices_mutex_);
+ DeviceMap devices;
+ std::swap(devices, devices_);
+ pthread_mutex_unlock(&devices_mutex_);
+ devices.clear();
+
+ LOG4CXX_DEBUG(logger_, "Devices deleted");
+
+ pthread_mutex_destroy(&connections_mutex_);
+ pthread_mutex_destroy(&devices_mutex_);
+}
+
+TransportAdapter::Error TransportAdapterImpl::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+
+ Error error = OK;
+
+ if ((error == OK) && device_scanner_) {
+ error = device_scanner_->Init();
+ }
+ if ((error == OK) && server_connection_factory_) {
+ error = server_connection_factory_->Init();
+ }
+ if ((error == OK) && client_connection_listener_) {
+ error = client_connection_listener_->Init();
+ }
+
+ initialised_ = (error == OK);
+
+ if (profile::Profile::instance()->use_last_state()) {
+ if (!Restore()) {
+ LOG4CXX_WARN(logger_, "could not restore transport adapter state");
+ error = FAIL;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit with error: " << error);
+ return error;
+}
+
+TransportAdapter::Error TransportAdapterImpl::SearchDevices() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (device_scanner_ == NULL) {
+ LOG4CXX_TRACE(logger_, "exit with NOT_SUPPORTED");
+ return NOT_SUPPORTED;
+ } else if (!device_scanner_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+ TransportAdapter::Error er = device_scanner_->Scan();
+ LOG4CXX_TRACE(logger_, "exit with error: " << er);
+ return er;
+}
+
+TransportAdapter::Error TransportAdapterImpl::Connect(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. DeviceUID " << device_id << " ApplicationHandle " <<
+ app_handle);
+ if (server_connection_factory_ == 0) {
+ LOG4CXX_TRACE(logger_, "exit with NOT_SUPPORTED");
+ return NOT_SUPPORTED;
+ }
+ if (!server_connection_factory_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+
+ pthread_mutex_lock(&connections_mutex_);
+ const bool already_exists =
+ connections_.end() !=
+ connections_.find(std::make_pair(device_id, app_handle));
+ if (!already_exists) {
+ ConnectionInfo& info = connections_[std::make_pair(device_id, app_handle)];
+ info.app_handle = app_handle;
+ info.device_id = device_id;
+ info.state = ConnectionInfo::NEW;
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+ if (already_exists) {
+ LOG4CXX_TRACE(logger_, "exit with ALREADY_EXISTS");
+ return ALREADY_EXISTS;
+ }
+
+ const TransportAdapter::Error err =
+ server_connection_factory_->CreateConnection(device_id, app_handle);
+ if (TransportAdapter::OK != err) {
+ pthread_mutex_lock(&connections_mutex_);
+ connections_.erase(std::make_pair(device_id, app_handle));
+ pthread_mutex_unlock(&connections_mutex_);
+ }
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+}
+
+TransportAdapter::Error TransportAdapterImpl::ConnectDevice(
+ const DeviceUID& device_handle) {
+ LOG4CXX_TRACE(logger_, "enter with device_handle: " << &device_handle);
+ DeviceSptr device = FindDevice(device_handle);
+ if (device) {
+ TransportAdapter::Error err = ConnectDevice(device);
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with BAD_PARAM");
+ return BAD_PARAM;
+ }
+}
+
+TransportAdapter::Error TransportAdapterImpl::Disconnect(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id << ", device_id: " <<
+ &device_id);
+ if (!initialised_) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+ ConnectionSptr connection = FindEstablishedConnection(device_id, app_handle);
+ if (connection.valid()) {
+ TransportAdapter::Error err = connection->Disconnect();
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with BAD_PARAM");
+ return BAD_PARAM;
+ }
+}
+
+TransportAdapter::Error TransportAdapterImpl::DisconnectDevice(
+ const DeviceUID& device_id) {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id);
+ if (!initialised_) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+
+ Error error = OK;
+ pthread_mutex_lock(&connections_mutex_);
+ for (ConnectionMap::iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+
+ ConnectionInfo& info = it->second;
+ if (info.device_id == device_id &&
+ info.state != ConnectionInfo::FINALISING) {
+ if (OK != info.connection->Disconnect()) {
+ error = FAIL;
+ LOG4CXX_ERROR(logger_, "Error on disconnect" << error);
+ }
+ }
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with error " << error);
+ return error;
+}
+
+TransportAdapter::Error TransportAdapterImpl::SendData(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle,
+ const RawMessagePtr data) {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id << ", app_handle: " <<
+ &app_handle << ", data: " << data);
+ if (!initialised_) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+
+ ConnectionSptr connection = FindEstablishedConnection(device_id, app_handle);
+ if (connection.get() != 0) {
+ TransportAdapter::Error err = connection->SendData(data);
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with BAD_PARAM");
+ return BAD_PARAM;
+ }
+}
+
+TransportAdapter::Error TransportAdapterImpl::StartClientListening() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (client_connection_listener_ == 0) {
+ LOG4CXX_TRACE(logger_, "exit with NOT_SUPPORTED");
+ return NOT_SUPPORTED;
+ }
+ if (!client_connection_listener_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+ TransportAdapter::Error err = client_connection_listener_->StartListening();
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+}
+
+TransportAdapter::Error TransportAdapterImpl::StopClientListening() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (client_connection_listener_ == 0) {
+ LOG4CXX_TRACE(logger_, "exit with NOT_SUPPORTED");
+ return NOT_SUPPORTED;
+ }
+ if (!client_connection_listener_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_, "exit with BAD_STATE");
+ return BAD_STATE;
+ }
+ TransportAdapter::Error err = client_connection_listener_->StopListening();
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+}
+
+DeviceList TransportAdapterImpl::GetDeviceList() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ DeviceList devices;
+ pthread_mutex_lock(&devices_mutex_);
+ for (DeviceMap::const_iterator it = devices_.begin(); it != devices_.end();
+ ++it) {
+ devices.push_back(it->first);
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with DeviceList. It's' size = " << devices.size());
+ return devices;
+}
+
+DeviceSptr TransportAdapterImpl::AddDevice(DeviceSptr device) {
+ LOG4CXX_TRACE(logger_, "enter. device: " << device);
+ DeviceSptr existing_device;
+ bool same_device_found = false;
+ pthread_mutex_lock(&devices_mutex_);
+ for (DeviceMap::const_iterator i = devices_.begin(); i != devices_.end();
+ ++i) {
+ existing_device = i->second;
+ if (device->IsSameAs(existing_device.get())) {
+ same_device_found = true;
+ LOG4CXX_DEBUG(logger_, "device " << device << "already exists");
+ break;
+ }
+ }
+ if (!same_device_found) {
+ devices_[device->unique_device_id()] = device;
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+ if (same_device_found) {
+ LOG4CXX_TRACE(logger_, "exit with TRUE. Condition: same_device_found");
+ return existing_device;
+ } else {
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnDeviceListUpdated(this);
+ }
+ if (ToBeAutoConnected(device)) {
+ ConnectDevice(device);
+ }
+ LOG4CXX_TRACE(logger_, "exit with DeviceSptr " << device);
+ return device;
+ }
+}
+
+void TransportAdapterImpl::SearchDeviceDone(const DeviceVector& devices) {
+ LOG4CXX_TRACE(logger_, "enter. devices: " << &devices);
+ DeviceMap new_devices;
+ for (DeviceVector::const_iterator it = devices.begin(); it != devices.end();
+ ++it) {
+ DeviceSptr device = *it;
+ bool device_found = false;
+
+ pthread_mutex_lock(&devices_mutex_);
+ for (DeviceMap::iterator it = devices_.begin(); it != devices_.end();
+ ++it) {
+ DeviceSptr existing_device = it->second;
+ if (device->IsSameAs(existing_device.get())) {
+ existing_device->set_keep_on_disconnect(true);
+ device_found = true;
+ LOG4CXX_DEBUG(logger_, "device found. DeviceSptr" << it->second);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+
+ if (!device_found) {
+ LOG4CXX_INFO(logger_, "Adding new device " << device->unique_device_id()
+ << " (\"" << device->name()
+ << "\")");
+ }
+
+ device->set_keep_on_disconnect(true);
+ new_devices[device->unique_device_id()] = device;
+ }
+
+ pthread_mutex_lock(&connections_mutex_);
+ std::set<DeviceUID> connected_devices;
+ for (ConnectionMap::const_iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ const ConnectionInfo& info = it->second;
+ if (info.state != ConnectionInfo::FINALISING) {
+ connected_devices.insert(info.device_id);
+ }
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+
+ DeviceMap all_devices = new_devices;
+ pthread_mutex_lock(&devices_mutex_);
+ for (DeviceMap::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ DeviceSptr existing_device = it->second;
+
+ if (all_devices.end() == all_devices.find(it->first)) {
+ if (connected_devices.end() != connected_devices.find(it->first)) {
+ existing_device->set_keep_on_disconnect(false);
+ all_devices[it->first] = existing_device;
+ }
+ }
+ }
+ devices_ = all_devices;
+ pthread_mutex_unlock(&devices_mutex_);
+
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnDeviceListUpdated(this);
+ (*it)->OnSearchDeviceDone(this);
+ }
+
+ for (DeviceMap::iterator it = new_devices.begin(); it != new_devices.end(); ++it) {
+ DeviceSptr device = it->second;
+ if (ToBeAutoConnected(device)) {
+ ConnectDevice(device);
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::ApplicationListUpdated(const DeviceUID& device_handle) {
+ // default implementation does nothing
+ // and is reimplemented in MME transport adapter only
+}
+
+void TransportAdapterImpl::FindNewApplicationsRequest() {
+ LOG4CXX_TRACE(logger_, "enter");
+ for (TransportAdapterListenerList::iterator i = listeners_.begin(); i != listeners_.end();
+ ++i) {
+ TransportAdapterListener* listener = *i;
+ listener->OnFindNewApplicationsRequest(this);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::SearchDeviceFailed(const SearchDeviceError& error) {
+ LOG4CXX_TRACE(logger_, "enter");
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnSearchDeviceFailed(this, error);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool TransportAdapterImpl::IsSearchDevicesSupported() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ return device_scanner_ != 0;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool TransportAdapterImpl::IsServerOriginatedConnectSupported() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ return server_connection_factory_ != 0;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool TransportAdapterImpl::IsClientOriginatedConnectSupported() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ return client_connection_listener_ != 0;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::ConnectionCreated(
+ ConnectionSptr connection, const DeviceUID& device_id,
+ const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter connection:" << connection << ", device_id: " << &device_id
+ << ", app_handle: " << &app_handle);
+ pthread_mutex_lock(&connections_mutex_);
+ ConnectionInfo& info = connections_[std::make_pair(device_id, app_handle)];
+ info.app_handle = app_handle;
+ info.device_id = device_id;
+ info.connection = connection;
+ info.state = ConnectionInfo::NEW;
+ pthread_mutex_unlock(&connections_mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::DeviceDisconnected(
+ const DeviceUID& device_handle, const DisconnectDeviceError& error) {
+ const DeviceUID device_uid = device_handle;
+ LOG4CXX_TRACE(logger_, "enter. device_handle: " << &device_uid << ", error: " <<
+ &error);
+ ApplicationList app_list = GetApplicationList(device_uid);
+ for (ApplicationList::const_iterator i = app_list.begin(); i != app_list.end(); ++i) {
+ ApplicationHandle app_handle = *i;
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ TransportAdapterListener* listener = *it;
+ listener->OnUnexpectedDisconnect(this, device_uid, app_handle, CommunicationError());
+ }
+ }
+
+ pthread_mutex_lock(&connections_mutex_);
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ TransportAdapterListener* listener = *it;
+ listener->OnDisconnectDeviceDone(this, device_uid);
+ }
+ for (ApplicationList::const_iterator i = app_list.begin(); i != app_list.end(); ++i) {
+ ApplicationHandle app_handle = *i;
+ connections_.erase(std::make_pair(device_uid, app_handle));
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+
+ RemoveDevice(device_uid);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::DisconnectDone(
+ const DeviceUID& device_handle, const ApplicationHandle& app_handle) {
+ const DeviceUID device_uid = device_handle;
+ const ApplicationHandle app_uid = app_handle;
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_uid << ", app_handle: " <<
+ &app_uid);
+ bool device_disconnected = true;
+ pthread_mutex_lock(&connections_mutex_);
+ for (ConnectionMap::const_iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ const DeviceUID& current_device_id = it->first.first;
+ const ApplicationHandle& current_app_handle = it->first.second;
+ if (current_device_id == device_uid && current_app_handle != app_uid) {
+ device_disconnected = false;
+ LOG4CXX_DEBUG(logger_,
+ "break. Condition: current_device_id == device_id && current_app_handle != app_handle");
+ break;
+ }
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ TransportAdapterListener* listener = *it;
+ listener->OnDisconnectDone(this, device_uid, app_uid);
+ if (device_disconnected) {
+ listener->OnDisconnectDeviceDone(this, device_uid);
+ }
+ }
+ pthread_mutex_lock(&connections_mutex_);
+ connections_.erase(std::make_pair(device_uid, app_uid));
+ pthread_mutex_unlock(&connections_mutex_);
+
+ if (device_disconnected) {
+ RemoveDevice(device_uid);
+ }
+
+ Store();
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::DataReceiveDone(const DeviceUID& device_id,
+ const ApplicationHandle& app_handle,
+ RawMessagePtr message) {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id << ", app_handle: " <<
+ &app_handle << ", message: " << message);
+
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ metric_observer_->StartRawMsg(message.get());
+ }
+#endif // TIME_TESTER
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnDataReceiveDone(this, device_id, app_handle, message);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::DataReceiveFailed(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle,
+ const DataReceiveError& error) {
+ LOG4CXX_TRACE(logger_, "enter");
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnDataReceiveFailed(this, device_id, app_handle, error);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::DataSendDone(const DeviceUID& device_id,
+ const ApplicationHandle& app_handle,
+ RawMessagePtr message) {
+ LOG4CXX_TRACE(logger_, "enter");
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnDataSendDone(this, device_id, app_handle, message);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::DataSendFailed(const DeviceUID& device_id,
+ const ApplicationHandle& app_handle,
+ RawMessagePtr message,
+ const DataSendError& error) {
+ LOG4CXX_TRACE(logger_, "enter");
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnDataSendFailed(this, device_id, app_handle, message, error);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+DeviceSptr TransportAdapterImpl::FindDevice(const DeviceUID& device_id) const {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id);
+ DeviceSptr ret;
+ LOG4CXX_DEBUG(logger_, "devices_.size() = " << devices_.size());
+ pthread_mutex_lock(&devices_mutex_);
+ DeviceMap::const_iterator it = devices_.find(device_id);
+ if (it != devices_.end()) {
+ ret = it->second;
+ } else {
+ LOG4CXX_WARN(logger_, "Device " << device_id << " not found.");
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with DeviceSptr: " << ret);
+ return ret;
+}
+
+void TransportAdapterImpl::ConnectDone(const DeviceUID& device_id,
+ const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id << ", app_handle: " <<
+ &app_handle);
+ pthread_mutex_lock(&connections_mutex_);
+ ConnectionMap::iterator it_conn =
+ connections_.find(std::make_pair(device_id, app_handle));
+ if (it_conn != connections_.end()) {
+ ConnectionInfo& info = it_conn->second;
+ info.state = ConnectionInfo::ESTABLISHED;
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnConnectDone(this, device_id, app_handle);
+ }
+
+ Store();
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::ConnectFailed(const DeviceUID& device_handle,
+ const ApplicationHandle& app_handle, const ConnectError& error) {
+ const DeviceUID device_uid = device_handle;
+ const ApplicationHandle app_uid = app_handle;
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_uid << ", app_handle: " <<
+ &app_uid << ", error: " << &error);
+ pthread_mutex_lock(&connections_mutex_);
+ connections_.erase(std::make_pair(device_uid, app_uid));
+ pthread_mutex_unlock(&connections_mutex_);
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnConnectFailed(this, device_uid, app_uid, error);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::AddListener(TransportAdapterListener* listener) {
+ LOG4CXX_TRACE(logger_, "enter");
+ listeners_.push_back(listener);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+ApplicationList TransportAdapterImpl::GetApplicationList(
+ const DeviceUID& device_id) const {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id);
+ DeviceSptr device = FindDevice(device_id);
+ if (device.valid()) {
+ ApplicationList lst = device->GetApplicationList();
+ LOG4CXX_TRACE(logger_, "exit with ApplicationList. It's size = " << lst.size() <<
+ " Condition: device.valid()");
+ return lst;
+ }
+ LOG4CXX_TRACE(logger_, "exit with empty ApplicationList. Condition: NOT device.valid()");
+ return ApplicationList();
+}
+
+void TransportAdapterImpl::ConnectionFinished(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id << ", app_handle: " <<
+ &app_handle);
+ pthread_mutex_lock(&connections_mutex_);
+ ConnectionMap::iterator it =
+ connections_.find(std::make_pair(device_id, app_handle));
+ if (it != connections_.end()) {
+ ConnectionInfo& info = it->second;
+ info.state = ConnectionInfo::FINALISING;
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterImpl::ConnectionAborted(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle,
+ const CommunicationError& error) {
+ ConnectionFinished(device_id, app_handle);
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ (*it)->OnUnexpectedDisconnect(this, device_id, app_handle, error);
+ }
+}
+
+bool TransportAdapterImpl::IsInitialised() const {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (!initialised_) {
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !initialised_");
+ return false;
+ }
+ if (device_scanner_ && !device_scanner_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_,
+ "exit with FALSE. Condition: device_scanner_ && !device_scanner_->IsInitialised()");
+ return false;
+ }
+ if (server_connection_factory_ &&
+ !server_connection_factory_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_,
+ "exit with FALSE. Condition: server_connection_factory_ && !server_connection_factory_->IsInitialised()");
+ return false;
+ }
+ if (client_connection_listener_ &&
+ !client_connection_listener_->IsInitialised()) {
+ LOG4CXX_TRACE(logger_,
+ "exit with FALSE. Condition: client_connection_listener_ && !client_connection_listener_->IsInitialised()");
+ return false;
+ }
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+std::string TransportAdapterImpl::DeviceName(const DeviceUID& device_id) const {
+ DeviceSptr device = FindDevice(device_id);
+ if (device.valid()) {
+ return device->name();
+ } else {
+ return "";
+ }
+}
+
+std::string TransportAdapterImpl::GetConnectionType() const {
+ const std::string deviceType = GetDeviceType();
+ std::string result("USB_serial_number");
+ if ("sdl-tcp" == deviceType || "sdl-bluetooth" == deviceType) {
+ result.assign("BTMAC");
+ }
+ return result;
+}
+
+#ifdef TIME_TESTER
+void TransportAdapterImpl::SetTimeMetricObserver(TMMetricObserver* observer) {
+ metric_observer_ = observer;
+}
+#endif // TIME_TESTER
+
+#ifdef TIME_TESTER
+TMMetricObserver* TransportAdapterImpl::GetTimeMetricObserver() {
+ return metric_observer_;
+}
+#endif // TIME_TESTER
+
+void TransportAdapterImpl::Store() const {
+}
+
+bool TransportAdapterImpl::Restore() {
+ return true;
+}
+
+bool TransportAdapterImpl::ToBeAutoConnected(DeviceSptr device) const {
+ return false;
+}
+
+ConnectionSptr TransportAdapterImpl::FindEstablishedConnection(
+ const DeviceUID& device_id, const ApplicationHandle& app_handle) const {
+ LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id << ", app_handle: " <<
+ &app_handle);
+ ConnectionSptr connection;
+ pthread_mutex_lock(&connections_mutex_);
+ ConnectionMap::const_iterator it =
+ connections_.find(std::make_pair(device_id, app_handle));
+ if (it != connections_.end()) {
+ const ConnectionInfo& info = it->second;
+ if (info.state == ConnectionInfo::ESTABLISHED) {
+ connection = info.connection;
+ }
+ }
+ pthread_mutex_unlock(&connections_mutex_);
+ LOG4CXX_TRACE(logger_, "exit with ConnectionSptr: " << connection);
+ return connection;
+}
+
+TransportAdapter::Error TransportAdapterImpl::ConnectDevice(DeviceSptr device) {
+ LOG4CXX_TRACE(logger_, "enter. device: " << device);
+ DeviceUID device_id = device->unique_device_id();
+ ApplicationList app_list = device->GetApplicationList();
+ LOG4CXX_INFO(logger_, "Device " << device->name() << " has "
+ << app_list.size() << " applications.");
+ bool errors_occurred = false;
+ for (ApplicationList::iterator it = app_list.begin(); it != app_list.end(); ++it) {
+ const ApplicationHandle app_handle = *it;
+ LOG4CXX_DEBUG(logger_, "Attempt to connect device " << device_id <<
+ ", channel " << app_handle);
+ const Error error = Connect(device_id, app_handle);
+ switch (error) {
+ case OK:
+ LOG4CXX_DEBUG(logger_, "error = OK");
+ break;
+ case ALREADY_EXISTS:
+ LOG4CXX_DEBUG(logger_, "error = ALREADY_EXISTS");
+ break;
+ default:
+ LOG4CXX_ERROR(logger_, "Connect to device " << device_id <<
+ ", channel " << app_handle <<
+ " failed with error " << error);
+ errors_occurred = true;
+ LOG4CXX_DEBUG(logger_, "switch (error), default case");
+ break;
+ }
+ }
+ if (errors_occurred) {
+ LOG4CXX_TRACE(logger_, "exit with error:FAIL");
+ return FAIL;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with error:OK");
+ return OK;
+ }
+}
+
+void TransportAdapterImpl::RemoveDevice(const DeviceUID& device_handle) {
+ LOG4CXX_TRACE(logger_, "enter. device_handle: " << &device_handle);
+ pthread_mutex_lock(&devices_mutex_);
+ DeviceMap::iterator i = devices_.find(
+ device_handle); //ykazakov: there is no erase for const iterator on QNX
+ if (i != devices_.end()) {
+ DeviceSptr device = i->second;
+ if (!device->keep_on_disconnect()) {
+ devices_.erase(i);
+ for (TransportAdapterListenerList::iterator it = listeners_.begin();
+ it != listeners_.end(); ++it) {
+ TransportAdapterListener* listener = *it;
+ listener->OnDeviceListUpdated(this);
+ }
+ }
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+
+} // namespace transport_adapter
+
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc
new file mode 100644
index 0000000000..18128d681e
--- /dev/null
+++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2014, 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 <algorithm>
+
+#include "utils/logger.h"
+
+#include "transport_manager/transport_adapter/transport_adapter_listener_impl.h"
+#include "transport_manager/transport_manager_impl.h"
+#include "transport_manager/transport_adapter/transport_adapter_event.h"
+
+namespace transport_manager {
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+TransportAdapterListenerImpl::TransportAdapterListenerImpl(
+ TransportManagerImpl* manager, TransportAdapter* adapter) :
+ transport_manager_impl_(manager), transport_adapter_(adapter) {
+}
+
+void TransportAdapterListenerImpl::OnSearchDeviceDone(
+ const TransportAdapter* adapter) {
+ LOG4CXX_TRACE(logger_, "enter. adapter* " << adapter);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_SEARCH_DONE,
+ transport_adapter_, "", 0, RawMessagePtr(), BaseErrorPtr());
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnSearchDeviceFailed(
+ const TransportAdapter* adapter, const SearchDeviceError& error) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", error: " << &error);
+ SearchDeviceError* err = new SearchDeviceError(error);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_SEARCH_FAIL,
+ transport_adapter_, "", 0, RawMessagePtr(), BaseErrorPtr(err));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDeviceListUpdated(
+ const TransportAdapter* adapter) {
+ LOG4CXX_TRACE(logger_, "enter. adapter* " << adapter);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_DEVICE_LIST_UPDATED,
+ transport_adapter_, "", 0, RawMessagePtr(), BaseErrorPtr());
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnFindNewApplicationsRequest(
+ const TransportAdapter* adapter) {
+ LOG4CXX_TRACE(logger_, "enter. adapter* " << adapter);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::ON_FIND_NEW_APPLICATIONS_REQUEST,
+ transport_adapter_, "", 0, RawMessagePtr(), BaseErrorPtr());
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnConnectDone(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& application_id) {
+ LOG4CXX_TRACE(logger_, "enter adapter*: " << adapter << ", device: " << &device <<
+ ", application_id: " << &application_id);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_CONNECT_DONE,
+ transport_adapter_, device, application_id, RawMessagePtr(),
+ BaseErrorPtr(new BaseError()));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnConnectFailed(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id, const ConnectError& error) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id << ", error: " << &error);
+ ConnectError* err = new ConnectError(error);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_CONNECT_FAIL,
+ transport_adapter_, device, app_id, RawMessagePtr(), BaseErrorPtr(err));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDisconnectDone(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_DISCONNECT_DONE,
+ transport_adapter_, device, app_id, RawMessagePtr(),
+ BaseErrorPtr(new BaseError()));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDisconnectFailed(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id, const DisconnectError& error) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id << ", error: " << &error);
+ DisconnectError* err = new DisconnectError(error);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_DISCONNECT_FAIL,
+ transport_adapter_, device, app_id, RawMessagePtr(), BaseErrorPtr(err));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDisconnectDeviceDone(
+ const TransportAdapter* adapter, const DeviceUID& device) {
+}
+
+void TransportAdapterListenerImpl::OnDisconnectDeviceFailed(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const DisconnectDeviceError& error) {
+}
+
+void TransportAdapterListenerImpl::OnDataReceiveDone(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id, const RawMessagePtr data_container) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id << ", data_container: " << data_container);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_RECEIVED_DONE,
+ transport_adapter_, device, app_id, data_container,
+ BaseErrorPtr(new BaseError()));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDataReceiveFailed(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id, const DataReceiveError& error) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id << ", error: " << &error);
+ DataReceiveError* err = new DataReceiveError(error);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_RECEIVED_FAIL,
+ transport_adapter_, device, app_id, RawMessagePtr(), BaseErrorPtr(err));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDataSendDone(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id, const RawMessagePtr data_container) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id << ", data_container: " << data_container);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_SEND_DONE,
+ transport_adapter_, device, app_id, data_container,
+ new BaseError());
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnDataSendFailed(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id, const RawMessagePtr data_container,
+ const DataSendError& error) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id << ", data_container: " << data_container << ", error: "
+ << &error);
+ DataSendError* err = new DataSendError(error);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_SEND_FAIL,
+ transport_adapter_, device, app_id, data_container, BaseErrorPtr(err));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnConnectRequested(
+ const TransportAdapter* adapter, const DeviceUID& device_handle,
+ const ApplicationHandle& app_handle) {
+}
+
+void TransportAdapterListenerImpl::OnUnexpectedDisconnect(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& application, const CommunicationError& error) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application: " << &application << ", error: " << &error);
+ CommunicationError* err = new CommunicationError(error);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_UNEXPECTED_DISCONNECT,
+ transport_adapter_, device, application, RawMessagePtr(), BaseErrorPtr(err));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportAdapterListenerImpl::OnCommunicationError(
+ const TransportAdapter* adapter, const DeviceUID& device,
+ const ApplicationHandle& app_id) {
+ LOG4CXX_TRACE(logger_, "enter. adapter: " << adapter << ", device: " << &device <<
+ ", application_id: " << &app_id);
+ const TransportAdapterEvent event(
+ TransportAdapterListenerImpl::EventTypeEnum::ON_COMMUNICATION_ERROR,
+ transport_adapter_, device, app_id, RawMessagePtr(),
+ BaseErrorPtr(new BaseError()));
+ if (transport_manager::E_SUCCESS
+ != transport_manager_impl_->ReceiveEventFromDevice(event)) {
+ LOG4CXX_WARN(logger_, "Failed to receive event from device");
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/transport_manager_default.cc b/src/components/transport_manager/src/transport_manager_default.cc
new file mode 100644
index 0000000000..ffd1b3d860
--- /dev/null
+++ b/src/components/transport_manager/src/transport_manager_default.cc
@@ -0,0 +1,107 @@
+/*
+ * \file transport_manager_default.cc
+ * \brief TransportManagerDefault class source file.
+ *
+ * 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 "config_profile/profile.h"
+
+#include "transport_manager/transport_manager_default.h"
+#include "transport_manager/tcp/tcp_transport_adapter.h"
+#include "utils/logger.h"
+
+#ifdef BLUETOOTH_SUPPORT
+#include "transport_manager/bluetooth/bluetooth_transport_adapter.h"
+#endif
+
+// CUSTOMER_PASA
+
+#if defined(USB_SUPPORT)
+#include "transport_manager/usb/usb_aoa_adapter.h"
+#endif // USB_SUPPORT
+
+
+
+namespace transport_manager {
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+int TransportManagerDefault::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (E_SUCCESS != TransportManagerImpl::Init()) {
+ LOG4CXX_TRACE(logger_, "exit with E_TM_IS_NOT_INITIALIZED. Condition: E_SUCCESS != TransportManagerImpl::Init()");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ transport_adapter::TransportAdapterImpl* ta;
+#ifdef BLUETOOTH_SUPPORT
+
+ ta = new transport_adapter::BluetoothTransportAdapter;
+
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ ta->SetTimeMetricObserver(metric_observer_);
+ }
+#endif // TIME_TESTER
+ AddTransportAdapter(ta);
+#endif
+ uint16_t port = profile::Profile::instance()->transport_manager_tcp_adapter_port();
+ ta = new transport_adapter::TcpTransportAdapter(port);
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ ta->SetTimeMetricObserver(metric_observer_);
+ }
+#endif // TIME_TESTER
+ AddTransportAdapter(ta);
+
+// CUSTOMER_PASA
+
+#if defined(USB_SUPPORT)
+ ta = new transport_adapter::UsbAoaAdapter();
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ ta->SetTimeMetricObserver(metric_observer_);
+ }
+#endif // TIME_TESTER
+ AddTransportAdapter(ta);
+#endif // USB_SUPPORT
+
+
+
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+TransportManagerDefault::~TransportManagerDefault() {}
+
+TransportManagerDefault::TransportManagerDefault()
+ : TransportManagerImpl() {}
+
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/transport_manager_impl.cc b/src/components/transport_manager/src/transport_manager_impl.cc
new file mode 100644
index 0000000000..16810ef47d
--- /dev/null
+++ b/src/components/transport_manager/src/transport_manager_impl.cc
@@ -0,0 +1,987 @@
+/*
+ * Copyright (c) 2014, 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 "transport_manager/transport_manager_impl.h"
+
+#include <pthread.h>
+#include <stdint.h>
+#include <cstring>
+#include <queue>
+#include <set>
+#include <algorithm>
+#include <limits>
+#include <functional>
+#include <sstream>
+
+#include "utils/macro.h"
+#include "utils/logger.h"
+#include "transport_manager/common.h"
+#include "transport_manager/transport_manager_listener.h"
+#include "transport_manager/transport_manager_listener_empty.h"
+#include "transport_manager/transport_adapter/transport_adapter.h"
+#include "transport_manager/transport_adapter/transport_adapter_event.h"
+#include "config_profile/profile.h"
+
+using ::transport_manager::transport_adapter::TransportAdapter;
+
+namespace transport_manager {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+TransportManagerImpl::Connection TransportManagerImpl::convert(
+ const TransportManagerImpl::ConnectionInternal& p) {
+ LOG4CXX_TRACE(logger_, "enter. ConnectionInternal: " << &p);
+ TransportManagerImpl::Connection c;
+ c.application = p.application;
+ c.device = p.device;
+ c.id = p.id;
+ LOG4CXX_TRACE(logger_, "exit with TransportManagerImpl::Connection. It's ConnectionUID = "
+ << c.id);
+ return c;
+}
+
+TransportManagerImpl::TransportManagerImpl()
+ : message_queue_mutex_(),
+ all_thread_active_(false),
+ message_queue_thread_(),
+ event_queue_thread_(),
+ device_listener_thread_wakeup_(),
+ is_initialized_(false),
+#ifdef TIME_TESTER
+ metric_observer_(NULL),
+#endif // TIME_TESTER
+ connection_id_counter_(0) {
+ LOG4CXX_INFO(logger_, "==============================================");
+ pthread_mutex_init(&message_queue_mutex_, NULL);
+ pthread_cond_init(&message_queue_cond_, NULL);
+ pthread_mutex_init(&event_queue_mutex_, 0);
+ pthread_cond_init(&device_listener_thread_wakeup_, NULL);
+ LOG4CXX_DEBUG(logger_, "TransportManager object created");
+}
+
+TransportManagerImpl::~TransportManagerImpl() {
+ LOG4CXX_DEBUG(logger_, "TransportManager object destroying");
+
+ for (std::vector<TransportAdapter*>::iterator it =
+ transport_adapters_.begin();
+ it != transport_adapters_.end(); ++it) {
+ delete *it;
+ }
+
+ for (std::map<TransportAdapter*, TransportAdapterListenerImpl*>::iterator it =
+ transport_adapter_listeners_.begin();
+ it != transport_adapter_listeners_.end(); ++it) {
+ delete it->second;
+ }
+
+ pthread_mutex_destroy(&message_queue_mutex_);
+ pthread_cond_destroy(&message_queue_cond_);
+ pthread_mutex_destroy(&event_queue_mutex_);
+ pthread_cond_destroy(&device_listener_thread_wakeup_);
+ LOG4CXX_INFO(logger_, "TransportManager object destroyed");
+}
+
+int TransportManagerImpl::ConnectDevice(const DeviceHandle& device_handle) {
+ LOG4CXX_TRACE(logger_, "enter. DeviceHandle: " << &device_handle);
+ if (!this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TransportManager is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: !this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+
+ DeviceUID device_id = converter_.HandleToUid(device_handle);
+ LOG4CXX_DEBUG(logger_, "Convert handle to id " << device_id);
+
+ transport_adapter::TransportAdapter* ta = device_to_adapter_map_[device_id];
+ if (NULL == ta) {
+ LOG4CXX_ERROR(logger_, "No device adapter found by id " << device_id);
+ LOG4CXX_TRACE(logger_, "exit with E_INVALID_HANDLE. Condition: NULL == ta");
+ return E_INVALID_HANDLE;
+ }
+
+ TransportAdapter::Error ta_error = ta->ConnectDevice(device_id);
+ int err = (TransportAdapter::OK == ta_error) ? E_SUCCESS : E_INTERNAL_ERROR;
+ LOG4CXX_TRACE(logger_, "exit with error: " << err);
+ return err;
+}
+
+int TransportManagerImpl::DisconnectDevice(const DeviceHandle& device_handle) {
+ LOG4CXX_TRACE(logger_, "enter. DeviceHandle: " << &device_handle);
+ if (!this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TransportManager is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: !this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ DeviceUID device_id = converter_.HandleToUid(device_handle);
+ LOG4CXX_DEBUG(logger_, "Convert handle to id" << device_id);
+
+ transport_adapter::TransportAdapter* ta = device_to_adapter_map_[device_id];
+ if (NULL == ta) {
+ LOG4CXX_WARN(logger_, "No device adapter found by id " << device_id);
+ LOG4CXX_TRACE(logger_, "exit with E_INVALID_HANDLE. Condition: NULL == ta");
+ return E_INVALID_HANDLE;
+ }
+ ta->DisconnectDevice(device_id);
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::Disconnect(const ConnectionUID& cid) {
+ LOG4CXX_TRACE(logger_, "enter. ConnectionUID: " << &cid);
+ if (!this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TransportManager is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: !this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+
+ ConnectionInternal* connection = GetConnection(cid);
+ if (NULL == connection) {
+ LOG4CXX_ERROR(logger_, "TransportManagerImpl::Disconnect: Connection does not exist.");
+ LOG4CXX_TRACE(logger_, "exit with E_INVALID_HANDLE. Condition: NULL == connection");
+ return E_INVALID_HANDLE;
+ }
+
+ pthread_mutex_lock(&event_queue_mutex_);
+ int messages_count = 0;
+ for (EventQueue::const_iterator it = event_queue_.begin();
+ it != event_queue_.end();
+ ++it) {
+ if (it->application_id == static_cast<ApplicationHandle>(cid)) {
+ ++messages_count;
+ }
+ }
+ pthread_mutex_unlock(&event_queue_mutex_);
+
+ if (messages_count > 0) {
+ connection->messages_count = messages_count;
+ connection->shutDown = true;
+
+ const uint32_t disconnect_timeout =
+ profile::Profile::instance()->transport_manager_disconnect_timeout();
+ if (disconnect_timeout > 0) {
+ connection->timer->start(disconnect_timeout);
+ }
+ } else {
+ connection->transport_adapter->Disconnect(connection->device,
+ connection->application);
+ }
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::DisconnectForce(const ConnectionUID& cid) {
+ LOG4CXX_TRACE(logger_, "enter ConnectionUID: " << &cid);
+ if (false == this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TransportManager is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: false == this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ pthread_mutex_lock(&event_queue_mutex_);
+ // Clear messages for this connection
+ // Note that MessageQueue typedef is assumed to be std::list,
+ // or there is a problem here. One more point versus typedefs-everywhere
+ MessageQueue::iterator e = message_queue_.begin();
+ while (e != message_queue_.end()) {
+ if (static_cast<ConnectionUID>((*e)->connection_key()) == cid) {
+ RaiseEvent(&TransportManagerListener::OnTMMessageSendFailed,
+ DataSendTimeoutError(), *e);
+ e = message_queue_.erase(e);
+ } else {
+ ++e;
+ }
+ }
+ pthread_mutex_unlock(&event_queue_mutex_);
+ const ConnectionInternal* connection = GetConnection(cid);
+ if (NULL == connection) {
+ LOG4CXX_ERROR(
+ logger_,
+ "TransportManagerImpl::DisconnectForce: Connection does not exist.");
+ LOG4CXX_TRACE(logger_, "exit with E_INVALID_HANDLE. Condition: NULL == connection");
+ return E_INVALID_HANDLE;
+ }
+ connection->transport_adapter->Disconnect(connection->device,
+ connection->application);
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::AddEventListener(TransportManagerListener* listener) {
+ LOG4CXX_TRACE(logger_, "enter. TransportManagerListener: " << listener);
+ transport_manager_listener_.push_back(listener);
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::Stop() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (!all_thread_active_) {
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: !all_thread_active_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ all_thread_active_ = false;
+
+ pthread_mutex_lock(&event_queue_mutex_);
+ pthread_cond_signal(&device_listener_thread_wakeup_);
+ pthread_mutex_unlock(&event_queue_mutex_);
+
+ pthread_mutex_lock(&message_queue_mutex_);
+ pthread_cond_signal(&message_queue_cond_);
+ pthread_mutex_unlock(&message_queue_mutex_);
+
+ pthread_join(message_queue_thread_, 0);
+ pthread_join(event_queue_thread_, 0);
+
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::SendMessageToDevice(const RawMessagePtr message) {
+ LOG4CXX_TRACE(logger_, "enter. RawMessageSptr: " << message);
+ LOG4CXX_INFO(logger_, "Send message to device called with arguments "
+ << message.get());
+ if (false == this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TM is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: false == this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+
+ const ConnectionInternal* connection =
+ GetConnection(message->connection_key());
+ if (NULL == connection) {
+ LOG4CXX_ERROR(logger_, "Connection with id " << message->connection_key()
+ << " does not exist.");
+ LOG4CXX_TRACE(logger_, "exit with E_INVALID_HANDLE. Condition: NULL == connection");
+ return E_INVALID_HANDLE;
+ }
+
+ if (connection->shutDown) {
+ LOG4CXX_ERROR(logger_, "TransportManagerImpl::Disconnect: Connection is to shut down.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_CONNECTION_IS_TO_SHUTDOWN. Condition: connection->shutDown");
+ return E_CONNECTION_IS_TO_SHUTDOWN;
+ }
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ metric_observer_->StartRawMsg(message.get());
+ }
+#endif // TIME_TESTER
+ this->PostMessage(message);
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::ReceiveEventFromDevice(const TransportAdapterEvent& event) {
+ LOG4CXX_TRACE(logger_, "enter. TransportAdapterEvent: " << &event);
+ if (!is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TM is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: false == this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ this->PostEvent(event);
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::RemoveDevice(const DeviceHandle& device_handle) {
+ LOG4CXX_TRACE(logger_, "enter. DeviceHandle: " << &device_handle);
+ DeviceUID device_id = converter_.HandleToUid(device_handle);
+ if (false == this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TM is not initialized.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: false == this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ device_to_adapter_map_.erase(device_id);
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::AddTransportAdapter(
+ transport_adapter::TransportAdapter* transport_adapter) {
+ LOG4CXX_TRACE(logger_, "enter. TransportAdapter: " << transport_adapter);
+
+ if (transport_adapter_listeners_.find(transport_adapter) !=
+ transport_adapter_listeners_.end()) {
+ LOG4CXX_ERROR(logger_, "Adapter already exists.");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_ADAPTER_EXISTS. Condition: transport_adapter_listeners_.find(transport_adapter) != transport_adapter_listeners_.end()");
+ return E_ADAPTER_EXISTS;
+ }
+ transport_adapter_listeners_[transport_adapter] =
+ new TransportAdapterListenerImpl(this, transport_adapter);
+ transport_adapter->AddListener(
+ transport_adapter_listeners_[transport_adapter]);
+
+ if (transport_adapter->IsInitialised() ||
+ transport_adapter->Init() == TransportAdapter::OK) {
+ transport_adapters_.push_back(transport_adapter);
+ }
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::SearchDevices() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (!this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TM is not initialized");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: !this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+
+ LOG4CXX_INFO(logger_, "Search device called");
+
+ bool success_occurred = false;
+
+ for (std::vector<TransportAdapter*>::iterator it =
+ transport_adapters_.begin();
+ it != transport_adapters_.end(); ++it) {
+ LOG4CXX_DEBUG(logger_, "Iterating over transport adapters");
+ TransportAdapter::Error scanResult = (*it)->SearchDevices();
+ if (transport_adapter::TransportAdapter::OK == scanResult) {
+ success_occurred = true;
+ } else {
+ LOG4CXX_ERROR(logger_, "Transport Adapter search failed "
+ << *it << "[" << (*it)->GetDeviceType()
+ << "]");
+ switch (scanResult) {
+ case transport_adapter::TransportAdapter::NOT_SUPPORTED: {
+ LOG4CXX_ERROR(logger_, "Search feature is not supported "
+ << *it << "[" << (*it)->GetDeviceType()
+ << "]");
+ LOG4CXX_DEBUG(logger_, "scanResult = TransportAdapter::NOT_SUPPORTED");
+ break;
+ }
+ case transport_adapter::TransportAdapter::BAD_STATE: {
+ LOG4CXX_ERROR(logger_, "Transport Adapter has bad state " << *it << "[" <<
+ (*it)->GetDeviceType()
+ << "]");
+ LOG4CXX_DEBUG(logger_, "scanResult = TransportAdapter::BAD_STATE");
+ break;
+ }
+ default: {
+ LOG4CXX_ERROR(logger_, "Invalid scan result");
+ LOG4CXX_DEBUG(logger_, "scanResult = default switch case");
+ return E_ADAPTERS_FAIL;
+ }
+ }
+ }
+ }
+ int transport_adapter_search = (success_occurred || transport_adapters_.empty())
+ ? E_SUCCESS
+ : E_ADAPTERS_FAIL;
+ if (transport_adapter_search == E_SUCCESS) {
+ LOG4CXX_TRACE(logger_,
+ "exit with E_SUCCESS. Condition: success_occured || transport_adapters_.empty()");
+ } else {
+ LOG4CXX_TRACE(logger_,
+ "exit with E_ADAPTERS_FAIL. Condition: success_occured || transport_adapters_.empty()");
+ }
+ return transport_adapter_search;
+}
+
+int TransportManagerImpl::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ all_thread_active_ = true;
+
+ int error_code = pthread_create(&message_queue_thread_, 0,
+ &MessageQueueStartThread, this);
+ if (0 != error_code) {
+ LOG4CXX_ERROR(logger_,
+ "Message queue thread is not created exit with error code "
+ << error_code);
+ LOG4CXX_TRACE(logger_, "exit with E_TM_IS_NOT_INITIALIZED. Condition: 0 != error_code");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ pthread_setname_np(message_queue_thread_, "TM MessageQueue");
+
+ error_code = pthread_create(&event_queue_thread_, 0,
+ &EventListenerStartThread, this);
+ if (0 != error_code) {
+ LOG4CXX_ERROR(logger_,
+ "Event queue thread is not created exit with error code "
+ << error_code);
+ LOG4CXX_TRACE(logger_, "exit with E_TM_IS_NOT_INITIALIZED. Condition: 0 != error_code");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+ pthread_setname_np(event_queue_thread_, "TM EventListener");
+
+ is_initialized_ = true;
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+int TransportManagerImpl::Visibility(const bool& on_off) const {
+ LOG4CXX_TRACE(logger_, "enter. On_off: " << &on_off);
+ TransportAdapter::Error ret;
+
+ LOG4CXX_DEBUG(logger_, "Visibility change requested to " << on_off);
+ if (false == this->is_initialized_) {
+ LOG4CXX_ERROR(logger_, "TM is not initialized");
+ LOG4CXX_TRACE(logger_,
+ "exit with E_TM_IS_NOT_INITIALIZED. Condition: false == this->is_initialized_");
+ return E_TM_IS_NOT_INITIALIZED;
+ }
+
+ for (std::vector<TransportAdapter*>::const_iterator it =
+ transport_adapters_.begin();
+ it != transport_adapters_.end(); ++it) {
+ if (on_off) {
+ ret = (*it)->StartClientListening();
+ } else {
+ ret = (*it)->StopClientListening();
+ }
+ if (TransportAdapter::Error::NOT_SUPPORTED == ret) {
+ LOG4CXX_DEBUG(logger_, "Visibility change is not supported for adapter "
+ << *it << "[" << (*it)->GetDeviceType() << "]");
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit with E_SUCCESS");
+ return E_SUCCESS;
+}
+
+void TransportManagerImpl::UpdateDeviceList(TransportAdapter* ta) {
+ LOG4CXX_TRACE(logger_, "enter. TransportAdapter: " << ta);
+ std::set<DeviceInfo> old_devices;
+ for (DeviceInfoList::iterator it = device_list_.begin();
+ it != device_list_.end();) {
+ if (it->first == ta) {
+ old_devices.insert(it->second);
+ it = device_list_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ std::set<DeviceInfo> new_devices;
+ const DeviceList dev_list = ta->GetDeviceList();
+ for (DeviceList::const_iterator it = dev_list.begin();
+ it != dev_list.end(); ++it) {
+ DeviceHandle device_handle = converter_.UidToHandle(*it);
+ DeviceInfo info(device_handle, *it, ta->DeviceName(*it), ta->GetConnectionType());
+ device_list_.push_back(std::make_pair(ta, info));
+ new_devices.insert(info);
+ }
+
+ std::set<DeviceInfo> added_devices;
+ std::set_difference(new_devices.begin(), new_devices.end(),
+ old_devices.begin(), old_devices.end(),
+ std::inserter(added_devices, added_devices.begin()));
+ for (std::set<DeviceInfo>::const_iterator it = added_devices.begin();
+ it != added_devices.end();
+ ++it) {
+ RaiseEvent(&TransportManagerListener::OnDeviceAdded, *it);
+ }
+
+ std::set<DeviceInfo> removed_devices;
+ std::set_difference(old_devices.begin(), old_devices.end(),
+ new_devices.begin(), new_devices.end(),
+ std::inserter(removed_devices, removed_devices.begin()));
+
+ for (std::set<DeviceInfo>::const_iterator it = removed_devices.begin();
+ it != removed_devices.end();
+ ++it) {
+ RaiseEvent(&TransportManagerListener::OnDeviceRemoved, *it);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportManagerImpl::PostMessage(const RawMessagePtr message) {
+ LOG4CXX_TRACE(logger_, "enter. RawMessageSptr: " << message);
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.AcquireForWriting();
+#else
+ pthread_mutex_lock(&message_queue_mutex_);
+#endif
+ message_queue_.push_back(message);
+ pthread_cond_signal(&message_queue_cond_);
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.Release();
+#else
+ pthread_mutex_unlock(&message_queue_mutex_);
+#endif
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportManagerImpl::RemoveMessage(const RawMessagePtr message) {
+ // TODO: Reconsider necessity of this method, remove if it's useless,
+ // make to work otherwise.
+ // 2013-08-21 dchmerev@luxoft.com
+ LOG4CXX_TRACE(logger_, "enter RawMessageSptr: " << message);
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.AcquireForWriting();
+#else
+ pthread_mutex_lock(&message_queue_mutex_);
+#endif
+ std::remove(message_queue_.begin(), message_queue_.end(), message);
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.Release();
+#else
+ pthread_mutex_unlock(&message_queue_mutex_);
+#endif
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportManagerImpl::PostEvent(const TransportAdapterEvent& event) {
+ LOG4CXX_TRACE(logger_, "enter. TransportAdapterEvent: " << &event);
+#ifdef USE_RWLOCK
+ event_queue_rwlock_.AcquireForWriting();
+#else
+ pthread_mutex_lock(&event_queue_mutex_);
+#endif
+ event_queue_.push_back(event);
+ pthread_cond_signal(&device_listener_thread_wakeup_);
+#ifdef USE_RWLOCK
+ event_queue_rwlock_.Release();
+#else
+ pthread_mutex_unlock(&event_queue_mutex_);
+#endif
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void* TransportManagerImpl::EventListenerStartThread(void* data) {
+ LOG4CXX_TRACE(logger_, "enter Data: " << data);
+ if (NULL != data) {
+ static_cast<TransportManagerImpl*>(data)->EventListenerThread();
+ }
+ LOG4CXX_TRACE(logger_, "exit with 0");
+ return 0;
+}
+
+void TransportManagerImpl::AddConnection(const ConnectionInternal& c) {
+ LOG4CXX_TRACE(logger_, "enter ConnectionInternal: " << &c);
+ connections_.push_back(c);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportManagerImpl::RemoveConnection(uint32_t id) {
+ LOG4CXX_TRACE(logger_, "enter Id: " << id);
+ for (std::vector<ConnectionInternal>::iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ if (it->id == id) {
+ connections_.erase(it);
+ break;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportManagerImpl::ConnectionInternal* TransportManagerImpl::GetConnection(
+ const ConnectionUID& id) {
+ LOG4CXX_TRACE(logger_, "enter. ConnectionUID: " << &id);
+ for (std::vector<ConnectionInternal>::iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ if (it->id == id) {
+ LOG4CXX_TRACE(logger_, "exit with ConnectionInternal. It's adress: " << &*it);
+ return &*it;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit with NULL");
+ return NULL;
+
+}
+
+TransportManagerImpl::ConnectionInternal* TransportManagerImpl::GetConnection(
+ const DeviceUID& device, const ApplicationHandle& application) {
+ LOG4CXX_TRACE(logger_, "enter DeviceUID: " << &device << "ApplicationHandle: " <<
+ &application);
+ for (std::vector<ConnectionInternal>::iterator it = connections_.begin();
+ it != connections_.end(); ++it) {
+ if (it->device == device && it->application == application) {
+ LOG4CXX_TRACE(logger_, "exit with ConnectionInternal. It's adress: " << &*it);
+ return &*it;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit with NULL");
+ return NULL;
+}
+
+void TransportManagerImpl::OnDeviceListUpdated(TransportAdapter* ta) {
+ LOG4CXX_TRACE(logger_, "enter. TransportAdapter: " << ta);
+ const DeviceList device_list = ta->GetDeviceList();
+ LOG4CXX_INFO(logger_, "DEVICE_LIST_UPDATED " << device_list.size());
+ for (DeviceList::const_iterator it = device_list.begin();
+ it != device_list.end(); ++it) {
+ device_to_adapter_map_.insert(std::make_pair(*it, ta));
+ DeviceHandle device_handle = converter_.UidToHandle(*it);
+ DeviceInfo info(device_handle, *it, ta->DeviceName(*it), ta->GetConnectionType());
+ RaiseEvent(&TransportManagerListener::OnDeviceFound, info);
+ }
+ UpdateDeviceList(ta);
+ std::vector<DeviceInfo> device_infos;
+ for (DeviceInfoList::const_iterator it = device_list_.begin();
+ it != device_list_.end(); ++it) {
+ device_infos.push_back(it->second);
+ }
+ RaiseEvent(&TransportManagerListener::OnDeviceListUpdated, device_infos);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void TransportManagerImpl::EventListenerThread() {
+ LOG4CXX_TRACE(logger_, "enter");
+#ifndef USE_RWLOCK
+ pthread_mutex_lock(&event_queue_mutex_);
+#endif
+ LOG4CXX_INFO(logger_, "Event listener thread started");
+ while (true) {
+ while (event_queue_.size() > 0) {
+#ifdef USE_RWLOCK
+ event_queue_rwlock_.AcquireForReading();
+#endif
+ LOG4CXX_INFO(logger_, "Event listener queue pushed to process events");
+ EventQueue::iterator current_it = event_queue_.begin();
+ const TransportAdapterEvent event = *(current_it);
+ event_queue_.erase(current_it);
+#ifdef USE_RWLOCK
+ event_queue_rwlock_.Release();
+#else
+ pthread_mutex_unlock(&event_queue_mutex_);
+#endif
+ ConnectionInternal* connection = GetConnection(event.device_uid, event.application_id);
+
+ switch (event.event_type) {
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_SEARCH_DONE: {
+ RaiseEvent(&TransportManagerListener::OnScanDevicesFinished);
+ LOG4CXX_DEBUG(logger_, "event_type = ON_SEARCH_DONE");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_SEARCH_FAIL: {
+ // error happened in real search process (external error)
+ RaiseEvent(&TransportManagerListener::OnScanDevicesFailed,
+ *static_cast<SearchDeviceError*>(event.event_error.get()));
+ LOG4CXX_DEBUG(logger_, "event_type = ON_SEARCH_FAIL");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_DEVICE_LIST_UPDATED: {
+ OnDeviceListUpdated(event.transport_adapter);
+ LOG4CXX_DEBUG(logger_, "event_type = ON_DEVICE_LIST_UPDATED");
+ break;
+ }
+ case TransportAdapterListenerImpl::ON_FIND_NEW_APPLICATIONS_REQUEST: {
+ RaiseEvent(&TransportManagerListener::OnFindNewApplicationsRequest);
+ LOG4CXX_DEBUG(logger_, "event_type = ON_FIND_NEW_APPLICATIONS_REQUEST");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_CONNECT_DONE: {
+ const DeviceHandle device_handle = converter_.UidToHandle(event.device_uid);
+ AddConnection(ConnectionInternal(this, event.transport_adapter, ++connection_id_counter_,
+ event.device_uid, event.application_id,
+ device_handle));
+ RaiseEvent(&TransportManagerListener::OnConnectionEstablished,
+ DeviceInfo(device_handle, event.device_uid,
+ event.transport_adapter->DeviceName(event.device_uid),
+ event.transport_adapter->GetConnectionType()),
+ connection_id_counter_);
+ LOG4CXX_DEBUG(logger_, "event_type = ON_CONNECT_DONE");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_CONNECT_FAIL: {
+ RaiseEvent(&TransportManagerListener::OnConnectionFailed,
+ DeviceInfo(converter_.UidToHandle(event.device_uid), event.device_uid,
+ event.transport_adapter->DeviceName(event.device_uid),
+ event.transport_adapter->GetConnectionType()),
+ ConnectError());
+ LOG4CXX_DEBUG(logger_, "event_type = ON_CONNECT_FAIL");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_DISCONNECT_DONE: {
+ if (NULL == connection) {
+ LOG4CXX_ERROR(logger_, "Connection not found");
+ LOG4CXX_DEBUG(logger_,
+ "event_type = ON_DISCONNECT_DONE && NULL == connection");
+ break;
+ }
+ RaiseEvent(&TransportManagerListener::OnConnectionClosed,
+ connection->id);
+ RemoveConnection(connection->id);
+ LOG4CXX_DEBUG(logger_, "event_type = ON_DISCONNECT_DONE");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_DISCONNECT_FAIL: {
+ const DeviceHandle device_handle = converter_.UidToHandle(event.device_uid);
+ RaiseEvent(&TransportManagerListener::OnDisconnectFailed,
+ device_handle, DisconnectDeviceError());
+ LOG4CXX_DEBUG(logger_, "event_type = ON_DISCONNECT_FAIL");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_SEND_DONE: {
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ metric_observer_->StopRawMsg(event.event_data.get());
+ }
+#endif // TIME_TESTER
+ if (connection == NULL) {
+ LOG4CXX_ERROR(logger_, "Connection ('" << event.device_uid << ", "
+ << event.application_id
+ << ") not found");
+ LOG4CXX_DEBUG(logger_, "event_type = ON_SEND_DONE. Condition: NULL == connection");
+ break;
+ }
+ RaiseEvent(&TransportManagerListener::OnTMMessageSend, event.event_data);
+ this->RemoveMessage(event.event_data);
+ if (connection->shutDown && --connection->messages_count == 0) {
+ connection->timer->stop();
+ connection->transport_adapter->Disconnect(connection->device,
+ connection->application);
+ }
+ LOG4CXX_DEBUG(logger_, "event_type = ON_SEND_DONE");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_SEND_FAIL: {
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ metric_observer_->StopRawMsg(event.event_data.get());
+ }
+#endif // TIME_TESTER
+ if (connection == NULL) {
+ LOG4CXX_ERROR(logger_, "Connection ('" << event.device_uid << ", "
+ << event.application_id
+ << ") not found");
+ LOG4CXX_DEBUG(logger_, "event_type = ON_SEND_FAIL. Condition: NULL == connection");
+ break;
+ }
+
+ // TODO(YK): start timer here to wait before notify caller
+ // and remove unsent messages
+ LOG4CXX_ERROR(logger_, "Transport adapter failed to send data");
+ // TODO(YK): potential error case -> thread unsafe
+ // update of message content
+ if (event.event_data.valid()) {
+ event.event_data->set_waiting(true);
+ } else {
+ LOG4CXX_DEBUG(logger_, "Data is invalid");
+ }
+ LOG4CXX_DEBUG(logger_, "eevent_type = ON_SEND_FAIL");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_RECEIVED_DONE: {
+ if (connection == NULL) {
+ LOG4CXX_ERROR(logger_, "Connection ('" << event.device_uid << ", "
+ << event.application_id
+ << ") not found");
+ LOG4CXX_DEBUG(logger_, "event_type = ON_RECEIVED_DONE. Condition: NULL == connection");
+ break;
+ }
+ event.event_data->set_connection_key(connection->id);
+#ifdef TIME_TESTER
+ if (metric_observer_) {
+ metric_observer_->StopRawMsg(event.event_data.get());
+ }
+#endif // TIME_TESTER
+ RaiseEvent(&TransportManagerListener::OnTMMessageReceived, event.event_data);
+ LOG4CXX_DEBUG(logger_, "event_type = ON_RECEIVED_DONE");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_RECEIVED_FAIL: {
+ LOG4CXX_DEBUG(logger_, "Event ON_RECEIVED_FAIL");
+ if (connection == NULL) {
+ LOG4CXX_ERROR(logger_, "Connection ('" << event.device_uid << ", "
+ << event.application_id
+ << ") not found");
+ break;
+ }
+
+ RaiseEvent(&TransportManagerListener::OnTMMessageReceiveFailed,
+ connection->id, *static_cast<DataReceiveError*>(event.event_error.get()));
+ LOG4CXX_DEBUG(logger_, "event_type = ON_RECEIVED_FAIL");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_COMMUNICATION_ERROR: {
+ LOG4CXX_DEBUG(logger_, "event_type = ON_COMMUNICATION_ERROR");
+ break;
+ }
+ case TransportAdapterListenerImpl::EventTypeEnum::ON_UNEXPECTED_DISCONNECT: {
+ if (connection) {
+ RaiseEvent(&TransportManagerListener::OnUnexpectedDisconnect,
+ connection->id,
+ *static_cast<CommunicationError*>(event.event_error.get()));
+ RemoveConnection(connection->id);
+ } else {
+ LOG4CXX_ERROR(logger_, "Connection ('" << event.device_uid << ", "
+ << event.application_id
+ << ") not found");
+ }
+ LOG4CXX_DEBUG(logger_, "eevent_type = ON_UNEXPECTED_DISCONNECT");
+ break;
+ }
+ } // switch
+#ifndef USE_RWLOCK
+ pthread_mutex_lock(&event_queue_mutex_);
+#endif
+ } // while (event_queue_.size() > 0)
+
+ if (all_thread_active_) {
+ pthread_cond_wait(&device_listener_thread_wakeup_, &event_queue_mutex_);
+ } else {
+ LOG4CXX_DEBUG(logger_, "break. Condition: NOT all_thread_active_");
+ break;
+ }
+ } // while (true)
+
+ pthread_mutex_unlock(&event_queue_mutex_);
+
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+#ifdef TIME_TESTER
+void TransportManagerImpl::SetTimeMetricObserver(TMMetricObserver* observer) {
+ metric_observer_ = observer;
+}
+#endif // TIME_TESTER
+
+void* TransportManagerImpl::MessageQueueStartThread(void* data) {
+ LOG4CXX_TRACE(logger_, "enter. Data:" << data);
+ if (NULL != data) {
+ static_cast<TransportManagerImpl*>(data)->MessageQueueThread();
+ }
+ LOG4CXX_TRACE(logger_, "exit with 0");
+ return 0;
+}
+
+void TransportManagerImpl::MessageQueueThread() {
+ LOG4CXX_TRACE(logger_, "enter");
+#ifndef USE_RWLOCK
+ pthread_mutex_lock(&message_queue_mutex_);
+#endif
+
+ while (all_thread_active_) {
+ // TODO(YK): add priority processing
+
+ while (message_queue_.size() > 0) {
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.AcquireForReading();
+#endif
+ MessageQueue::iterator it = message_queue_.begin();
+ while (it != message_queue_.end() && it->valid() && (*it)->IsWaiting()) {
+ ++it;
+ }
+ if (it == message_queue_.end()) {
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.Release();
+#endif
+ LOG4CXX_TRACE(logger_, "break. Condition: it == message_queue_.end()");
+ break;
+ }
+ RawMessagePtr active_msg = *it;
+#ifdef USE_RWLOCK
+ message_queue_rwlock_.Release();
+#else
+ pthread_mutex_unlock(&message_queue_mutex_);
+#endif
+ if (active_msg.valid() && !active_msg->IsWaiting()) {
+ ConnectionInternal* connection =
+ GetConnection(active_msg->connection_key());
+ if (connection == NULL) {
+ std::stringstream ss;
+ ss << "Connection " << active_msg->connection_key() << " not found";
+ LOG4CXX_ERROR(logger_, ss.str());
+ RaiseEvent(&TransportManagerListener::OnTMMessageSendFailed,
+ DataSendError(ss.str()), active_msg);
+ message_queue_.remove(active_msg);
+ continue;
+ }
+ TransportAdapter* transport_adapter = connection->transport_adapter;
+ LOG4CXX_DEBUG(logger_, "Got adapter "
+ << transport_adapter << "["
+ << transport_adapter->GetDeviceType() << "]"
+ << " by session id "
+ << active_msg->connection_key());
+
+ if (NULL == transport_adapter) {
+ std::string error_text =
+ "Transport adapter is not found - message removed";
+ LOG4CXX_ERROR(logger_, error_text);
+ RaiseEvent(&TransportManagerListener::OnTMMessageSendFailed,
+ DataSendError(error_text), active_msg);
+ message_queue_.remove(active_msg);
+ } else {
+ if (TransportAdapter::OK ==
+ transport_adapter->SendData(
+ connection->device, connection->application, active_msg)) {
+ LOG4CXX_INFO(logger_, "Data sent to adapter");
+ active_msg->set_waiting(true);
+ } else {
+ LOG4CXX_ERROR(logger_, "Data sent error");
+ RaiseEvent(&TransportManagerListener::OnTMMessageSendFailed,
+ DataSendError("Send failed - message removed"),
+ active_msg);
+ message_queue_.remove(active_msg);
+ }
+ }
+ }
+#ifndef USE_RWLOCK
+ pthread_mutex_lock(&message_queue_mutex_);
+#endif
+ }
+ pthread_cond_wait(&message_queue_cond_, &message_queue_mutex_);
+ } // while(true)
+
+ message_queue_.clear();
+
+ pthread_mutex_unlock(&message_queue_mutex_);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportManagerImpl::ConnectionInternal::ConnectionInternal(
+ TransportManagerImpl* transport_manager, TransportAdapter* transport_adapter,
+ const ConnectionUID& id, const DeviceUID& dev_id, const ApplicationHandle& app_id,
+ const DeviceHandle& device_handle)
+ : transport_manager(transport_manager),
+ transport_adapter(transport_adapter),
+ timer(new TimerInternal("TM DiscRoutine", this, &ConnectionInternal::DisconnectFailedRoutine)),
+ shutDown(false),
+ device_handle_(device_handle),
+ messages_count(0) {
+ Connection::id = id;
+ Connection::device = dev_id;
+ Connection::application = app_id;
+}
+
+void TransportManagerImpl::ConnectionInternal::DisconnectFailedRoutine() {
+ LOG4CXX_TRACE(logger_, "enter");
+ transport_manager->RaiseEvent(&TransportManagerListener::OnDisconnectFailed,
+ device_handle_, DisconnectDeviceError());
+ shutDown = false;
+ timer->stop();
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+} // namespace transport_manager
+
+
diff --git a/src/components/transport_manager/src/usb/libusb/platform_usb_device.cc b/src/components/transport_manager/src/usb/libusb/platform_usb_device.cc
new file mode 100644
index 0000000000..103e03a4f6
--- /dev/null
+++ b/src/components/transport_manager/src/usb/libusb/platform_usb_device.cc
@@ -0,0 +1,85 @@
+/**
+ *
+ * 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 "transport_manager/usb/libusb/platform_usb_device.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+
+PlatformUsbDevice::PlatformUsbDevice(
+ uint8_t bus_number, uint8_t address,
+ const libusb_device_descriptor& device_descriptor,
+ libusb_device* device_libusb, libusb_device_handle* device_handle_libusb)
+ : bus_number_(bus_number),
+ address_(address),
+ vendor_id_(device_descriptor.idVendor),
+ product_id_(device_descriptor.idProduct),
+ device_descriptor_(device_descriptor),
+ libusb_device_handle_(device_handle_libusb),
+ libusb_device_(device_libusb) {}
+
+std::string PlatformUsbDevice::GetDescString(uint8_t index) const {
+ LOG4CXX_TRACE(logger_, "enter. index: " << int(index));
+ unsigned char buf[128];
+ const int libusb_ret = libusb_get_string_descriptor_ascii(
+ libusb_device_handle_, index, buf, sizeof(buf));
+ if (libusb_ret < 0) {
+ LOG4CXX_ERROR(logger_, "Failed to get USB string descriptor: "
+ << libusb_error_name(libusb_ret));
+ LOG4CXX_TRACE(logger_, "exit with empty string");
+ return "";
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+ return std::string(reinterpret_cast<char*>(buf));
+}
+
+std::string PlatformUsbDevice::GetManufacturer() const {
+ return GetDescString(device_descriptor_.iManufacturer);
+}
+
+std::string PlatformUsbDevice::GetProductName() const {
+ return GetDescString(device_descriptor_.iProduct);
+}
+
+std::string PlatformUsbDevice::GetSerialNumber() const {
+ return GetDescString(device_descriptor_.iSerialNumber);
+}
+
+} // namespace
+} // namespace
diff --git a/src/components/transport_manager/src/usb/libusb/usb_connection.cc b/src/components/transport_manager/src/usb/libusb/usb_connection.cc
new file mode 100644
index 0000000000..76f2f99e4c
--- /dev/null
+++ b/src/components/transport_manager/src/usb/libusb/usb_connection.cc
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2013-2014, 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 <unistd.h>
+#include <iomanip>
+
+#include <libusb/libusb.h>
+
+#include <sstream>
+
+#include "transport_manager/usb/libusb/usb_connection.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+
+UsbConnection::UsbConnection(const DeviceUID& device_uid,
+ const ApplicationHandle& app_handle,
+ TransportAdapterController* controller,
+ const UsbHandlerSptr& usb_handler,
+ PlatformUsbDevice* device)
+ : device_uid_(device_uid),
+ app_handle_(app_handle),
+ controller_(controller),
+ usb_handler_(usb_handler),
+ libusb_device_(device->GetLibusbDevice()),
+ device_handle_(device->GetLibusbHandle()),
+ in_endpoint_(0),
+ in_endpoint_max_packet_size_(0),
+ out_endpoint_(0),
+ out_endpoint_max_packet_size_(0),
+ in_buffer_(NULL),
+ in_transfer_(NULL),
+ out_transfer_(0),
+ out_messages_(),
+ current_out_message_(),
+ bytes_sent_(0),
+ disconnecting_(false),
+ waiting_in_transfer_cancel_(false),
+ waiting_out_transfer_cancel_(false) {
+}
+
+UsbConnection::~UsbConnection() {
+ LOG4CXX_TRACE(logger_, "enter with this" << this);
+ Finalise();
+ libusb_free_transfer(in_transfer_);
+ delete[] in_buffer_;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+// Callback for handling income and outcome data from lib_usb
+void InTransferCallback(libusb_transfer* transfer) {
+ static_cast<UsbConnection*>(transfer->user_data)->OnInTransfer(transfer);
+}
+
+void OutTransferCallback(libusb_transfer* transfer) {
+ static_cast<UsbConnection*>(transfer->user_data)->OnOutTransfer(transfer);
+}
+
+bool UsbConnection::PostInTransfer() {
+ LOG4CXX_TRACE(logger_, "enter");
+ libusb_fill_bulk_transfer(in_transfer_, device_handle_, in_endpoint_,
+ in_buffer_, in_endpoint_max_packet_size_,
+ InTransferCallback, this, 0);
+ const int libusb_ret = libusb_submit_transfer(in_transfer_);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_, "libusb_submit_transfer failed: "
+ << libusb_error_name(libusb_ret));
+ LOG4CXX_TRACE(logger_,
+ "exit with FALSE. Condition: LIBUSB_SUCCESS != libusb_submit_transfer");
+ return false;
+ }
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+std::string hex_data(const unsigned char* const buffer, const int actual_length) {
+ std::ostringstream hexdata;
+ for (int i = 0; i < actual_length; ++i) {
+ hexdata << " " << std::hex << std::setw(2) << std::setfill('0')
+ << int(buffer[i]);
+ }
+ return hexdata.str();
+}
+
+void UsbConnection::OnInTransfer(libusb_transfer* transfer) {
+ LOG4CXX_TRACE(logger_, "enter with Libusb_transfer*: " << transfer);
+ if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+ LOG4CXX_DEBUG(logger_,
+ "USB incoming transfer, size:" << transfer->actual_length
+ << ", data:" << hex_data(transfer->buffer, transfer->actual_length));
+ RawMessagePtr data(new protocol_handler::RawMessage(
+ 0, 0, in_buffer_, transfer->actual_length));
+ controller_->DataReceiveDone(device_uid_, app_handle_, data);
+ } else {
+ LOG4CXX_ERROR(logger_, "USB incoming transfer failed: "
+ << libusb_error_name(transfer->status));
+ controller_->DataReceiveFailed(device_uid_, app_handle_,
+ DataReceiveError());
+ }
+ if (disconnecting_) {
+ waiting_in_transfer_cancel_ = false;
+ } else {
+ if (!PostInTransfer()) {
+ LOG4CXX_ERROR(logger_, "USB incoming transfer failed with "
+ << "LIBUSB_TRANSFER_NO_DEVICE. Abort connection.");
+ AbortConnection();
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbConnection::PopOutMessage() {
+ LOG4CXX_TRACE(logger_, "enter");
+ bytes_sent_ = 0;
+ if (out_messages_.empty()) {
+ current_out_message_.reset();
+ } else {
+ current_out_message_ = out_messages_.front();
+ out_messages_.pop_front();
+ PostOutTransfer();
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+bool UsbConnection::PostOutTransfer() {
+ LOG4CXX_TRACE(logger_, "enter");
+ out_transfer_ = libusb_alloc_transfer(0);
+ if (0 == out_transfer_) {
+ LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: 0 == out_transfer_");
+ return false;
+ }
+ libusb_fill_bulk_transfer(out_transfer_, device_handle_, out_endpoint_,
+ current_out_message_->data() + bytes_sent_,
+ current_out_message_->data_size() - bytes_sent_,
+ OutTransferCallback, this, 0);
+ const int libusb_ret = libusb_submit_transfer(out_transfer_);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_, "libusb_submit_transfer failed: "
+ << libusb_error_name(libusb_ret) << ". Abort connection.");
+ AbortConnection();
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: "
+ << "LIBUSB_SUCCESS != libusb_fill_bulk_transfer");
+ return false;
+ }
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+void UsbConnection::OnOutTransfer(libusb_transfer* transfer) {
+ LOG4CXX_TRACE(logger_, "enter with Libusb_transfer*: " << transfer);
+ sync_primitives::AutoLock locker(out_messages_mutex_);
+ if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+ bytes_sent_ += transfer->actual_length;
+ if (bytes_sent_ == current_out_message_->data_size()) {
+ LOG4CXX_DEBUG(logger_, "USB out transfer, data sent: "
+ << current_out_message_.get());
+ controller_->DataSendDone(device_uid_, app_handle_, current_out_message_);
+ PopOutMessage();
+ }
+ } else {
+ LOG4CXX_ERROR(logger_, "USB out transfer failed: "
+ << libusb_error_name(transfer->status));
+ controller_->DataSendFailed(device_uid_, app_handle_, current_out_message_,
+ DataSendError());
+ PopOutMessage();
+ }
+ if (!current_out_message_.valid()) {
+ libusb_free_transfer(transfer);
+ out_transfer_ = NULL;
+ waiting_out_transfer_cancel_ = false;
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error UsbConnection::SendData(RawMessagePtr message) {
+ LOG4CXX_TRACE(logger_, "enter with RawMessagePtr: " << message.get());
+ if (disconnecting_) {
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::BAD_STATE. Condition: "
+ << "disconnecting_");
+ return TransportAdapter::BAD_STATE;
+ }
+ sync_primitives::AutoLock locker(out_messages_mutex_);
+ if (current_out_message_.valid()) {
+ out_messages_.push_back(message);
+ } else {
+ current_out_message_ = message;
+ if (!PostOutTransfer()) {
+ controller_->DataSendFailed(device_uid_, app_handle_, message,
+ DataSendError());
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL. Condition: !PostOutTransfer()");
+ return TransportAdapter::FAIL;
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK.");
+ return TransportAdapter::OK;
+}
+
+void UsbConnection::Finalise() {
+ LOG4CXX_TRACE(logger_, "enter");
+ LOG4CXX_DEBUG(logger_, "Finalise USB connection " << device_uid_);
+ {
+ sync_primitives::AutoLock locker(out_messages_mutex_);
+ disconnecting_ = true;
+ if (out_transfer_) {
+ waiting_out_transfer_cancel_ = true;
+ if ( LIBUSB_SUCCESS != libusb_cancel_transfer(out_transfer_)) {
+ waiting_out_transfer_cancel_ = false;
+ }
+ }
+ if (in_transfer_) {
+ waiting_in_transfer_cancel_ = true;
+ if ( LIBUSB_SUCCESS != libusb_cancel_transfer(in_transfer_)) {
+ waiting_in_transfer_cancel_ = false;
+ }
+ }
+ for (std::list<RawMessagePtr>::iterator it = out_messages_.begin();
+ it != out_messages_.end(); it = out_messages_.erase(it)) {
+ controller_->DataSendFailed(device_uid_, app_handle_, *it, DataSendError());
+ }
+ }
+ while (waiting_in_transfer_cancel_ || waiting_out_transfer_cancel_) {
+ pthread_yield();
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbConnection::AbortConnection() {
+ LOG4CXX_TRACE(logger_, "enter");
+ controller_->ConnectionAborted(device_uid_, app_handle_, CommunicationError());
+ Disconnect();
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error UsbConnection::Disconnect() {
+ Finalise();
+ controller_->DisconnectDone(device_uid_, app_handle_);
+ return TransportAdapter::OK;
+}
+
+bool UsbConnection::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (!FindEndpoints()) {
+ LOG4CXX_ERROR(logger_, "EndPoints was not found");
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !FindEndpoints()");
+ return false;
+ }
+ in_buffer_ = new unsigned char[in_endpoint_max_packet_size_];
+ in_transfer_ = libusb_alloc_transfer(0);
+ if (NULL == in_transfer_) {
+ LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: NULL == in_transfer_");
+ return false;
+ }
+
+ controller_->ConnectDone(device_uid_, app_handle_);
+ if (!PostInTransfer()) {
+ LOG4CXX_ERROR(logger_, "PostInTransfer failed. Call ConnectionAborted");
+ controller_->ConnectionAborted(device_uid_, app_handle_,
+ CommunicationError());
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: !PostInTransfer()");
+ return false;
+ }
+
+ LOG4CXX_TRACE(logger_, "exit with TRUE");
+ return true;
+}
+
+bool UsbConnection::FindEndpoints() {
+ LOG4CXX_TRACE(logger_, "enter");
+ struct libusb_config_descriptor* config;
+ const int libusb_ret =
+ libusb_get_active_config_descriptor(libusb_device_, &config);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_, "libusb_get_active_config_descriptor failed: "
+ << libusb_error_name(libusb_ret));
+ LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return false;
+ }
+
+ bool find_in_endpoint = true;
+ bool find_out_endpoint = true;
+
+ for (int i = 0; i < config->bNumInterfaces; ++i) {
+ const libusb_interface& interface = config->interface[i];
+ for (int i = 0; i < interface.num_altsetting; ++i) {
+ const libusb_interface_descriptor& iface_desc = interface.altsetting[i];
+ for (int i = 0; i < iface_desc.bNumEndpoints; ++i) {
+ const libusb_endpoint_descriptor& endpoint_desc =
+ iface_desc.endpoint[i];
+
+ const uint8_t endpoint_dir =
+ endpoint_desc.bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK;
+ if (find_in_endpoint && endpoint_dir == LIBUSB_ENDPOINT_IN) {
+ in_endpoint_ = endpoint_desc.bEndpointAddress;
+ in_endpoint_max_packet_size_ = endpoint_desc.wMaxPacketSize;
+ find_in_endpoint = false;
+ } else if (find_out_endpoint && endpoint_dir == LIBUSB_ENDPOINT_OUT) {
+ out_endpoint_ = endpoint_desc.bEndpointAddress;
+ out_endpoint_max_packet_size_ = endpoint_desc.wMaxPacketSize;
+ find_out_endpoint = false;
+ }
+ }
+ }
+ }
+ libusb_free_config_descriptor(config);
+
+ const bool result = !(find_in_endpoint || find_out_endpoint);
+ LOG4CXX_TRACE(logger_, "exit with " << (result ? "TRUE" : "FALSE"));
+ return result;
+}
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/usb/libusb/usb_handler.cc b/src/components/transport_manager/src/usb/libusb/usb_handler.cc
new file mode 100644
index 0000000000..eb0ffdb4dc
--- /dev/null
+++ b/src/components/transport_manager/src/usb/libusb/usb_handler.cc
@@ -0,0 +1,474 @@
+/**
+ * \file usb_handler.cc
+ * \brief UsbHandler class source file.
+ *
+ * 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 <cstring>
+#include <cstdlib>
+
+#include "transport_manager/usb/common.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+class UsbHandler::ControlTransferSequenceState {
+ public:
+ ControlTransferSequenceState(class UsbHandler* usb_handler,
+ UsbControlTransferSequence* sequence,
+ PlatformUsbDevice* device);
+ ~ControlTransferSequenceState();
+ void Finish();
+ bool Finished() const {
+ return finished_;
+ }
+ UsbControlTransfer* CurrentTransfer();
+ UsbControlTransfer* Next();
+ UsbHandler* usb_handler() const {
+ return usb_handler_;
+ }
+ PlatformUsbDevice* device() const {
+ return device_;
+ }
+
+ private:
+ UsbHandler* usb_handler_;
+ PlatformUsbDevice* device_;
+ bool finished_;
+ UsbControlTransferSequence* sequence_;
+ UsbControlTransferSequence::Transfers::const_iterator current_transfer_;
+};
+
+UsbHandler::UsbHandler()
+ : shutdown_requested_(false),
+ thread_(),
+ usb_device_listeners_(),
+ devices_(),
+ transfer_sequences_(),
+ device_handles_to_close_(),
+ libusb_context_(NULL),
+ arrived_callback_handle_(),
+ left_callback_handle_() {}
+
+UsbHandler::~UsbHandler() {
+ shutdown_requested_ = true;
+ if (libusb_context_ != 0) {
+ libusb_hotplug_deregister_callback(libusb_context_,
+ arrived_callback_handle_);
+ libusb_hotplug_deregister_callback(libusb_context_, left_callback_handle_);
+ }
+ pthread_join(thread_, 0);
+ LOG4CXX_INFO(logger_, "UsbHandler thread finished");
+ if (libusb_context_) {
+ libusb_exit(libusb_context_);
+ libusb_context_ = 0;
+ }
+}
+
+void UsbHandler::DeviceArrived(libusb_device* device_libusb) {
+ LOG4CXX_TRACE(logger_, "enter. libusb_device* " << device_libusb);
+ const uint8_t bus_number = libusb_get_bus_number(device_libusb);
+ const uint8_t device_address = libusb_get_device_address(device_libusb);
+ libusb_device_descriptor descriptor;
+ int libusb_ret = libusb_get_device_descriptor(device_libusb, &descriptor);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_, "libusb_get_device_descriptor failed: " << libusb_ret);
+ LOG4CXX_TRACE(logger_, "exit. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return;
+ }
+
+ libusb_device_handle* device_handle_libusb;
+ libusb_ret = libusb_open(device_libusb, &device_handle_libusb);
+ if (libusb_ret != LIBUSB_SUCCESS) {
+ LOG4CXX_ERROR(logger_, "libusb_open failed: " << libusb_error_name(libusb_ret));
+ LOG4CXX_TRACE(logger_, "exit. Condition: libusb_ret != LIBUSB_SUCCESS");
+ return;
+ }
+
+ int configuration;
+ libusb_ret = libusb_get_configuration(device_handle_libusb, &configuration);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_INFO(logger_, "libusb_get_configuration failed: " << libusb_error_name(
+ libusb_ret));
+ LOG4CXX_TRACE(logger_, "exit. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return;
+ }
+
+ if (configuration != kUsbConfiguration) {
+ libusb_ret = libusb_set_configuration(device_handle_libusb, kUsbConfiguration);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_INFO(logger_, "libusb_set_configuration failed: " << libusb_error_name(
+ libusb_ret));
+ LOG4CXX_TRACE(logger_, "exit. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return;
+ }
+ }
+
+ libusb_ret = libusb_claim_interface(device_handle_libusb, 0);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_INFO(logger_, "libusb_claim_interface failed: " << libusb_error_name(libusb_ret));
+ CloseDeviceHandle(device_handle_libusb);
+ LOG4CXX_TRACE(logger_, "exit. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return;
+ }
+
+ PlatformUsbDevice* device(new PlatformUsbDevice(bus_number, device_address,
+ descriptor, device_libusb,
+ device_handle_libusb));
+ devices_.push_back(device);
+
+ for (std::list<UsbDeviceListener*>::iterator it =
+ usb_device_listeners_.begin();
+ it != usb_device_listeners_.end(); ++it) {
+ (*it)->OnDeviceArrived(device);
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbHandler::DeviceLeft(libusb_device* device_libusb) {
+ LOG4CXX_TRACE(logger_, "enter. libusb_device* " << device_libusb);
+ PlatformUsbDevice* device = NULL;
+ for (Devices::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ if ((*it)->GetLibusbDevice() == device_libusb) {
+ device = *it;
+ break;
+ }
+ }
+ if (NULL == device) {
+ LOG4CXX_TRACE(logger_, "enter. Condition: NULL == device");
+ return;
+ }
+
+ for (std::list<UsbDeviceListener*>::iterator it =
+ usb_device_listeners_.begin();
+ it != usb_device_listeners_.end(); ++it) {
+ (*it)->OnDeviceLeft(device);
+ }
+
+ for (Devices::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ if ((*it)->GetLibusbDevice() == device_libusb) {
+ devices_.erase(it);
+ break;
+ }
+ }
+
+ if (device->GetLibusbHandle()) {
+ libusb_release_interface(device->GetLibusbHandle(), 0);
+ CloseDeviceHandle(device->GetLibusbHandle());
+ }
+ delete device;
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbHandler::StartControlTransferSequence(
+ UsbControlTransferSequence* sequence, PlatformUsbDevice* device) {
+ LOG4CXX_TRACE(logger_, "enter. UsbControlTransferSequence* " << sequence <<
+ "PlatformUsbDevice* " << device);
+ TransferSequences::iterator it = transfer_sequences_.insert(
+ transfer_sequences_.end(),
+ new ControlTransferSequenceState(this, sequence, device));
+ SubmitControlTransfer(*it);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbHandler::CloseDeviceHandle(libusb_device_handle* device_handle) {
+ device_handles_to_close_.push_back(device_handle);
+}
+
+void* UsbHandlerThread(void* data) {
+ static_cast<UsbHandler*>(data)->Thread();
+ return 0;
+}
+
+int ArrivedCallback(libusb_context* context, libusb_device* device,
+ libusb_hotplug_event event, void* data) {
+ LOG4CXX_TRACE(logger_, "enter. libusb device arrived (bus number "
+ << static_cast<int>(libusb_get_bus_number(device))
+ << ", device address "
+ << static_cast<int>(
+ libusb_get_device_address(device)) << ")");
+ UsbHandler* usb_handler = static_cast<UsbHandler*>(data);
+ usb_handler->DeviceArrived(device);
+ LOG4CXX_TRACE(logger_, "exit with 0");
+ return 0;
+}
+
+int LeftCallback(libusb_context* context, libusb_device* device,
+ libusb_hotplug_event event, void* data) {
+ LOG4CXX_TRACE(logger_, "enter libusb device left (bus number "
+ << static_cast<int>(libusb_get_bus_number(device))
+ << ", device address "
+ << static_cast<int>(
+ libusb_get_device_address(device)) << ")");
+ UsbHandler* usb_handler = static_cast<UsbHandler*>(data);
+ usb_handler->DeviceLeft(device);
+ LOG4CXX_TRACE(logger_, "exit with 0");
+ return 0;
+}
+
+TransportAdapter::Error UsbHandler::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ int libusb_ret = libusb_init(&libusb_context_);
+
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_, "libusb_init failed: " << libusb_ret);
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return TransportAdapter::FAIL;
+ }
+
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+ LOG4CXX_ERROR(logger_, "LIBUSB_CAP_HAS_HOTPLUG not supported");
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: !libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)");
+ return TransportAdapter::FAIL;
+ }
+
+ libusb_ret = libusb_hotplug_register_callback(
+ libusb_context_, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
+ LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY,
+ LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, ArrivedCallback, this,
+ &arrived_callback_handle_);
+
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_,
+ "libusb_hotplug_register_callback failed: " << libusb_ret);
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return TransportAdapter::FAIL;
+ }
+
+ libusb_ret = libusb_hotplug_register_callback(
+ libusb_context_, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+ static_cast<libusb_hotplug_flag>(0), LIBUSB_HOTPLUG_MATCH_ANY,
+ LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, LeftCallback, this,
+ &left_callback_handle_);
+
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_,
+ "libusb_hotplug_register_callback failed: " << libusb_ret);
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: LIBUSB_SUCCESS != libusb_ret");
+ return TransportAdapter::FAIL;
+ }
+
+ const int thread_start_error =
+ pthread_create(&thread_, 0, &UsbHandlerThread, this);
+ if (0 != thread_start_error) {
+ LOG4CXX_ERROR(logger_, "USB device scanner thread start failed, error code "
+ << thread_start_error);
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::FAIL. Condition: 0 !== thread_start_error");
+ return TransportAdapter::FAIL;
+ }
+ LOG4CXX_INFO(logger_, "UsbHandler thread started");
+ pthread_setname_np(thread_, "UsbHandler" );
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::OK. Condition: 0 == thread_start_error");
+ return TransportAdapter::OK;
+}
+
+void UsbHandler::Thread() {
+ LOG4CXX_TRACE(logger_, "enter");
+ int completed = 0;
+ while (!shutdown_requested_) {
+ libusb_handle_events_completed(libusb_context_, &completed);
+
+ for (TransferSequences::iterator it = transfer_sequences_.begin();
+ it != transfer_sequences_.end();) {
+ ControlTransferSequenceState* sequence_state = *it;
+ if (sequence_state->Finished()) {
+ delete *it;
+ it = transfer_sequences_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ for (std::list<libusb_device_handle*>::iterator it =
+ device_handles_to_close_.begin();
+ it != device_handles_to_close_.end();
+ it = device_handles_to_close_.erase(it)) {
+ libusb_close(*it);
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbTransferSequenceCallback(libusb_transfer* transfer) {
+ LOG4CXX_TRACE(logger_, "enter. libusb_transfer* " << transfer);
+ UsbHandler::ControlTransferSequenceState* sequence_state =
+ static_cast<UsbHandler::ControlTransferSequenceState*>(transfer->user_data);
+ sequence_state->usb_handler()->ControlTransferCallback(transfer);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbHandler::SubmitControlTransfer(
+ ControlTransferSequenceState* sequence_state) {
+ LOG4CXX_TRACE(logger_, "enter. ControlTransferSequenceState* " << sequence_state);
+ UsbControlTransfer* transfer = sequence_state->CurrentTransfer();
+ if (NULL == transfer) {
+ LOG4CXX_TRACE(logger_, "exit. Condition: NULL == transfer");
+ return;
+ }
+
+ libusb_transfer* libusb_transfer = libusb_alloc_transfer(0);
+ if (0 == libusb_transfer) {
+ LOG4CXX_ERROR(logger_, "libusb_alloc_transfer failed");
+ sequence_state->Finish();
+ LOG4CXX_TRACE(logger_, "exit. Condition: 0 == libusb_transfer");
+ return;
+ }
+
+ assert(transfer->Type() == UsbControlTransfer::VENDOR);
+ const libusb_request_type request_type = LIBUSB_REQUEST_TYPE_VENDOR;
+
+ libusb_endpoint_direction endpoint_direction;
+ if (transfer->Direction() == UsbControlTransfer::IN) {
+ endpoint_direction = LIBUSB_ENDPOINT_IN;
+ } else if (transfer->Direction() == UsbControlTransfer::OUT) {
+ endpoint_direction = LIBUSB_ENDPOINT_OUT;
+ } else {
+ assert(0);
+ }
+ const uint8_t request = transfer->Request();
+ const uint16_t value = transfer->Value();
+ const uint16_t index = transfer->Index();
+ const uint16_t length = transfer->Length();
+
+ unsigned char* buffer =
+ static_cast<unsigned char*>(malloc(length + LIBUSB_CONTROL_SETUP_SIZE));
+ if (NULL == buffer) {
+ LOG4CXX_ERROR(logger_, "buffer allocation failed");
+ libusb_free_transfer(libusb_transfer);
+ sequence_state->Finish();
+ LOG4CXX_TRACE(logger_, "exit. Condition: NULL == buffer");
+ return;
+ }
+
+ libusb_fill_control_setup(buffer, request_type | endpoint_direction, request,
+ value, index, length);
+
+ if (0 != length && endpoint_direction == LIBUSB_ENDPOINT_OUT) {
+ const char* data = static_cast<UsbControlOutTransfer*>(transfer)->Data();
+ memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, length);
+ }
+ libusb_fill_control_transfer(
+ libusb_transfer, sequence_state->device()->GetLibusbHandle(), buffer,
+ UsbTransferSequenceCallback, sequence_state, 0);
+ libusb_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
+
+ const int libusb_ret = libusb_submit_transfer(libusb_transfer);
+ if (LIBUSB_SUCCESS != libusb_ret) {
+ LOG4CXX_ERROR(logger_, "libusb_submit_transfer failed: "
+ << libusb_error_name(libusb_ret));
+ libusb_free_transfer(libusb_transfer);
+ sequence_state->Finish();
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbHandler::ControlTransferCallback(libusb_transfer* transfer) {
+ LOG4CXX_TRACE(logger_, "enter. libusb_transfer* " << transfer);
+ ControlTransferSequenceState* sequence_state =
+ static_cast<ControlTransferSequenceState*>(transfer->user_data);
+ if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+ LOG4CXX_INFO(logger_, "USB control transfer completed");
+ UsbControlTransfer* current_transfer = sequence_state->CurrentTransfer();
+ bool submit_next = true;
+ if (current_transfer &&
+ current_transfer->Direction() == UsbControlTransfer::IN) {
+ submit_next =
+ static_cast<UsbControlInTransfer*>(current_transfer)
+ ->OnCompleted(libusb_control_transfer_get_data(transfer));
+ }
+
+ sequence_state->Next();
+ if (submit_next && !sequence_state->Finished()) {
+ SubmitControlTransfer(sequence_state);
+ } else {
+ sequence_state->Finish();
+ }
+ } else {
+ LOG4CXX_ERROR(logger_, "USB control transfer failed: " << transfer->status);
+ sequence_state->Finish();
+ }
+ libusb_free_transfer(transfer);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+UsbHandler::ControlTransferSequenceState::ControlTransferSequenceState(
+ UsbHandler* usb_handler, UsbControlTransferSequence* sequence,
+ PlatformUsbDevice* device)
+ : usb_handler_(usb_handler),
+ device_(device),
+ finished_(false),
+ sequence_(sequence),
+ current_transfer_(sequence->transfers().begin()) {}
+
+UsbHandler::ControlTransferSequenceState::~ControlTransferSequenceState() {
+ delete sequence_;
+}
+
+UsbControlTransfer* UsbHandler::ControlTransferSequenceState::Next() {
+ LOG4CXX_TRACE(logger_, "enter");
+ if (finished_) {
+ LOG4CXX_TRACE(logger_, "exit with NULL. Condition: finished_");
+ return NULL;
+ }
+ if (++current_transfer_ == sequence_->transfers().end()) {
+ Finish();
+ LOG4CXX_TRACE(logger_,
+ "exit with NULL. Condition: ++current_transfer_ == sequence_->transfers().end()");
+ return NULL;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with UsbControlTransfer* " << *current_transfer_ <<
+ ".Condition: ++current_transfer_ !== sequence_->transfers().end()");
+ return *current_transfer_;
+ }
+}
+
+UsbControlTransfer* UsbHandler::ControlTransferSequenceState::CurrentTransfer() {
+ return finished_ ? NULL : *current_transfer_;
+}
+
+void UsbHandler::ControlTransferSequenceState::Finish() {
+ finished_ = true;
+}
+
+} // namespace
+} // namespace
diff --git a/src/components/transport_manager/src/usb/qnx/platform_usb_device.cc b/src/components/transport_manager/src/usb/qnx/platform_usb_device.cc
new file mode 100644
index 0000000000..0f35a16ae7
--- /dev/null
+++ b/src/components/transport_manager/src/usb/qnx/platform_usb_device.cc
@@ -0,0 +1,79 @@
+/**
+ * \file platform_usb_device.cc
+ * \brief QNX PlatformUsbDevice class source file.
+ *
+ * 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 "transport_manager/usb/qnx/platform_usb_device.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+PlatformUsbDevice::PlatformUsbDevice(
+ usbd_device_instance_t* instance, usbd_device* device,
+ const usbd_device_descriptor_t& device_descriptor)
+ : bus_number_(instance->path),
+ address_(instance->devno),
+ vendor_id_(instance->ident.vendor),
+ product_id_(instance->ident.device),
+ device_descriptor_(device_descriptor),
+ usbd_device_instance_(*instance),
+ usbd_device_(device) {}
+
+std::string PlatformUsbDevice::GetDescString(uint8_t index) const {
+ char* str = usbd_string(usbd_device_, index, 0);
+ if (NULL == str) {
+ LOG4CXX_INFO(logger_, "Failed to get USB string descriptor");
+ return "";
+ }
+ return std::string(str);
+}
+
+std::string PlatformUsbDevice::GetManufacturer() const {
+ return GetDescString(device_descriptor_.iManufacturer);
+}
+
+std::string PlatformUsbDevice::GetProductName() const {
+ return GetDescString(device_descriptor_.iProduct);
+}
+
+std::string PlatformUsbDevice::GetSerialNumber() const {
+ return GetDescString(device_descriptor_.iSerialNumber);
+}
+
+} // namespace
+} // namespace
diff --git a/src/components/transport_manager/src/usb/qnx/usb_connection.cc b/src/components/transport_manager/src/usb/qnx/usb_connection.cc
new file mode 100644
index 0000000000..da5d30136b
--- /dev/null
+++ b/src/components/transport_manager/src/usb/qnx/usb_connection.cc
@@ -0,0 +1,404 @@
+/**
+ * \file usb_connection.cc
+ * \brief UsbConnection class source file.
+ *
+ * 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 <sched.h>
+#include <cstring>
+
+#include "transport_manager/usb/qnx/usb_connection.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+UsbConnection::UsbConnection(const DeviceUID& device_uid,
+ const ApplicationHandle& app_handle,
+ TransportAdapterController* controller,
+ const UsbHandlerSptr& libusb_handler,
+ PlatformUsbDevice* device)
+ : device_uid_(device_uid),
+ app_handle_(app_handle),
+ controller_(controller),
+ libusb_handler_(libusb_handler),
+ usbd_device_(device->GetUsbdDevice()),
+ in_pipe_(NULL),
+ out_pipe_(NULL),
+ in_buffer_(NULL),
+ in_urb_(NULL),
+ out_urb_(NULL),
+ out_messages_(),
+ current_out_message_(),
+ out_messages_mutex_(),
+ bytes_sent_(0),
+ disconnecting_(false),
+ pending_in_transfer_(false),
+ pending_out_transfer_(false) {
+ pthread_mutex_init(&out_messages_mutex_, 0);
+}
+
+UsbConnection::~UsbConnection() {
+ Finalise();
+ if (in_urb_) usbd_free_urb(in_urb_);
+ if (out_urb_) usbd_free_urb(out_urb_);
+
+ if (in_pipe_) {
+ const int close_pipe_rc = usbd_close_pipe(in_pipe_);
+ if (EOK != close_pipe_rc) {
+ LOG4CXX_ERROR(logger_, "Failed to close pipe: " << close_pipe_rc);
+ }
+ }
+ if (out_pipe_) {
+ const int close_pipe_rc = usbd_close_pipe(out_pipe_);
+ if (EOK != close_pipe_rc) {
+ LOG4CXX_ERROR(logger_, "Failed to close pipe: " << close_pipe_rc);
+ }
+ }
+
+ pthread_mutex_destroy(&out_messages_mutex_);
+}
+
+void InTransferCallback(usbd_urb* urb, usbd_pipe*, void* data) {
+ static_cast<UsbConnection*>(data)->OnInTransfer(urb);
+}
+
+void OutTransferCallback(usbd_urb* urb, usbd_pipe*, void* data) {
+ static_cast<UsbConnection*>(data)->OnOutTransfer(urb);
+}
+
+bool UsbConnection::PostInTransfer() {
+ usbd_setup_bulk(in_urb_, URB_DIR_IN, in_buffer_, kInBufferSize);
+ pending_in_transfer_ = true;
+ const int io_rc =
+ usbd_io(in_urb_, in_pipe_, InTransferCallback, this, USBD_TIME_INFINITY);
+ if (EOK != io_rc) {
+ pending_in_transfer_ = false;
+ LOG4CXX_ERROR(logger_, "Failed to post in transfer: " << io_rc);
+ return false;
+ }
+ return true;
+}
+
+void UsbConnection::OnInTransfer(usbd_urb* urb) {
+ uint32_t status = 0;
+ uint32_t len = 0;
+ bool error = false;
+ const int urb_status_rc = usbd_urb_status(urb, &status, &len);
+ if (EOK != urb_status_rc && EIO != urb_status_rc) { // EIO is OK
+ LOG4CXX_ERROR(logger_, "Get in urb status failed: " << urb_status_rc);
+ error = true;
+ }
+ LOG4CXX_INFO(logger_, "USB in transfer, status " << std::hex << status
+ << ", length " << std::dec
+ << len);
+
+ if (!error) {
+ switch (status) {
+ case USBD_STATUS_CMP:
+ case USBD_STATUS_CMP_ERR | USBD_STATUS_DATA_UNDERRUN:
+ error = false;
+ break;
+ default:
+ error = true;
+ break;
+ }
+ }
+
+ if (error) {
+ LOG4CXX_ERROR(logger_, "USB in transfer failed");
+ controller_->DataReceiveFailed(device_uid_, app_handle_,
+ DataReceiveError());
+ } else {
+ RawMessagePtr msg(new protocol_handler::RawMessage(0, 0, in_buffer_, len));
+ controller_->DataReceiveDone(device_uid_, app_handle_, msg);
+ }
+
+ pending_in_transfer_ = false;
+ if (!disconnecting_) {
+ if (!PostInTransfer()) {
+ controller_->ConnectionAborted(device_uid_, app_handle_,
+ CommunicationError());
+ Disconnect();
+ }
+ }
+}
+
+void UsbConnection::PopOutMessage() {
+ bytes_sent_ = 0;
+ if (out_messages_.empty()) {
+ current_out_message_.reset();
+ } else {
+ current_out_message_ = out_messages_.front();
+ out_messages_.pop_front();
+ }
+}
+
+bool UsbConnection::PostOutTransfer() {
+ const int len = current_out_message_->data_size() - bytes_sent_;
+ out_buffer_ = usbd_alloc(len);
+ memmove(out_buffer_, current_out_message_->data() + bytes_sent_, len);
+ usbd_setup_bulk(out_urb_, URB_DIR_OUT, out_buffer_, len);
+ LOG4CXX_INFO(logger_, "out transfer :" << len);
+ pending_out_transfer_ = true;
+ const int io_rc = usbd_io(out_urb_, out_pipe_, OutTransferCallback, this,
+ USBD_TIME_INFINITY);
+ if (EOK != io_rc) {
+ pending_out_transfer_ = false;
+ usbd_free(out_buffer_);
+ LOG4CXX_ERROR(logger_, "Failed to post out transfer: " << io_rc);
+ return false;
+ }
+ return true;
+}
+
+void UsbConnection::OnOutTransfer(usbd_urb* urb) {
+ usbd_free(out_buffer_);
+ uint32_t status = 0;
+ uint32_t len = 0;
+ bool error = false;
+ const int urb_status_rc = usbd_urb_status(urb, &status, &len);
+ if (EOK != urb_status_rc && EIO != urb_status_rc) { // EIO is OK
+ LOG4CXX_ERROR(logger_, "Get out urb status failed: " << urb_status_rc);
+ error = true;
+ }
+ LOG4CXX_INFO(logger_, "USB out transfer, status " << std::hex << status
+ << ", length " << std::dec
+ << len);
+
+ if (!error) {
+ switch (status) {
+ case USBD_STATUS_CMP:
+ case USBD_STATUS_CMP_ERR | USBD_STATUS_DATA_UNDERRUN:
+ error = false;
+ break;
+ default:
+ error = true;
+ break;
+ }
+ }
+
+ pthread_mutex_lock(&out_messages_mutex_);
+
+ if (error) {
+ LOG4CXX_ERROR(logger_, "USB out transfer failed");
+ controller_->DataSendFailed(device_uid_, app_handle_, current_out_message_,
+ DataSendError());
+ PopOutMessage();
+ } else {
+ bytes_sent_ += len;
+ if (bytes_sent_ == current_out_message_->data_size()) {
+ LOG4CXX_INFO(logger_, "USB out transfer, data sent: "
+ << current_out_message_.get());
+ controller_->DataSendDone(device_uid_, app_handle_, current_out_message_);
+ PopOutMessage();
+ }
+ }
+
+ if ((!disconnecting_) && current_out_message_.valid()) {
+ PostOutTransfer();
+ } else {
+ pending_out_transfer_ = false;
+ }
+ pthread_mutex_unlock(&out_messages_mutex_);
+}
+
+TransportAdapter::Error UsbConnection::SendData(RawMessagePtr message) {
+ if (disconnecting_) {
+ return TransportAdapter::BAD_STATE;
+ }
+ pthread_mutex_lock(&out_messages_mutex_);
+ if (current_out_message_.valid()) {
+ out_messages_.push_back(message);
+ } else {
+ current_out_message_ = message;
+ if (!PostOutTransfer()) {
+ controller_->DataSendFailed(device_uid_, app_handle_, message,
+ DataSendError());
+ }
+ }
+ pthread_mutex_unlock(&out_messages_mutex_);
+ return TransportAdapter::OK;
+}
+
+void UsbConnection::Finalise() {
+ LOG4CXX_INFO(logger_, "Finalising");
+ pthread_mutex_lock(&out_messages_mutex_);
+ disconnecting_ = true;
+ usbd_abort_pipe(in_pipe_);
+ usbd_abort_pipe(out_pipe_);
+ for (std::list<RawMessagePtr>::iterator it = out_messages_.begin();
+ it != out_messages_.end(); it = out_messages_.erase(it)) {
+ controller_->DataSendFailed(device_uid_, app_handle_, *it, DataSendError());
+ }
+ pthread_mutex_unlock(&out_messages_mutex_);
+ while (pending_in_transfer_ || pending_out_transfer_) sched_yield();
+}
+
+TransportAdapter::Error UsbConnection::Disconnect() {
+ LOG4CXX_INFO(logger_, "Disconnecting");
+ Finalise();
+ controller_->DisconnectDone(device_uid_, app_handle_);
+ return TransportAdapter::OK;
+}
+
+bool UsbConnection::Init() {
+ if (!OpenEndpoints()) return false;
+
+ in_urb_ = usbd_alloc_urb(NULL);
+ out_urb_ = usbd_alloc_urb(NULL);
+ if (NULL == in_urb_ || NULL == out_urb_) {
+ LOG4CXX_ERROR(logger_, "usbd_alloc_urb failed");
+ return false;
+ }
+
+ in_buffer_ = static_cast<unsigned char*>(usbd_alloc(kInBufferSize));
+ if (NULL == in_buffer_) {
+ LOG4CXX_ERROR(logger_, "usbd_alloc failed");
+ return false;
+ }
+
+ controller_->ConnectDone(device_uid_, app_handle_);
+
+ if (!PostInTransfer()) {
+ controller_->ConnectionAborted(device_uid_, app_handle_,
+ CommunicationError());
+ return true;
+ }
+
+ return true;
+}
+
+bool UsbConnection::OpenEndpoints() {
+ usbd_descriptors_t* in_endpoint_desc = NULL;
+ usbd_descriptors_t* out_endpoint_desc = NULL;
+
+ usbd_desc_node* device_desc_node = NULL;
+ usbd_device_descriptor_t* device_desc =
+ usbd_device_descriptor(usbd_device_, &device_desc_node);
+ if (0 == device_desc) {
+ LOG4CXX_ERROR(logger_, "Device descriptor not found");
+ return false;
+ }
+ usbd_desc_node* cfg_desc_node = NULL;
+ usbd_descriptors_t* config_desc = NULL;
+ usbd_descriptors_t* iface_desc = NULL;
+ int cfg = 0;
+ bool found = false;
+ while (!found) {
+ config_desc =
+ usbd_parse_descriptors(usbd_device_, device_desc_node,
+ USB_DESC_CONFIGURATION, cfg++, &cfg_desc_node);
+ if (config_desc == NULL) {
+ break;
+ }
+ LOG4CXX_INFO(logger_, "USB configuration "
+ << static_cast<int>(config_desc->configuration
+ .bConfigurationValue));
+ int iface = 0;
+ usbd_desc_node* iface_desc_node;
+ while (!found) {
+ iface_desc =
+ usbd_parse_descriptors(usbd_device_, cfg_desc_node,
+ USB_DESC_INTERFACE, iface++, &iface_desc_node);
+ if (iface_desc == NULL) {
+ break;
+ }
+#if ENABLE_LOG
+ const uint8_t interface_number = iface_desc->interface.bInterfaceNumber;
+#endif
+ const uint8_t interface_subclass =
+ iface_desc->interface.bInterfaceSubClass;
+ LOG4CXX_INFO(logger_, "USB interface number "
+ << static_cast<int>(interface_number)
+ << ", subclass " << std::hex
+ << static_cast<int>(interface_subclass)
+ << std::dec);
+ if (interface_subclass != 0xff) {
+ continue;
+ }
+ int endpoint = 0;
+ in_endpoint_desc = NULL;
+ out_endpoint_desc = NULL;
+ while (true) {
+ usbd_descriptors_t* endpoint_desc = usbd_parse_descriptors(
+ usbd_device_, iface_desc_node, USB_DESC_ENDPOINT, endpoint++, NULL);
+ if (NULL == endpoint_desc) break;
+ const uint8_t attributes = endpoint_desc->endpoint.bmAttributes;
+ if ((attributes & 0x03) == USB_ATTRIB_BULK) {
+ const uint8_t endpoint_address =
+ endpoint_desc->endpoint.bEndpointAddress;
+ LOG4CXX_INFO(logger_, "Endpoint with address "
+ << std::hex
+ << static_cast<int>(endpoint_address)
+ << std::dec << " found");
+ if (endpoint_address & USB_ENDPOINT_IN) {
+ if (NULL == in_endpoint_desc) {
+ in_endpoint_desc = endpoint_desc;
+ }
+ } else {
+ if (NULL == out_endpoint_desc) {
+ out_endpoint_desc = endpoint_desc;
+ }
+ }
+ }
+ }
+ if (in_endpoint_desc != NULL && out_endpoint_desc != NULL) {
+ found = true;
+ }
+ }
+ }
+
+ if (!found) return false;
+
+ int open_pipe_rc = usbd_open_pipe(usbd_device_, in_endpoint_desc, &in_pipe_);
+ if (EOK != open_pipe_rc) {
+ LOG4CXX_ERROR(logger_, "Cannot open input pipe, error " << open_pipe_rc);
+ return false;
+ }
+
+ open_pipe_rc = usbd_open_pipe(usbd_device_, out_endpoint_desc, &out_pipe_);
+ if (EOK != open_pipe_rc) {
+ LOG4CXX_ERROR(logger_, "Cannot open output pipe, error " << open_pipe_rc);
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/usb/qnx/usb_handler.cc b/src/components/transport_manager/src/usb/qnx/usb_handler.cc
new file mode 100644
index 0000000000..7ab36169b1
--- /dev/null
+++ b/src/components/transport_manager/src/usb/qnx/usb_handler.cc
@@ -0,0 +1,302 @@
+/**
+ * \file usb_handler.cc
+ * \brief UsbHandler class source file.
+ *
+ * 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 <cstring>
+#include <cstdlib>
+
+#include "transport_manager/usb/common.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+namespace {
+UsbHandler* usb_handler;
+}
+
+UsbHandler::UsbHandler()
+ : usb_device_listeners_(),
+ devices_(),
+ usbd_general_connection_(NULL),
+ usbd_aoa_connection_(NULL) {
+ usb_handler = this;
+}
+
+UsbHandler::~UsbHandler() {
+ usb_handler = NULL;
+ if (usbd_general_connection_) {
+ const int disconnect_rc = usbd_disconnect(usbd_general_connection_);
+ if (EOK != disconnect_rc) {
+ LOG4CXX_ERROR(logger_, "usbd_disconnect failed, error code "
+ << disconnect_rc);
+ }
+ }
+ if (usbd_aoa_connection_) {
+ const int disconnect_rc = usbd_disconnect(usbd_aoa_connection_);
+ if (EOK != disconnect_rc) {
+ LOG4CXX_ERROR(logger_, "usbd_disconnect failed, error code "
+ << disconnect_rc);
+ }
+ }
+}
+
+bool operator==(const usbd_device_instance_t& a,
+ const usbd_device_instance_t& b) {
+ return a.path == b.path && a.devno == b.devno;
+}
+
+void UsbHandler::DeviceArrived(usbd_connection* connection,
+ usbd_device_instance_t* instance) {
+ for (Devices::const_iterator it = devices_.begin(); it != devices_.end();
+ ++it) {
+ if ((*it)->GetDeviceInstance() == *instance) return;
+ }
+ usbd_device* device_usbd = 0;
+ const int attach_rc = usbd_attach(connection, instance, 0, &device_usbd);
+ if (EOK != attach_rc) {
+ LOG4CXX_ERROR(logger_, "usbd_attach failed: " << attach_rc);
+ return;
+ }
+
+ usbd_desc_node* node;
+ usbd_device_descriptor_t* descriptor =
+ usbd_device_descriptor(device_usbd, &node);
+ if (NULL == descriptor) {
+ LOG4CXX_ERROR(logger_, "usbd_device_descriptor failed");
+ return;
+ }
+
+ PlatformUsbDevice* device(
+ new PlatformUsbDevice(instance, device_usbd, *descriptor));
+ devices_.push_back(device);
+ for (std::list<UsbDeviceListener*>::iterator it =
+ usb_device_listeners_.begin();
+ it != usb_device_listeners_.end(); ++it) {
+ (*it)->OnDeviceArrived(device);
+ }
+}
+
+void UsbHandler::DeviceLeft(usbd_device_instance_t* instance) {
+ PlatformUsbDevice* device = NULL;
+ for (Devices::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ if (((*it)->GetDeviceInstance()) == *instance) {
+ device = *it;
+ break;
+ }
+ }
+ if (NULL == device) {
+ return;
+ }
+
+ for (std::list<UsbDeviceListener*>::iterator it =
+ usb_device_listeners_.begin();
+ it != usb_device_listeners_.end(); ++it) {
+ (*it)->OnDeviceLeft(device);
+ }
+
+ for (Devices::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ if ((*it)->GetDeviceInstance() == *instance) {
+ const int detach_rc = usbd_detach((*it)->GetUsbdDevice());
+ if (EOK != detach_rc)
+ LOG4CXX_ERROR(logger_, "usbd_detach failed: " << detach_rc);
+ devices_.erase(it);
+ break;
+ }
+ }
+
+ delete device;
+}
+
+void UsbHandler::StartControlTransferSequence(
+ UsbControlTransferSequence* sequence, PlatformUsbDevice* device) {
+ usbd_descriptors_t* descriptor = usbd_parse_descriptors(
+ device->GetUsbdDevice(), NULL, USB_DESC_DEVICE, 0, NULL);
+ if (NULL == descriptor) {
+ LOG4CXX_ERROR(logger_, "usbd_parse_descriptors failed");
+ }
+
+ usbd_pipe* usb_pipe = 0;
+ const int open_pipe_rc =
+ usbd_open_pipe(device->GetUsbdDevice(), descriptor, &usb_pipe);
+ if (EOK != open_pipe_rc) {
+ LOG4CXX_ERROR(logger_, "usbd_open_pipe failed, error " << open_pipe_rc);
+ return;
+ }
+
+ for (UsbControlTransferSequence::Transfers::const_iterator it =
+ sequence->transfers().begin();
+ it != sequence->transfers().end(); ++it) {
+ UsbControlTransfer* transfer = *it;
+
+ usbd_urb* urb = usbd_alloc_urb(NULL);
+ if (NULL == urb) {
+ LOG4CXX_ERROR(logger_, "usbd_alloc_urb failed");
+ break;
+ }
+
+ unsigned char* buf =
+ static_cast<unsigned char*>(usbd_alloc(transfer->Length()));
+ if (NULL == buf) {
+ LOG4CXX_ERROR(logger_, "usbd_alloc failed");
+ break;
+ }
+
+ uint32_t flags = 0;
+ if (transfer->Direction() == UsbControlTransfer::IN) {
+ flags = URB_DIR_IN;
+ } else if (transfer->Direction() == UsbControlTransfer::OUT) {
+ flags = URB_DIR_OUT;
+ UsbControlOutTransfer* out_transfer =
+ static_cast<UsbControlOutTransfer*>(transfer);
+ std::copy(out_transfer->Data(),
+ out_transfer->Data() + out_transfer->Length(), buf);
+ } else {
+ assert(0);
+ }
+
+ assert(transfer->Type() == UsbControlTransfer::VENDOR);
+
+ usbd_setup_vendor(urb, flags, transfer->Request(), USB_TYPE_VENDOR,
+ transfer->Value(), transfer->Index(), buf,
+ transfer->Length());
+ const int io_rc = usbd_io(urb, usb_pipe, 0, 0, USBD_TIME_DEFAULT);
+
+ bool submit_next = true;
+ if (io_rc == EOK) {
+ if (transfer->Direction() == UsbControlTransfer::IN) {
+ submit_next =
+ static_cast<UsbControlInTransfer*>(transfer)->OnCompleted(buf);
+ }
+ } else {
+ LOG4CXX_ERROR(logger_, "usbd_io failed, error " << io_rc);
+ submit_next = false;
+ }
+ usbd_free(buf);
+ usbd_free_urb(urb);
+ if (!submit_next) break;
+ }
+ usbd_close_pipe(usb_pipe);
+
+ delete sequence;
+}
+
+void ArrivedCallback(usbd_connection* connection,
+ usbd_device_instance_t* instance) {
+ if (kAoaVid == instance->ident.vendor) return;
+ LOG4CXX_INFO(logger_, "USB device arrived (path "
+ << static_cast<int>(instance->path) << ", devno "
+ << static_cast<int>(instance->devno) << ", config "
+ << static_cast<int>(instance->config) << ", iface "
+ << static_cast<int>(instance->iface) << ")");
+ usb_handler->DeviceArrived(connection, instance);
+}
+
+void ArrivedAoaCallback(usbd_connection* connection,
+ usbd_device_instance_t* instance) {
+ if (kAoaVid != instance->ident.vendor) return;
+ LOG4CXX_INFO(logger_, "USB AOA device arrived (path "
+ << static_cast<int>(instance->path) << ", devno "
+ << static_cast<int>(instance->devno) << ", config "
+ << static_cast<int>(instance->config) << ", iface "
+ << static_cast<int>(instance->iface) << ")");
+ usb_handler->DeviceArrived(connection, instance);
+}
+
+void LeftCallback(usbd_connection* connection,
+ usbd_device_instance_t* instance) {
+ if (kAoaVid == instance->ident.vendor) return;
+ LOG4CXX_INFO(logger_, "USB device left (path "
+ << static_cast<int>(instance->path) << ", devno "
+ << static_cast<int>(instance->devno) << ", config "
+ << static_cast<int>(instance->config) << ", iface "
+ << static_cast<int>(instance->iface) << ")");
+ usb_handler->DeviceLeft(instance);
+}
+
+void LeftAoaCallback(usbd_connection* connection,
+ usbd_device_instance_t* instance) {
+ if (kAoaVid != instance->ident.vendor) return;
+ LOG4CXX_INFO(logger_, "USB AOA device left (path "
+ << static_cast<int>(instance->path) << ", devno "
+ << static_cast<int>(instance->devno) << ", config "
+ << static_cast<int>(instance->config) << ", iface "
+ << static_cast<int>(instance->iface) << ")");
+ usb_handler->DeviceLeft(instance);
+}
+
+TransportAdapter::Error UsbHandler::Init() {
+ {
+ usbd_device_ident_t interest = {
+ USBD_CONNECT_WILDCARD, USBD_CONNECT_WILDCARD, kAoaInterfaceSubclass,
+ USBD_CONNECT_WILDCARD, USBD_CONNECT_WILDCARD};
+ usbd_funcs_t funcs = {_USBDI_NFUNCS, ArrivedCallback, LeftCallback, NULL};
+ usbd_connect_parm_t cparms = {NULL, USB_VERSION, USBD_VERSION, 0, 0,
+ NULL, 0, &interest, &funcs};
+
+ const int connect_rc = usbd_connect(&cparms, &usbd_general_connection_);
+
+ if (EOK != connect_rc) {
+ LOG4CXX_ERROR(logger_, "usbd_connect failed, error code " << connect_rc);
+ return TransportAdapter::FAIL;
+ }
+ }
+ {
+ usbd_device_ident_t interest = {
+ kAoaVid, USBD_CONNECT_WILDCARD, USBD_CONNECT_WILDCARD,
+ kAoaInterfaceSubclass, USBD_CONNECT_WILDCARD};
+ usbd_funcs_t funcs = {_USBDI_NFUNCS, ArrivedAoaCallback,
+ LeftAoaCallback, NULL};
+ usbd_connect_parm_t cparms = {NULL, USB_VERSION, USBD_VERSION, 0, 0,
+ NULL, 0, &interest, &funcs};
+
+ const int connect_rc = usbd_connect(&cparms, &usbd_aoa_connection_);
+
+ if (EOK != connect_rc) {
+ LOG4CXX_ERROR(logger_, "usbd_connect failed, error code " << connect_rc);
+ return TransportAdapter::FAIL;
+ }
+ }
+
+ return TransportAdapter::OK;
+}
+
+} // namespace
+} // namespace
diff --git a/src/components/transport_manager/src/usb/usb_aoa_adapter.cc b/src/components/transport_manager/src/usb/usb_aoa_adapter.cc
new file mode 100644
index 0000000000..464b9ea35e
--- /dev/null
+++ b/src/components/transport_manager/src/usb/usb_aoa_adapter.cc
@@ -0,0 +1,90 @@
+/**
+ * \file usb_aoa_adapter.cpp
+ * \brief UsbAoaAdapter class source file.
+ *
+ * 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 "transport_manager/usb/usb_aoa_adapter.h"
+#include "transport_manager/usb/usb_device_scanner.h"
+#include "transport_manager/usb/usb_connection_factory.h"
+#include "transport_manager/usb/common.h"
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+UsbAoaAdapter::UsbAoaAdapter()
+ : TransportAdapterImpl(new UsbDeviceScanner(this),
+ new UsbConnectionFactory(this), 0),
+ is_initialised_(false),
+ usb_handler_(new UsbHandler()) {
+ static_cast<UsbDeviceScanner*>(device_scanner_)->SetUsbHandler(usb_handler_);
+ static_cast<UsbConnectionFactory*>(server_connection_factory_)
+ ->SetUsbHandler(usb_handler_);
+}
+
+UsbAoaAdapter::~UsbAoaAdapter() {}
+
+DeviceType UsbAoaAdapter::GetDeviceType() const {
+ return "sdl-usb-aoa";
+}
+
+bool UsbAoaAdapter::IsInitialised() const {
+ return is_initialised_ && TransportAdapterImpl::IsInitialised();
+}
+
+TransportAdapter::Error UsbAoaAdapter::Init() {
+ LOG4CXX_TRACE(logger_, "enter");
+ TransportAdapter::Error error = usb_handler_->Init();
+ if (error != TransportAdapter::OK) {
+ LOG4CXX_TRACE(logger_, "exit with error " << error <<
+ ". Condition: error != TransportAdapter::OK");
+ return error;
+ }
+ error = TransportAdapterImpl::Init();
+ if (error != TransportAdapter::OK) {
+ LOG4CXX_TRACE(logger_, "exit with error " << error <<
+ ". Condition: error != TransportAdapter::OK");
+ return error;
+ }
+ is_initialised_ = true;
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK");
+ return TransportAdapter::OK;
+}
+
+bool UsbAoaAdapter::ToBeAutoConnected(DeviceSptr device) const {
+ return true;
+}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/usb/usb_connection_factory.cc b/src/components/transport_manager/src/usb/usb_connection_factory.cc
new file mode 100644
index 0000000000..f68edebd06
--- /dev/null
+++ b/src/components/transport_manager/src/usb/usb_connection_factory.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, 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 "transport_manager/usb/usb_connection_factory.h"
+#include "transport_manager/usb/usb_device.h"
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+#include "utils/logger.h"
+
+#if defined(__QNXNTO__)
+#include "transport_manager/usb/qnx/usb_connection.h"
+#else
+#include "transport_manager/usb/libusb/usb_connection.h"
+#endif
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+UsbConnectionFactory::UsbConnectionFactory(
+ TransportAdapterController* controller)
+ : controller_(controller), usb_handler_() {}
+
+TransportAdapter::Error UsbConnectionFactory::Init() {
+ return TransportAdapter::OK;
+}
+
+void UsbConnectionFactory::SetUsbHandler(const UsbHandlerSptr& usb_handler) {
+ usb_handler_ = usb_handler;
+}
+
+TransportAdapter::Error UsbConnectionFactory::CreateConnection(
+ const DeviceUID& device_uid, const ApplicationHandle& app_handle) {
+ LOG4CXX_TRACE(logger_, "enter DeviceUID: " << &device_uid << ", ApplicationHandle: " <<
+ &app_handle);
+ DeviceSptr device = controller_->FindDevice(device_uid);
+ if (!device.valid()) {
+ LOG4CXX_ERROR(logger_, "device " << device_uid << " not found");
+ LOG4CXX_TRACE(logger_,
+ "exit with TransportAdapter::BAD_PARAM. Condition: !device.valid()");
+ return TransportAdapter::BAD_PARAM;
+ }
+
+ UsbDevice* usb_device = static_cast<UsbDevice*>(device.get());
+ UsbConnection* usb_connection =
+ new UsbConnection(device_uid, app_handle, controller_, usb_handler_,
+ usb_device->usb_device());
+ ConnectionSptr connection(usb_connection);
+
+ controller_->ConnectionCreated(connection, device_uid, app_handle);
+
+ if (usb_connection->Init()) {
+ LOG4CXX_INFO(logger_, "USB connection initialised");
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::OK. Condition: USB connection initialised");
+ return TransportAdapter::OK;
+ } else {
+ LOG4CXX_TRACE(logger_, "exit with TransportAdapter::FAIL. Condition: USB connection NOT initialised");
+ return TransportAdapter::FAIL;
+ }
+}
+
+void UsbConnectionFactory::Terminate() {}
+
+bool UsbConnectionFactory::IsInitialised() const {
+ return true;
+}
+
+UsbConnectionFactory::~UsbConnectionFactory() {}
+
+} // namespace transport_adapter
+} // namespace transport_manager
diff --git a/src/components/transport_manager/src/usb/usb_device_scanner.cc b/src/components/transport_manager/src/usb/usb_device_scanner.cc
new file mode 100644
index 0000000000..bf9535941c
--- /dev/null
+++ b/src/components/transport_manager/src/usb/usb_device_scanner.cc
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2014, 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 <sstream>
+
+#include "transport_manager/transport_adapter/transport_adapter_impl.h"
+#include "transport_manager/usb/usb_device_scanner.h"
+#include "transport_manager/usb/usb_device.h"
+#include "transport_manager/usb/common.h"
+
+#include "utils/logger.h"
+
+namespace transport_manager {
+namespace transport_adapter {
+
+CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager")
+
+class AoaInitSequence : public UsbControlTransferSequence {
+ public:
+ AoaInitSequence();
+ virtual ~AoaInitSequence() {}
+
+ private:
+ class AoaGetProtocolRequest;
+ class AoaSendIdString;
+ class AoaTurnIntoAccessoryMode;
+};
+
+void UsbDeviceScanner::OnDeviceArrived(PlatformUsbDevice* device) {
+ LOG4CXX_TRACE(logger_, "enter. PlatformUsbDevice* " << device);
+ if (IsAppleDevice(device)) {
+ SupportedDeviceFound(device);
+ } else {
+ if (IsGoogleAccessory(device)) {
+ SupportedDeviceFound(device);
+ } else {
+ TurnIntoAccessoryMode(device);
+ }
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbDeviceScanner::OnDeviceLeft(PlatformUsbDevice* device) {
+ LOG4CXX_TRACE(logger_, "enter. PlatformUsbDevice " << device);
+ bool list_changed = false;
+ pthread_mutex_lock(&devices_mutex_);
+ for (Devices::iterator it = devices_.begin(); it != devices_.end(); ++it) {
+ if (device == *it) {
+ devices_.erase(it);
+ list_changed = true;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+ if (list_changed) {
+ UpdateList();
+ }
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+UsbDeviceScanner::UsbDeviceScanner(TransportAdapterController* controller)
+ : controller_(controller) {
+ pthread_mutex_init(&devices_mutex_, 0);
+}
+
+UsbDeviceScanner::~UsbDeviceScanner() {
+ pthread_mutex_destroy(&devices_mutex_);
+}
+
+class AoaInitSequence::AoaGetProtocolRequest : public UsbControlInTransfer {
+ virtual ~AoaGetProtocolRequest() {}
+ virtual RequestType Type() const {
+ return VENDOR;
+ }
+ virtual uint8_t Request() const {
+ return 51;
+ }
+ virtual uint16_t Value() const {
+ return 0;
+ }
+ virtual uint16_t Index() const {
+ return 0;
+ }
+ virtual uint16_t Length() const {
+ return 2;
+ }
+ virtual bool OnCompleted(unsigned char* data) const {
+ const int protocol_version = data[1] << 8 | data[0];
+ LOG4CXX_INFO(logger_, "AOA protocol version " << protocol_version);
+ if (protocol_version == 0) {
+ // AOA protocol not supported
+ return false;
+ }
+ return true;
+ }
+};
+
+class AoaInitSequence::AoaSendIdString : public UsbControlOutTransfer {
+ public:
+ AoaSendIdString(uint16_t index, const char* string, uint16_t length)
+ : index_(index), string_(string), length_(length) {}
+
+ private:
+ virtual ~AoaSendIdString() {}
+ virtual RequestType Type() const {
+ return VENDOR;
+ }
+ virtual uint8_t Request() const {
+ return 52;
+ }
+ virtual uint16_t Value() const {
+ return 0;
+ }
+ virtual uint16_t Index() const {
+ return index_;
+ }
+ virtual uint16_t Length() const {
+ return length_;
+ }
+ virtual const char* Data() const {
+ return string_;
+ }
+ uint16_t index_;
+ const char* string_;
+ uint16_t length_;
+};
+
+class AoaInitSequence::AoaTurnIntoAccessoryMode : public UsbControlOutTransfer {
+ virtual ~AoaTurnIntoAccessoryMode() {}
+ virtual RequestType Type() const {
+ return VENDOR;
+ }
+ virtual uint8_t Request() const {
+ return 53;
+ }
+ virtual uint16_t Value() const {
+ return 0;
+ }
+ virtual uint16_t Index() const {
+ return 0;
+ }
+ virtual uint16_t Length() const {
+ return 0;
+ }
+ virtual const char* Data() const {
+ return 0;
+ }
+};
+
+static char manufacturer[] = "Ford";
+static char model_name[] = "HMI";
+static char description[] = "Human machine interface";
+static char version[] = "1.0";
+static char uri[] = "http://www.ford.com";
+static char serial_num[] = "N000000";
+
+AoaInitSequence::AoaInitSequence() : UsbControlTransferSequence() {
+ AddTransfer(new AoaGetProtocolRequest);
+ AddTransfer(new AoaSendIdString(0, manufacturer, sizeof(manufacturer)));
+ AddTransfer(new AoaSendIdString(1, model_name, sizeof(model_name)));
+ AddTransfer(new AoaSendIdString(2, description, sizeof(description)));
+ AddTransfer(new AoaSendIdString(3, version, sizeof(version)));
+ AddTransfer(new AoaSendIdString(4, uri, sizeof(uri)));
+ AddTransfer(new AoaSendIdString(5, serial_num, sizeof(serial_num)));
+ AddTransfer(new AoaTurnIntoAccessoryMode);
+}
+
+void UsbDeviceScanner::TurnIntoAccessoryMode(PlatformUsbDevice* device) {
+ LOG4CXX_TRACE(logger_, "enter. PlatformUsbDevice: " << device);
+ GetUsbHandler()->StartControlTransferSequence(new AoaInitSequence, device);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbDeviceScanner::SupportedDeviceFound(PlatformUsbDevice* device) {
+ LOG4CXX_TRACE(logger_, "enter PlatformUsbDevice: " << device);
+
+ pthread_mutex_lock(&devices_mutex_);
+ devices_.push_back(device);
+ pthread_mutex_unlock(&devices_mutex_);
+ LOG4CXX_INFO(logger_, "USB device (bus number "
+ << static_cast<int>(device->bus_number())
+ << ", address "
+ << static_cast<int>(device->address())
+ << ") identified as: " << device->GetManufacturer()
+ << ", " << device->GetProductName());
+ UpdateList();
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+TransportAdapter::Error UsbDeviceScanner::Init() {
+ return TransportAdapter::OK;
+}
+
+TransportAdapter::Error UsbDeviceScanner::Scan() {
+ return TransportAdapter::OK;
+}
+
+void UsbDeviceScanner::UpdateList() {
+ LOG4CXX_TRACE(logger_, "enter");
+ DeviceVector device_vector;
+ pthread_mutex_lock(&devices_mutex_);
+ for (Devices::const_iterator it = devices_.begin(); it != devices_.end();
+ ++it) {
+ const std::string device_name =
+ (*it)->GetManufacturer() + " " + (*it)->GetProductName();
+ std::ostringstream oss;
+ oss << (*it)->GetManufacturer() << ":" << (*it)->GetProductName() << ":"
+ << (*it)->GetSerialNumber() << ":"
+ << static_cast<int>((*it)->bus_number()) << ":"
+ << static_cast<int>((*it)->address());
+ const DeviceUID device_uid = oss.str();
+ DeviceSptr device(new UsbDevice(*it, device_name, device_uid));
+ device_vector.push_back(device);
+ }
+ pthread_mutex_unlock(&devices_mutex_);
+
+ LOG4CXX_INFO(logger_, "USB search done " << device_vector.size());
+ controller_->SearchDeviceDone(device_vector);
+ LOG4CXX_TRACE(logger_, "exit");
+}
+
+void UsbDeviceScanner::Terminate() {}
+
+bool UsbDeviceScanner::IsInitialised() const {
+ return true;
+}
+
+} // namespace
+} // namespace