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             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 ~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:
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     }
135 };
136 
137 class LocIpcRecver {
138     LocIpcSender& mIpcSender;
139 protected:
140     const shared_ptr<ILocIpcListener> mDataCb;
LocIpcRecver(const shared_ptr<ILocIpcListener> & listener,LocIpcSender & sender)141     inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) :
142             mIpcSender(sender), mDataCb(listener) {}
143     LocIpcRecver(LocIpcRecver const& recver) = delete;
144     LocIpcRecver& operator=(LocIpcRecver const& recver) = delete;
145     virtual ssize_t recv() const = 0;
146 public:
147     virtual ~LocIpcRecver() = default;
recvData()148     inline bool recvData() const { return isRecvable() && (recv() > 0); }
isRecvable()149     inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); }
onListenerReady()150     virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); }
151     virtual void abort() const = 0;
152     virtual const char* getName() const = 0;
153 };
154 
155 class Sock {
156     static const char MSG_ABORT[];
157     static const char LOC_IPC_HEAD[];
158     const uint32_t mMaxTxSize;
159     ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
160                    socklen_t addrlen) const;
161     ssize_t recvfrom(const shared_ptr<ILocIpcListener>& dataCb, int sid, int flags,
162                      struct sockaddr *srcAddr, socklen_t *addrlen) const;
163 public:
164     int mSid;
mMaxTxSize(maxTxSize)165     inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {}
~Sock()166     inline ~Sock() { close(); }
isValid()167     inline bool isValid() const { return -1 != mSid; }
168     ssize_t send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr,
169                  socklen_t addrlen) const;
170     ssize_t recv(const shared_ptr<ILocIpcListener>& dataCb, int flags, struct sockaddr *srcAddr,
171                  socklen_t *addrlen, int sid = -1) const;
172     ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen);
close()173     inline void close() {
174         if (isValid()) {
175             ::close(mSid);
176             mSid = -1;
177         }
178     }
179 };
180 
181 }
182 
183 #endif //__LOC_IPC__
184