/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "SocketComm" #include #include #include #include #include #include #include "SocketComm.h" // Socket to use when communicating with Host PC static constexpr int DEBUG_SOCKET = 33452; namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace V2_0 { namespace impl { SocketComm::SocketComm(MessageProcessor* messageProcessor) : mListenFd(-1), mMessageProcessor(messageProcessor) {} SocketComm::~SocketComm() { } void SocketComm::start() { if (!listen()) { return; } mListenThread = std::make_unique(std::bind(&SocketComm::listenThread, this)); } void SocketComm::stop() { if (mListenFd > 0) { ::close(mListenFd); if (mListenThread->joinable()) { mListenThread->join(); } mListenFd = -1; } } void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) { std::lock_guard lock(mMutex); for (std::unique_ptr const& conn : mOpenConnections) { conn->sendMessage(msg); } } bool SocketComm::listen() { int retVal; struct sockaddr_in servAddr; mListenFd = socket(AF_INET, SOCK_STREAM, 0); if (mListenFd < 0) { ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mListenFd, errno); mListenFd = -1; return false; } memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = INADDR_ANY; servAddr.sin_port = htons(DEBUG_SOCKET); retVal = bind(mListenFd, reinterpret_cast(&servAddr), sizeof(servAddr)); if(retVal < 0) { ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno); close(mListenFd); mListenFd = -1; return false; } ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET); ::listen(mListenFd, 1); return true; } SocketConn* SocketComm::accept() { sockaddr_in cliAddr; socklen_t cliLen = sizeof(cliAddr); int sfd = ::accept(mListenFd, reinterpret_cast(&cliAddr), &cliLen); if (sfd > 0) { char addr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &cliAddr.sin_addr, addr, INET_ADDRSTRLEN); ALOGD("%s: Incoming connection received from %s:%d", __FUNCTION__, addr, cliAddr.sin_port); return new SocketConn(mMessageProcessor, sfd); } return nullptr; } void SocketComm::listenThread() { while (true) { SocketConn* conn = accept(); if (conn == nullptr) { return; } conn->start(); { std::lock_guard lock(mMutex); mOpenConnections.push_back(std::unique_ptr(conn)); } } } /** * Called occasionally to clean up connections that have been closed. */ void SocketComm::removeClosedConnections() { std::lock_guard lock(mMutex); std::remove_if(mOpenConnections.begin(), mOpenConnections.end(), [](std::unique_ptr const& c) { return !c->isOpen(); }); } SocketConn::SocketConn(MessageProcessor* messageProcessor, int sfd) : CommConn(messageProcessor), mSockFd(sfd) {} /** * Reads, in a loop, exactly numBytes from the given fd. If the connection is closed, returns * an empty buffer, otherwise will return exactly the given number of bytes. */ std::vector readExactly(int fd, int numBytes) { std::vector buffer(numBytes); int totalRead = 0; int offset = 0; while (totalRead < numBytes) { int numRead = ::read(fd, &buffer.data()[offset], numBytes - offset); if (numRead == 0) { buffer.resize(0); return buffer; } totalRead += numRead; } return buffer; } /** * Reads an int, guaranteed to be non-zero, from the given fd. If the connection is closed, returns * -1. */ int32_t readInt(int fd) { std::vector buffer = readExactly(fd, sizeof(int32_t)); if (buffer.size() == 0) { return -1; } int32_t value = *reinterpret_cast(buffer.data()); return ntohl(value); } std::vector SocketConn::read() { int32_t msgSize = readInt(mSockFd); if (msgSize <= 0) { ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mSockFd); return std::vector(); } return readExactly(mSockFd, msgSize); } void SocketConn::stop() { if (mSockFd > 0) { close(mSockFd); mSockFd = -1; } } int SocketConn::write(const std::vector& data) { static constexpr int MSG_HEADER_LEN = 4; int retVal = 0; union { uint32_t msgLen; uint8_t msgLenBytes[MSG_HEADER_LEN]; }; // Prepare header for the message msgLen = static_cast(data.size()); msgLen = htonl(msgLen); if (mSockFd > 0) { retVal = ::write(mSockFd, msgLenBytes, MSG_HEADER_LEN); if (retVal == MSG_HEADER_LEN) { retVal = ::write(mSockFd, data.data(), data.size()); } } return retVal; } } // impl } // namespace V2_0 } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android