FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
python-zeroconf/src/zeroconf/_transport.py at master · python-zeroconf/python-zeroconf · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
python-zeroconf
/
python-zeroconf
Public
Notifications
You must be signed in to change notification settings
Fork
230
Star
734
Code
Issues
46
Pull requests
8
Discussions
Actions
Projects
Wiki
Security and quality
5
Insights
Additional navigation options
Code
Issues
Pull requests
Discussions
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
python-zeroconf
/
src
/
zeroconf
/
_transport.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
129 lines (109 loc) · 4.72 KB
Breadcrumbs
python-zeroconf
/
src
/
zeroconf
/
_transport.py
Copy path
File metadata and controls
129 lines (109 loc) · 4.72 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""Multicast DNS Service Discovery for Python, v0.14-wmcbrine
Copyright 2003 Paul Scott-Murphy, 2014 William McBrine
This module provides a framework for the use of DNS Service Discovery
using IP multicast.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
"""
from
__future__
import
annotations
import
asyncio
import
logging
import
socket
import
sys
from
typing
import
cast
from
.
_logger
import
log
def
_strip_zone
(
address
:
str
)
->
str
:
"""Drop a ``%zone`` suffix from an IPv6 address string."""
percent
=
address
.
find
(
"%"
)
return
address
[:
percent
]
if
percent
!=
-
1
else
address
class
_WrappedTransport
:
"""A wrapper for transports."""
__slots__
=
(
"fileno"
,
"is_ipv6"
,
"multicast_index"
,
"sock"
,
"sock_name"
,
"transport"
,
)
def
__init__
(
self
,
transport
:
asyncio
.
DatagramTransport
,
is_ipv6
:
bool
,
sock
:
socket
.
socket
,
fileno
:
int
,
sock_name
:
tuple
,
multicast_index
:
int
=
0
,
)
->
None
:
"""Initialize the wrapped transport.
``multicast_index`` is the IPV6_MULTICAST_IF interface index the
sender joined the group with, carried so a group leave uses the same
index the join did (the bound socket's scope_id is 0 for global IPv6).
"""
self
.
transport
=
transport
self
.
is_ipv6
=
is_ipv6
self
.
sock
=
sock
self
.
fileno
=
fileno
self
.
sock_name
=
sock_name
self
.
multicast_index
=
multicast_index
@
property
def
interface_key
(
self
)
->
tuple
[
str
,
int
]:
"""The bound (address, scope_id) identifying this sender's interface.
Used to diff senders against the desired interface set. The scope_id
keeps link-local IPv6 addresses that repeat across interfaces (same
address, different zone) from colliding to one key.
"""
sock_name
=
self
.
sock_name
if
self
.
is_ipv6
:
scope_id
=
cast
(
int
,
sock_name
[
3
])
if
len
(
sock_name
)
>
3
else
0
return
(
_strip_zone
(
sock_name
[
0
]),
scope_id
)
return
(
cast
(
str
,
sock_name
[
0
]),
0
)
@
property
def
multicast_interface
(
self
)
->
str
|
tuple
[
tuple
[
str
,
int
,
int
],
int
]:
"""The interface value a group leave takes for this transport.
For IPv6 this carries ``multicast_index`` (the index the join used),
not the bound scope_id, so leave and join stay symmetric.
"""
address
,
_scope_id
=
self
.
interface_key
if
self
.
is_ipv6
:
return
((
address
,
0
,
0
),
self
.
multicast_index
)
return
address
def
make_wrapped_transport
(
transport
:
asyncio
.
DatagramTransport
)
->
_WrappedTransport
:
"""Make a wrapped transport."""
sock
:
socket
.
socket
=
transport
.
get_extra_info
(
"socket"
)
is_ipv6
=
sock
.
family
==
socket
.
AF_INET6
multicast_index
=
0
if
is_ipv6
:
# IPV6_MULTICAST_IF holds the interface index new_respond_socket
# joined the group with; capture it so a later group leave uses the
# same index. This is on the startup/connection path, and the index
# only selects the interface for a future (benign) group leave, so a
# read failure (Windows rejects it with WSAEINVAL; other platforms
# shouldn't) keeps the default index 0 rather than aborting setup.
try
:
multicast_index
=
sock
.
getsockopt
(
socket
.
IPPROTO_IPV6
,
socket
.
IPV6_MULTICAST_IF
)
except
OSError
as
exc
:
# Windows rejects this read (WSAEINVAL) for every v6 socket, so it is
# expected and benign there; keep it at debug. Elsewhere a failure is
# unexpected and means a later group leave uses the wrong index (a
# benign no-op that leaks the membership), so surface it at warning.
level
=
logging
.
DEBUG
if
sys
.
platform
==
"win32"
else
logging
.
WARNING
log
.
log
(
level
,
"Unable to read IPV6_MULTICAST_IF, using default index 0: %s"
,
exc
)
return
_WrappedTransport
(
transport
=
transport
,
is_ipv6
=
is_ipv6
,
sock
=
sock
,
fileno
=
sock
.
fileno
(),
sock_name
=
sock
.
getsockname
(),
multicast_index
=
multicast_index
,
)
Back
|
FazBrowse Home
|
New Git URL