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:
~ILocIpcListener()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.
onListenerReady()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;
isInWatch(const unordered_set<int> & idsToWatch,int id)63     inline bool isInWatch(const unordered_set<int>& idsToWatch, int id) {
64         return idsToWatch.find(id) != idsToWatch.end();
65     }
66 protected:
~LocIpcQrtrWatcher()67     inline virtual ~LocIpcQrtrWatcher() {}
LocIpcQrtrWatcher(unordered_set<int> servicesToWatch)68     inline LocIpcQrtrWatcher(unordered_set<int> servicesToWatch)
69             : mServicesToWatch(servicesToWatch) {}
70 public:
71     enum class ServiceStatus { UP, DOWN };
isServiceInWatch(int serviceId)72     inline bool isServiceInWatch(int serviceId) {
73         return isInWatch(mServicesToWatch, serviceId);
74     }
isClientInWatch(int nodeId)75     inline bool isClientInWatch(int nodeId) {
76         lock_guard<mutex> lock(mMutex);
77         return isInWatch(mClientsToWatch, nodeId);
78     }
addClientToWatch(int nodeId)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;
onClientGone(int nodeId,int portId)85     inline virtual void onClientGone(int nodeId, int portId) {}
getServicesToWatch()86     inline const unordered_set<int>& getServicesToWatch() { return mServicesToWatch; }
87 };
88 
89 class LocIpc {
90 public:
91     inline LocIpc() = default;
~LocIpc()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>
getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener> & listener,int service,int instance)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;
isSendable()165     inline bool isSendable() const { return isOperable(); }
sendData(const uint8_t data[],uint32_t length,int32_t msgId)166     inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const {
167         return isSendable() && (send(data, length, msgId) > 0);
168     }
getRecver(const shared_ptr<ILocIpcListener> & listener)169     virtual unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) {
170         return nullptr;
171     }
copyDestAddrFrom(const LocIpcSender & otherSender)172     inline virtual void copyDestAddrFrom(const LocIpcSender& otherSender) {}
173 };
174 
175 class LocIpcRecver {
176     LocIpcSender& mIpcSender;
177 protected:
178     const shared_ptr<ILocIpcListener> mDataCb;
LocIpcRecver(const shared_ptr<ILocIpcListener> & listener,LocIpcSender & sender)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;
recvData()186     inline bool recvData() const { return isRecvable() && (recv() > 0); }
isRecvable()187     inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); }
onListenerReady()188     virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); }
getLastSender()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;
mMaxTxSize(maxTxSize)206     inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {}
~Sock()207     inline ~Sock() { close(); }
isValid()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);
close()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:
recv()225     inline virtual ssize_t recv() const override {
226         return mSock->recv(*this, mDataCb, 0, nullptr, nullptr);
227     }
228 public:
SockRecver(const shared_ptr<ILocIpcListener> & listener,LocIpcSender & sender,shared_ptr<Sock> sock)229     inline SockRecver(const shared_ptr<ILocIpcListener>& listener,
230                   LocIpcSender& sender, shared_ptr<Sock> sock) :
231             LocIpcRecver(listener, sender), mSock(sock) {
232     }
getName()233     inline virtual const char* getName() const override {
234         return "SockRecver";
235     }
abort()236     inline virtual void abort() const override {}
237 };
238 
239 }
240 
241 #endif //__LOC_IPC__
242