blob: 9de425b62c828e9e7ca1a9441311858d67d233b4 [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 +000014
Teresa Charlin9bab4962019-09-06 12:28:35 +010015namespace armnn
16{
17namespace profiling
18{
19
20SocketProfilingConnection::SocketProfilingConnection()
21{
Jim Flynnbbfe6032020-07-20 16:57:44 +010022 arm::pipe::Initialize();
Teresa Charlin9bab4962019-09-06 12:28:35 +010023 memset(m_Socket, 0, sizeof(m_Socket));
24 // Note: we're using Linux specific SOCK_CLOEXEC flag.
25 m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
26 if (m_Socket[0].fd == -1)
27 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010028 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000029 std::string("SocketProfilingConnection: Socket construction failed: ") + strerror(errno),
30 m_Socket[0].fd,
31 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010032 }
33
34 // Connect to the named unix domain socket.
Rob Hughes25b74362020-01-13 11:14:59 +000035 sockaddr_un server{};
Teresa Charlin9bab4962019-09-06 12:28:35 +010036 memset(&server, 0, sizeof(sockaddr_un));
37 // As m_GatorNamespace begins with a null character we need to ignore that when getting its length.
38 memcpy(server.sun_path, m_GatorNamespace, strlen(m_GatorNamespace + 1) + 1);
39 server.sun_family = AF_UNIX;
40 if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
41 {
Colm Donelan9ea77002019-10-17 14:02:44 +010042 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +010043 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000044 std::string("SocketProfilingConnection: Cannot connect to stream socket: ") + strerror(errno),
45 m_Socket[0].fd,
46 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010047 }
48
49 // Our socket will only be interested in polling reads.
50 m_Socket[0].events = POLLIN;
51
52 // Make the socket non blocking.
Jim Flynnbbfe6032020-07-20 16:57:44 +010053 if (!arm::pipe::SetNonBlocking(m_Socket[0].fd))
Teresa Charlin9bab4962019-09-06 12:28:35 +010054 {
Colm Donelan9ea77002019-10-17 14:02:44 +010055 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +010056 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000057 std::string("SocketProfilingConnection: Failed to set socket as non blocking: ") + strerror(errno),
58 m_Socket[0].fd,
59 errno);
Teresa Charlin9bab4962019-09-06 12:28:35 +010060 }
61}
62
Matteo Martincigh54fb9572019-10-02 12:50:57 +010063bool SocketProfilingConnection::IsOpen() const
Teresa Charlin9bab4962019-09-06 12:28:35 +010064{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010065 return m_Socket[0].fd > 0;
Teresa Charlin9bab4962019-09-06 12:28:35 +010066}
67
68void SocketProfilingConnection::Close()
69{
Jim Flynnbbfe6032020-07-20 16:57:44 +010070 if (arm::pipe::Close(m_Socket[0].fd) != 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010071 {
Jim Flynnbbfe6032020-07-20 16:57:44 +010072 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +000073 std::string("SocketProfilingConnection: Cannot close stream socket: ") + strerror(errno),
74 m_Socket[0].fd,
75 errno);
FinnWilliamsArma0c78712019-09-16 12:06:47 +010076 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010077
78 memset(m_Socket, 0, sizeof(m_Socket));
Teresa Charlin9bab4962019-09-06 12:28:35 +010079}
80
Matteo Martincigh24e8f922019-09-19 11:57:46 +010081bool SocketProfilingConnection::WritePacket(const unsigned char* buffer, uint32_t length)
Teresa Charlin9bab4962019-09-06 12:28:35 +010082{
Matteo Martincigh24e8f922019-09-19 11:57:46 +010083 if (buffer == nullptr || length == 0)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010084 {
85 return false;
86 }
Matteo Martincigh24e8f922019-09-19 11:57:46 +010087
Jim Flynnbbfe6032020-07-20 16:57:44 +010088 return arm::pipe::Write(m_Socket[0].fd, buffer, length) != -1;
Teresa Charlin9bab4962019-09-06 12:28:35 +010089}
90
Jim Flynnbbfe6032020-07-20 16:57:44 +010091arm::pipe::Packet SocketProfilingConnection::ReadPacket(uint32_t timeout)
Teresa Charlin9bab4962019-09-06 12:28:35 +010092{
Matteo Martincigh8d9590e2019-10-15 09:35:29 +010093 // Is there currently at least a header worth of data waiting to be read?
94 int bytes_available = 0;
Jim Flynnbbfe6032020-07-20 16:57:44 +010095 arm::pipe::Ioctl(m_Socket[0].fd, FIONREAD, &bytes_available);
Colm Donelana21620d2019-10-11 13:09:49 +010096 if (bytes_available >= 8)
FinnWilliamsArma0c78712019-09-16 12:06:47 +010097 {
Colm Donelana21620d2019-10-11 13:09:49 +010098 // Yes there is. Read it:
99 return ReceivePacket();
100 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100101
102 // Poll for data on the socket or until timeout occurs
Jim Flynnbbfe6032020-07-20 16:57:44 +0100103 int pollResult = arm::pipe::Poll(&m_Socket[0], 1, static_cast<int>(timeout));
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100104
105 switch (pollResult)
Colm Donelana21620d2019-10-11 13:09:49 +0100106 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100107 case -1: // Error
Jim Flynnbbfe6032020-07-20 16:57:44 +0100108 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000109 std::string("SocketProfilingConnection: Error occured while reading from socket: ") + strerror(errno),
110 m_Socket[0].fd,
111 errno);
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100112
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100113 case 0: // Timeout
Jim Flynnbbfe6032020-07-20 16:57:44 +0100114 throw arm::pipe::TimeoutException("SocketProfilingConnection: Timeout while reading from socket");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100115
116 default: // Normal poll return but it could still contain an error signal
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100117 // Check if the socket reported an error
118 if (m_Socket[0].revents & (POLLNVAL | POLLERR | POLLHUP))
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100119 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100120 if (m_Socket[0].revents == POLLNVAL)
121 {
122 // This is an unrecoverable error.
123 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100124 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000125 std::string("SocketProfilingConnection: Error occured while polling receiving socket: POLLNVAL."),
126 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100127 }
128 if (m_Socket[0].revents == POLLERR)
129 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100130 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000131 std::string(
132 "SocketProfilingConnection: Error occured while polling receiving socket: POLLERR: ")
133 + strerror(errno),
134 m_Socket[0].fd,
135 errno);
Colm Donelan9ea77002019-10-17 14:02:44 +0100136 }
137 if (m_Socket[0].revents == POLLHUP)
138 {
139 // This is an unrecoverable error.
140 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100141 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000142 std::string("SocketProfilingConnection: Connection closed by remote client: POLLHUP."),
143 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100144 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100145 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100146
147 // Check if there is data to read
148 if (!(m_Socket[0].revents & (POLLIN)))
149 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100150 // This is a corner case. The socket as been woken up but not with any data.
151 // We'll throw a timeout exception to loop around again.
Sadik Armagana97a0be2020-03-03 10:44:56 +0000152 throw armnn::TimeoutException(
153 "SocketProfilingConnection: File descriptor was polled but no data was available to receive.");
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100154 }
155
156 return ReceivePacket();
Colm Donelana21620d2019-10-11 13:09:49 +0100157 }
158}
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100159
Jim Flynnbbfe6032020-07-20 16:57:44 +0100160arm::pipe::Packet SocketProfilingConnection::ReceivePacket()
Colm Donelana21620d2019-10-11 13:09:49 +0100161{
162 char header[8] = {};
Jim Flynnbbfe6032020-07-20 16:57:44 +0100163 long receiveResult = arm::pipe::Read(m_Socket[0].fd, &header, sizeof(header));
Colm Donelan9ea77002019-10-17 14:02:44 +0100164 // We expect 8 as the result here. 0 means EOF, socket is closed. -1 means there been some other kind of error.
165 switch( receiveResult )
Colm Donelana21620d2019-10-11 13:09:49 +0100166 {
Colm Donelan9ea77002019-10-17 14:02:44 +0100167 case 0:
168 // Socket has closed.
169 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100170 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000171 std::string("SocketProfilingConnection: Remote socket has closed the connection."),
172 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100173 case -1:
174 // There's been a socket error. We will presume it's unrecoverable.
175 Close();
Jim Flynnbbfe6032020-07-20 16:57:44 +0100176 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000177 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
178 m_Socket[0].fd,
179 errno);
Colm Donelan9ea77002019-10-17 14:02:44 +0100180 default:
181 if (receiveResult < 8)
182 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100183 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000184 std::string(
185 "SocketProfilingConnection: The received packet did not contains a valid PIPE header."),
186 m_Socket[0].fd);
Colm Donelan9ea77002019-10-17 14:02:44 +0100187 }
188 break;
Colm Donelana21620d2019-10-11 13:09:49 +0100189 }
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100190
Colm Donelana21620d2019-10-11 13:09:49 +0100191 // stream_metadata_identifier is the first 4 bytes
192 uint32_t metadataIdentifier = 0;
193 std::memcpy(&metadataIdentifier, header, sizeof(metadataIdentifier));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100194
Colm Donelana21620d2019-10-11 13:09:49 +0100195 // data_length is the next 4 bytes
196 uint32_t dataLength = 0;
197 std::memcpy(&dataLength, header + 4u, sizeof(dataLength));
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100198
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100199 std::unique_ptr<unsigned char[]> packetData;
Colm Donelana21620d2019-10-11 13:09:49 +0100200 if (dataLength > 0)
201 {
Matteo Martincigh8d9590e2019-10-15 09:35:29 +0100202 packetData = std::make_unique<unsigned char[]>(dataLength);
Jim Flynnbbfe6032020-07-20 16:57:44 +0100203 long receivedLength = arm::pipe::Read(m_Socket[0].fd, packetData.get(), dataLength);
Jim Flynne11ff892019-10-04 04:25:43 -0700204 if (receivedLength < 0)
205 {
Jim Flynnbbfe6032020-07-20 16:57:44 +0100206 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000207 std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
208 m_Socket[0].fd,
209 errno);
Jim Flynne11ff892019-10-04 04:25:43 -0700210 }
211 if (dataLength != static_cast<uint32_t>(receivedLength))
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100212 {
213 // What do we do here if we can't read in a full packet?
Jim Flynnbbfe6032020-07-20 16:57:44 +0100214 throw arm::pipe::SocketConnectionException(
Sadik Armagana97a0be2020-03-03 10:44:56 +0000215 std::string("SocketProfilingConnection: Invalid PIPE packet."),
216 m_Socket[0].fd);
Matteo Martincigh24e8f922019-09-19 11:57:46 +0100217 }
FinnWilliamsArma0c78712019-09-16 12:06:47 +0100218 }
Colm Donelana21620d2019-10-11 13:09:49 +0100219
Jim Flynnbbfe6032020-07-20 16:57:44 +0100220 return arm::pipe::Packet(metadataIdentifier, dataLength, packetData);
Teresa Charlin9bab4962019-09-06 12:28:35 +0100221}
222
223} // namespace profiling
224} // namespace armnn