F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
TcpServerSocket.cpp
Go to the documentation of this file.
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 // ======================================================================
13 #include <Fw/Logger/Logger.hpp>
14 #include <Fw/Types/Assert.hpp>
15 #include <FpConfig.hpp>
16 
17 #ifdef TGT_OS_TYPE_VXWORKS
18  #include <socket.h>
19  #include <inetLib.h>
20  #include <fioLib.h>
21  #include <hostLib.h>
22  #include <ioLib.h>
23  #include <vxWorks.h>
24  #include <sockLib.h>
25  #include <taskLib.h>
26  #include <sysLib.h>
27  #include <errnoLib.h>
28  #include <cstring>
29 #elif defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN
30  #include <sys/socket.h>
31  #include <unistd.h>
32  #include <arpa/inet.h>
33 #else
34  #error OS not supported for IP Socket Communications
35 #endif
36 
37 #include <cstring>
38 
39 namespace Drv {
40 
42 
44  this->m_lock.lock();
45  U16 port = this->m_port;
46  this->m_lock.unlock();
47  return port;
48 }
49 
51  NATIVE_INT_TYPE serverFd = -1;
52  struct sockaddr_in address;
53  this->close();
54  // Acquire a socket, or return error
55  if ((serverFd = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) {
57  }
58  // Set up the address port and name
59  address.sin_family = AF_INET;
60  this->m_lock.lock();
61  address.sin_port = htons(this->m_port);
62  this->m_lock.unlock();
63 
64  // OS specific settings
65 #if defined TGT_OS_TYPE_VXWORKS || TGT_OS_TYPE_DARWIN
66  address.sin_len = static_cast<U8>(sizeof(struct sockaddr_in));
67 #endif
68  // First IP address to socket sin_addr
69  if (IpSocket::addressToIp4(m_hostname, &(address.sin_addr)) != SOCK_SUCCESS) {
70  ::close(serverFd);
72  };
73 
74  // TCP requires bind to an address to the socket
75  if (::bind(serverFd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)) < 0) {
76  ::close(serverFd);
77  return SOCK_FAILED_TO_BIND;
78  }
79 
80  socklen_t size = sizeof(address);
81  if (::getsockname(serverFd, reinterpret_cast<struct sockaddr *>(&address), &size) == -1) {
82  ::close(serverFd);
84  }
85  U16 port = ntohs(address.sin_port);
86  Fw::Logger::logMsg("Listening for single client at %s:%hu\n", reinterpret_cast<POINTER_CAST>(m_hostname), port);
87  // TCP requires listening on the socket. Since we only expect a single client, set the TCP backlog (second argument) to 1 to prevent queuing of multiple clients.
88  if (::listen(serverFd, 1) < 0) {
89  ::close(serverFd);
90  return SOCK_FAILED_TO_LISTEN; // What we have here is a failure to communicate
91  }
92 
93  this->m_lock.lock();
94  m_base_fd = serverFd;
95  m_port = port;
96  this->m_lock.unLock();
97 
98  return this->IpSocket::startup();
99 }
100 
102  this->m_lock.lock();
103  if (this->m_base_fd != -1) {
104  (void)::shutdown(this->m_base_fd, SHUT_RDWR);
105  (void)::close(this->m_base_fd);
106  this->m_base_fd = -1;
107  }
108  this->m_lock.unLock();
109  this->IpSocket::shutdown();
110 }
111 
113  NATIVE_INT_TYPE clientFd = -1;
114  NATIVE_INT_TYPE serverFd = -1;
115 
116  // Check started before allowing open
117  if (not this->isStarted()) {
118  return SOCK_NOT_STARTED;
119  }
120 
121  this->m_lock.lock();
122  serverFd = this->m_base_fd;
123  this->m_lock.unLock();
124 
125  // TCP requires accepting on the socket to get the client socket file descriptor.
126  clientFd = ::accept(serverFd, nullptr, nullptr);
127  if (clientFd < 0) {
128  return SOCK_FAILED_TO_ACCEPT; // What we have here is a failure to communicate
129  }
130  // Setup client send timeouts
131  if (IpSocket::setupTimeouts(clientFd) != SOCK_SUCCESS) {
132  ::close(clientFd);
134  }
135 
136  Fw::Logger::logMsg("Accepted client at %s:%hu\n", reinterpret_cast<POINTER_CAST>(m_hostname), m_port);
137  fd = clientFd;
138  return SOCK_SUCCESS;
139 }
140 
141 I32 TcpServerSocket::sendProtocol(const U8* const data, const U32 size) {
142  return static_cast<I32>(::send(this->m_fd, data, size, SOCKET_IP_SEND_FLAGS));
143 }
144 
145 I32 TcpServerSocket::recvProtocol(U8* const data, const U32 size) {
146  return static_cast<I32>(::recv(this->m_fd, data, size, SOCKET_IP_RECV_FLAGS));
147 }
148 
149 } // namespace Drv
PlatformPointerCastType POINTER_CAST
Definition: BasicTypes.h:53
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:26
C++-compatible configuration header for fprime configuration.
@ SOCKET_IP_RECV_FLAGS
Definition: IpCfg.hpp:20
@ SOCKET_IP_SEND_FLAGS
Definition: IpCfg.hpp:19
Helper base-class for setting up Berkeley sockets.
Definition: IpSocket.hpp:47
void close()
closes the socket
Definition: IpSocket.cpp:123
U16 m_port
IP address port used.
Definition: IpSocket.hpp:219
bool isStarted()
Returns true when the socket is started.
Definition: IpSocket.cpp:107
char m_hostname[SOCKET_MAX_HOSTNAME_SIZE]
Hostname to supply.
Definition: IpSocket.hpp:222
SocketIpStatus send(const U8 *const data, const U32 size)
send data out the IP socket from the given buffer
Definition: IpSocket.cpp:168
Os::Mutex m_lock
Definition: IpSocket.hpp:215
static SocketIpStatus addressToIp4(const char *address, void *ip4)
converts a given address in dot form x.x.x.x to an ip address. ONLY works for IPv4.
Definition: IpSocket.cpp:86
NATIVE_INT_TYPE m_fd
Definition: IpSocket.hpp:216
SocketIpStatus recv(U8 *const data, U32 &size)
receive data from the IP socket from the given buffer
Definition: IpSocket.cpp:207
SocketIpStatus setupTimeouts(NATIVE_INT_TYPE socketFd)
setup the socket timeout properties of the opened outgoing socket
Definition: IpSocket.cpp:69
virtual void shutdown()
shutdown the socket
Definition: IpSocket.cpp:134
virtual SocketIpStatus startup()
startup the socket, a no-op on unless this is server
Definition: IpSocket.cpp:141
TcpServerSocket()
Constructor for client socket tcp implementation.
I32 sendProtocol(const U8 *const data, const U32 size) override
Protocol specific implementation of send. Called directly with retry from send.
SocketIpStatus openProtocol(NATIVE_INT_TYPE &fd) override
Tcp specific implementation for opening a client socket connected to this server.
void shutdown() override
Shutdown and close the server socket followed by the open client.
I32 recvProtocol(U8 *const data, const U32 size) override
Protocol specific implementation of recv. Called directly with error handling from recv.
U16 getListenPort()
get the port being listened on
SocketIpStatus startup() override
Opens the server socket and listens, does not block.
static void logMsg(const char *fmt, POINTER_CAST a0=0, POINTER_CAST a1=0, POINTER_CAST a2=0, POINTER_CAST a3=0, POINTER_CAST a4=0, POINTER_CAST a5=0, POINTER_CAST a6=0, POINTER_CAST a7=0, POINTER_CAST a8=0, POINTER_CAST a9=0)
Definition: Logger.cpp:18
void unlock()
alias for unLock to meet BasicLockable requirements
Definition: Mutex.hpp:16
void unLock()
unlock the mutex
Definition: Mutex.cpp:13
void lock()
lock the mutex
Definition: Mutex.cpp:12
SocketIpStatus
Status enumeration for socket return values.
Definition: IpSocket.hpp:23
@ SOCK_INVALID_IP_ADDRESS
Bad IP address supplied.
Definition: IpSocket.hpp:27
@ SOCK_FAILED_TO_ACCEPT
Failed to accept connection.
Definition: IpSocket.hpp:35
@ SOCK_SUCCESS
Socket operation successful.
Definition: IpSocket.hpp:24
@ SOCK_FAILED_TO_BIND
Failed to bind to socket.
Definition: IpSocket.hpp:33
@ SOCK_FAILED_TO_SET_SOCKET_OPTIONS
Failed to configure socket.
Definition: IpSocket.hpp:29
@ SOCK_FAILED_TO_GET_SOCKET
Socket open failed.
Definition: IpSocket.hpp:25
@ SOCK_FAILED_TO_LISTEN
Failed to listen on socket.
Definition: IpSocket.hpp:34
@ SOCK_FAILED_TO_READ_BACK_PORT
Failed to read back port from connection.
Definition: IpSocket.hpp:38
@ SOCK_NOT_STARTED
Socket has not been started.
Definition: IpSocket.hpp:37