4
4
* SPDX-License-Identifier: BSD-3-Clause
5
5
*/
6
6
7
- #include <string.h>
8
- #include <time.h>
9
-
10
7
#include "pico/stdlib.h"
11
8
#include "pico/cyw43_arch.h"
12
- #include "lwip/pbuf.h"
13
- #include "lwip/altcp_tcp.h"
14
- #include "lwip/altcp_tls.h"
15
- #include "lwip/dns.h"
16
9
17
10
#define TLS_CLIENT_SERVER "worldtimeapi.org"
18
11
#define TLS_CLIENT_HTTP_REQUEST "GET /api/ip HTTP/1.1\r\n" \
21
14
"\r\n"
22
15
#define TLS_CLIENT_TIMEOUT_SECS 15
23
16
24
-
25
- typedef struct TLS_CLIENT_T_ {
26
- struct altcp_pcb * pcb ;
27
- bool complete ;
28
- } TLS_CLIENT_T ;
29
-
30
- static struct altcp_tls_config * tls_config = NULL ;
31
-
32
- static err_t tls_client_close (void * arg ) {
33
- TLS_CLIENT_T * state = (TLS_CLIENT_T * )arg ;
34
- err_t err = ERR_OK ;
35
-
36
- state -> complete = true;
37
- if (state -> pcb != NULL ) {
38
- altcp_arg (state -> pcb , NULL );
39
- altcp_poll (state -> pcb , NULL , 0 );
40
- altcp_recv (state -> pcb , NULL );
41
- altcp_err (state -> pcb , NULL );
42
- err = altcp_close (state -> pcb );
43
- if (err != ERR_OK ) {
44
- printf ("close failed %d, calling abort\n" , err );
45
- altcp_abort (state -> pcb );
46
- err = ERR_ABRT ;
47
- }
48
- state -> pcb = NULL ;
49
- }
50
- return err ;
51
- }
52
-
53
- static err_t tls_client_connected (void * arg , struct altcp_pcb * pcb , err_t err ) {
54
- TLS_CLIENT_T * state = (TLS_CLIENT_T * )arg ;
55
- if (err != ERR_OK ) {
56
- printf ("connect failed %d\n" , err );
57
- return tls_client_close (state );
58
- }
59
-
60
- printf ("connected to server, sending request\n" );
61
- err = altcp_write (state -> pcb , TLS_CLIENT_HTTP_REQUEST , strlen (TLS_CLIENT_HTTP_REQUEST ), TCP_WRITE_FLAG_COPY );
62
- if (err != ERR_OK ) {
63
- printf ("error writing data, err=%d" , err );
64
- return tls_client_close (state );
65
- }
66
-
67
- return ERR_OK ;
68
- }
69
-
70
- static err_t tls_client_poll (void * arg , struct altcp_pcb * pcb ) {
71
- printf ("timed out" );
72
- return tls_client_close (arg );
73
- }
74
-
75
- static void tls_client_err (void * arg , err_t err ) {
76
- TLS_CLIENT_T * state = (TLS_CLIENT_T * )arg ;
77
- printf ("tls_client_err %d\n" , err );
78
- state -> pcb = NULL ; /* pcb freed by lwip when _err function is called */
79
- }
80
-
81
- static err_t tls_client_recv (void * arg , struct altcp_pcb * pcb , struct pbuf * p , err_t err ) {
82
- TLS_CLIENT_T * state = (TLS_CLIENT_T * )arg ;
83
- if (!p ) {
84
- printf ("connection closed\n" );
85
- return tls_client_close (state );
86
- }
87
-
88
- if (p -> tot_len > 0 ) {
89
- /* For simplicity this examples creates a buffer on stack the size of the data pending here,
90
- and copies all the data to it in one go.
91
- Do be aware that the amount of data can potentially be a bit large (TLS record size can be 16 KB),
92
- so you may want to use a smaller fixed size buffer and copy the data to it using a loop, if memory is a concern */
93
- char buf [p -> tot_len + 1 ];
94
-
95
- pbuf_copy_partial (p , buf , p -> tot_len , 0 );
96
- buf [p -> tot_len ] = 0 ;
97
-
98
- printf ("***\nnew data received from server:\n***\n\n%s\n" , buf );
99
-
100
- altcp_recved (pcb , p -> tot_len );
101
- }
102
- pbuf_free (p );
103
-
104
- return ERR_OK ;
105
- }
106
-
107
- static void tls_client_connect_to_server_ip (const ip_addr_t * ipaddr , TLS_CLIENT_T * state )
108
- {
109
- err_t err ;
110
- u16_t port = 443 ;
111
-
112
- printf ("connecting to server IP %s port %d\n" , ipaddr_ntoa (ipaddr ), port );
113
- err = altcp_connect (state -> pcb , ipaddr , port , tls_client_connected );
114
- if (err != ERR_OK )
115
- {
116
- fprintf (stderr , "error initiating connect, err=%d\n" , err );
117
- tls_client_close (state );
118
- }
119
- }
120
-
121
- static void tls_client_dns_found (const char * hostname , const ip_addr_t * ipaddr , void * arg )
122
- {
123
- if (ipaddr )
124
- {
125
- printf ("DNS resolving complete\n" );
126
- tls_client_connect_to_server_ip (ipaddr , (TLS_CLIENT_T * ) arg );
127
- }
128
- else
129
- {
130
- printf ("error resolving hostname %s\n" , hostname );
131
- tls_client_close (arg );
132
- }
133
- }
134
-
135
-
136
- static bool tls_client_open (const char * hostname , void * arg ) {
137
- err_t err ;
138
- ip_addr_t server_ip ;
139
- TLS_CLIENT_T * state = (TLS_CLIENT_T * )arg ;
140
-
141
- state -> pcb = altcp_tls_new (tls_config , IPADDR_TYPE_ANY );
142
- if (!state -> pcb ) {
143
- printf ("failed to create pcb\n" );
144
- return false;
145
- }
146
-
147
- altcp_arg (state -> pcb , state );
148
- altcp_poll (state -> pcb , tls_client_poll , TLS_CLIENT_TIMEOUT_SECS * 2 );
149
- altcp_recv (state -> pcb , tls_client_recv );
150
- altcp_err (state -> pcb , tls_client_err );
151
-
152
- /* Set SNI */
153
- mbedtls_ssl_set_hostname (altcp_tls_context (state -> pcb ), hostname );
154
-
155
- printf ("resolving %s\n" , hostname );
156
-
157
- // cyw43_arch_lwip_begin/end should be used around calls into lwIP to ensure correct locking.
158
- // You can omit them if you are in a callback from lwIP. Note that when using pico_cyw_arch_poll
159
- // these calls are a no-op and can be omitted, but it is a good practice to use them in
160
- // case you switch the cyw43_arch type later.
161
- cyw43_arch_lwip_begin ();
162
-
163
- err = dns_gethostbyname (hostname , & server_ip , tls_client_dns_found , state );
164
- if (err == ERR_OK )
165
- {
166
- /* host is in DNS cache */
167
- tls_client_connect_to_server_ip (& server_ip , state );
168
- }
169
- else if (err != ERR_INPROGRESS )
170
- {
171
- printf ("error initiating DNS resolving, err=%d\n" , err );
172
- tls_client_close (state -> pcb );
173
- }
174
-
175
- cyw43_arch_lwip_end ();
176
-
177
- return err == ERR_OK || err == ERR_INPROGRESS ;
178
- }
179
-
180
- // Perform initialisation
181
- static TLS_CLIENT_T * tls_client_init (void ) {
182
- TLS_CLIENT_T * state = calloc (1 , sizeof (TLS_CLIENT_T ));
183
- if (!state ) {
184
- printf ("failed to allocate state\n" );
185
- return NULL ;
186
- }
187
-
188
- return state ;
189
- }
190
-
191
- void run_tls_client_test (void ) {
192
- /* No CA certificate checking */
193
- tls_config = altcp_tls_create_config_client (NULL , 0 );
194
-
195
- TLS_CLIENT_T * state = tls_client_init ();
196
- if (!state ) {
197
- return ;
198
- }
199
- if (!tls_client_open (TLS_CLIENT_SERVER , state )) {
200
- return ;
201
- }
202
- while (!state -> complete ) {
203
- // the following #ifdef is only here so this same example can be used in multiple modes;
204
- // you do not need it in your code
205
- #if PICO_CYW43_ARCH_POLL
206
- // if you are using pico_cyw43_arch_poll, then you must poll periodically from your
207
- // main loop (not from a timer) to check for Wi-Fi driver or lwIP work that needs to be done.
208
- cyw43_arch_poll ();
209
- // you can poll as often as you like, however if you have nothing else to do you can
210
- // choose to sleep until either a specified time, or cyw43_arch_poll() has work to do:
211
- cyw43_arch_wait_for_work_until (make_timeout_time_ms (1000 ));
212
- #else
213
- // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
214
- // is done via interrupt in the background. This sleep is just an example of some (blocking)
215
- // work you might be doing.
216
- sleep_ms (1000 );
217
- #endif
218
- }
219
- free (state );
220
- altcp_tls_free_config (tls_config );
221
- }
17
+ extern bool run_tls_client_test (const uint8_t * cert , size_t cert_len , const char * server , const char * request , int timeout );
222
18
223
19
int main () {
224
20
stdio_init_all ();
@@ -233,12 +29,17 @@ int main() {
233
29
printf ("failed to connect\n" );
234
30
return 1 ;
235
31
}
236
- run_tls_client_test ();
237
-
32
+ bool pass = run_tls_client_test (NULL , 0 , TLS_CLIENT_SERVER , TLS_CLIENT_HTTP_REQUEST , TLS_CLIENT_TIMEOUT_SECS );
33
+ if (pass ) {
34
+ printf ("Test passed\n" );
35
+ } else {
36
+ printf ("Test failed\n" );
37
+ }
238
38
/* sleep a bit to let usb stdio write out any buffer to host */
239
39
sleep_ms (100 );
240
40
241
41
cyw43_arch_deinit ();
242
- return 0 ;
42
+ printf ("All done\n" );
43
+ return pass ? 0 : 1 ;
243
44
}
244
45
0 commit comments