14
14
from __future__ import annotations
15
15
16
16
try :
17
- from typing import TYPE_CHECKING , Optional
17
+ from typing import TYPE_CHECKING , Optional , Tuple
18
18
19
19
if TYPE_CHECKING :
20
20
from esp32spi .adafruit_esp32spi import ESP_SPIcontrol # noqa: UP007
@@ -40,7 +40,7 @@ class SocketPool:
40
40
SOCK_STREAM = const (1 )
41
41
SOCK_DGRAM = const (2 )
42
42
AF_INET = const (2 )
43
- SOL_SOCKET = const (0xfff )
43
+ SOL_SOCKET = const (0xFFF )
44
44
SO_REUSEADDR = const (0x0004 )
45
45
46
46
# implementation specific constants
@@ -95,6 +95,7 @@ def __init__(
95
95
self ._type = type
96
96
self ._buffer = b""
97
97
self ._socknum = socknum if socknum is not None else self ._interface .get_socket ()
98
+ self ._bound = ()
98
99
self .settimeout (0 )
99
100
100
101
def __enter__ (self ):
@@ -156,12 +157,12 @@ def recv_into(self, buffer, nbytes: int = 0):
156
157
if not 0 <= nbytes <= len (buffer ):
157
158
raise ValueError ("nbytes must be 0 to len(buffer)" )
158
159
159
- last_read_time = time .monotonic ()
160
+ last_read_time = time .monotonic_ns ()
160
161
num_to_read = len (buffer ) if nbytes == 0 else nbytes
161
162
num_read = 0
162
163
while num_to_read > 0 :
163
164
# we might have read socket data into the self._buffer with:
164
- # esp32spi_wsgiserver: socket_readline
165
+ # adafruit_wsgi. esp32spi_wsgiserver: socket_readline
165
166
if len (self ._buffer ) > 0 :
166
167
bytes_to_read = min (num_to_read , len (self ._buffer ))
167
168
buffer [num_read : num_read + bytes_to_read ] = self ._buffer [:bytes_to_read ]
@@ -173,24 +174,38 @@ def recv_into(self, buffer, nbytes: int = 0):
173
174
174
175
num_avail = self ._available ()
175
176
if num_avail > 0 :
176
- last_read_time = time .monotonic ()
177
- bytes_read = self ._interface .socket_read (self ._socknum , min (num_to_read , num_avail ))
177
+ last_read_time = time .monotonic_ns ()
178
+ bytes_read = self ._interface .socket_read (
179
+ self ._socknum , min (num_to_read , num_avail )
180
+ )
178
181
buffer [num_read : num_read + len (bytes_read )] = bytes_read
179
182
num_read += len (bytes_read )
180
183
num_to_read -= len (bytes_read )
181
184
elif num_read > 0 :
182
185
# We got a message, but there are no more bytes to read, so we can stop.
183
186
break
184
187
# No bytes yet, or more bytes requested.
185
- if self ._timeout > 0 and time .monotonic () - last_read_time > self ._timeout :
188
+
189
+ if self ._timeout == 0 : # if in non-blocking mode, stop now.
190
+ break
191
+
192
+ # Time out if there's a positive timeout set.
193
+ delta = (time .monotonic_ns () - last_read_time ) // 1_000_000
194
+ if self ._timeout > 0 and delta > self ._timeout :
186
195
raise OSError (errno .ETIMEDOUT )
187
196
return num_read
188
197
189
198
def settimeout (self , value ):
190
- """Set the read timeout for sockets.
191
- If value is 0 socket reads will block until a message is available .
199
+ """Set the read timeout for sockets in seconds .
200
+ ``0`` means non-blocking. ``None`` means block indefinitely .
192
201
"""
193
- self ._timeout = value
202
+ if value is None :
203
+ self ._timeout = - 1
204
+ else :
205
+ if value < 0 :
206
+ raise ValueError ("Timeout cannot be a negative number" )
207
+ # internally in milliseconds as an int
208
+ self ._timeout = int (value * 1000 )
194
209
195
210
def _available (self ):
196
211
"""Returns how many bytes of data are available to be read (up to the MAX_PACKET length)"""
@@ -230,35 +245,41 @@ def close(self):
230
245
231
246
def setsockopt (self , * opts , ** kwopts ):
232
247
"""Dummy call for compatibility."""
233
- # FIXME
234
- pass
235
248
236
- def listen (self , backlog ):
237
- """Dummy call for compatibility."""
238
- # FIXME
239
- # probably nothing to do actually
240
- # maybe check that we have called bind or something ?
241
- pass
249
+ def setblocking (self , flag : bool ):
250
+ """Set the blocking behaviour of this socket.
251
+ :param bool flag: False means non-blocking, True means block indefinitely.
252
+ """
253
+ if flag :
254
+ self .settimeout (None )
255
+ else :
256
+ self .settimeout (0 )
242
257
243
- def setblocking (self , blocking ):
244
- """Dummy call for compatibility."""
245
- # FIXME
246
- # is this settimeout(0) ? (if True) or something else ?
247
- pass
258
+ def bind (self , address : Tuple [str , int ]):
259
+ """Bind a socket to an address"""
260
+ self ._bound = address
248
261
249
- def bind (self , host_port ):
250
- host , port = host_port
262
+ def listen (self , backlog : int ): # pylint: disable=unused-argument
263
+ """Set socket to listen for incoming connections.
264
+ :param int backlog: length of backlog queue for waiting connections (ignored)
265
+ """
266
+ if not self ._bound :
267
+ self ._bound = (self ._interface .ip_address , 80 )
268
+ port = self ._bound [1 ]
251
269
self ._interface .start_server (port , self ._socknum )
252
- print (f"Binding to { self ._socknum } " )
253
270
254
271
def accept (self ):
272
+ """Accept a connection on a listening socket of type SOCK_STREAM,
273
+ creating a new socket of type SOCK_STREAM. Returns a tuple of
274
+ (new_socket, remote_address)
275
+ """
255
276
client_sock_num = self ._interface .socket_available (self ._socknum )
256
277
if client_sock_num != SocketPool .NO_SOCKET_AVAIL :
257
278
sock = Socket (self ._socket_pool , socknum = client_sock_num )
258
279
# get remote information (addr and port)
259
280
remote = self ._interface .get_remote_data (client_sock_num )
260
- IP_ADDRESS = "{}.{}.{}.{}" .format (* remote [' ip_addr' ])
261
- PORT = remote [' port' ]
262
- client_address = (IP_ADDRESS , PORT )
281
+ ip_address = "{}.{}.{}.{}" .format (* remote [" ip_addr" ])
282
+ port = remote [" port" ]
283
+ client_address = (ip_address , port )
263
284
return sock , client_address
264
285
raise OSError (errno .ECONNRESET )
0 commit comments