1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CHRE_HOST_SOCKET_SERVER_H_
18 #define CHRE_HOST_SOCKET_SERVER_H_
19 
20 #include <poll.h>
21 
22 #include <atomic>
23 #include <functional>
24 #include <map>
25 #include <mutex>
26 #include <vector>
27 
28 #include <android-base/macros.h>
29 #include <cutils/sockets.h>
30 
31 namespace android::chre {
32 
33 class SocketServer {
34  public:
35   SocketServer();
36 
37   /**
38    * Defines the function signature of the callback given to run() which
39    * receives message data sent in by a client.
40    *
41    * @param clientId A unique identifier for the client that sent this request
42    *        (assigned locally)
43    * @param data Pointer to buffer containing the raw message data
44    * @param len Number of bytes of data received
45    */
46   typedef std::function<void(uint16_t clientId, void *data, size_t len)>
47       ClientMessageCallback;
48 
49   /**
50    * Opens the socket, and runs the receive loop until an error is encountered,
51    * or SIGINT/SIGTERM is received. Masks off all other signals.
52    *
53    * @param socketName Android socket name to use when listening
54    * @param allowSocketCreation If true, allow creation of the socket rather
55    *        than strictly inheriting it from init (used primarily for
56    *        development purposes)
57    * @param clientMessageCallback Callback to be invoked when a message is
58    *        received from a client
59    */
60   void run(const char *socketName, bool allowSocketCreation,
61            ClientMessageCallback clientMessageCallback);
62 
63   /**
64    * Delivers data to all connected clients. This method is thread-safe.
65    *
66    * @param data Pointer to buffer containing message data
67    * @param length Number of bytes of data to send
68    */
69   void sendToAllClients(const void *data, size_t length);
70 
71   /**
72    * Sends a message to one client, specified via its unique client ID. This
73    * method is thread-safe.
74    *
75    * @param data
76    * @param length
77    * @param clientId
78    *
79    * @return true if the message was successfully sent to the specified client
80    */
81   bool sendToClientById(const void *data, size_t length, uint16_t clientId);
82 
shutdownServer()83   static void shutdownServer() {
84     sSignalReceived = true;
85   }
86 
87  private:
88   DISALLOW_COPY_AND_ASSIGN(SocketServer);
89 
90   static constexpr size_t kMaxActiveClients = 8;
91   static constexpr int kMaxPendingConnectionRequests =
92       static_cast<int>(kMaxActiveClients);
93   static constexpr size_t kMaxPacketSize = 1024 * 1024;
94 
95   // This is the same value as defined in
96   // host/hal_generic/common/hal_client_id.h. It is redefined here to avoid
97   // adding dependency path at multiple places for such a temporary change,
98   // which will be removed after migrating generic HAL to multiclient HAL.
99   static constexpr uint16_t kMaxHalClientId = 0x1ff;
100 
101   int mSockFd = INVALID_SOCKET;
102   // Socket client id and Hal client id are using the same field in the fbs
103   // message. To keep their id range disjoint enables message routing for both
104   // at the same time. There are 0xffff - 0x01ff = 0xfe00 (65024) socket
105   // client ids to use, which should be more than enough.
106   uint16_t mNextClientId = kMaxHalClientId + 1;
107   // TODO: std::vector-ify this
108   struct pollfd mPollFds[1 + kMaxActiveClients] = {};
109 
110   struct ClientData {
111     uint16_t clientId;
112   };
113 
114   // Maps from socket FD to ClientData
115   std::map<int, ClientData> mClients;
116 
117   // A buffer to read packets into. Allocated here to prevent a large object on
118   // the stack.
119   std::vector<uint8_t> mRecvBuffer = std::vector<uint8_t>(kMaxPacketSize);
120 
121   // Ensures that mClients can be safely iterated over from other threads
122   // without worrying about potential modification from the RX thread
123   std::mutex mClientsMutex;
124 
125   ClientMessageCallback mClientMessageCallback;
126 
127   void acceptClientConnection();
128 
129   void disconnectClient(int clientSocket);
130 
131   void handleClientData(int clientSocket);
132 
133   bool sendToClientSocket(const void *data, size_t length, int clientSocket,
134                           uint16_t clientId);
135 
136   void serviceSocket();
137 
138   static std::atomic<bool> sSignalReceived;
139 };
140 
141 }  // namespace android::chre
142 
143 #endif  // CHRE_HOST_SOCKET_SERVER_H_
144