1 /* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation, nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #ifndef __LOC_SOCKET__ 31 #define __LOC_SOCKET__ 32 33 #include <string> 34 #include <memory> 35 #include <unistd.h> 36 #include <sys/socket.h> 37 #include <sys/un.h> 38 #include <LocThread.h> 39 40 namespace loc_util { 41 42 class LocIpcSender; 43 44 class LocIpc { 45 friend LocIpcSender; 46 public: LocIpc()47 inline LocIpc() : mIpcFd(-1), mStopRequested(false), mRunnable(nullptr) {} ~LocIpc()48 inline virtual ~LocIpc() { stopListening(); } 49 50 // Listen for new messages in current thread. Calling this funciton will 51 // block current thread. The listening can be stopped by calling stopListening(). 52 // 53 // Argument name is the path of the unix local socket to be listened. 54 // The function will return true on success, and false on failure. 55 bool startListeningBlocking(const std::string& name); 56 57 // Create a new LocThread and listen for new messages in it. 58 // Calling this function will return immediately and won't block current thread. 59 // The listening can be stopped by calling stopListening(). 60 // 61 // Argument name is the path of the unix local socket to be be listened. 62 // The function will return true on success, and false on failure. 63 bool startListeningNonBlocking(const std::string& name); 64 65 // Stop listening to new messages. 66 void stopListening(); 67 68 // Send out a message. 69 // Call this function to send a message in argument data to socket in argument name. 70 // 71 // Argument name contains the name of the target unix socket. data contains the 72 // message to be sent out. Convert your message to a string before calling this function. 73 // The function will return true on success, and false on failure. 74 static bool send(const char name[], const std::string& data); 75 static bool send(const char name[], const uint8_t data[], uint32_t length); 76 77 protected: 78 // Callback function for receiving incoming messages. 79 // Override this function in your derived class to process incoming messages. 80 // For each received message, this callback function will be called once. 81 // This callback function will be called in the calling thread of startListeningBlocking 82 // or in the new LocThread created by startListeningNonBlocking. 83 // 84 // Argument data contains the received message. You need to parse it. onReceive(const std::string &)85 inline virtual void onReceive(const std::string& /*data*/) {} 86 87 // LocIpc client can overwrite this function to get notification 88 // when the socket for LocIpc is ready to receive messages. onListenerReady()89 inline virtual void onListenerReady() {} 90 91 private: 92 static bool sendData(int fd, const sockaddr_un& addr, 93 const uint8_t data[], uint32_t length); 94 95 int mIpcFd; 96 bool mStopRequested; 97 LocThread mThread; 98 LocRunnable *mRunnable; 99 }; 100 101 class LocIpcSender { 102 public: 103 // Constructor of LocIpcSender class 104 // 105 // Argument destSocket contains the full path name of destination socket. 106 // This class hides generated fd and destination address object from user. LocIpcSender(const char * destSocket)107 inline LocIpcSender(const char* destSocket): 108 LocIpcSender(std::make_shared<int>(::socket(AF_UNIX, SOCK_DGRAM, 0)), destSocket) { 109 if (-1 == *mSocket) { 110 mSocket = nullptr; 111 } 112 } 113 114 // Replicate a new LocIpcSender object with new destination socket. replicate(const char * destSocket)115 inline LocIpcSender* replicate(const char* destSocket) { 116 return (nullptr == mSocket) ? nullptr : new LocIpcSender(mSocket, destSocket); 117 } 118 ~LocIpcSender()119 inline ~LocIpcSender() { 120 if (nullptr != mSocket && mSocket.unique()) { 121 ::close(*mSocket); 122 } 123 } 124 125 // Send out a message. 126 // Call this function to send a message 127 // 128 // Argument data and length contains the message to be sent out. 129 // Return true when succeeded send(const uint8_t data[],uint32_t length)130 inline bool send(const uint8_t data[], uint32_t length) { 131 bool rtv = false; 132 if (nullptr != mSocket && nullptr != data) { 133 rtv = LocIpc::sendData(*mSocket, mDestAddr, data, length); 134 } 135 return rtv; 136 } 137 138 private: 139 std::shared_ptr<int> mSocket; 140 struct sockaddr_un mDestAddr; 141 LocIpcSender(const std::shared_ptr<int> & mySocket,const char * destSocket)142 inline LocIpcSender(const std::shared_ptr<int>& mySocket, const char* destSocket) : 143 mSocket(mySocket), 144 mDestAddr({.sun_family = AF_UNIX, {}}) { 145 if ((nullptr != mSocket) && (-1 != *mSocket) && (nullptr != destSocket)) { 146 snprintf(mDestAddr.sun_path, sizeof(mDestAddr.sun_path), "%s", destSocket); 147 } 148 } 149 }; 150 151 } 152 153 #endif //__LOC_SOCKET__ 154