1616# limitations under the License.
1717# -----------------------------------------------------------------------------
1818import os
19+ import aenum
20+ import socket
21+ import asyncio as aio
1922import ctypes as c
2023from .general import Platform
2124
2225
26+ class SockaddrUn (c .Structure ):
27+ _fields_ = [("sun_family" , c .c_ushort ), ("sun_path" , c .c_char * 108 )]
28+
29+
30+ aenum .extend_enum (socket .AddressFamily , "AF_UNIX" , 1 )
31+ AF_UNIX = socket .AddressFamily (1 )
32+ NULL = 0
33+
34+
2335class Cng :
2436 __instance = None
2537
@@ -45,7 +57,7 @@ def client_conf_paths(self):
4557
4658 def default_transport (self ):
4759 # Note: %TEMP% won't be redirected even when the executable is a MSIX/MicrosoftStore app
48- return 'unix://' + os .path .expandvars (r'%TEMP%\ndn\ nfd.sock' )
60+ return 'unix://' + os .path .expandvars (r'%TEMP%\nfd.sock' )
4961
5062 def default_pib_schema (self ):
5163 return 'pib-sqlite3'
@@ -60,3 +72,71 @@ def default_tpm_schema(self):
6072 def default_tpm_paths (self ):
6173 return [os .path .expandvars (r'%LOCALAPPDATA%\ndn\ndnsec-key-file' ),
6274 os .path .expandvars (r'%USERPROFILE%\ndn\ndnsec-key-file' )]
75+
76+ @staticmethod
77+ def _iocp_connect (proactor , conn , address ):
78+ # _overlapped.WSAConnect(conn.fileno(), address)
79+ addr = SockaddrUn (AF_UNIX .value , address .encode () + b"\0 " )
80+ winsock = c .windll .ws2_32
81+ winsock .connect (conn .fileno (), addr , 110 )
82+
83+ fut = proactor ._loop .create_future ()
84+ fut .set_result (None )
85+ return fut
86+
87+ @staticmethod
88+ async def _create_unix_connection (
89+ loop , protocol_factory , path = None , * ,
90+ ssl = None , sock = None ,
91+ server_hostname = None ,
92+ ssl_handshake_timeout = None ):
93+ assert server_hostname is None or isinstance (server_hostname , str )
94+ if ssl :
95+ if server_hostname is None :
96+ raise ValueError (
97+ 'you have to pass server_hostname when using ssl' )
98+ else :
99+ if server_hostname is not None :
100+ raise ValueError ('server_hostname is only meaningful with ssl' )
101+ if ssl_handshake_timeout is not None :
102+ raise ValueError (
103+ 'ssl_handshake_timeout is only meaningful with ssl' )
104+
105+ if path is not None :
106+ if sock is not None :
107+ raise ValueError (
108+ 'path and sock can not be specified at the same time' )
109+
110+ path = os .fspath (path )
111+ sock = socket .socket (AF_UNIX , socket .SOCK_STREAM , 0 )
112+ try :
113+ sock .setblocking (False )
114+ # await loop.sock_connect(sock, path)
115+ await Win32 ._iocp_connect (loop ._proactor , sock , path )
116+ except OSError :
117+ sock .close ()
118+ raise
119+
120+ else :
121+ if sock is None :
122+ raise ValueError ('no path and sock were specified' )
123+ if sock .family != AF_UNIX or sock .type != socket .SOCK_STREAM :
124+ raise ValueError (
125+ f'A UNIX Domain Stream Socket was expected, got { sock !r} ' )
126+ sock .setblocking (False )
127+
128+ transport , protocol = await loop ._create_connection_transport (
129+ sock , protocol_factory , ssl , server_hostname ,
130+ ssl_handshake_timeout = ssl_handshake_timeout )
131+ return transport , protocol
132+
133+ async def open_unix_connection (self , path = None ):
134+ """
135+ Similar to `open_connection` but works with UNIX Domain Sockets.
136+ """
137+ loop = aio .events .get_running_loop ()
138+ reader = aio .StreamReader (limit = 2 ** 16 , loop = loop )
139+ protocol = aio .StreamReaderProtocol (reader , loop = loop )
140+ transport , _ = await Win32 ._create_unix_connection (loop , lambda : protocol , path )
141+ writer = aio .StreamWriter (transport , protocol , reader , loop )
142+ return reader , writer
0 commit comments