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 length)= 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             getLocIpcInetTcpSender(const char* serverName, int32_t port);
71     static shared_ptr<LocIpcSender>
72             getLocIpcQrtrSender(int service, int instance);
73     static shared_ptr<LocIpcSender>
74             getLocIpcQsockSender(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             getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener,
81                                    const char* serverName, int32_t port);
82     static unique_ptr<LocIpcRecver>
83             getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
84                                 int service, int instance);
85     static unique_ptr<LocIpcRecver>
86             getLocIpcQsockRecver(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 ~LocIpcSender() = default;
127     virtual bool isOperable() const = 0;
128     virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t msgId) const = 0;
129 public:
isSendable()130     inline bool isSendable() const { return isOperable(); }
sendData(const uint8_t data[],uint32_t length,int32_t msgId)131     inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const {
132         return isSendable() && (send(data, length, msgId) > 0);
133     }
134 };
135 
136 class LocIpcRecver {
137     LocIpcSender& mIpcSender;
138 protected:
139     const shared_ptr<ILocIpcListener> mDataCb;
LocIpcRecver(const shared_ptr<ILocIpcListener> & listener,LocIpcSender & sender)140     inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) :
141             mIpcSender(sender), mDataCb(listener) {}
142     LocIpcRecver(LocIpcRecver const& recver) = delete;
143     LocIpcRecver& operator=(LocIpcRecver const& recver) = delete;
144     virtual ssize_t recv() const = 0;
145 public:
146     virtual ~LocIpcRecver() = default;
recvData()147     inline bool recvData() const { return isRecvable() && (recv() > 0); }
isRecvable()148     inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); }
onListenerReady()149     virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); }
150     virtual void abort() const = 0;
151     virtual const char* getName() const = 0;
152 };
153 
154 class Sock {
155     static const char MSG_ABORT[];
156     static const char LOC_IPC_HEAD[];
157     const uint32_t mMaxTxSize;
158     ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
159                    socklen_t addrlen) const;
160     ssize_t recvfrom(const shared_ptr<ILocIpcListener>& dataCb, int sid, int flags,
161                      struct sockaddr *srcAddr, socklen_t *addrlen) const;
162 public:
163     int mSid;
mMaxTxSize(maxTxSize)164     inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {}
~Sock()165     inline ~Sock() { close(); }
isValid()166     inline bool isValid() const { return -1 != mSid; }
167     ssize_t send(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
168                  socklen_t addrlen) const;
169     ssize_t recv(const shared_ptr<ILocIpcListener>& dataCb, int flags, struct sockaddr *srcAddr,
170                  socklen_t *addrlen, int sid = -1) const;
171     ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen);
close()172     inline void close() {
173         if (isValid()) {
174             ::close(mSid);
175             mSid = -1;
176         }
177     }
178 };
179 
180 }
181 
182 #endif //__LOC_IPC__
183