Michael Bestas | 3a0209e | 2023-05-04 01:15:47 +0300 | [diff] [blame] | 1 | /* Copyright (c) 2017-2018, 2020 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_IPC__ |
| 31 | #define __LOC_IPC__ |
| 32 | |
| 33 | #include <string> |
| 34 | #include <memory> |
| 35 | #include <unistd.h> |
| 36 | #include <sys/socket.h> |
| 37 | #include <sys/un.h> |
| 38 | #include <unordered_set> |
| 39 | #include <mutex> |
| 40 | #include <LocThread.h> |
| 41 | |
| 42 | using namespace std; |
| 43 | |
| 44 | namespace loc_util { |
| 45 | |
| 46 | class LocIpcRecver; |
| 47 | class LocIpcSender; |
| 48 | |
| 49 | class ILocIpcListener { |
| 50 | protected: |
| 51 | inline virtual ~ILocIpcListener() {} |
| 52 | public: |
| 53 | // LocIpc client can overwrite this function to get notification |
| 54 | // when the socket for LocIpc is ready to receive messages. |
| 55 | inline virtual void onListenerReady() {} |
| 56 | virtual void onReceive(const char* data, uint32_t len, const LocIpcRecver* recver) = 0; |
| 57 | }; |
| 58 | |
| 59 | class LocIpcQrtrWatcher { |
| 60 | const unordered_set<int> mServicesToWatch; |
| 61 | unordered_set<int> mClientsToWatch; |
| 62 | mutex mMutex; |
| 63 | inline bool isInWatch(const unordered_set<int>& idsToWatch, int id) { |
| 64 | return idsToWatch.find(id) != idsToWatch.end(); |
| 65 | } |
| 66 | protected: |
| 67 | inline virtual ~LocIpcQrtrWatcher() {} |
| 68 | inline LocIpcQrtrWatcher(unordered_set<int> servicesToWatch) |
| 69 | : mServicesToWatch(servicesToWatch) {} |
| 70 | public: |
| 71 | enum class ServiceStatus { UP, DOWN }; |
| 72 | inline bool isServiceInWatch(int serviceId) { |
| 73 | return isInWatch(mServicesToWatch, serviceId); |
| 74 | } |
| 75 | inline bool isClientInWatch(int nodeId) { |
| 76 | lock_guard<mutex> lock(mMutex); |
| 77 | return isInWatch(mClientsToWatch, nodeId); |
| 78 | } |
| 79 | inline void addClientToWatch(int nodeId) { |
| 80 | lock_guard<mutex> lock(mMutex); |
| 81 | mClientsToWatch.emplace(nodeId); |
| 82 | } |
| 83 | virtual void onServiceStatusChange(int sericeId, int instanceId, ServiceStatus status, |
| 84 | const LocIpcSender& sender) = 0; |
Michael Bestas | db7342c | 2021-01-06 19:23:51 +0200 | [diff] [blame] | 85 | inline virtual void onClientGone(int nodeId __unused, int portId __unused) {} |
Michael Bestas | 3a0209e | 2023-05-04 01:15:47 +0300 | [diff] [blame] | 86 | inline const unordered_set<int>& getServicesToWatch() { return mServicesToWatch; } |
| 87 | }; |
| 88 | |
| 89 | class LocIpc { |
| 90 | public: |
| 91 | inline LocIpc() = default; |
| 92 | inline virtual ~LocIpc() { |
| 93 | stopNonBlockingListening(); |
| 94 | } |
| 95 | |
| 96 | static shared_ptr<LocIpcSender> |
| 97 | getLocIpcLocalSender(const char* localSockName); |
| 98 | static shared_ptr<LocIpcSender> |
| 99 | getLocIpcInetUdpSender(const char* serverName, int32_t port); |
| 100 | static shared_ptr<LocIpcSender> |
| 101 | getLocIpcInetTcpSender(const char* serverName, int32_t port); |
| 102 | static shared_ptr<LocIpcSender> |
| 103 | getLocIpcQrtrSender(int service, int instance); |
| 104 | |
| 105 | static unique_ptr<LocIpcRecver> |
| 106 | getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener, |
| 107 | const char* localSockName); |
| 108 | static unique_ptr<LocIpcRecver> |
| 109 | getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener, |
| 110 | const char* serverName, int32_t port); |
| 111 | static unique_ptr<LocIpcRecver> |
| 112 | getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener, |
| 113 | const char* serverName, int32_t port); |
| 114 | inline static unique_ptr<LocIpcRecver> |
| 115 | getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener, |
| 116 | int service, int instance) { |
| 117 | const shared_ptr<LocIpcQrtrWatcher> qrtrWatcher = nullptr; |
| 118 | return getLocIpcQrtrRecver(listener, service, instance, qrtrWatcher); |
| 119 | } |
| 120 | static unique_ptr<LocIpcRecver> |
| 121 | getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener, |
| 122 | int service, int instance, |
| 123 | const shared_ptr<LocIpcQrtrWatcher>& qrtrWatcher); |
| 124 | |
| 125 | static pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>> |
| 126 | getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener, |
| 127 | int instance); |
| 128 | |
| 129 | // Listen for new messages in current thread. Calling this funciton will |
| 130 | // block current thread. |
| 131 | // The listening can be stopped by calling stopBlockingListening() passing |
| 132 | // in the same ipcRecver obj handle. |
| 133 | static bool startBlockingListening(LocIpcRecver& ipcRecver); |
| 134 | static void stopBlockingListening(LocIpcRecver& ipcRecver); |
| 135 | |
| 136 | // Create a new LocThread and listen for new messages in it. |
| 137 | // Calling this function will return immediately and won't block current thread. |
| 138 | // The listening can be stopped by calling stopNonBlockingListening(). |
| 139 | bool startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver); |
| 140 | void stopNonBlockingListening(); |
| 141 | |
| 142 | // Send out a message. |
| 143 | // Call this function to send a message in argument data to socket in argument name. |
| 144 | // |
| 145 | // Argument name contains the name of the target unix socket. data contains the |
| 146 | // message to be sent out. Convert your message to a string before calling this function. |
| 147 | // The function will return true on success, and false on failure. |
| 148 | static bool send(LocIpcSender& sender, const uint8_t data[], |
| 149 | uint32_t length, int32_t msgId = -1); |
| 150 | |
| 151 | private: |
| 152 | LocThread mThread; |
| 153 | }; |
| 154 | |
| 155 | /* this is only when client needs to implement Sender / Recver that are not already provided by |
| 156 | the factor methods prvoided by LocIpc. */ |
| 157 | |
| 158 | class LocIpcSender { |
| 159 | protected: |
| 160 | LocIpcSender() = default; |
| 161 | virtual bool isOperable() const = 0; |
| 162 | virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t msgId) const = 0; |
| 163 | public: |
| 164 | virtual ~LocIpcSender() = default; |
| 165 | inline bool isSendable() const { return isOperable(); } |
| 166 | inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const { |
| 167 | return isSendable() && (send(data, length, msgId) > 0); |
| 168 | } |
Michael Bestas | db7342c | 2021-01-06 19:23:51 +0200 | [diff] [blame] | 169 | virtual unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener __unused) { |
Michael Bestas | 3a0209e | 2023-05-04 01:15:47 +0300 | [diff] [blame] | 170 | return nullptr; |
| 171 | } |
Michael Bestas | db7342c | 2021-01-06 19:23:51 +0200 | [diff] [blame] | 172 | inline virtual void copyDestAddrFrom(const LocIpcSender& otherSender __unused) {} |
Michael Bestas | 3a0209e | 2023-05-04 01:15:47 +0300 | [diff] [blame] | 173 | }; |
| 174 | |
| 175 | class LocIpcRecver { |
| 176 | LocIpcSender& mIpcSender; |
| 177 | protected: |
| 178 | const shared_ptr<ILocIpcListener> mDataCb; |
| 179 | inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) : |
| 180 | mIpcSender(sender), mDataCb(listener) {} |
| 181 | LocIpcRecver(LocIpcRecver const& recver) = delete; |
| 182 | LocIpcRecver& operator=(LocIpcRecver const& recver) = delete; |
| 183 | virtual ssize_t recv() const = 0; |
| 184 | public: |
| 185 | virtual ~LocIpcRecver() = default; |
| 186 | inline bool recvData() const { return isRecvable() && (recv() > 0); } |
| 187 | inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); } |
| 188 | virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); } |
| 189 | inline virtual unique_ptr<LocIpcSender> getLastSender() const { |
| 190 | return nullptr; |
| 191 | } |
| 192 | virtual void abort() const = 0; |
| 193 | virtual const char* getName() const = 0; |
| 194 | }; |
| 195 | |
| 196 | class Sock { |
| 197 | static const char MSG_ABORT[]; |
| 198 | static const char LOC_IPC_HEAD[]; |
| 199 | const uint32_t mMaxTxSize; |
| 200 | ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr, |
| 201 | socklen_t addrlen) const; |
| 202 | ssize_t recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, |
| 203 | int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const; |
| 204 | public: |
| 205 | int mSid; |
| 206 | inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {} |
| 207 | inline ~Sock() { close(); } |
| 208 | inline bool isValid() const { return -1 != mSid; } |
| 209 | ssize_t send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr, |
| 210 | socklen_t addrlen) const; |
| 211 | ssize_t recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags, |
| 212 | struct sockaddr *srcAddr, socklen_t *addrlen, int sid = -1) const; |
| 213 | ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen); |
| 214 | inline void close() { |
| 215 | if (isValid()) { |
| 216 | ::close(mSid); |
| 217 | mSid = -1; |
| 218 | } |
| 219 | } |
| 220 | }; |
| 221 | |
| 222 | class SockRecver : public LocIpcRecver { |
| 223 | shared_ptr<Sock> mSock; |
| 224 | protected: |
| 225 | inline virtual ssize_t recv() const override { |
| 226 | return mSock->recv(*this, mDataCb, 0, nullptr, nullptr); |
| 227 | } |
| 228 | public: |
| 229 | inline SockRecver(const shared_ptr<ILocIpcListener>& listener, |
| 230 | LocIpcSender& sender, shared_ptr<Sock> sock) : |
| 231 | LocIpcRecver(listener, sender), mSock(sock) { |
| 232 | } |
| 233 | inline virtual const char* getName() const override { |
| 234 | return "SockRecver"; |
| 235 | } |
| 236 | inline virtual void abort() const override {} |
| 237 | }; |
| 238 | |
| 239 | } |
| 240 | |
| 241 | #endif //__LOC_IPC__ |