GCC Code Coverage Report


Directory: Drv/Ip/
File: TcpServerSocket.cpp
Date: 2026-11-03 21:16:25
Exec Total Coverage
Lines: 43 60 71.7%
Functions: 7 7 100.0%
Branches: 14 30 46.7%

Line Branch Exec Source
1 // ======================================================================
2 // \title TcpServerSocket.cpp
3 // \author mstarch
4 // \brief cpp file for TcpServerSocket core implementation classes
5 //
6 // \copyright
7 // Copyright 2009-2020, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 #include <Drv/Ip/TcpServerSocket.hpp>
13 #include <Fw/FPrimeBasicTypes.hpp>
14 #include <Fw/Logger/Logger.hpp>
15 #include <Fw/Types/Assert.hpp>
16
17 #include <cstring>
18
19 namespace Drv {
20
21 4 TcpServerSocket::TcpServerSocket() : IpSocket() {}
22
23 103 U16 TcpServerSocket::getListenPort() {
24 103 U16 port = this->m_port;
25 103 return port;
26 }
27
28 4 SocketIpStatus TcpServerSocket::startup(SocketDescriptor& socketDescriptor) {
29 4 struct sockaddr_in address;
30 // Acquire a socket, or return error
31 4 int serverFd = ::socket(AF_INET, SOCK_STREAM, 0);
32
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (serverFd == -1) {
33 ✗ return SOCK_FAILED_TO_GET_SOCKET;
34 }
35 // Set up the address port and name
36 4 address.sin_family = AF_INET;
37 4 address.sin_port = htons(this->m_port);
38
39 // OS specific settings
40 #if defined TGT_OS_TYPE_VXWORKS || TGT_OS_TYPE_DARWIN
41 address.sin_len = static_cast<U8>(sizeof(struct sockaddr_in));
42 #endif
43 // Convert the configured IPv4 address (dotted-quad) to a network-order in_addr.
44
1/1
✓ Branch 3 taken 4 times.
4 const SocketIpStatus addressStatus = IpSocket::addressToIp4(this->m_ipv4_address, &(address.sin_addr));
45
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (addressStatus != SOCK_SUCCESS) {
46 ✗ (void)::close(serverFd);
47 ✗ return SOCK_INVALID_IP_ADDRESS;
48 };
49
50
2/3
✓ Branch 5 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
4 if (IpSocket::setupSocketOptions(serverFd) != SOCK_SUCCESS) {
51 ✗ (void)::close(serverFd);
52 ✗ return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
53 }
54
55 // TCP requires bind to an address to the socket
56
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (::bind(serverFd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) < 0) {
57 ✗ (void)::close(serverFd);
58 ✗ return SOCK_FAILED_TO_BIND;
59 }
60
61 4 socklen_t size = sizeof(address);
62 4 const int socknameStatus = ::getsockname(serverFd, reinterpret_cast<struct sockaddr*>(&address), &size);
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (socknameStatus == -1) {
64 ✗ (void)::close(serverFd);
65 ✗ return SOCK_FAILED_TO_READ_BACK_PORT;
66 }
67 // TCP requires listening on the socket. Since we only expect a single client, set the TCP backlog (second argument)
68 // to 1 to prevent queuing of multiple clients.
69
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (::listen(serverFd, 1) < 0) {
70 ✗ (void)::close(serverFd);
71 ✗ return SOCK_FAILED_TO_LISTEN; // What we have here is a failure to communicate
72 }
73
1/1
✓ Branch 8 taken 4 times.
4 Fw::Logger::log("Listening for single client at %s:%hu\n", this->m_ipv4_address, this->m_port);
74 4 FW_ASSERT(serverFd != -1);
75 4 socketDescriptor.serverFd = serverFd;
76 4 this->m_port = ntohs(address.sin_port);
77 4 return SOCK_SUCCESS;
78 }
79
80 4 void TcpServerSocket::terminate(const SocketDescriptor& socketDescriptor) {
81
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (socketDescriptor.serverFd >= 0) {
82 4 (void)::shutdown(socketDescriptor.serverFd, SHUT_RDWR); // Shutdown first to avoid hanging "accept" calls
83 4 (void)::close(socketDescriptor.serverFd);
84 }
85 4 }
86
87 103 SocketIpStatus TcpServerSocket::openProtocol(SocketDescriptor& socketDescriptor) {
88 103 int clientFd = -1;
89 103 int serverFd = socketDescriptor.serverFd;
90
91 // Check for not started yet, may be true in the case of start-up reconnect attempts
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (serverFd == -1) {
93 ✗ return SOCK_NOT_STARTED;
94 }
95
96 // TCP requires accepting on the socket to get the client socket file descriptor.
97 103 clientFd = ::accept(serverFd, nullptr, nullptr);
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (clientFd < 0) {
99 ✗ return SOCK_FAILED_TO_ACCEPT; // What we have here is a failure to communicate
100 }
101 // Setup client send timeouts
102
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 103 times.
103 if (IpSocket::setupTimeouts(clientFd) != SOCK_SUCCESS) {
103 ✗ (void)::close(clientFd);
104 ✗ return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
105 }
106 // Sends to a client that has disconnected must not raise SIGPIPE
107
1/2
✗ Branch 5 not taken.
✓ Branch 6 taken 103 times.
103 if (IpSocket::setupNoSigPipe(clientFd) != SOCK_SUCCESS) {
108 ✗ (void)::close(clientFd);
109 ✗ return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
110 }
111
112 103 Fw::Logger::log("Accepted client at %s:%hu\n", this->m_ipv4_address, this->m_port);
113 103 socketDescriptor.fd = clientFd;
114 103 return SOCK_SUCCESS;
115 }
116
117 103 FwSignedSizeType TcpServerSocket::sendProtocol(const SocketDescriptor& socketDescriptor,
118 const U8* const data,
119 const FwSizeType size) {
120 return static_cast<FwSignedSizeType>(
121 103 ::send(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_SEND_FLAGS | SEND_NO_SIGNAL_FLAGS));
122 }
123
124 202 FwSignedSizeType TcpServerSocket::recvProtocol(const SocketDescriptor& socketDescriptor,
125 U8* const data,
126 const FwSizeType size) {
127 // recv will return 0 if the client has done an orderly shutdown
128 return static_cast<FwSignedSizeType>(
129 202 ::recv(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_RECV_FLAGS));
130 }
131
132 } // namespace Drv
133