xref: /aosp_15_r20/external/armnn/profiling/client/src/SocketProfilingConnection.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
4*89c4ff92SAndroid Build Coastguard Worker //
5*89c4ff92SAndroid Build Coastguard Worker 
6*89c4ff92SAndroid Build Coastguard Worker #include "SocketProfilingConnection.hpp"
7*89c4ff92SAndroid Build Coastguard Worker 
8*89c4ff92SAndroid Build Coastguard Worker #include <common/include/SocketConnectionException.hpp>
9*89c4ff92SAndroid Build Coastguard Worker 
10*89c4ff92SAndroid Build Coastguard Worker #include <cerrno>
11*89c4ff92SAndroid Build Coastguard Worker #include <cstring>
12*89c4ff92SAndroid Build Coastguard Worker #include <fcntl.h>
13*89c4ff92SAndroid Build Coastguard Worker #include <string>
14*89c4ff92SAndroid Build Coastguard Worker 
15*89c4ff92SAndroid Build Coastguard Worker 
16*89c4ff92SAndroid Build Coastguard Worker namespace arm
17*89c4ff92SAndroid Build Coastguard Worker {
18*89c4ff92SAndroid Build Coastguard Worker namespace pipe
19*89c4ff92SAndroid Build Coastguard Worker {
20*89c4ff92SAndroid Build Coastguard Worker 
SocketProfilingConnection()21*89c4ff92SAndroid Build Coastguard Worker SocketProfilingConnection::SocketProfilingConnection()
22*89c4ff92SAndroid Build Coastguard Worker {
23*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_SOCKETS)
24*89c4ff92SAndroid Build Coastguard Worker     arm::pipe::Initialize();
25*89c4ff92SAndroid Build Coastguard Worker     memset(m_Socket, 0, sizeof(m_Socket));
26*89c4ff92SAndroid Build Coastguard Worker     // Note: we're using Linux specific SOCK_CLOEXEC flag.
27*89c4ff92SAndroid Build Coastguard Worker     m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
28*89c4ff92SAndroid Build Coastguard Worker     if (m_Socket[0].fd == -1)
29*89c4ff92SAndroid Build Coastguard Worker     {
30*89c4ff92SAndroid Build Coastguard Worker         throw arm::pipe::SocketConnectionException(
31*89c4ff92SAndroid Build Coastguard Worker             std::string("SocketProfilingConnection: Socket construction failed: ")  + strerror(errno),
32*89c4ff92SAndroid Build Coastguard Worker             m_Socket[0].fd,
33*89c4ff92SAndroid Build Coastguard Worker             errno);
34*89c4ff92SAndroid Build Coastguard Worker     }
35*89c4ff92SAndroid Build Coastguard Worker 
36*89c4ff92SAndroid Build Coastguard Worker     // Connect to the named unix domain socket.
37*89c4ff92SAndroid Build Coastguard Worker     sockaddr_un server{};
38*89c4ff92SAndroid Build Coastguard Worker     memset(&server, 0, sizeof(sockaddr_un));
39*89c4ff92SAndroid Build Coastguard Worker     // As m_GatorNamespace begins with a null character we need to ignore that when getting its length.
40*89c4ff92SAndroid Build Coastguard Worker     memcpy(server.sun_path, m_GatorNamespace, strlen(m_GatorNamespace + 1) + 1);
41*89c4ff92SAndroid Build Coastguard Worker     server.sun_family = AF_UNIX;
42*89c4ff92SAndroid Build Coastguard Worker     if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
43*89c4ff92SAndroid Build Coastguard Worker     {
44*89c4ff92SAndroid Build Coastguard Worker         Close();
45*89c4ff92SAndroid Build Coastguard Worker         throw arm::pipe::SocketConnectionException(
46*89c4ff92SAndroid Build Coastguard Worker             std::string("SocketProfilingConnection: Cannot connect to stream socket: ")  + strerror(errno),
47*89c4ff92SAndroid Build Coastguard Worker             m_Socket[0].fd,
48*89c4ff92SAndroid Build Coastguard Worker             errno);
49*89c4ff92SAndroid Build Coastguard Worker     }
50*89c4ff92SAndroid Build Coastguard Worker 
51*89c4ff92SAndroid Build Coastguard Worker     // Our socket will only be interested in polling reads.
52*89c4ff92SAndroid Build Coastguard Worker     m_Socket[0].events = POLLIN;
53*89c4ff92SAndroid Build Coastguard Worker 
54*89c4ff92SAndroid Build Coastguard Worker     // Make the socket non blocking.
55*89c4ff92SAndroid Build Coastguard Worker     if (!arm::pipe::SetNonBlocking(m_Socket[0].fd))
56*89c4ff92SAndroid Build Coastguard Worker     {
57*89c4ff92SAndroid Build Coastguard Worker         Close();
58*89c4ff92SAndroid Build Coastguard Worker         throw arm::pipe::SocketConnectionException(
59*89c4ff92SAndroid Build Coastguard Worker             std::string("SocketProfilingConnection: Failed to set socket as non blocking: ")  + strerror(errno),
60*89c4ff92SAndroid Build Coastguard Worker             m_Socket[0].fd,
61*89c4ff92SAndroid Build Coastguard Worker             errno);
62*89c4ff92SAndroid Build Coastguard Worker     }
63*89c4ff92SAndroid Build Coastguard Worker #endif
64*89c4ff92SAndroid Build Coastguard Worker }
65*89c4ff92SAndroid Build Coastguard Worker 
IsOpen() const66*89c4ff92SAndroid Build Coastguard Worker bool SocketProfilingConnection::IsOpen() const
67*89c4ff92SAndroid Build Coastguard Worker {
68*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_SOCKETS)
69*89c4ff92SAndroid Build Coastguard Worker     return m_Socket[0].fd > 0;
70*89c4ff92SAndroid Build Coastguard Worker #else
71*89c4ff92SAndroid Build Coastguard Worker     return false;
72*89c4ff92SAndroid Build Coastguard Worker #endif
73*89c4ff92SAndroid Build Coastguard Worker }
74*89c4ff92SAndroid Build Coastguard Worker 
Close()75*89c4ff92SAndroid Build Coastguard Worker void SocketProfilingConnection::Close()
76*89c4ff92SAndroid Build Coastguard Worker {
77*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_SOCKETS)
78*89c4ff92SAndroid Build Coastguard Worker     if (arm::pipe::Close(m_Socket[0].fd) != 0)
79*89c4ff92SAndroid Build Coastguard Worker     {
80*89c4ff92SAndroid Build Coastguard Worker         throw arm::pipe::SocketConnectionException(
81*89c4ff92SAndroid Build Coastguard Worker             std::string("SocketProfilingConnection: Cannot close stream socket: ")  + strerror(errno),
82*89c4ff92SAndroid Build Coastguard Worker             m_Socket[0].fd,
83*89c4ff92SAndroid Build Coastguard Worker             errno);
84*89c4ff92SAndroid Build Coastguard Worker     }
85*89c4ff92SAndroid Build Coastguard Worker 
86*89c4ff92SAndroid Build Coastguard Worker     memset(m_Socket, 0, sizeof(m_Socket));
87*89c4ff92SAndroid Build Coastguard Worker #endif
88*89c4ff92SAndroid Build Coastguard Worker }
89*89c4ff92SAndroid Build Coastguard Worker 
WritePacket(const unsigned char * buffer,uint32_t length)90*89c4ff92SAndroid Build Coastguard Worker bool SocketProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
91*89c4ff92SAndroid Build Coastguard Worker {
92*89c4ff92SAndroid Build Coastguard Worker     if (buffer == nullptr || length == 0)
93*89c4ff92SAndroid Build Coastguard Worker     {
94*89c4ff92SAndroid Build Coastguard Worker         return false;
95*89c4ff92SAndroid Build Coastguard Worker     }
96*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_SOCKETS)
97*89c4ff92SAndroid Build Coastguard Worker     return arm::pipe::Write(m_Socket[0].fd, buffer, length) != -1;
98*89c4ff92SAndroid Build Coastguard Worker #else
99*89c4ff92SAndroid Build Coastguard Worker     return false;
100*89c4ff92SAndroid Build Coastguard Worker #endif
101*89c4ff92SAndroid Build Coastguard Worker }
102*89c4ff92SAndroid Build Coastguard Worker 
ReadPacket(uint32_t timeout)103*89c4ff92SAndroid Build Coastguard Worker arm::pipe::Packet SocketProfilingConnection::ReadPacket(uint32_t timeout)
104*89c4ff92SAndroid Build Coastguard Worker {
105*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_SOCKETS)
106*89c4ff92SAndroid Build Coastguard Worker     // Is there currently at least a header worth of data waiting to be read?
107*89c4ff92SAndroid Build Coastguard Worker     int bytes_available = 0;
108*89c4ff92SAndroid Build Coastguard Worker     arm::pipe::Ioctl(m_Socket[0].fd, FIONREAD, &bytes_available);
109*89c4ff92SAndroid Build Coastguard Worker     if (bytes_available >= 8)
110*89c4ff92SAndroid Build Coastguard Worker     {
111*89c4ff92SAndroid Build Coastguard Worker         // Yes there is. Read it:
112*89c4ff92SAndroid Build Coastguard Worker         return ReceivePacket();
113*89c4ff92SAndroid Build Coastguard Worker     }
114*89c4ff92SAndroid Build Coastguard Worker 
115*89c4ff92SAndroid Build Coastguard Worker     // Poll for data on the socket or until timeout occurs
116*89c4ff92SAndroid Build Coastguard Worker     int pollResult = arm::pipe::Poll(&m_Socket[0], 1, static_cast<int>(timeout));
117*89c4ff92SAndroid Build Coastguard Worker 
118*89c4ff92SAndroid Build Coastguard Worker     switch (pollResult)
119*89c4ff92SAndroid Build Coastguard Worker     {
120*89c4ff92SAndroid Build Coastguard Worker     case -1: // Error
121*89c4ff92SAndroid Build Coastguard Worker         throw arm::pipe::SocketConnectionException(
122*89c4ff92SAndroid Build Coastguard Worker             std::string("SocketProfilingConnection: Error occured while reading from socket: ") + strerror(errno),
123*89c4ff92SAndroid Build Coastguard Worker             m_Socket[0].fd,
124*89c4ff92SAndroid Build Coastguard Worker             errno);
125*89c4ff92SAndroid Build Coastguard Worker 
126*89c4ff92SAndroid Build Coastguard Worker     case 0: // Timeout
127*89c4ff92SAndroid Build Coastguard Worker         throw arm::pipe::TimeoutException("SocketProfilingConnection: Timeout while reading from socket");
128*89c4ff92SAndroid Build Coastguard Worker 
129*89c4ff92SAndroid Build Coastguard Worker     default: // Normal poll return but it could still contain an error signal
130*89c4ff92SAndroid Build Coastguard Worker         // Check if the socket reported an error
131*89c4ff92SAndroid Build Coastguard Worker         if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
132*89c4ff92SAndroid Build Coastguard Worker         {
133*89c4ff92SAndroid Build Coastguard Worker             if (m_Socket[0].revents == POLLNVAL)
134*89c4ff92SAndroid Build Coastguard Worker             {
135*89c4ff92SAndroid Build Coastguard Worker                 // This is an unrecoverable error.
136*89c4ff92SAndroid Build Coastguard Worker                 Close();
137*89c4ff92SAndroid Build Coastguard Worker                 throw arm::pipe::SocketConnectionException(
138*89c4ff92SAndroid Build Coastguard Worker                     std::string("SocketProfilingConnection: Error occured while polling receiving socket: POLLNVAL."),
139*89c4ff92SAndroid Build Coastguard Worker                     m_Socket[0].fd);
140*89c4ff92SAndroid Build Coastguard Worker             }
141*89c4ff92SAndroid Build Coastguard Worker             if (m_Socket[0].revents == POLLERR)
142*89c4ff92SAndroid Build Coastguard Worker             {
143*89c4ff92SAndroid Build Coastguard Worker                 throw arm::pipe::SocketConnectionException(
144*89c4ff92SAndroid Build Coastguard Worker                     std::string(
145*89c4ff92SAndroid Build Coastguard Worker                         "SocketProfilingConnection: Error occured while polling receiving socket: POLLERR: ")
146*89c4ff92SAndroid Build Coastguard Worker                         + strerror(errno),
147*89c4ff92SAndroid Build Coastguard Worker                     m_Socket[0].fd,
148*89c4ff92SAndroid Build Coastguard Worker                     errno);
149*89c4ff92SAndroid Build Coastguard Worker             }
150*89c4ff92SAndroid Build Coastguard Worker             if (m_Socket[0].revents == POLLHUP)
151*89c4ff92SAndroid Build Coastguard Worker             {
152*89c4ff92SAndroid Build Coastguard Worker                 // This is an unrecoverable error.
153*89c4ff92SAndroid Build Coastguard Worker                 Close();
154*89c4ff92SAndroid Build Coastguard Worker                 throw arm::pipe::SocketConnectionException(
155*89c4ff92SAndroid Build Coastguard Worker                     std::string("SocketProfilingConnection: Connection closed by remote client: POLLHUP."),
156*89c4ff92SAndroid Build Coastguard Worker                     m_Socket[0].fd);
157*89c4ff92SAndroid Build Coastguard Worker             }
158*89c4ff92SAndroid Build Coastguard Worker         }
159*89c4ff92SAndroid Build Coastguard Worker 
160*89c4ff92SAndroid Build Coastguard Worker         // Check if there is data to read
161*89c4ff92SAndroid Build Coastguard Worker         if (!(m_Socket[0].revents & (POLLIN)))
162*89c4ff92SAndroid Build Coastguard Worker         {
163*89c4ff92SAndroid Build Coastguard Worker             // This is a corner case. The socket as been woken up but not with any data.
164*89c4ff92SAndroid Build Coastguard Worker             // We'll throw a timeout exception to loop around again.
165*89c4ff92SAndroid Build Coastguard Worker             throw arm::pipe::TimeoutException(
166*89c4ff92SAndroid Build Coastguard Worker                 "SocketProfilingConnection: File descriptor was polled but no data was available to receive.");
167*89c4ff92SAndroid Build Coastguard Worker         }
168*89c4ff92SAndroid Build Coastguard Worker 
169*89c4ff92SAndroid Build Coastguard Worker         return ReceivePacket();
170*89c4ff92SAndroid Build Coastguard Worker     }
171*89c4ff92SAndroid Build Coastguard Worker #else
172*89c4ff92SAndroid Build Coastguard Worker     IgnoreUnused(timeout);
173*89c4ff92SAndroid Build Coastguard Worker     throw arm::pipe::TimeoutException(
174*89c4ff92SAndroid Build Coastguard Worker         "SocketProfilingConnection: Cannot use ReadPacket function with sockets disabled");
175*89c4ff92SAndroid Build Coastguard Worker #endif
176*89c4ff92SAndroid Build Coastguard Worker }
177*89c4ff92SAndroid Build Coastguard Worker 
ReceivePacket()178*89c4ff92SAndroid Build Coastguard Worker arm::pipe::Packet SocketProfilingConnection::ReceivePacket()
179*89c4ff92SAndroid Build Coastguard Worker {
180*89c4ff92SAndroid Build Coastguard Worker #if !defined(ARMNN_DISABLE_SOCKETS)
181*89c4ff92SAndroid Build Coastguard Worker     char header[8] = {};
182*89c4ff92SAndroid Build Coastguard Worker     long receiveResult = arm::pipe::Read(m_Socket[0].fd, &header, sizeof(header));
183*89c4ff92SAndroid Build Coastguard Worker     // We expect 8 as the result here. 0 means EOF, socket is closed. -1 means there been some other kind of error.
184*89c4ff92SAndroid Build Coastguard Worker     switch( receiveResult )
185*89c4ff92SAndroid Build Coastguard Worker     {
186*89c4ff92SAndroid Build Coastguard Worker         case 0:
187*89c4ff92SAndroid Build Coastguard Worker             // Socket has closed.
188*89c4ff92SAndroid Build Coastguard Worker             Close();
189*89c4ff92SAndroid Build Coastguard Worker             throw arm::pipe::SocketConnectionException(
190*89c4ff92SAndroid Build Coastguard Worker                 std::string("SocketProfilingConnection: Remote socket has closed the connection."),
191*89c4ff92SAndroid Build Coastguard Worker                 m_Socket[0].fd);
192*89c4ff92SAndroid Build Coastguard Worker         case -1:
193*89c4ff92SAndroid Build Coastguard Worker             // There's been a socket error. We will presume it's unrecoverable.
194*89c4ff92SAndroid Build Coastguard Worker             Close();
195*89c4ff92SAndroid Build Coastguard Worker             throw arm::pipe::SocketConnectionException(
196*89c4ff92SAndroid Build Coastguard Worker                 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
197*89c4ff92SAndroid Build Coastguard Worker                 m_Socket[0].fd,
198*89c4ff92SAndroid Build Coastguard Worker                 errno);
199*89c4ff92SAndroid Build Coastguard Worker         default:
200*89c4ff92SAndroid Build Coastguard Worker             if (receiveResult < 8)
201*89c4ff92SAndroid Build Coastguard Worker             {
202*89c4ff92SAndroid Build Coastguard Worker                  throw arm::pipe::SocketConnectionException(
203*89c4ff92SAndroid Build Coastguard Worker                      std::string(
204*89c4ff92SAndroid Build Coastguard Worker                          "SocketProfilingConnection: The received packet did not contains a valid PIPE header."),
205*89c4ff92SAndroid Build Coastguard Worker                      m_Socket[0].fd);
206*89c4ff92SAndroid Build Coastguard Worker             }
207*89c4ff92SAndroid Build Coastguard Worker             break;
208*89c4ff92SAndroid Build Coastguard Worker     }
209*89c4ff92SAndroid Build Coastguard Worker 
210*89c4ff92SAndroid Build Coastguard Worker     // stream_metadata_identifier is the first 4 bytes
211*89c4ff92SAndroid Build Coastguard Worker     uint32_t metadataIdentifier = 0;
212*89c4ff92SAndroid Build Coastguard Worker     std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
213*89c4ff92SAndroid Build Coastguard Worker 
214*89c4ff92SAndroid Build Coastguard Worker     // data_length is the next 4 bytes
215*89c4ff92SAndroid Build Coastguard Worker     uint32_t dataLength = 0;
216*89c4ff92SAndroid Build Coastguard Worker     std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
217*89c4ff92SAndroid Build Coastguard Worker 
218*89c4ff92SAndroid Build Coastguard Worker     std::unique_ptr<unsigned char[]> packetData;
219*89c4ff92SAndroid Build Coastguard Worker     if (dataLength > 0)
220*89c4ff92SAndroid Build Coastguard Worker     {
221*89c4ff92SAndroid Build Coastguard Worker         packetData = std::make_unique<unsigned char[]>(dataLength);
222*89c4ff92SAndroid Build Coastguard Worker         long receivedLength = arm::pipe::Read(m_Socket[0].fd, packetData.get(), dataLength);
223*89c4ff92SAndroid Build Coastguard Worker         if (receivedLength < 0)
224*89c4ff92SAndroid Build Coastguard Worker         {
225*89c4ff92SAndroid Build Coastguard Worker             throw arm::pipe::SocketConnectionException(
226*89c4ff92SAndroid Build Coastguard Worker                 std::string("SocketProfilingConnection: Error occured while reading the packet: ")  + strerror(errno),
227*89c4ff92SAndroid Build Coastguard Worker                 m_Socket[0].fd,
228*89c4ff92SAndroid Build Coastguard Worker                 errno);
229*89c4ff92SAndroid Build Coastguard Worker         }
230*89c4ff92SAndroid Build Coastguard Worker         if (dataLength != static_cast<uint32_t>(receivedLength))
231*89c4ff92SAndroid Build Coastguard Worker         {
232*89c4ff92SAndroid Build Coastguard Worker             // What do we do here if we can't read in a full packet?
233*89c4ff92SAndroid Build Coastguard Worker             throw arm::pipe::SocketConnectionException(
234*89c4ff92SAndroid Build Coastguard Worker                 std::string("SocketProfilingConnection: Invalid PIPE packet."),
235*89c4ff92SAndroid Build Coastguard Worker                 m_Socket[0].fd);
236*89c4ff92SAndroid Build Coastguard Worker         }
237*89c4ff92SAndroid Build Coastguard Worker     }
238*89c4ff92SAndroid Build Coastguard Worker 
239*89c4ff92SAndroid Build Coastguard Worker     return arm::pipe::Packet(metadataIdentifier, dataLength, packetData);
240*89c4ff92SAndroid Build Coastguard Worker #else
241*89c4ff92SAndroid Build Coastguard Worker     throw arm::pipe::TimeoutException(
242*89c4ff92SAndroid Build Coastguard Worker         "SocketProfilingConnection: Cannot use ReceivePacket function with sockets disabled");
243*89c4ff92SAndroid Build Coastguard Worker #endif
244*89c4ff92SAndroid Build Coastguard Worker }
245*89c4ff92SAndroid Build Coastguard Worker 
246*89c4ff92SAndroid Build Coastguard Worker } // namespace pipe
247*89c4ff92SAndroid Build Coastguard Worker } // namespace arm
248