]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/abstractions/secure_sockets/freertos_plus_tcp/iot_secure_sockets.c
af809c24c06fa0ff4ce129bc163b625a3c2b76f7
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / abstractions / secure_sockets / freertos_plus_tcp / iot_secure_sockets.c
1 /*\r
2  * Amazon FreeRTOS Secure Sockets V1.1.5\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /* Define _SECURE_SOCKETS_WRAPPER_NOT_REDEFINE to prevent secure sockets functions\r
27  * from redefining in iot_secure_sockets_wrapper_metrics.h */\r
28 #define _SECURE_SOCKETS_WRAPPER_NOT_REDEFINE\r
29 \r
30 /* FreeRTOS includes. */\r
31 #include "FreeRTOS.h"\r
32 #include "FreeRTOSIPConfig.h"\r
33 #include "list.h"\r
34 #include "semphr.h"\r
35 #include "FreeRTOS_IP.h"\r
36 #include "FreeRTOS_Sockets.h"\r
37 #include "iot_secure_sockets.h"\r
38 #include "task.h"\r
39 \r
40 #undef _SECURE_SOCKETS_WRAPPER_NOT_REDEFINE\r
41 \r
42 /* Internal context structure. */\r
43 typedef struct SSOCKETContext\r
44 {\r
45     Socket_t xSocket;\r
46     char * pcDestination;\r
47     BaseType_t xSendFlags;\r
48     BaseType_t xRecvFlags;\r
49     BaseType_t xConnectAttempted;\r
50 } SSOCKETContext_t, * SSOCKETContextPtr_t;\r
51 \r
52 /*\r
53  * Helper routines.\r
54  */\r
55 \r
56 /*\r
57  * @brief Network send callback.\r
58  */\r
59 static BaseType_t prvNetworkSend( void * pvContext,\r
60                                   const unsigned char * pucData,\r
61                                   size_t xDataLength )\r
62 {\r
63     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) pvContext; /*lint !e9087 cast used for portability. */\r
64 \r
65     return FreeRTOS_send( pxContext->xSocket, pucData, xDataLength, pxContext->xSendFlags );\r
66 }\r
67 /*-----------------------------------------------------------*/\r
68 \r
69 /*\r
70  * @brief Network receive callback.\r
71  */\r
72 static BaseType_t prvNetworkRecv( void * pvContext,\r
73                                   unsigned char * pucReceiveBuffer,\r
74                                   size_t xReceiveLength )\r
75 {\r
76     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) pvContext; /*lint !e9087 cast used for portability. */\r
77 \r
78     return FreeRTOS_recv( pxContext->xSocket, pucReceiveBuffer, xReceiveLength, pxContext->xRecvFlags );\r
79 }\r
80 /*-----------------------------------------------------------*/\r
81 \r
82 /*\r
83  * Interface routines.\r
84  */\r
85 \r
86 int32_t SOCKETS_Close( Socket_t xSocket )\r
87 {\r
88     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */\r
89     int32_t lReturn;\r
90 \r
91     if( ( xSocket != SOCKETS_INVALID_SOCKET ) && ( NULL != pxContext ) )\r
92     {\r
93         /* Clean-up destination string. */\r
94         if( NULL != pxContext->pcDestination )\r
95         {\r
96             vPortFree( pxContext->pcDestination );\r
97         }\r
98 \r
99         /* Close the underlying socket handle. */\r
100         ( void ) FreeRTOS_closesocket( pxContext->xSocket );\r
101 \r
102         /* Free the context. */\r
103         vPortFree( pxContext );\r
104         lReturn = SOCKETS_ERROR_NONE;\r
105     }\r
106     else\r
107     {\r
108         lReturn = SOCKETS_EINVAL;\r
109     }\r
110 \r
111     return lReturn;\r
112 }\r
113 /*-----------------------------------------------------------*/\r
114 \r
115 int32_t SOCKETS_Connect( Socket_t xSocket,\r
116                          SocketsSockaddr_t * pxAddress,\r
117                          Socklen_t xAddressLength )\r
118 {\r
119     int32_t lStatus = SOCKETS_ERROR_NONE;\r
120     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */\r
121     struct freertos_sockaddr xTempAddress = { 0 };\r
122 \r
123     if( ( pxContext != SOCKETS_INVALID_SOCKET ) && ( pxAddress != NULL ) )\r
124     {\r
125         /* A connection was attempted. If this function fails, then the socket is invalid and the user\r
126          * must call SOCKETS_Close(), on this socket, and SOCKETS_Socket() to get a new socket. */\r
127         pxContext->xConnectAttempted = pdTRUE;\r
128 \r
129         /* Connect the wrapped socket. */\r
130         xTempAddress.sin_addr = pxAddress->ulAddress;\r
131         xTempAddress.sin_family = pxAddress->ucSocketDomain;\r
132         xTempAddress.sin_len = ( uint8_t ) sizeof( xTempAddress );\r
133         xTempAddress.sin_port = pxAddress->usPort;\r
134         lStatus = FreeRTOS_connect( pxContext->xSocket, &xTempAddress, xAddressLength );\r
135     }\r
136     else\r
137     {\r
138         lStatus = SOCKETS_SOCKET_ERROR;\r
139     }\r
140 \r
141     return lStatus;\r
142 }\r
143 /*-----------------------------------------------------------*/\r
144 \r
145 uint32_t SOCKETS_GetHostByName( const char * pcHostName )\r
146 {\r
147     return FreeRTOS_gethostbyname( pcHostName );\r
148 }\r
149 /*-----------------------------------------------------------*/\r
150 \r
151 int32_t SOCKETS_Recv( Socket_t xSocket,\r
152                       void * pvBuffer,\r
153                       size_t xBufferLength,\r
154                       uint32_t ulFlags )\r
155 {\r
156     int32_t lStatus = SOCKETS_SOCKET_ERROR;\r
157     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */\r
158 \r
159     if( ( xSocket != SOCKETS_INVALID_SOCKET ) &&\r
160         ( pvBuffer != NULL ) )\r
161     {\r
162         pxContext->xRecvFlags = ( BaseType_t ) ulFlags;\r
163 \r
164         /* Receive unencrypted. */\r
165         lStatus = prvNetworkRecv( pxContext, pvBuffer, xBufferLength );\r
166     }\r
167     else\r
168     {\r
169         lStatus = SOCKETS_EINVAL;\r
170     }\r
171 \r
172     return lStatus;\r
173 }\r
174 /*-----------------------------------------------------------*/\r
175 \r
176 int32_t SOCKETS_Send( Socket_t xSocket,\r
177                       const void * pvBuffer,\r
178                       size_t xDataLength,\r
179                       uint32_t ulFlags )\r
180 {\r
181     int32_t lStatus = SOCKETS_SOCKET_ERROR;\r
182     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */\r
183 \r
184     if( ( xSocket != SOCKETS_INVALID_SOCKET ) &&\r
185         ( pvBuffer != NULL ) )\r
186     {\r
187         pxContext->xSendFlags = ( BaseType_t ) ulFlags;\r
188 \r
189         /* Send unencrypted. */\r
190         lStatus = prvNetworkSend( pxContext, pvBuffer, xDataLength );\r
191     }\r
192     else\r
193     {\r
194         lStatus = SOCKETS_EINVAL;\r
195     }\r
196 \r
197     return lStatus;\r
198 }\r
199 /*-----------------------------------------------------------*/\r
200 \r
201 int32_t SOCKETS_SetSockOpt( Socket_t xSocket,\r
202                             int32_t lLevel,\r
203                             int32_t lOptionName,\r
204                             const void * pvOptionValue,\r
205                             size_t xOptionLength )\r
206 {\r
207     int32_t lStatus = SOCKETS_ERROR_NONE;\r
208     TickType_t xTimeout;\r
209     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */\r
210 \r
211     if( ( xSocket != SOCKETS_INVALID_SOCKET ) && ( xSocket != NULL ) )\r
212     {\r
213         switch( lOptionName )\r
214         {\r
215             case SOCKETS_SO_NONBLOCK:\r
216                 xTimeout = 0;\r
217 \r
218                 /* Non-blocking connect is not supported.  Socket may be set to nonblocking\r
219                  * only after a connection is made. */\r
220                 if( pdTRUE == pxContext->xConnectAttempted )\r
221                 {\r
222                     lStatus = FreeRTOS_setsockopt( pxContext->xSocket,\r
223                                                    lLevel,\r
224                                                    SOCKETS_SO_RCVTIMEO,\r
225                                                    &xTimeout,\r
226                                                    sizeof( xTimeout ) );\r
227 \r
228                     if( lStatus == SOCKETS_ERROR_NONE )\r
229                     {\r
230                         lStatus = FreeRTOS_setsockopt( pxContext->xSocket,\r
231                                                        lLevel,\r
232                                                        SOCKETS_SO_SNDTIMEO,\r
233                                                        &xTimeout,\r
234                                                        sizeof( xTimeout ) );\r
235                     }\r
236                 }\r
237                 else\r
238                 {\r
239                     lStatus = SOCKETS_EISCONN;\r
240                 }\r
241 \r
242                 break;\r
243 \r
244             case SOCKETS_SO_RCVTIMEO:\r
245             case SOCKETS_SO_SNDTIMEO:\r
246                 /* Comply with Berkeley standard - a 0 timeout is wait forever. */\r
247                 xTimeout = *( ( const TickType_t * ) pvOptionValue ); /*lint !e9087 pvOptionValue passed should be of TickType_t */\r
248 \r
249                 if( xTimeout == 0U )\r
250                 {\r
251                     xTimeout = portMAX_DELAY;\r
252                 }\r
253 \r
254                 lStatus = FreeRTOS_setsockopt( pxContext->xSocket,\r
255                                                lLevel,\r
256                                                lOptionName,\r
257                                                &xTimeout,\r
258                                                xOptionLength );\r
259                 break;\r
260 \r
261             default:\r
262                 lStatus = FreeRTOS_setsockopt( pxContext->xSocket,\r
263                                                lLevel,\r
264                                                lOptionName,\r
265                                                pvOptionValue,\r
266                                                xOptionLength );\r
267                 break;\r
268         }\r
269     }\r
270     else\r
271     {\r
272         lStatus = SOCKETS_EINVAL;\r
273     }\r
274 \r
275     return lStatus;\r
276 }\r
277 /*-----------------------------------------------------------*/\r
278 \r
279 int32_t SOCKETS_Shutdown( Socket_t xSocket,\r
280                           uint32_t ulHow )\r
281 {\r
282     int32_t lReturn;\r
283     SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */\r
284 \r
285     if( ( xSocket != SOCKETS_INVALID_SOCKET ) && ( xSocket != NULL ) )\r
286     {\r
287         lReturn = FreeRTOS_shutdown( pxContext->xSocket, ( BaseType_t ) ulHow );\r
288     }\r
289     else\r
290     {\r
291         lReturn = SOCKETS_EINVAL;\r
292     }\r
293 \r
294     return lReturn;\r
295 }\r
296 /*-----------------------------------------------------------*/\r
297 \r
298 Socket_t SOCKETS_Socket( int32_t lDomain,\r
299                          int32_t lType,\r
300                          int32_t lProtocol )\r
301 {\r
302     SSOCKETContextPtr_t pxContext = NULL;\r
303     Socket_t xSocket;\r
304 \r
305     /* Ensure that only supported values are supplied. */\r
306     configASSERT( lDomain == SOCKETS_AF_INET );\r
307     configASSERT( lType == SOCKETS_SOCK_STREAM );\r
308     configASSERT( lProtocol == SOCKETS_IPPROTO_TCP );\r
309 \r
310     /* Create the wrapped socket. */\r
311     xSocket = FreeRTOS_socket( lDomain, lType, lProtocol );\r
312 \r
313     if( xSocket != FREERTOS_INVALID_SOCKET )\r
314     {\r
315         /* Allocate the internal context structure. */\r
316         if( NULL == ( pxContext = pvPortMalloc( sizeof( SSOCKETContext_t ) ) ) )\r
317         {\r
318             /* Need to close socket. */\r
319             ( void ) FreeRTOS_closesocket( xSocket );\r
320             pxContext = SOCKETS_INVALID_SOCKET;\r
321         }\r
322         else\r
323         {\r
324             memset( pxContext, 0, sizeof( SSOCKETContext_t ) );\r
325             pxContext->xSocket = xSocket;\r
326         }\r
327     }\r
328     else\r
329     {\r
330         pxContext = SOCKETS_INVALID_SOCKET;\r
331     }\r
332 \r
333     return pxContext;\r
334 }\r
335 /*-----------------------------------------------------------*/\r
336 \r
337 BaseType_t SOCKETS_Init( void )\r
338 {\r
339     /* Empty initialization for this port. */\r
340     return pdPASS;\r
341 }\r
342 /*-----------------------------------------------------------*/\r