blob: c231045b1088ab9aff019b7afdec4c4ad62b74b6 [file] [log] [blame]
Teresa Charlin9bab4962019-09-06 12:28:35 +01001//
Jim Flynn6da6a452020-07-14 14:26:27 +01002// Copyright © 2019 Arm Ltd and Contributors. All rights reserved.
Teresa Charlin9bab4962019-09-06 12:28:35 +01003// SPDX-License-Identifier: MIT
4//
5
6#include "SocketProfilingConnection.hpp"
7
Sadik Armagana97a0be2020-03-03 10:44:56 +00008#include "common/include/SocketConnectionException.hpp"
9
Colm Donelana21620d2019-10-11 13:09:49 +010010#include <cerrno>
Teresa Charlin9bab4962019-09-06 12:28:35 +010011#include <fcntl.h>
Teresa Charlin9bab4962019-09-06 12:28:35 +010012#include <string>
13
Rob Hughes25b74362020-01-13 11:14:59 +000014using namespace armnnUtils;
15
Teresa Charlin9bab4962019-09-06 12:28:35 +010016namespace armnn
17{
18namespace profiling
19{
20
21SocketProfilingConnection::SocketProfilingConnection()
22{
Rob Hughes25b74362020-01-13 11:14:59 +000023 Sockets::Initialize();
Teresa Charlin9bab4962019-09-06 12:28:35 +010024 memset(m_Socket, 0, sizeof(m_Socket));
25 // Note: we're using Linux specific SOCK_CLOEXEC flag.
26 m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
27 if (m_Socket[0].fd == -1)
28 {
Sadik Armagana97a0be2020-03-03 10:44:56 +000029 throw armnnProfiling::SocketConnectionException(
30 std::string("SocketProfilingConnection: Socket construction failed: ") + strerror(errno),
31 m_Socket[0].fd,
32 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010033 }
34
35 // Connect to the named unix domain socket.
Rob Hughes25b74362020-01-13 11:14:59 +000036 sockaddr_un server{};
Teresa Charlin9bab4962019-09-06 12:28:35 +010037 memset(&server, 0, sizeof(sockaddr_un));
38 // As m_GatorNamespace begins with a null character we need to ignore that when getting its length.
39 memcpy(server.sun_path, m_GatorNamespace, strlen(m_GatorNamespace + 1) + 1);
40 server.sun_family = AF_UNIX;
41 if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
42 {
Colm Donelan9ea77002019-10-17 14:02:44 +010043 Close();
Sadik Armagana97a0be2020-03-03 10:44:56 +000044 throw armnnProfiling::SocketConnectionException(
45 std::string("SocketProfilingConnection: Cannot connect to stream socket: ") + strerror(errno),
46 m_Socket[0].fd,
47 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010048 }
49
50 // Our socket will only be interested in polling reads.
51 m_Socket[0].events = POLLIN;
52
53 // Make the socket non blocking.
Rob Hughes25b74362020-01-13 11:14:59 +000054 if (!Sockets::SetNonBlocking(m_Socket[0].fd))
Teresa Charlin9bab4962019-09-06 12:28:35 +010055 {
Colm Donelan9ea77002019-10-17 14:02:44 +010056 Close();
Sadik Armagana97a0be2020-03-03 10:44:56 +000057 throw armnnProfiling::SocketConnectionException(
58 std::string("SocketProfilingConnection: Failed to set socket as non blocking: ") + strerror(errno),
59 m_Socket[0].fd,
60 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010061 }
62}
63
Matteo Martincigh54fb9572019-10-02 12:50:57 +010064bool SocketProfilingConnection::IsOpen() const
Teresa Charlin9bab4962019-09-06 12:28:35 +010065{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010066 return m_Socket[0].fd > 0;
Teresa Charlin9bab4962019-09-06 12:28:35 +010067}
68
69void SocketProfilingConnection::Close()
70{
Rob Hughes25b74362020-01-13 11:14:59 +000071 if (Sockets::Close(m_Socket[0].fd) != 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010072 {
Sadik Armagana97a0be2020-03-03 10:44:56 +000073 throw armnnProfiling::SocketConnectionException(
74 std::string("SocketProfilingConnection: Cannot close stream socket: ") + strerror(errno),
75 m_Socket[0].fd,
76 errno);
FinnWilliamsArma0c78712019-09-16 12:06:47 +010077 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010078
79 memset(m_Socket, 0, sizeof(m_Socket));
Teresa Charlin9bab4962019-09-06 12:28:35 +010080}
81
Matteo Martincigh24e8f922019-09-19 11:57:46 +010082bool SocketProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
Teresa Charlin9bab4962019-09-06 12:28:35 +010083{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010084 if (buffer == nullptr || length == 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010085 {
86 return false;
87 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010088
Rob Hughes25b74362020-01-13 11:14:59 +000089 return Sockets::Write(m_Socket[0].fd, buffer, length) != -1;
Teresa Charlin9bab4962019-09-06 12:28:35 +010090}
91
92Packet SocketProfilingConnection::ReadPacket(uint32_t timeout)
93{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010094 // Is there currently at least a header worth of data waiting to be read?
95 int bytes_available = 0;
Rob Hughes25b74362020-01-13 11:14:59 +000096 Sockets::Ioctl(m_Socket[0].fd, FIONREAD, &bytes_available);
Colm Donelana21620d2019-10-11 13:09:49 +010097 if (bytes_available >= 8)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010098 {
Colm Donelana21620d2019-10-11 13:09:49 +010099 // Yes there is. Read it:
100 return ReceivePacket();
101 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100102
103 // Poll for data on the socket or until timeout occurs
Rob Hughes25b74362020-01-13 11:14:59 +0000104 int pollResult = Sockets::Poll(&m_Socket[0], 1, static_cast<int>(timeout));
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100105
106 switch (pollResult)
Colm Donelana21620d2019-10-11 13:09:49 +0100107 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100108 case -1: // Error
Sadik Armagana97a0be2020-03-03 10:44:56 +0000109 throw armnnProfiling::SocketConnectionException(
110 std::string("SocketProfilingConnection: Error occured while reading from socket: ") + strerror(errno),
111 m_Socket[0].fd,
112 errno);
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100113
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100114 case 0: // Timeout
Sadik Armagana97a0be2020-03-03 10:44:56 +0000115 throw TimeoutException("SocketProfilingConnection: Timeout while reading from socket");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100116
117 default: // Normal poll return but it could still contain an error signal
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100118 // Check if the socket reported an error
119 if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100120 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100121 if (m_Socket[0].revents == POLLNVAL)
122 {
123 // This is an unrecoverable error.
124 Close();
Sadik Armagana97a0be2020-03-03 10:44:56 +0000125 throw armnnProfiling::SocketConnectionException(
126 std::string("SocketProfilingConnection: Error occured while polling receiving socket: POLLNVAL."),
127 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100128 }
129 if (m_Socket[0].revents == POLLERR)
130 {
Sadik Armagana97a0be2020-03-03 10:44:56 +0000131 throw armnnProfiling::SocketConnectionException(
132 std::string(
133 "SocketProfilingConnection: Error occured while polling receiving socket: POLLERR: ")
134 + strerror(errno),
135 m_Socket[0].fd,
136 errno);
Colm Donelan9ea77002019-10-17 14:02:44 +0100137 }
138 if (m_Socket[0].revents == POLLHUP)
139 {
140 // This is an unrecoverable error.
141 Close();
Sadik Armagana97a0be2020-03-03 10:44:56 +0000142 throw armnnProfiling::SocketConnectionException(
143 std::string("SocketProfilingConnection: Connection closed by remote client: POLLHUP."),
144 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100145 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100146 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100147
148 // Check if there is data to read
149 if (!(m_Socket[0].revents & (POLLIN)))
150 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100151 // This is a corner case. The socket as been woken up but not with any data.
152 // We'll throw a timeout exception to loop around again.
Sadik Armagana97a0be2020-03-03 10:44:56 +0000153 throw armnn::TimeoutException(
154 "SocketProfilingConnection: File descriptor was polled but no data was available to receive.");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100155 }
156
157 return ReceivePacket();
Colm Donelana21620d2019-10-11 13:09:49 +0100158 }
159}
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100160
Colm Donelana21620d2019-10-11 13:09:49 +0100161Packet SocketProfilingConnection::ReceivePacket()
162{
163 char header[8] = {};
Rob Hughes25b74362020-01-13 11:14:59 +0000164 long receiveResult = Sockets::Read(m_Socket[0].fd, &header, sizeof(header));
Colm Donelan9ea77002019-10-17 14:02:44 +0100165 // We expect 8 as the result here. 0 means EOF, socket is closed. -1 means there been some other kind of error.
166 switch( receiveResult )
Colm Donelana21620d2019-10-11 13:09:49 +0100167 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100168 case 0:
169 // Socket has closed.
170 Close();
Sadik Armagana97a0be2020-03-03 10:44:56 +0000171 throw armnnProfiling::SocketConnectionException(
172 std::string("SocketProfilingConnection: Remote socket has closed the connection."),
173 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100174 case -1:
175 // There's been a socket error. We will presume it's unrecoverable.
176 Close();
Sadik Armagana97a0be2020-03-03 10:44:56 +0000177 throw armnnProfiling::SocketConnectionException(
178 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
179 m_Socket[0].fd,
180 errno);
Colm Donelan9ea77002019-10-17 14:02:44 +0100181 default:
182 if (receiveResult < 8)
183 {
Sadik Armagana97a0be2020-03-03 10:44:56 +0000184 throw armnnProfiling::SocketConnectionException(
185 std::string(
186 "SocketProfilingConnection: The received packet did not contains a valid PIPE header."),
187 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100188 }
189 break;
Colm Donelana21620d2019-10-11 13:09:49 +0100190 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100191
Colm Donelana21620d2019-10-11 13:09:49 +0100192 // stream_metadata_identifier is the first 4 bytes
193 uint32_t metadataIdentifier = 0;
194 std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100195
Colm Donelana21620d2019-10-11 13:09:49 +0100196 // data_length is the next 4 bytes
197 uint32_t dataLength = 0;
198 std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100199
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100200 std::unique_ptr<unsigned char[]> packetData;
Colm Donelana21620d2019-10-11 13:09:49 +0100201 if (dataLength > 0)
202 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100203 packetData = std::make_unique<unsigned char[]>(dataLength);
Rob Hughes25b74362020-01-13 11:14:59 +0000204 long receivedLength = Sockets::Read(m_Socket[0].fd, packetData.get(), dataLength);
Jim Flynne11ff892019-10-04 04:25:43 -0700205 if (receivedLength < 0)
206 {
Sadik Armagana97a0be2020-03-03 10:44:56 +0000207 throw armnnProfiling::SocketConnectionException(
208 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
209 m_Socket[0].fd,
210 errno);
Jim Flynne11ff892019-10-04 04:25:43 -0700211 }
212 if (dataLength != static_cast<uint32_t>(receivedLength))
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100213 {
214 // What do we do here if we can't read in a full packet?
Sadik Armagana97a0be2020-03-03 10:44:56 +0000215 throw armnnProfiling::SocketConnectionException(
216 std::string("SocketProfilingConnection: Invalid PIPE packet."),
217 m_Socket[0].fd);
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100218 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100219 }
Colm Donelana21620d2019-10-11 13:09:49 +0100220
221 return Packet(metadataIdentifier, dataLength, packetData);
Teresa Charlin9bab4962019-09-06 12:28:35 +0100222}
223
224} // namespace profiling
225} // namespace armnn