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_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 <LocThread.h>
39 
40 using namespace std;
41 
42 namespace loc_util {
43 
44 
45 class LocIpcRecver;
46 class LocIpcSender;
47 class LocIpcRunnable;
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 
60 class LocIpc {
61 public:
LocIpc()62     inline LocIpc() : mRunnable(nullptr) {}
~LocIpc()63     inline virtual ~LocIpc() {
64         stopNonBlockingListening();
65     }
66 
67     static shared_ptr<LocIpcSender>
68             getLocIpcLocalSender(const char* localSockName);
69     static shared_ptr<LocIpcSender>
70             getLocIpcInetUdpSender(const char* serverName, int32_t port);
71     static shared_ptr<LocIpcSender>
72             getLocIpcInetTcpSender(const char* serverName, int32_t port);
73     static shared_ptr<LocIpcSender>
74             getLocIpcQrtrSender(int service, int instance);
75 
76     static unique_ptr<LocIpcRecver>
77             getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener,
78                                  const char* localSockName);
79     static unique_ptr<LocIpcRecver>
80             getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener,
81                                  const char* serverName, int32_t port);
82     static unique_ptr<LocIpcRecver>
83             getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener,
84                                    const char* serverName, int32_t port);
85     static unique_ptr<LocIpcRecver>
86             getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
87                                 int service, int instance);
88 
89     static pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>
90             getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener,
91                                                    int instance);
92 
93     // Listen for new messages in current thread. Calling this funciton will
94     // block current thread.
95     // The listening can be stopped by calling stopBlockingListening() passing
96     // in the same ipcRecver obj handle.
97     static bool startBlockingListening(LocIpcRecver& ipcRecver);
98     static void stopBlockingListening(LocIpcRecver& ipcRecver);
99 
100     // Create a new LocThread and listen for new messages in it.
101     // Calling this function will return immediately and won't block current thread.
102     // The listening can be stopped by calling stopNonBlockingListening().
103     bool startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver);
104     void stopNonBlockingListening();
105 
106     // Send out a message.
107     // Call this function to send a message in argument data to socket in argument name.
108     //
109     // Argument name contains the name of the target unix socket. data contains the
110     // message to be sent out. Convert your message to a string before calling this function.
111     // The function will return true on success, and false on failure.
112     static bool send(LocIpcSender& sender, const uint8_t data[],
113                      uint32_t length, int32_t msgId = -1);
114 
115 private:
116     LocThread mThread;
117     LocIpcRunnable *mRunnable;
118 };
119 
120 /* this is only when client needs to implement Sender / Recver that are not already provided by
121    the factor methods prvoided by LocIpc. */
122 
123 class LocIpcSender {
124 protected:
125     LocIpcSender() = default;
126     virtual bool isOperable() const = 0;
127     virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t msgId) const = 0;
128 public:
129     virtual ~LocIpcSender() = default;
informRecverRestarted()130     virtual void informRecverRestarted() {}
isSendable()131     inline bool isSendable() const { return isOperable(); }
sendData(const uint8_t data[],uint32_t length,int32_t msgId)132     inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const {
133         return isSendable() && (send(data, length, msgId) > 0);
134     }
getRecver(const shared_ptr<ILocIpcListener> & listener)135     virtual unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) {
136         return nullptr;
137     }
138 };
139 
140 class LocIpcRecver {
141     LocIpcSender& mIpcSender;
142 protected:
143     const shared_ptr<ILocIpcListener> mDataCb;
LocIpcRecver(const shared_ptr<ILocIpcListener> & listener,LocIpcSender & sender)144     inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) :
145             mIpcSender(sender), mDataCb(listener) {}
146     LocIpcRecver(LocIpcRecver const& recver) = delete;
147     LocIpcRecver& operator=(LocIpcRecver const& recver) = delete;
148     virtual ssize_t recv() const = 0;
149 public:
150     virtual ~LocIpcRecver() = default;
recvData()151     inline bool recvData() const { return isRecvable() && (recv() > 0); }
isRecvable()152     inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); }
onListenerReady()153     virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); }
getLastSender()154     inline virtual unique_ptr<LocIpcSender> getLastSender() const {
155         return nullptr;
156     }
157     virtual void abort() const = 0;
158     virtual const char* getName() const = 0;
159 };
160 
161 class Sock {
162     static const char MSG_ABORT[];
163     static const char LOC_IPC_HEAD[];
164     const uint32_t mMaxTxSize;
165     ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
166                    socklen_t addrlen) const;
167     ssize_t recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb,
168                      int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const;
169 public:
170     int mSid;
mMaxTxSize(maxTxSize)171     inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {}
~Sock()172     inline ~Sock() { close(); }
isValid()173     inline bool isValid() const { return -1 != mSid; }
174     ssize_t send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr,
175                  socklen_t addrlen) const;
176     ssize_t recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags,
177                  struct sockaddr *srcAddr, socklen_t *addrlen, int sid = -1) const;
178     ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen);
close()179     inline void close() {
180         if (isValid()) {
181             ::close(mSid);
182             mSid = -1;
183         }
184     }
185 };
186 
187 class SockRecver : public LocIpcRecver {
188     shared_ptr<Sock> mSock;
189 protected:
recv()190     inline virtual ssize_t recv() const override {
191         return mSock->recv(*this, mDataCb, 0, nullptr, nullptr);
192     }
193 public:
SockRecver(const shared_ptr<ILocIpcListener> & listener,LocIpcSender & sender,shared_ptr<Sock> sock)194     inline SockRecver(const shared_ptr<ILocIpcListener>& listener,
195                   LocIpcSender& sender, shared_ptr<Sock> sock) :
196             LocIpcRecver(listener, sender), mSock(sock) {
197     }
getName()198     inline virtual const char* getName() const override {
199         return "SockRecver";
200     }
abort()201     inline virtual void abort() const override {}
202 };
203 
204 }
205 
206 #endif //__LOC_IPC__
207