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