@@ -227,30 +227,55 @@ def __init__(
227
227
"""
228
228
if family != AF_INET :
229
229
raise RuntimeError ("Only AF_INET family supported by W5K modules." )
230
+ self ._socket_closed = False
230
231
self ._sock_type = type
231
232
self ._buffer = b""
232
233
self ._timeout = _default_socket_timeout
233
234
self ._listen_port = None
234
235
235
- self ._socknum = _the_interface .get_socket ()
236
+ self ._socknum = _the_interface .get_socket (reserve_socket = True )
236
237
if self ._socknum == _SOCKET_INVALID :
237
238
raise RuntimeError ("Failed to allocate socket." )
238
239
240
+ def __del__ (self ):
241
+ _the_interface .release_socket (self ._socknum )
242
+
239
243
def __enter__ (self ):
240
244
return self
241
245
242
246
def __exit__ (self , exc_type , exc_val , exc_tb ) -> None :
247
+ _the_interface .release_socket (self ._socknum )
243
248
if self ._sock_type == SOCK_STREAM :
244
- self ._disconnect ()
245
- stamp = time .monotonic ()
246
- while self ._status == wiznet5k .adafruit_wiznet5k .SNSR_SOCK_FIN_WAIT :
247
- if time .monotonic () - stamp > 1000 :
248
- raise RuntimeError ("Failed to disconnect socket" )
249
- self .close ()
250
- stamp = time .monotonic ()
251
- while self ._status != wiznet5k .adafruit_wiznet5k .SNSR_SOCK_CLOSED :
252
- if time .monotonic () - stamp > 1000 :
253
- raise RuntimeError ("Failed to close socket" )
249
+ _the_interface .write_snir (
250
+ self ._socknum , 0xFF
251
+ ) # Reset socket interrupt register.
252
+ _the_interface .socket_disconnect (self ._socknum )
253
+ mask = (
254
+ wiznet5k .adafruit_wiznet5k .SNIR_TIMEOUT
255
+ | wiznet5k .adafruit_wiznet5k .SNIR_DISCON
256
+ )
257
+ while not _the_interface .read_snir (self ._socknum )[0 ] & mask :
258
+ pass
259
+ _the_interface .write_snir (
260
+ self ._socknum , 0xFF
261
+ ) # Reset socket interrupt register.
262
+ _the_interface .socket_close (self ._socknum )
263
+ while (
264
+ _the_interface .socket_status (self ._socknum )[0 ]
265
+ != wiznet5k .adafruit_wiznet5k .SNSR_SOCK_CLOSED
266
+ ):
267
+ pass
268
+
269
+ # This works around problems with using a class method as a decorator.
270
+ def _check_socket_closed (func ): # pylint: disable=no-self-argument
271
+ """Decorator to check whether the socket object has been closed."""
272
+
273
+ def wrapper (self , * args , ** kwargs ):
274
+ if self ._socket_closed : # pylint: disable=protected-access
275
+ raise RuntimeError ("The socket has been closed." )
276
+ return func (self , * args , ** kwargs ) # pylint: disable=not-callable
277
+
278
+ return wrapper
254
279
255
280
@property
256
281
def _status (self ) -> int :
@@ -289,6 +314,7 @@ def _connected(self) -> bool:
289
314
self .close ()
290
315
return result
291
316
317
+ @_check_socket_closed
292
318
def getpeername (self ) -> Tuple [str , int ]:
293
319
"""
294
320
Return the remote address to which the socket is connected.
@@ -299,6 +325,7 @@ def getpeername(self) -> Tuple[str, int]:
299
325
self ._socknum
300
326
)
301
327
328
+ @_check_socket_closed
302
329
def bind (self , address : Tuple [Optional [str ], int ]) -> None :
303
330
"""
304
331
Bind the socket to address. The socket must not already be bound.
@@ -344,6 +371,7 @@ def _bind(self, address: Tuple[Optional[str], int]) -> None:
344
371
)
345
372
self ._buffer = b""
346
373
374
+ @_check_socket_closed
347
375
def listen (self , backlog : int = 0 ) -> None :
348
376
"""
349
377
Enable a server to accept connections.
@@ -355,6 +383,7 @@ def listen(self, backlog: int = 0) -> None:
355
383
_the_interface .socket_listen (self ._socknum , self ._listen_port )
356
384
self ._buffer = b""
357
385
386
+ @_check_socket_closed
358
387
def accept (
359
388
self ,
360
389
) -> Tuple [socket , Tuple [str , int ]]:
@@ -389,6 +418,7 @@ def accept(
389
418
raise RuntimeError ("Failed to open new listening socket" )
390
419
return client_sock , addr
391
420
421
+ @_check_socket_closed
392
422
def connect (self , address : Tuple [str , int ]) -> None :
393
423
"""
394
424
Connect to a remote socket at address.
@@ -408,6 +438,7 @@ def connect(self, address: Tuple[str, int]) -> None:
408
438
raise RuntimeError ("Failed to connect to host " , address [0 ])
409
439
self ._buffer = b""
410
440
441
+ @_check_socket_closed
411
442
def send (self , data : Union [bytes , bytearray ]) -> int :
412
443
"""
413
444
Send data to the socket. The socket must be connected to a remote socket.
@@ -423,6 +454,7 @@ def send(self, data: Union[bytes, bytearray]) -> int:
423
454
gc .collect ()
424
455
return bytes_sent
425
456
457
+ @_check_socket_closed
426
458
def sendto (self , data : bytearray , * flags_and_or_address : any ) -> int :
427
459
"""
428
460
Send data to the socket. The socket should not be connected to a remote socket, since the
@@ -446,6 +478,7 @@ def sendto(self, data: bytearray, *flags_and_or_address: any) -> int:
446
478
self .connect (address )
447
479
return self .send (data )
448
480
481
+ @_check_socket_closed
449
482
def recv (
450
483
# pylint: disable=too-many-branches
451
484
self ,
@@ -501,6 +534,7 @@ def _embed_recv(
501
534
gc .collect ()
502
535
return ret
503
536
537
+ @_check_socket_closed
504
538
def recvfrom (self , bufsize : int , flags : int = 0 ) -> Tuple [bytes , Tuple [str , int ]]:
505
539
"""
506
540
Receive data from the socket. The return value is a pair (bytes, address) where bytes is
@@ -521,6 +555,7 @@ def recvfrom(self, bufsize: int, flags: int = 0) -> Tuple[bytes, Tuple[str, int]
521
555
),
522
556
)
523
557
558
+ @_check_socket_closed
524
559
def recv_into (self , buffer : bytearray , nbytes : int = 0 , flags : int = 0 ) -> int :
525
560
"""
526
561
Receive up to nbytes bytes from the socket, storing the data into a buffer
@@ -539,6 +574,7 @@ def recv_into(self, buffer: bytearray, nbytes: int = 0, flags: int = 0) -> int:
539
574
buffer [:nbytes ] = bytes_received
540
575
return nbytes
541
576
577
+ @_check_socket_closed
542
578
def recvfrom_into (
543
579
self , buffer : bytearray , nbytes : int = 0 , flags : int = 0
544
580
) -> Tuple [int , Tuple [str , int ]]:
@@ -597,12 +633,15 @@ def _disconnect(self) -> None:
597
633
raise RuntimeError ("Socket must be a TCP socket." )
598
634
_the_interface .socket_disconnect (self ._socknum )
599
635
636
+ @_check_socket_closed
600
637
def close (self ) -> None :
601
638
"""
602
639
Mark the socket closed. Once that happens, all future operations on the socket object
603
640
will fail. The remote end will receive no more data.
604
641
"""
642
+ _the_interface .release_socket (self ._socknum )
605
643
_the_interface .socket_close (self ._socknum )
644
+ self ._socket_closed = True
606
645
607
646
def _available (self ) -> int :
608
647
"""
@@ -612,6 +651,7 @@ def _available(self) -> int:
612
651
"""
613
652
return _the_interface .socket_available (self ._socknum , self ._sock_type )
614
653
654
+ @_check_socket_closed
615
655
def settimeout (self , value : Optional [float ]) -> None :
616
656
"""
617
657
Set a timeout on blocking socket operations. The value argument can be a
@@ -628,6 +668,7 @@ def settimeout(self, value: Optional[float]) -> None:
628
668
else :
629
669
raise ValueError ("Timeout must be None, 0.0 or a positive numeric value." )
630
670
671
+ @_check_socket_closed
631
672
def gettimeout (self ) -> Optional [float ]:
632
673
"""
633
674
Return the timeout in seconds (float) associated with socket operations, or None if no
@@ -637,6 +678,7 @@ def gettimeout(self) -> Optional[float]:
637
678
"""
638
679
return self ._timeout
639
680
681
+ @_check_socket_closed
640
682
def setblocking (self , flag : bool ) -> None :
641
683
"""
642
684
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set
@@ -659,6 +701,7 @@ def setblocking(self, flag: bool) -> None:
659
701
else :
660
702
raise TypeError ("Flag must be a boolean." )
661
703
704
+ @_check_socket_closed
662
705
def getblocking (self ) -> bool :
663
706
"""
664
707
Return True if socket is in blocking mode, False if in non-blocking.
@@ -670,16 +713,19 @@ def getblocking(self) -> bool:
670
713
return self .gettimeout () == 0
671
714
672
715
@property
716
+ @_check_socket_closed
673
717
def family (self ) -> int :
674
718
"""Socket family (always 0x03 in this implementation)."""
675
719
return 3
676
720
677
721
@property
722
+ @_check_socket_closed
678
723
def type (self ):
679
724
"""Socket type."""
680
725
return self ._sock_type
681
726
682
727
@property
728
+ @_check_socket_closed
683
729
def proto (self ):
684
730
"""Socket protocol (always 0x00 in this implementation)."""
685
731
return 0
0 commit comments