GCC Code Coverage Report


Directory: ./
File: Drv/Ip/TcpServerSocket.cpp
Date: 2026-09-03 22:12:29
Exec Total Coverage
Lines: 0 56 0.0%
Functions: 0 7 0.0%
Branches: 0 28 0.0%

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 #ifdef TGT_OS_TYPE_VXWORKS
18 #include <errnoLib.h>
19 #include <fioLib.h>
20 #include <hostLib.h>
21 #include <inetLib.h>
22 #include <ioLib.h>
23 #include <sockLib.h>
24 #include <socket.h>
25 #include <sysLib.h>
26 #include <taskLib.h>
27 #include <vxWorks.h>
28 #include <cstring>
29 #elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
30 #include <arpa/inet.h>
31 #include <sys/socket.h>
32 #include <unistd.h>
33 #else
34 #error OS not supported for IP Socket Communications
35 #endif
36
37 #include <cstring>
38
39 namespace Drv {
40
41 TcpServerSocket::TcpServerSocket() : IpSocket() {}
42
43 U16 TcpServerSocket::getListenPort() {
44 U16 port = this->m_port;
45 return port;
46 }
47
48 SocketIpStatus TcpServerSocket::startup(SocketDescriptor& socketDescriptor) {
49 struct sockaddr_in address;
50 // Acquire a socket, or return error
51 int serverFd = ::socket(AF_INET, SOCK_STREAM, 0);
52 if (serverFd == -1) {
53 return SOCK_FAILED_TO_GET_SOCKET;
54 }
55 // Set up the address port and name
56 address.sin_family = AF_INET;
57 address.sin_port = htons(this->m_port);
58
59 // OS specific settings
60 #if defined TGT_OS_TYPE_VXWORKS || TGT_OS_TYPE_DARWIN
61 address.sin_len = static_cast<U8>(sizeof(struct sockaddr_in));
62 #endif
63 // Convert the configured IPv4 address (dotted-quad) to a network-order in_addr.
64 const SocketIpStatus addressStatus = IpSocket::addressToIp4(this->m_ipv4_address, &(address.sin_addr));
65 if (addressStatus != SOCK_SUCCESS) {
66 (void)::close(serverFd);
67 return SOCK_INVALID_IP_ADDRESS;
68 };
69
70 if (IpSocket::setupSocketOptions(serverFd) != SOCK_SUCCESS) {
71 (void)::close(serverFd);
72 return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
73 }
74
75 // TCP requires bind to an address to the socket
76 if (::bind(serverFd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) < 0) {
77 (void)::close(serverFd);
78 return SOCK_FAILED_TO_BIND;
79 }
80
81 socklen_t size = sizeof(address);
82 const int socknameStatus = ::getsockname(serverFd, reinterpret_cast<struct sockaddr*>(&address), &size);
83 if (socknameStatus == -1) {
84 (void)::close(serverFd);
85 return SOCK_FAILED_TO_READ_BACK_PORT;
86 }
87 // TCP requires listening on the socket. Since we only expect a single client, set the TCP backlog (second argument)
88 // to 1 to prevent queuing of multiple clients.
89 if (::listen(serverFd, 1) < 0) {
90 (void)::close(serverFd);
91 return SOCK_FAILED_TO_LISTEN; // What we have here is a failure to communicate
92 }
93 Fw::Logger::log("Listening for single client at %s:%hu\n", this->m_ipv4_address, this->m_port);
94 FW_ASSERT(serverFd != -1);
95 socketDescriptor.serverFd = serverFd;
96 this->m_port = ntohs(address.sin_port);
97 return SOCK_SUCCESS;
98 }
99
100 void TcpServerSocket::terminate(const SocketDescriptor& socketDescriptor) {
101 if (socketDescriptor.serverFd >= 0) {
102 (void)::shutdown(socketDescriptor.serverFd, SHUT_RDWR); // Shutdown first to avoid hanging "accept" calls
103 (void)::close(socketDescriptor.serverFd);
104 }
105 }
106
107 SocketIpStatus TcpServerSocket::openProtocol(SocketDescriptor& socketDescriptor) {
108 int clientFd = -1;
109 int serverFd = socketDescriptor.serverFd;
110
111 // Check for not started yet, may be true in the case of start-up reconnect attempts
112 if (serverFd == -1) {
113 return SOCK_NOT_STARTED;
114 }
115
116 // TCP requires accepting on the socket to get the client socket file descriptor.
117 clientFd = ::accept(serverFd, nullptr, nullptr);
118 if (clientFd < 0) {
119 return SOCK_FAILED_TO_ACCEPT; // What we have here is a failure to communicate
120 }
121 // Setup client send timeouts
122 if (IpSocket::setupTimeouts(clientFd) != SOCK_SUCCESS) {
123 (void)::close(clientFd);
124 return SOCK_FAILED_TO_SET_SOCKET_OPTIONS;
125 }
126
127 Fw::Logger::log("Accepted client at %s:%hu\n", this->m_ipv4_address, this->m_port);
128 socketDescriptor.fd = clientFd;
129 return SOCK_SUCCESS;
130 }
131
132 FwSignedSizeType TcpServerSocket::sendProtocol(const SocketDescriptor& socketDescriptor,
133 const U8* const data,
134 const FwSizeType size) {
135 return static_cast<FwSignedSizeType>(
136 ::send(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_SEND_FLAGS));
137 }
138
139 FwSignedSizeType TcpServerSocket::recvProtocol(const SocketDescriptor& socketDescriptor,
140 U8* const data,
141 const FwSizeType size) {
142 // recv will return 0 if the client has done an orderly shutdown
143 return static_cast<FwSignedSizeType>(
144 ::recv(socketDescriptor.fd, data, static_cast<size_t>(size), SOCKET_IP_RECV_FLAGS));
145 }
146
147 } // namespace Drv
148