@@ -165,7 +165,7 @@ static bool socketpool_socket_get_connection_info(socketpool_socket_obj_t *self,
165165
166166
167167
168- static airlift_socket_status_t socketpool_socket_status (socketpool_socket_obj_t * self ) {
168+ static airlift_client_socket_status_t client_socket_status (socketpool_socket_obj_t * self ) {
169169 const uint8_t * params [1 ] = { & self -> num };
170170 size_t param_lengths [1 ] = { 1 };
171171
@@ -185,43 +185,88 @@ static airlift_socket_status_t socketpool_socket_status(socketpool_socket_obj_t
185185 return result ;
186186}
187187
188- int socketpool_socket_accept (socketpool_socket_obj_t * self , mp_obj_t * peer_out , socketpool_socket_obj_t * accepted ) {
189- if (self -> type != SOCK_STREAM ) {
190- return - MP_EOPNOTSUPP ;
191- }
192-
193- if (common_hal_socketpool_socket_get_closed (self )) {
194- return - MP_EBADF ;
195- }
196-
188+ static bool server_socket_status (socketpool_socket_obj_t * self ) {
197189 const uint8_t * params [1 ] = { & self -> num };
198190 size_t param_lengths [1 ] = { 1 };
199191
200- uint8_t accept_socket_num ;
201- uint8_t * responses [1 ] = { & accept_socket_num };
192+ uint8_t result ;
193+ uint8_t * responses [1 ] = { & result };
202194 size_t response_lengths [1 ] = { 1 };
203195
204- size_t num_responses = wifi_radio_send_command_get_response (self -> socketpool -> radio , AVAIL_DATA_TCP_CMD ,
196+ // GET_STATE_TCP_CMD is a misnomer. It only checks whether there's a tcpserver for the socket.
197+ size_t num_responses = wifi_radio_send_command_get_response (self -> socketpool -> radio , GET_STATE_TCP_CMD ,
205198 params , param_lengths , LENGTHS_8 , MP_ARRAY_SIZE (params ),
206199 responses , response_lengths , LENGTHS_8 , MP_ARRAY_SIZE (responses ),
207200 AIRLIFT_DEFAULT_TIMEOUT_MS );
208201
209202 if (num_responses == 0 ) {
210203 raise_failed ();
211204 }
212- if (accept_socket_num == NO_SOCKET ) {
213- return - EBADF ;
205+
206+ return result == 1 ;
207+ }
208+
209+ int socketpool_socket_accept (socketpool_socket_obj_t * self , mp_obj_t * peer_out , socketpool_socket_obj_t * accepted ) {
210+ if (self -> type != SOCK_STREAM ) {
211+ return - MP_EOPNOTSUPP ;
212+ }
213+
214+ if (!server_socket_status (self )) {
215+ return - MP_ENOTCONN ;
214216 }
215217
216- return accept_socket_num ;
218+ const uint8_t * params [1 ] = { & self -> num };
219+ size_t param_lengths [1 ] = { 1 };
220+
221+ uint16_t accept_socket_num ;
222+ uint8_t * responses [1 ] = { (uint8_t * )& accept_socket_num };
223+ size_t response_lengths [1 ] = { sizeof (accept_socket_num ) };
224+
225+ const uint64_t start_time = supervisor_ticks_ms64 ();
226+ while (true) {
227+ // When passed a server socket, AVAIL_DATA_TCP_CMD returns the socket number on which to read data.
228+ // For client and UDP sockets, it returns the number of bytes available. (Quite a difference!)
229+ size_t num_responses = wifi_radio_send_command_get_response (self -> socketpool -> radio , AVAIL_DATA_TCP_CMD ,
230+ params , param_lengths , LENGTHS_8 , MP_ARRAY_SIZE (params ),
231+ responses , response_lengths , LENGTHS_8 , MP_ARRAY_SIZE (responses ),
232+ AIRLIFT_DEFAULT_TIMEOUT_MS );
233+
234+ if (num_responses == 0 ) {
235+ raise_failed ();
236+ }
237+
238+ if (accept_socket_num != NO_SOCKET ) {
239+ return accept_socket_num ;
240+ }
241+
242+ if (self -> timeout_ms == 0 ) {
243+ // Non-blocking raises a different exception than a timeout.
244+ return - MP_EAGAIN ;
245+ }
246+ if ((self -> timeout_ms != SOCKET_BLOCK_FOREVER &&
247+ supervisor_ticks_ms64 () - start_time >= self -> timeout_ms ) ||
248+ mp_hal_is_interrupted ()) {
249+ return - MP_ETIMEDOUT ;
250+ }
251+
252+ RUN_BACKGROUND_TASKS ;
253+ // Give the AirLift some time to do work instead of asking again immediately.
254+ mp_hal_delay_ms (50 );
255+ }
217256}
218257
258+
219259socketpool_socket_obj_t * common_hal_socketpool_socket_accept (socketpool_socket_obj_t * self , mp_obj_t * peer_out ) {
220260 socketpool_socket_obj_t * accepted = mp_obj_malloc_with_finaliser (socketpool_socket_obj_t , NULL );
221261 socketpool_socket_reset (accepted );
222262
223263 int ret = socketpool_socket_accept (self , peer_out , accepted );
224264 if (ret < 0 ) {
265+ if (ret == - MP_ETIMEDOUT ) {
266+ // There is a specific subclass for timeouts.
267+ mp_raise_msg (& mp_type_TimeoutError , NULL );
268+ }
269+ // Otherwise, raise a general OSError. Includes EAGAIN.
225270 mp_raise_OSError (- ret );
226271 }
227272
@@ -238,16 +283,27 @@ int common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self,
238283 mp_raise_OSError (MP_EINVAL );
239284 }
240285
241- // Validate the host name (which might a numeric IP string) to an IPv4 address first.
286+ // Validate the host name (which might be a numeric IP string) to an IPv4 address first.
242287 uint8_t ipv4 [IPV4_LENGTH ];
243288 if (!socketpool_gethostbyname_ipv4 (self -> socketpool , host , ipv4 )) {
244289 // Could not resolve hostname.
245290 common_hal_socketpool_socketpool_raise_gaierror_noname ();
246291 }
247292
293+ const uint8_t zero_ipv4 [IPV4_LENGTH ] = { 0 };
294+ uint8_t self_ipv4 [IPV4_LENGTH ];
295+ ipv4_uint32_to_bytes (wifi_radio_get_ipv4_address (self -> socketpool -> radio ), self_ipv4 );
296+
297+ // The bound host's IP must be this host: 0.0.0.0 or wifi.radio.ipv4_address.
298+ if (memcmp (ipv4 , zero_ipv4 , IPV4_LENGTH ) != 0 &&
299+ memcmp (ipv4 , self_ipv4 , IPV4_LENGTH ) != 0 ) {
300+ // Same as CPython.
301+ mp_raise_OSError (99 ); // EADDRNOTAVAIL (sometimes 125!)
302+ }
248303 self -> bound = true;
249304 memcpy (self -> hostname , host , hostlen );
250305 self -> hostname_len = hostlen ;
306+ self -> port = port ;
251307 return 0 ;
252308}
253309
@@ -256,9 +312,7 @@ void socketpool_socket_close(socketpool_socket_obj_t *self) {
256312 socketpool_socket_stop_client (self );
257313 }
258314
259- if (self -> server_started ) {
260- // TODO: how to shut down server?
261- }
315+ // Re server_started: there is no way to shut down a server.
262316}
263317
264318void common_hal_socketpool_socket_close (socketpool_socket_obj_t * self ) {
@@ -342,12 +396,13 @@ void socketpool_socket_start_server_mode(socketpool_socket_obj_t *self, airlift_
342396 return ;
343397 }
344398
399+ uint8_t zero_ipv4 [IPV4_LENGTH ] = { 0 };
345400 uint8_t port_bytes [2 ];
346401 be_uint16_to_uint8_bytes ((uint16_t )self -> port , port_bytes );
347402 uint8_t conn_mode = mode ;
348403
349- const uint8_t * params [5 ] = { self -> hostname , port_bytes , & self -> num , & conn_mode };
350- size_t param_lengths [5 ] = { self -> hostname_len , 4 , 2 , 1 , 1 };
404+ const uint8_t * params [4 ] = { zero_ipv4 , port_bytes , & self -> num , & conn_mode };
405+ size_t param_lengths [4 ] = { 4 , 2 , 1 , 1 };
351406
352407 uint8_t result ;
353408 uint8_t * responses [1 ] = { & result };
@@ -371,11 +426,23 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
371426}
372427
373428bool common_hal_socketpool_socket_get_closed (socketpool_socket_obj_t * self ) {
374- return socketpool_socket_status (self ) == SOCKET_CLOSED ;
429+ if (self -> client_started ) {
430+ return client_socket_status (self ) == SOCKET_CLOSED ;
431+ } else if (self -> server_started ) {
432+ return !server_socket_status (self );
433+ } else {
434+ return false;
435+ }
375436}
376437
377438bool common_hal_socketpool_socket_get_connected (socketpool_socket_obj_t * self ) {
378- return socketpool_socket_status (self ) == SOCKET_ESTABLISHED ;
439+ if (self -> client_started ) {
440+ return client_socket_status (self ) == SOCKET_ESTABLISHED ;
441+ } else if (self -> server_started ) {
442+ return server_socket_status (self );
443+ } else {
444+ return false;
445+ }
379446}
380447
381448bool common_hal_socketpool_socket_listen (socketpool_socket_obj_t * self , int backlog ) {
@@ -447,8 +514,10 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *self, uint8_t *buf, uin
447514 mp_hal_is_interrupted ()) {
448515 return 0 ;
449516 }
517+
450518 RUN_BACKGROUND_TASKS ;
451- mp_hal_delay_ms (500 );
519+ // Give the AirLift some time to do work instead of asking again immediately.
520+ mp_hal_delay_ms (50 );
452521 }
453522}
454523
@@ -542,7 +611,7 @@ mp_int_t common_hal_socketpool_socket_get_type(socketpool_socket_obj_t *self) {
542611
543612
544613int common_hal_socketpool_socket_setsockopt (socketpool_socket_obj_t * self , int level , int optname , const void * value , size_t optlen ) {
545- //// mp_raise_NotImplementedError(NULL); // TODO
614+ // TODO: not sure any of this can be implemented.
546615 return 0 ;
547616}
548617
0 commit comments