blob: b924f8dbc6290e6f6b7a1bd4bb9d59ed1d29a068 [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
Jim Flynndecd08b2022-03-13 22:35:46 +00008#include <common/include/SocketConnectionException.hpp>
Sadik Armagana97a0be2020-03-03 10:44:56 +00009
Colm Donelana21620d2019-10-11 13:09:49 +010010#include <cerrno>
Jim Flynndecd08b2022-03-13 22:35:46 +000011#include <cstring>
Teresa Charlin9bab4962019-09-06 12:28:35 +010012#include <fcntl.h>
Teresa Charlin9bab4962019-09-06 12:28:35 +010013#include <string>
14
Rob Hughes25b74362020-01-13 11:14:59 +000015
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000016namespace arm
Teresa Charlin9bab4962019-09-06 12:28:35 +010017{
Cathal Corbett5aa9fd72022-02-25 15:33:28 +000018namespace pipe
Teresa Charlin9bab4962019-09-06 12:28:35 +010019{
20
21SocketProfilingConnection::SocketProfilingConnection()
22{
Jim Flynne195a042022-04-12 17:19:28 +010023#if !defined(ARMNN_DISABLE_SOCKETS)
Jim Flynnbbfe6032020-07-20 16:57:44 +010024 arm::pipe::Initialize();
Teresa Charlin9bab4962019-09-06 12:28:35 +010025 memset(m_Socket, 0, sizeof(m_Socket));
26 // Note: we're using Linux specific SOCK_CLOEXEC flag.
27 m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
28 if (m_Socket[0].fd == -1)
29 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010030 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000031 std::string("SocketProfilingConnection: Socket construction failed: ") + strerror(errno),
32 m_Socket[0].fd,
33 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010034 }
35
36 // Connect to the named unix domain socket.
Rob Hughes25b74362020-01-13 11:14:59 +000037 sockaddr_un server{};
Teresa Charlin9bab4962019-09-06 12:28:35 +010038 memset(&server, 0, sizeof(sockaddr_un));
39 // As m_GatorNamespace begins with a null character we need to ignore that when getting its length.
40 memcpy(server.sun_path, m_GatorNamespace, strlen(m_GatorNamespace + 1) + 1);
41 server.sun_family = AF_UNIX;
42 if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
43 {
Colm Donelan9ea77002019-10-17 14:02:44 +010044 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +010045 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000046 std::string("SocketProfilingConnection: Cannot connect to stream socket: ") + strerror(errno),
47 m_Socket[0].fd,
48 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010049 }
50
51 // Our socket will only be interested in polling reads.
52 m_Socket[0].events = POLLIN;
53
54 // Make the socket non blocking.
Jim Flynnbbfe6032020-07-20 16:57:44 +010055 if (!arm::pipe::SetNonBlocking(m_Socket[0].fd))
Teresa Charlin9bab4962019-09-06 12:28:35 +010056 {
Colm Donelan9ea77002019-10-17 14:02:44 +010057 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +010058 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000059 std::string("SocketProfilingConnection: Failed to set socket as non blocking: ") + strerror(errno),
60 m_Socket[0].fd,
61 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010062 }
Jim Flynne195a042022-04-12 17:19:28 +010063#endif
Teresa Charlin9bab4962019-09-06 12:28:35 +010064}
65
Matteo Martincigh54fb9572019-10-02 12:50:57 +010066bool SocketProfilingConnection::IsOpen() const
Teresa Charlin9bab4962019-09-06 12:28:35 +010067{
Jim Flynne195a042022-04-12 17:19:28 +010068#if !defined(ARMNN_DISABLE_SOCKETS)
Matteo Martincigh24e8f922019-09-19 11:57:46 +010069 return m_Socket[0].fd > 0;
Jim Flynne195a042022-04-12 17:19:28 +010070#else
71 return false;
72#endif
Teresa Charlin9bab4962019-09-06 12:28:35 +010073}
74
75void SocketProfilingConnection::Close()
76{
Jim Flynne195a042022-04-12 17:19:28 +010077#if !defined(ARMNN_DISABLE_SOCKETS)
Jim Flynnbbfe6032020-07-20 16:57:44 +010078 if (arm::pipe::Close(m_Socket[0].fd) != 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010079 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010080 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000081 std::string("SocketProfilingConnection: Cannot close stream socket: ") + strerror(errno),
82 m_Socket[0].fd,
83 errno);
FinnWilliamsArma0c78712019-09-16 12:06:47 +010084 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010085
86 memset(m_Socket, 0, sizeof(m_Socket));
Jim Flynne195a042022-04-12 17:19:28 +010087#endif
Teresa Charlin9bab4962019-09-06 12:28:35 +010088}
89
Matteo Martincigh24e8f922019-09-19 11:57:46 +010090bool SocketProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
Teresa Charlin9bab4962019-09-06 12:28:35 +010091{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010092 if (buffer == nullptr || length == 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010093 {
94 return false;
95 }
Jim Flynne195a042022-04-12 17:19:28 +010096#if !defined(ARMNN_DISABLE_SOCKETS)
Jim Flynnbbfe6032020-07-20 16:57:44 +010097 return arm::pipe::Write(m_Socket[0].fd, buffer, length) != -1;
Jim Flynne195a042022-04-12 17:19:28 +010098#else
99 return false;
100#endif
Teresa Charlin9bab4962019-09-06 12:28:35 +0100101}
102
Jim Flynnbbfe6032020-07-20 16:57:44 +0100103arm::pipe::Packet SocketProfilingConnection::ReadPacket(uint32_t timeout)
Teresa Charlin9bab4962019-09-06 12:28:35 +0100104{
Jim Flynne195a042022-04-12 17:19:28 +0100105#if !defined(ARMNN_DISABLE_SOCKETS)
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100106 // Is there currently at least a header worth of data waiting to be read?
107 int bytes_available = 0;
Jim Flynnbbfe6032020-07-20 16:57:44 +0100108 arm::pipe::Ioctl(m_Socket[0].fd, FIONREAD, &bytes_available);
Colm Donelana21620d2019-10-11 13:09:49 +0100109 if (bytes_available >= 8)
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100110 {
Colm Donelana21620d2019-10-11 13:09:49 +0100111 // Yes there is. Read it:
112 return ReceivePacket();
113 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100114
115 // Poll for data on the socket or until timeout occurs
Jim Flynnbbfe6032020-07-20 16:57:44 +0100116 int pollResult = arm::pipe::Poll(&m_Socket[0], 1, static_cast<int>(timeout));
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100117
118 switch (pollResult)
Colm Donelana21620d2019-10-11 13:09:49 +0100119 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100120 case -1: // Error
Jim Flynnbbfe6032020-07-20 16:57:44 +0100121 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000122 std::string("SocketProfilingConnection: Error occured while reading from socket: ") + strerror(errno),
123 m_Socket[0].fd,
124 errno);
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100125
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100126 case 0: // Timeout
Jim Flynnbbfe6032020-07-20 16:57:44 +0100127 throw arm::pipe::TimeoutException("SocketProfilingConnection: Timeout while reading from socket");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100128
129 default: // Normal poll return but it could still contain an error signal
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100130 // Check if the socket reported an error
131 if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100132 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100133 if (m_Socket[0].revents == POLLNVAL)
134 {
135 // This is an unrecoverable error.
136 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100137 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000138 std::string("SocketProfilingConnection: Error occured while polling receiving socket: POLLNVAL."),
139 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100140 }
141 if (m_Socket[0].revents == POLLERR)
142 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100143 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000144 std::string(
145 "SocketProfilingConnection: Error occured while polling receiving socket: POLLERR: ")
146 + strerror(errno),
147 m_Socket[0].fd,
148 errno);
Colm Donelan9ea77002019-10-17 14:02:44 +0100149 }
150 if (m_Socket[0].revents == POLLHUP)
151 {
152 // This is an unrecoverable error.
153 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100154 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000155 std::string("SocketProfilingConnection: Connection closed by remote client: POLLHUP."),
156 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100157 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100158 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100159
160 // Check if there is data to read
161 if (!(m_Socket[0].revents & (POLLIN)))
162 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100163 // This is a corner case. The socket as been woken up but not with any data.
164 // We'll throw a timeout exception to loop around again.
Jim Flynndecd08b2022-03-13 22:35:46 +0000165 throw arm::pipe::TimeoutException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000166 "SocketProfilingConnection: File descriptor was polled but no data was available to receive.");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100167 }
168
169 return ReceivePacket();
Colm Donelana21620d2019-10-11 13:09:49 +0100170 }
Jim Flynne195a042022-04-12 17:19:28 +0100171#else
172 IgnoreUnused(timeout);
173 throw arm::pipe::TimeoutException(
174 "SocketProfilingConnection: Cannot use ReadPacket function with sockets disabled");
175#endif
Colm Donelana21620d2019-10-11 13:09:49 +0100176}
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100177
Jim Flynnbbfe6032020-07-20 16:57:44 +0100178arm::pipe::Packet SocketProfilingConnection::ReceivePacket()
Colm Donelana21620d2019-10-11 13:09:49 +0100179{
Jim Flynne195a042022-04-12 17:19:28 +0100180#if !defined(ARMNN_DISABLE_SOCKETS)
Colm Donelana21620d2019-10-11 13:09:49 +0100181 char header[8] = {};
Jim Flynnbbfe6032020-07-20 16:57:44 +0100182 long receiveResult = arm::pipe::Read(m_Socket[0].fd, &header, sizeof(header));
Colm Donelan9ea77002019-10-17 14:02:44 +0100183 // We expect 8 as the result here. 0 means EOF, socket is closed. -1 means there been some other kind of error.
184 switch( receiveResult )
Colm Donelana21620d2019-10-11 13:09:49 +0100185 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100186 case 0:
187 // Socket has closed.
188 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100189 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000190 std::string("SocketProfilingConnection: Remote socket has closed the connection."),
191 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100192 case -1:
193 // There's been a socket error. We will presume it's unrecoverable.
194 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100195 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000196 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
197 m_Socket[0].fd,
198 errno);
Colm Donelan9ea77002019-10-17 14:02:44 +0100199 default:
200 if (receiveResult < 8)
201 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100202 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000203 std::string(
204 "SocketProfilingConnection: The received packet did not contains a valid PIPE header."),
205 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100206 }
207 break;
Colm Donelana21620d2019-10-11 13:09:49 +0100208 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100209
Colm Donelana21620d2019-10-11 13:09:49 +0100210 // stream_metadata_identifier is the first 4 bytes
211 uint32_t metadataIdentifier = 0;
212 std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100213
Colm Donelana21620d2019-10-11 13:09:49 +0100214 // data_length is the next 4 bytes
215 uint32_t dataLength = 0;
216 std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100217
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100218 std::unique_ptr<unsigned char[]> packetData;
Colm Donelana21620d2019-10-11 13:09:49 +0100219 if (dataLength > 0)
220 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100221 packetData = std::make_unique<unsigned char[]>(dataLength);
Jim Flynnbbfe6032020-07-20 16:57:44 +0100222 long receivedLength = arm::pipe::Read(m_Socket[0].fd, packetData.get(), dataLength);
Jim Flynne11ff892019-10-04 04:25:43 -0700223 if (receivedLength < 0)
224 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100225 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000226 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
227 m_Socket[0].fd,
228 errno);
Jim Flynne11ff892019-10-04 04:25:43 -0700229 }
230 if (dataLength != static_cast<uint32_t>(receivedLength))
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100231 {
232 // What do we do here if we can't read in a full packet?
Jim Flynnbbfe6032020-07-20 16:57:44 +0100233 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000234 std::string("SocketProfilingConnection: Invalid PIPE packet."),
235 m_Socket[0].fd);
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100236 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100237 }
Colm Donelana21620d2019-10-11 13:09:49 +0100238
Jim Flynnbbfe6032020-07-20 16:57:44 +0100239 return arm::pipe::Packet(metadataIdentifier, dataLength, packetData);
Jim Flynne195a042022-04-12 17:19:28 +0100240#else
241 throw arm::pipe::TimeoutException(
242 "SocketProfilingConnection: Cannot use ReceivePacket function with sockets disabled");
243#endif
Teresa Charlin9bab4962019-09-06 12:28:35 +0100244}
245
Cathal Corbett5aa9fd72022-02-25 15:33:28 +0000246} // namespace pipe
247} // namespace arm