1 /*
2 * FreeRTOS V202212.00
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
24 *
25 */
26
27 /**
28 * @file sockets_wrapper.c
29 * @brief FreeRTOS Sockets connect and disconnect wrapper implementation.
30 */
31
32 /* Include header that defines log levels. */
33 #include "logging_levels.h"
34
35 /* Logging configuration for the Sockets. */
36 #ifndef LIBRARY_LOG_NAME
37 #define LIBRARY_LOG_NAME "SocketsWrapper"
38 #endif
39 #ifndef LIBRARY_LOG_LEVEL
40 #define LIBRARY_LOG_LEVEL LOG_INFO
41 #endif
42
43 extern void vLoggingPrintf( const char * pcFormatString,
44 ... );
45
46 #include "logging_stack.h"
47
48 /* Standard includes. */
49 #include <string.h>
50
51 /* FreeRTOS includes. */
52 #include "FreeRTOS.h"
53
54 #include "sockets_wrapper.h"
55
56 /*-----------------------------------------------------------*/
57
58 /* Maximum number of times to call FreeRTOS_recv when initiating a graceful shutdown. */
59 #ifndef FREERTOS_SOCKETS_WRAPPER_SHUTDOWN_LOOPS
60 #define FREERTOS_SOCKETS_WRAPPER_SHUTDOWN_LOOPS ( 3 )
61 #endif
62
63 /* A negative error code indicating a network failure. */
64 #define FREERTOS_SOCKETS_WRAPPER_NETWORK_ERROR ( -1 )
65
66 /*-----------------------------------------------------------*/
67
Sockets_Connect(Socket_t * pTcpSocket,const char * pHostName,uint16_t port,uint32_t receiveTimeoutMs,uint32_t sendTimeoutMs)68 BaseType_t Sockets_Connect( Socket_t * pTcpSocket,
69 const char * pHostName,
70 uint16_t port,
71 uint32_t receiveTimeoutMs,
72 uint32_t sendTimeoutMs )
73 {
74 Socket_t tcpSocket = FREERTOS_INVALID_SOCKET;
75 BaseType_t socketStatus = 0;
76 struct freertos_sockaddr serverAddress = { 0 };
77 TickType_t transportTimeout = 0;
78
79 /* Create a new TCP socket. */
80 tcpSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
81
82 if( tcpSocket == FREERTOS_INVALID_SOCKET )
83 {
84 LogError( ( "Failed to create new socket." ) );
85 socketStatus = FREERTOS_SOCKETS_WRAPPER_NETWORK_ERROR;
86 }
87 else
88 {
89 LogDebug( ( "Created new TCP socket." ) );
90
91 /* Connection parameters. */
92 serverAddress.sin_family = FREERTOS_AF_INET;
93 serverAddress.sin_port = FreeRTOS_htons( port );
94 serverAddress.sin_len = ( uint8_t ) sizeof( serverAddress );
95
96 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 )
97 serverAddress.sin_address.ulIP_IPv4 = ( uint32_t ) FreeRTOS_gethostbyname( pHostName );
98
99 /* Check for errors from DNS lookup. */
100 if( serverAddress.sin_address.ulIP_IPv4 == 0U )
101 #else
102 serverAddress.sin_addr = ( uint32_t ) FreeRTOS_gethostbyname( pHostName );
103
104 /* Check for errors from DNS lookup. */
105 if( serverAddress.sin_addr == 0U )
106 #endif /* defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 0 ) */
107
108 {
109 LogError( ( "Failed to connect to server: DNS resolution failed: Hostname=%s.",
110 pHostName ) );
111 socketStatus = FREERTOS_SOCKETS_WRAPPER_NETWORK_ERROR;
112 }
113 }
114
115 if( socketStatus == 0 )
116 {
117 /* Establish connection. */
118 LogDebug( ( "Creating TCP Connection to %s.", pHostName ) );
119 socketStatus = FreeRTOS_connect( tcpSocket, &serverAddress, sizeof( serverAddress ) );
120
121 if( socketStatus != 0 )
122 {
123 LogError( ( "Failed to connect to server: FreeRTOS_Connect failed: ReturnCode=%d,"
124 " Hostname=%s, Port=%u.",
125 socketStatus,
126 pHostName,
127 port ) );
128 }
129 }
130
131 if( socketStatus == 0 )
132 {
133 /* Set socket receive timeout. */
134 transportTimeout = pdMS_TO_TICKS( receiveTimeoutMs );
135 /* Setting the receive block time cannot fail. */
136 ( void ) FreeRTOS_setsockopt( tcpSocket,
137 0,
138 FREERTOS_SO_RCVTIMEO,
139 &transportTimeout,
140 sizeof( TickType_t ) );
141
142 /* Set socket send timeout. */
143 transportTimeout = pdMS_TO_TICKS( sendTimeoutMs );
144 /* Setting the send block time cannot fail. */
145 ( void ) FreeRTOS_setsockopt( tcpSocket,
146 0,
147 FREERTOS_SO_SNDTIMEO,
148 &transportTimeout,
149 sizeof( TickType_t ) );
150 }
151
152 /* Clean up on failure. */
153 if( socketStatus != 0 )
154 {
155 if( tcpSocket != FREERTOS_INVALID_SOCKET )
156 {
157 ( void ) FreeRTOS_closesocket( tcpSocket );
158 }
159 }
160 else
161 {
162 /* Set the socket. */
163 *pTcpSocket = tcpSocket;
164 LogInfo( ( "Established TCP connection with %s.", pHostName ) );
165 }
166
167 return socketStatus;
168 }
169
170 /*-----------------------------------------------------------*/
171
Sockets_Disconnect(Socket_t tcpSocket)172 void Sockets_Disconnect( Socket_t tcpSocket )
173 {
174 BaseType_t waitForShutdownLoopCount = 0;
175 uint8_t pDummyBuffer[ 2 ];
176
177 if( tcpSocket != FREERTOS_INVALID_SOCKET )
178 {
179 /* Initiate graceful shutdown. */
180 ( void ) FreeRTOS_shutdown( tcpSocket, FREERTOS_SHUT_RDWR );
181
182 /* Wait for the socket to disconnect gracefully (indicated by FreeRTOS_recv()
183 * returning a FREERTOS_EINVAL error) before closing the socket. */
184 while( FreeRTOS_recv( tcpSocket, pDummyBuffer, sizeof( pDummyBuffer ), 0 ) >= 0 )
185 {
186 /* We don't need to delay since FreeRTOS_recv should already have a timeout. */
187
188 if( ++waitForShutdownLoopCount >= FREERTOS_SOCKETS_WRAPPER_SHUTDOWN_LOOPS )
189 {
190 break;
191 }
192 }
193
194 ( void ) FreeRTOS_closesocket( tcpSocket );
195 }
196 }
197
198 /*-----------------------------------------------------------*/
199