Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-siosocks for openSUSE:Factory 
checked in at 2021-01-26 14:46:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-siosocks (Old)
 and      /work/SRC/openSUSE:Factory/.python-siosocks.new.28504 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-siosocks"

Tue Jan 26 14:46:27 2021 rev:2 rq:866034 version:0.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-siosocks/python-siosocks.changes  
2020-01-17 16:08:42.256534199 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-siosocks.new.28504/python-siosocks.changes   
    2021-01-26 14:49:57.267694348 +0100
@@ -1,0 +2,7 @@
+Thu Jan 21 14:22:45 UTC 2021 - andy great <[email protected]>
+
+- Update to version 0.2.0.
+  * add unified SocksException
+  * remove host/port redirection checks
+
+-------------------------------------------------------------------

Old:
----
  siosocks-0.1.0.tar.gz

New:
----
  siosocks-0.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-siosocks.spec ++++++
--- /var/tmp/diff_new_pack.X25G1S/_old  2021-01-26 14:49:58.123695515 +0100
+++ /var/tmp/diff_new_pack.X25G1S/_new  2021-01-26 14:49:58.123695515 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-siosocks
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-siosocks
-Version:        0.1.0
+Version:        0.2.0
 Release:        0
 Summary:        Sans-io socks proxy client/server with couple io backends
 License:        MIT

++++++ siosocks-0.1.0.tar.gz -> siosocks-0.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/PKG-INFO new/siosocks-0.2.0/PKG-INFO
--- old/siosocks-0.1.0/PKG-INFO 2019-09-21 16:51:23.000000000 +0200
+++ new/siosocks-0.2.0/PKG-INFO 2020-09-01 03:59:41.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: siosocks
-Version: 0.1.0
+Version: 0.2.0
 Summary: sans-io socks proxy client/server with couple io backends
 Home-page: https://github.com/pohmelie/siosocks
 Author: pohmelie
@@ -168,6 +168,30 @@
                                 username/password auth [default: False]
           -v, --version         Show siosocks version
         ```
+        
+        ### Exceptions
+        `siosocks` have unified exception for all types of socks-related 
errors:
+        ``` python
+        import asyncio
+        
+        from siosocks.exceptions import SocksException
+        from siosocks.io.asyncio import open_connection
+        
+        
+        async def main():
+            try:
+                r, w = await open_connection("127.0.0.1", 80, 
socks_host="localhost", socks_port=9050, socks_version=5)
+            except SocksException:
+                ...
+            else:
+                # at this point all socks-related tasks done and returned 
reader and writer
+                # are just plain asyncio objects without any siosocks proxies
+        
+        
+        loop = asyncio.get_event_loop()
+        loop.run_until_complete(main())
+        ```
+        
         ## Low-level
         Shadowsocks-like 
[client/server](https://github.com/pohmelie/siosocks/blob/master/examples/shadowsocks-like.py).
 Shadowsocks-like built on top of socks5 and encryption. It have ??client??, 
which is actually socks server and ??server??. So, precisely there are two 
servers: client side and server side. Purpose of shadowsocks is to encrypt data 
between ??incoming?? and ??outgoing?? servers. In common this looks like:
         ```
@@ -176,8 +200,9 @@
         Example above use Caesar cipher for simplicity (and security of 
course).
         
         # Roadmap/contibutions
-        * [ ] add more backends (average)
-        * [ ] speed up `passthrough` implementation (seems hard)
+        - [ ] add more backends (average)
+        - [ ] speed up `passthrough` implementation (seems hard)
+        - [ ] add client redirection
         
 Platform: UNKNOWN
 Classifier: Programming Language :: Python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/history.md 
new/siosocks-0.2.0/history.md
--- old/siosocks-0.1.0/history.md       2019-08-02 17:06:43.000000000 +0200
+++ new/siosocks-0.2.0/history.md       2020-09-01 03:54:18.000000000 +0200
@@ -1,2 +1,8 @@
+# x.x.x (xxxx-xx-xx)
+
+# 0.2.0 (2020-09-01)
+- add unified `SocksException`
+- remove host/port redirection checks (fixes #3)
+
 # 0.0.2 (2019-08-02)
-* initial release
+- initial release
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/readme.md new/siosocks-0.2.0/readme.md
--- old/siosocks-0.1.0/readme.md        2019-09-21 16:46:34.000000000 +0200
+++ new/siosocks-0.2.0/readme.md        2020-09-01 03:48:40.000000000 +0200
@@ -160,6 +160,30 @@
                         username/password auth [default: False]
   -v, --version         Show siosocks version
 ```
+
+### Exceptions
+`siosocks` have unified exception for all types of socks-related errors:
+``` python
+import asyncio
+
+from siosocks.exceptions import SocksException
+from siosocks.io.asyncio import open_connection
+
+
+async def main():
+    try:
+        r, w = await open_connection("127.0.0.1", 80, socks_host="localhost", 
socks_port=9050, socks_version=5)
+    except SocksException:
+        ...
+    else:
+        # at this point all socks-related tasks done and returned reader and 
writer
+        # are just plain asyncio objects without any siosocks proxies
+
+
+loop = asyncio.get_event_loop()
+loop.run_until_complete(main())
+```
+
 ## Low-level
 Shadowsocks-like 
[client/server](https://github.com/pohmelie/siosocks/blob/master/examples/shadowsocks-like.py).
 Shadowsocks-like built on top of socks5 and encryption. It have ??client??, 
which is actually socks server and ??server??. So, precisely there are two 
servers: client side and server side. Purpose of shadowsocks is to encrypt data 
between ??incoming?? and ??outgoing?? servers. In common this looks like:
 ```
@@ -168,5 +192,6 @@
 Example above use Caesar cipher for simplicity (and security of course).
 
 # Roadmap/contibutions
-* [ ] add more backends (average)
-* [ ] speed up `passthrough` implementation (seems hard)
+- [ ] add more backends (average)
+- [ ] speed up `passthrough` implementation (seems hard)
+- [ ] add client redirection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/__init__.py 
new/siosocks-0.2.0/siosocks/__init__.py
--- old/siosocks-0.1.0/siosocks/__init__.py     2019-09-21 16:47:06.000000000 
+0200
+++ new/siosocks-0.2.0/siosocks/__init__.py     2020-09-01 03:54:27.000000000 
+0200
@@ -1,2 +1,2 @@
-__version__ = "0.1.0"
+__version__ = "0.2.0"
 version = tuple(map(int, __version__.split(".")))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/exceptions.py 
new/siosocks-0.2.0/siosocks/exceptions.py
--- old/siosocks-0.1.0/siosocks/exceptions.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/siosocks-0.2.0/siosocks/exceptions.py   2020-09-01 02:14:34.000000000 
+0200
@@ -0,0 +1,2 @@
+class SocksException(Exception):
+    pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/interface.py 
new/siosocks-0.2.0/siosocks/interface.py
--- old/siosocks-0.1.0/siosocks/interface.py    2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/siosocks/interface.py    2020-09-01 03:42:43.000000000 
+0200
@@ -1,5 +1,6 @@
 import abc
-import contextlib
+
+from siosocks.exceptions import SocksException
 
 
 class AbstractSocksIO(abc.ABC):
@@ -29,32 +30,35 @@
         """
 
 
-def _common_engine(protocol, io):
+async def async_engine(protocol, io):
     generator_method, data = protocol.send, None
     while True:
         try:
             message = generator_method(data)
+        except SocksException:
+            raise
         except StopIteration:
             break
         method = message.pop("method")
         try:
             generator_method = protocol.send
-            data = yield getattr(io, method)(**message)
-        except Exception as e:
-            generator_method, data = protocol.throw, e
-
-
-async def async_engine(protocol, io):
-    engine = _common_engine(protocol, io)
-    data = None
-    with contextlib.suppress(StopIteration):
-        while True:
-            data = await engine.send(data)
+            data = await getattr(io, method)(**message)
+        except Exception as exc:
+            generator_method, data = protocol.throw, exc
 
 
 def sync_engine(protocol, io):
-    engine = _common_engine(protocol, io)
-    data = None
-    with contextlib.suppress(StopIteration):
-        while True:
-            data = engine.send(data)
+    generator_method, data = protocol.send, None
+    while True:
+        try:
+            message = generator_method(data)
+        except SocksException:
+            raise
+        except StopIteration:
+            break
+        method = message.pop("method")
+        try:
+            generator_method = protocol.send
+            data = getattr(io, method)(**message)
+        except Exception as exc:
+            generator_method, data = protocol.throw, exc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/io/asyncio.py 
new/siosocks-0.2.0/siosocks/io/asyncio.py
--- old/siosocks-0.1.0/siosocks/io/asyncio.py   2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/siosocks/io/asyncio.py   2020-09-01 02:25:39.000000000 
+0200
@@ -1,6 +1,7 @@
 import asyncio
 import logging
 
+from ..exceptions import SocksException
 from ..interface import AbstractSocksIO, async_engine
 from ..protocol import SocksServer, SocksClient, DEFAULT_ENCODING
 from .const import DEFAULT_BLOCK_SIZE
@@ -94,8 +95,8 @@
     socks_enabled = all(socks_required)
     socks_disabled = not any(socks_required)
     if socks_enabled == socks_disabled:
-        raise ValueError("Partly passed socks required arguments: "
-                         "socks_host = {!r}, socks_port = {!r}, socks_version 
= {!r}".format(*socks_required))
+        raise SocksException("Partly passed socks required arguments: "
+                             "socks_host = {!r}, socks_port = {!r}, 
socks_version = {!r}".format(*socks_required))
     if socks_enabled:
         reader, writer = await asyncio.open_connection(socks_host, socks_port, 
**open_connection_extras)
         protocol = SocksClient(host, port, socks_version, username=username, 
password=password, encoding=encoding,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/io/trio.py 
new/siosocks-0.2.0/siosocks/io/trio.py
--- old/siosocks-0.1.0/siosocks/io/trio.py      2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/siosocks/io/trio.py      2020-09-01 02:25:59.000000000 
+0200
@@ -2,6 +2,7 @@
 
 import trio
 
+from ..exceptions import SocksException
 from ..interface import AbstractSocksIO, async_engine
 from ..protocol import SocksServer, SocksClient, DEFAULT_ENCODING
 from .const import DEFAULT_BLOCK_SIZE
@@ -82,8 +83,8 @@
     socks_enabled = all(socks_required)
     socks_disabled = not any(socks_required)
     if socks_enabled == socks_disabled:
-        raise ValueError("Partly passed socks required arguments: "
-                         "socks_host = {!r}, socks_port = {!r}, socks_version 
= {!r}".format(*socks_required))
+        raise SocksException("Partly passed socks required arguments: "
+                             "socks_host = {!r}, socks_port = {!r}, 
socks_version = {!r}".format(*socks_required))
     if socks_enabled:
         stream = await trio.open_tcp_stream(socks_host, socks_port, 
**open_tcp_stream_extras)
         protocol = SocksClient(host, port, socks_version, username=username, 
password=password, encoding=encoding,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/protocol.py 
new/siosocks-0.2.0/siosocks/protocol.py
--- old/siosocks-0.1.0/siosocks/protocol.py     2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/siosocks/protocol.py     2020-09-01 03:45:54.000000000 
+0200
@@ -3,12 +3,17 @@
 import contextlib
 from ipaddress import IPv4Address, IPv6Address
 
+from .exceptions import SocksException
 from .sansio import SansIORW
 
 
 DEFAULT_ENCODING = "utf-8"
 
 
+def _hex(i: int):
+    return f"0x{i:0>2x}"
+
+
 class SocksCommand(enum.IntEnum):
     tcp_connect = 0x01
     tcp_bind = 0x02
@@ -29,7 +34,7 @@
 
     def verify_version(self, version):
         if version != self.version:
-            raise ValueError(f"Expect socks version {self.version}, but got 
{version}")
+            raise SocksException(f"Expect socks version {self.version}, but 
got {version}")
 
     @abc.abstractmethod
     def run(self):
@@ -65,7 +70,7 @@
         self.verify_version(version)
         user_id = yield from self.io.read_c_string()  # noqa
         if command != SocksCommand.tcp_connect:
-            raise ValueError(f"Socks command {command} is not supported")
+            raise SocksException(f"Socks command {_hex(command)} is not 
supported")
         ipv4 = IPv4Address(ipv4)
         if self.domain_flag_value_low <= ipv4 <= self.domain_flag_value_high:
             host = yield from self.io.read_c_string()
@@ -73,9 +78,9 @@
             host = ipv4.compressed
         try:
             yield from self.io.connect(host, port)
-        except Exception:
+        except Exception as exc:
             yield from self.write_response(Socks4Code.fail)
-            raise
+            raise SocksException from exc
         else:
             yield from self.write_response(Socks4Code.success)
             yield from self.io.passthrough()
@@ -94,11 +99,9 @@
         yield from self.io.write_c_string(user_id)
         if self.domain_flag_value_low <= ipv4 <= self.domain_flag_value_high:
             yield from self.io.write_c_string(host)
-        _, code, port, ipv4 = yield from self.io.read_struct(self.fmt)
+        _, code, *_ = yield from self.io.read_struct(self.fmt)
         if code != Socks4Code.success:
-            raise ValueError(f"Code {code} not equal to 'success' code 
{Socks4Code.success}")
-        if port != 0 or not IPv4Address(ipv4).is_unspecified:
-            raise ValueError("Socks redirect is not supported")
+            raise SocksException(f"Code {_hex(code)} not equal to 'success' 
code {_hex(Socks4Code.success)}")
         yield from self.io.passthrough()
 
 
@@ -152,6 +155,8 @@
             host = IPv6Address(octets).compressed
         elif address_type == Socks5AddressType.domain:
             host = (yield from self.io.read_pascal_string())
+        else:
+            raise SocksException(f"Unknown address type {_hex(address_type)}")
         port = yield from self.io.read_struct("H")
         return command, host, port
 
@@ -181,18 +186,18 @@
             auth_method = Socks5AuthMethod.no_acceptable
         yield from self.io.write_struct("BB", self.version, auth_method)
         if auth_method == Socks5AuthMethod.no_acceptable:
-            raise ValueError("No acceptible auth method")
+            raise SocksException("No acceptible auth method")
         if auth_method == Socks5AuthMethod.username_password:
             auth_version = yield from self.io.read_struct("B")
             if auth_version != 1:
-                raise ValueError(f"Username/password auth version 
{auth_version} not supported")
+                raise SocksException(f"Username/password auth version 
{_hex(auth_version)} not supported")
             received_username = yield from self.io.read_pascal_string()
             received_password = yield from self.io.read_pascal_string()
             auth_successful = received_username == username and 
received_password == password
             auth_return_code = 0 if auth_successful else 1
             yield from self.io.write_struct("BB", auth_version, 
auth_return_code)
             if not auth_successful:
-                raise ValueError("Wrong username or password")
+                raise SocksException("Wrong username or password")
 
     def run(self, username=None, password=None):
         version = yield from self.io.read_struct("B")
@@ -201,12 +206,12 @@
         command, host, port = yield from self.read_command()
         if command != SocksCommand.tcp_connect:
             yield from 
self.write_command(Socks5Code.command_not_supported_or_protocol_error)
-            raise ValueError(f"Socks command {command} is not supported")
+            raise SocksException(f"Socks command {_hex(command)} is not 
supported")
         try:
             yield from self.io.connect(host, port)
-        except Exception:
+        except Exception as exc:
             yield from self.write_command(Socks5Code.general_failure)
-            raise
+            raise SocksException from exc
         else:
             yield from self.write_command(Socks5Code.request_granted)
             yield from self.io.passthrough()
@@ -224,27 +229,24 @@
         version, code = yield from self.io.read_struct("BB")
         self.verify_version(version)
         if code != auth_method:
-            raise ValueError(f"Auth method {auth_method} not accepted with 
{code} code")
+            raise SocksException(f"Auth method {_hex(auth_method)} not 
accepted with {_hex(code)} code")
         if auth_method == Socks5AuthMethod.username_password:
             yield from self.io.write_struct("B", 1)
             yield from self.io.write_pascal_string(username)
             yield from self.io.write_pascal_string(password)
             auth_version, code = yield from self.io.read_struct("BB")
             if auth_version != 1:
-                raise ValueError(f"Username/password auth version 
{auth_version} not supported")
+                raise SocksException(f"Username/password auth version 
{_hex(auth_version)} not supported")
             if code != 0:
-                raise ValueError(f"Username/password auth failed with code 
{code}")
+                raise SocksException(f"Username/password auth failed with code 
{_hex(code)}")
 
     def run(self, host, port, username=None, password=None):
         yield from self.io.write_struct("B", self.version)
         yield from self.auth(username, password)
         yield from self.write_command(SocksCommand.tcp_connect, host, port)
-        code, host, port = yield from self.read_command()
+        code, *_ = yield from self.read_command()
         if code != Socks5Code.request_granted:
-            raise ValueError(f"Code {code} not equal to 'success' code 
{Socks5Code.request_granted}")
-        # not sure if this is enough
-        if port != 0:
-            raise ValueError("Socks redirect is not supported")
+            raise SocksException(f"Code {_hex(code)} not equal to 'success' 
code {_hex(Socks5Code.request_granted)}")
         yield from self.io.passthrough()
 
 
@@ -252,30 +254,30 @@
                 strict_security_policy=True, encoding=DEFAULT_ENCODING):
     auth_required = username is not None
     if 4 in allowed_versions and auth_required and strict_security_policy:
-        raise ValueError("Socks4 do not provide auth methods, "
-                         "but socks4 allowed and auth provided and "
-                         "strict security policy enabled")
+        raise SocksException("Socks4 do not provide auth methods, "
+                             "but socks4 allowed and auth provided and "
+                             "strict security policy enabled")
     io = SansIORW(encoding)
     version = yield from io.read_struct("B", put_back=True)
     if version not in allowed_versions:
-        raise ValueError(f"Version {version} is not in allowed 
{allowed_versions}")
+        raise SocksException(f"Version {version} is not in allowed 
{allowed_versions}")
     if version == 4:
         yield from Socks4Server(io).run()
     elif version == 5:
         yield from Socks5Server(io).run(username, password)
     else:
-        raise ValueError(f"Version {version} is not supported")
+        raise SocksException(f"Version {version} is not supported")
 
 
 def SocksClient(host, port, version, *, username=None, password=None, 
encoding=DEFAULT_ENCODING,
                 socks4_extras={}, socks5_extras={}):
     auth_required = username is not None
     if version == 4 and auth_required:
-        raise ValueError("Socks4 do not provide auth methods, but auth 
provided")
+        raise SocksException("Socks4 do not provide auth methods, but auth 
provided")
     io = SansIORW(encoding)
     if version == 4:
         yield from Socks4Client(io).run(host, port, **socks4_extras)
     elif version == 5:
         yield from Socks5Client(io).run(host, port, username, password, 
**socks5_extras)
     else:
-        raise ValueError(f"Version {version} is not supported")
+        raise SocksException(f"Version {version} is not supported")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks/sansio.py 
new/siosocks-0.2.0/siosocks/sansio.py
--- old/siosocks-0.1.0/siosocks/sansio.py       2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/siosocks/sansio.py       2020-09-01 03:03:14.000000000 
+0200
@@ -1,5 +1,7 @@
 import struct
 
+from .exceptions import SocksException
+
 
 MAX_STRING_SIZE = 2 ** 10
 
@@ -20,7 +22,7 @@
     def _read(self):
         data = yield dict(method="read")
         if not data:
-            raise EOFError
+            raise SocksException("Unexpected end of data")
         return data
 
     def read_exactly(self, count, *, put_back=False):
@@ -32,7 +34,7 @@
         while True:
             pos = self.buffer.find(delimiter)
             if max_size is not None and (pos == -1 and len(self.buffer) > 
max_size or pos > max_size):
-                raise ValueError(f"Buffer became too long ({len(self.buffer)} 
> {max_size})")
+                raise SocksException(f"Buffer became too long 
({len(self.buffer)} > {max_size})")
             if pos != -1:
                 return self._take_first(pos, put_back=put_back)
             self.buffer += yield from self._read()
@@ -75,7 +77,7 @@
         b = s if self.encoding is None else s.encode(self.encoding)
         size = len(b)
         if size > 255:
-            raise ValueError(f"Pascal string must be no longer than 255 
characters, got {size}")
+            raise SocksException(f"Pascal string must be no longer than 255 
characters, got {size}")
         yield from self.write_struct("B", size)
         yield from self.write(b)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks.egg-info/PKG-INFO 
new/siosocks-0.2.0/siosocks.egg-info/PKG-INFO
--- old/siosocks-0.1.0/siosocks.egg-info/PKG-INFO       2019-09-21 
16:51:23.000000000 +0200
+++ new/siosocks-0.2.0/siosocks.egg-info/PKG-INFO       2020-09-01 
03:59:41.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: siosocks
-Version: 0.1.0
+Version: 0.2.0
 Summary: sans-io socks proxy client/server with couple io backends
 Home-page: https://github.com/pohmelie/siosocks
 Author: pohmelie
@@ -168,6 +168,30 @@
                                 username/password auth [default: False]
           -v, --version         Show siosocks version
         ```
+        
+        ### Exceptions
+        `siosocks` have unified exception for all types of socks-related 
errors:
+        ``` python
+        import asyncio
+        
+        from siosocks.exceptions import SocksException
+        from siosocks.io.asyncio import open_connection
+        
+        
+        async def main():
+            try:
+                r, w = await open_connection("127.0.0.1", 80, 
socks_host="localhost", socks_port=9050, socks_version=5)
+            except SocksException:
+                ...
+            else:
+                # at this point all socks-related tasks done and returned 
reader and writer
+                # are just plain asyncio objects without any siosocks proxies
+        
+        
+        loop = asyncio.get_event_loop()
+        loop.run_until_complete(main())
+        ```
+        
         ## Low-level
         Shadowsocks-like 
[client/server](https://github.com/pohmelie/siosocks/blob/master/examples/shadowsocks-like.py).
 Shadowsocks-like built on top of socks5 and encryption. It have ??client??, 
which is actually socks server and ??server??. So, precisely there are two 
servers: client side and server side. Purpose of shadowsocks is to encrypt data 
between ??incoming?? and ??outgoing?? servers. In common this looks like:
         ```
@@ -176,8 +200,9 @@
         Example above use Caesar cipher for simplicity (and security of 
course).
         
         # Roadmap/contibutions
-        * [ ] add more backends (average)
-        * [ ] speed up `passthrough` implementation (seems hard)
+        - [ ] add more backends (average)
+        - [ ] speed up `passthrough` implementation (seems hard)
+        - [ ] add client redirection
         
 Platform: UNKNOWN
 Classifier: Programming Language :: Python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/siosocks.egg-info/SOURCES.txt 
new/siosocks-0.2.0/siosocks.egg-info/SOURCES.txt
--- old/siosocks-0.1.0/siosocks.egg-info/SOURCES.txt    2019-09-21 
16:51:23.000000000 +0200
+++ new/siosocks-0.2.0/siosocks.egg-info/SOURCES.txt    2020-09-01 
03:59:41.000000000 +0200
@@ -6,6 +6,7 @@
 setup.py
 siosocks/__init__.py
 siosocks/__main__.py
+siosocks/exceptions.py
 siosocks/interface.py
 siosocks/protocol.py
 siosocks/sansio.py
@@ -25,17 +26,27 @@
 tests/test_socketserver.py
 tests/test_trio.py
 tests/__pycache__/test_asyncio.cpython-36-pytest-5.0.1.pyc
+tests/__pycache__/test_asyncio.cpython-37-pytest-6.0.1.pyc
 tests/__pycache__/test_asyncio.cpython-38-pytest-5.0.1.pyc
+tests/__pycache__/test_asyncio.cpython-38-pytest-5.4.3.pyc
 tests/__pycache__/test_bug.cpython-36-pytest-5.0.1.pyc
 tests/__pycache__/test_bug2.cpython-36-pytest-5.0.1.pyc
 tests/__pycache__/test_protocol.cpython-36-PYTEST.pyc
 tests/__pycache__/test_protocol.cpython-36-pytest-5.0.1.pyc
+tests/__pycache__/test_protocol.cpython-37-pytest-6.0.1.pyc
 tests/__pycache__/test_protocol.cpython-38-pytest-5.0.1.pyc
+tests/__pycache__/test_protocol.cpython-38-pytest-5.4.3.pyc
 tests/__pycache__/test_sansio.cpython-36-PYTEST.pyc
 tests/__pycache__/test_sansio.cpython-36-pytest-5.0.1.pyc
+tests/__pycache__/test_sansio.cpython-37-pytest-6.0.1.pyc
 tests/__pycache__/test_sansio.cpython-38-pytest-5.0.1.pyc
+tests/__pycache__/test_sansio.cpython-38-pytest-5.4.3.pyc
 tests/__pycache__/test_socketserver.cpython-36-pytest-5.0.1.pyc
+tests/__pycache__/test_socketserver.cpython-37-pytest-6.0.1.pyc
 tests/__pycache__/test_socketserver.cpython-38-pytest-5.0.1.pyc
+tests/__pycache__/test_socketserver.cpython-38-pytest-5.4.3.pyc
 tests/__pycache__/test_trio.cpython-36-pytest-5.0.1.pyc
+tests/__pycache__/test_trio.cpython-37-pytest-6.0.1.pyc
 tests/__pycache__/test_trio.cpython-38-pytest-5.0.1.pyc
+tests/__pycache__/test_trio.cpython-38-pytest-5.4.3.pyc
 tests/__pycache__/test_trio2.cpython-36-pytest-5.0.1.pyc
\ No newline at end of file
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_asyncio.cpython-37-pytest-6.0.1.pyc 
and 
new/siosocks-0.2.0/tests/__pycache__/test_asyncio.cpython-37-pytest-6.0.1.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_asyncio.cpython-38-pytest-5.4.3.pyc 
and 
new/siosocks-0.2.0/tests/__pycache__/test_asyncio.cpython-38-pytest-5.4.3.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_protocol.cpython-37-pytest-6.0.1.pyc 
and 
new/siosocks-0.2.0/tests/__pycache__/test_protocol.cpython-37-pytest-6.0.1.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_protocol.cpython-38-pytest-5.4.3.pyc 
and 
new/siosocks-0.2.0/tests/__pycache__/test_protocol.cpython-38-pytest-5.4.3.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_sansio.cpython-37-pytest-6.0.1.pyc 
and 
new/siosocks-0.2.0/tests/__pycache__/test_sansio.cpython-37-pytest-6.0.1.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_sansio.cpython-38-pytest-5.4.3.pyc 
and 
new/siosocks-0.2.0/tests/__pycache__/test_sansio.cpython-38-pytest-5.4.3.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_socketserver.cpython-37-pytest-6.0.1.pyc
 and 
new/siosocks-0.2.0/tests/__pycache__/test_socketserver.cpython-37-pytest-6.0.1.pyc
 differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_socketserver.cpython-38-pytest-5.4.3.pyc
 and 
new/siosocks-0.2.0/tests/__pycache__/test_socketserver.cpython-38-pytest-5.4.3.pyc
 differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_trio.cpython-37-pytest-6.0.1.pyc and 
new/siosocks-0.2.0/tests/__pycache__/test_trio.cpython-37-pytest-6.0.1.pyc 
differ
Binary files 
old/siosocks-0.1.0/tests/__pycache__/test_trio.cpython-38-pytest-5.4.3.pyc and 
new/siosocks-0.2.0/tests/__pycache__/test_trio.cpython-38-pytest-5.4.3.pyc 
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/tests/test_asyncio.py 
new/siosocks-0.2.0/tests/test_asyncio.py
--- old/siosocks-0.1.0/tests/test_asyncio.py    2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/tests/test_asyncio.py    2020-09-01 02:28:28.000000000 
+0200
@@ -3,6 +3,7 @@
 import pytest
 
 from siosocks.io.asyncio import socks_server_handler, open_connection
+from siosocks.exceptions import SocksException
 
 
 HOST = "127.0.0.1"
@@ -52,7 +53,14 @@
 
 
 @pytest.mark.asyncio
-async def test_connection_partly_passed_error():
-    with pytest.raises(ValueError):
+async def test_connection_socks_failed(socks_server_port, unused_tcp_port):
+    with pytest.raises(SocksException):
+        await open_connection(HOST, unused_tcp_port,
+                              socks_host=HOST, socks_port=socks_server_port, 
socks_version=4)
+
+
[email protected]
+async def test_connection_partly_passed_error(endpoint_port, 
socks_server_port):
+    with pytest.raises(SocksException):
         await open_connection(HOST, endpoint_port,
                               socks_host=HOST, socks_port=socks_server_port)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/tests/test_protocol.py 
new/siosocks-0.2.0/tests/test_protocol.py
--- old/siosocks-0.1.0/tests/test_protocol.py   2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/tests/test_protocol.py   2020-09-01 03:47:59.000000000 
+0200
@@ -3,6 +3,7 @@
 
 import pytest
 
+from siosocks.exceptions import SocksException
 from siosocks.protocol import SocksClient, SocksServer
 from siosocks.sansio import SansIORW
 
@@ -62,7 +63,7 @@
         io = SansIORW(encoding="utf-8")
         yield from io.read_exactly(1)
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("abc", 123, 6), server())
 
 
@@ -72,7 +73,7 @@
         io = SansIORW(encoding="utf-8")
         yield from io.read_exactly(1)
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("abc", 123, 4, username="yoba", password="foo"), 
server())
 
 
@@ -91,10 +92,11 @@
         yield from io.write_struct("BBH4s", 0, 0x5b, 0, b"\x00" * 4)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("127.0.0.1", 123, 4, 
socks4_extras=dict(user_id="yoba")), server())
 
 
[email protected]("this check removed")
 def test_client_socks4_redirect_not_supported_by_port():
 
     def server():
@@ -110,10 +112,11 @@
         yield from io.write_struct("BBH4s", 0, 0x5a, 666, b"\x00" * 4)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("127.0.0.1", 123, 4, 
socks4_extras=dict(user_id="yoba")), server())
 
 
[email protected]("this check removed")
 def test_client_socks4_redirect_not_supported_by_host():
 
     def server():
@@ -129,7 +132,7 @@
         yield from io.write_struct("BBH4s", 0, 0x5a, 0, b"\x7f\x00\x00\x01")
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("127.0.0.1", 123, 4, 
socks4_extras=dict(user_id="yoba")), server())
 
 
@@ -178,7 +181,7 @@
         yield from io.write(b"\x04")
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(username="foo"))
 
 
@@ -189,7 +192,7 @@
         yield from io.write(b"\x06")
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer())
 
 
@@ -200,7 +203,7 @@
         yield from io.write(b"\x06")
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(allowed_versions={6}))
 
 
@@ -212,7 +215,7 @@
         yield from io.write_c_string("yoba")
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer())
 
 
@@ -229,7 +232,7 @@
         assert ipv4 == b"\x00" * 4
         raise RuntimeError("connection failed")
 
-    with pytest.raises(RuntimeError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(), fail_connection=True)
 
 
@@ -277,7 +280,7 @@
         yield from io.write_struct("BB", 1, 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("abc", 666, 5), server())
 
 
@@ -292,7 +295,7 @@
         yield from io.write_struct("BB", 5, 1)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("abc", 666, 5), server())
 
 
@@ -314,7 +317,7 @@
         yield from io.write_struct("BB", 0, 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("abc", 666, 5, username="yoba", password="foo"), 
server())
 
 
@@ -336,7 +339,7 @@
         yield from io.write_struct("BB", 1, 1)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("abc", 666, 5, username="yoba", password="foo"), 
server())
 
 
@@ -354,7 +357,7 @@
         yield from io.write_struct("4B", 6, 0, 0, 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("127.0.0.1", 666, 5), server())
 
 
@@ -374,10 +377,11 @@
         yield from io.write_struct("H", 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("127.0.0.1", 666, 5), server())
 
 
[email protected]("this check removed")
 def test_client_socks5_command_redirect_is_not_allowed():
 
     def server():
@@ -394,7 +398,7 @@
         yield from io.write_struct("H", 1)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(SocksClient("127.0.0.1", 666, 5), server())
 
 
@@ -464,7 +468,7 @@
         yield from io.write_struct("B", 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer())
 
 
@@ -479,7 +483,7 @@
         yield from io.write_struct("B", 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(allowed_versions={5}, username="yoba", 
password="foo"))
 
 
@@ -498,7 +502,7 @@
         assert (auth_version, retcode) == (1, 1)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(allowed_versions={5}, username="yoba", 
password="foo"))
 
 
@@ -517,7 +521,7 @@
         assert (auth_version, retcode) == (1, 1)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(allowed_versions={5}, username="yoba", 
password="foo"))
 
 
@@ -537,7 +541,22 @@
         assert (ipv4, port) == (b"\x00" * 4, 0)
         yield from io.passthrough()
 
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
+        rotor(client(), SocksServer())
+
+
+def test_server_socks5_address_type_not_supported():
+
+    def client():
+        io = SansIORW(encoding="utf-8")
+        yield from io.write_struct("B", 5)
+        yield from io.write_struct("BB", 1, 0)
+        version, auth_method = yield from io.read_struct("BB")
+        assert (version, auth_method) == (5, 0)
+        yield from io.write_struct("4B", 5, 2, 0, 13)
+        yield from io.passthrough()
+
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer())
 
 
@@ -555,7 +574,7 @@
         assert (version, command, zero, address_type) == (5, 1, 0, 1)
         raise RuntimeError("connection failed")
 
-    with pytest.raises(RuntimeError):
+    with pytest.raises(SocksException):
         rotor(client(), SocksServer(), fail_connection=True)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/tests/test_sansio.py 
new/siosocks-0.2.0/tests/test_sansio.py
--- old/siosocks-0.1.0/tests/test_sansio.py     2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/tests/test_sansio.py     2020-09-01 03:10:45.000000000 
+0200
@@ -1,6 +1,7 @@
 import pytest
 
 from siosocks.sansio import SansIORW
+from siosocks.exceptions import SocksException
 
 
 @pytest.fixture
@@ -47,7 +48,7 @@
     assert io.read_exactly(3) == b"123"
     assert io.read_exactly(1, put_back=True) == b"4"
     assert io.read_exactly(1) == b"4"
-    with pytest.raises(EOFError):
+    with pytest.raises(SocksException):
         io.set(b"1").read_exactly(2)
 
 
@@ -56,11 +57,11 @@
     assert io.read_until(b"3", put_back=True) == b"12"
     assert io.read_until(b"3") == b"12"
     assert io.read_until(b"5", max_size=2) == b"34"
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         io.set(b"1", b"234", b"56").read_until(b"4", max_size=2)
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         io.set(b"123", b"456").read_until(b"4", max_size=2)
-    with pytest.raises(EOFError):
+    with pytest.raises(SocksException):
         io.set(b"123").read_until(b"4")
 
 
@@ -69,7 +70,7 @@
     assert io.read_struct("3B", put_back=True) == (1, 2, 3)
     assert io.read_struct("3B") == (1, 2, 3)
     assert io.set(b"\x01\x02").read_struct("B") == 1
-    with pytest.raises(EOFError):
+    with pytest.raises(SocksException):
         io.set(b"\x01").read_struct("3B")
 
 
@@ -77,13 +78,13 @@
     io.set(b"foo", b"bar", b"\x00", b"tail")
     assert io.read_c_string() == "foobar"
     assert io.read_exactly(4) == b"tail"
-    with pytest.raises(EOFError):
+    with pytest.raises(SocksException):
         io.set(b"foobar").read_c_string()
 
 
 def test_read_pascal_string(io):
     assert io.set(b"\x06", b"foobar").read_pascal_string() == "foobar"
-    with pytest.raises(EOFError):
+    with pytest.raises(SocksException):
         io.set(b"\x07", b"foobar").read_pascal_string()
 
 
@@ -111,5 +112,5 @@
 def test_write_pascal_string(io):
     io.write_pascal_string("foobar")
     assert io.buffer == [b"\x06", b"foobar"]
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         io.write_pascal_string("x" * 256)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/tests/test_socketserver.py 
new/siosocks-0.2.0/tests/test_socketserver.py
--- old/siosocks-0.1.0/tests/test_socketserver.py       2019-08-02 
02:10:24.000000000 +0200
+++ new/siosocks-0.2.0/tests/test_socketserver.py       2020-09-01 
02:32:31.000000000 +0200
@@ -7,6 +7,7 @@
 
 from siosocks.io.socket import socks_server_handler
 from siosocks.io.asyncio import open_connection
+from siosocks.exceptions import SocksException
 
 
 HOST = "127.0.0.1"
@@ -61,6 +62,6 @@
 
 @pytest.mark.asyncio
 async def test_connection_partly_passed_error():
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         await open_connection(HOST, endpoint_port,
                               socks_host=HOST, socks_port=socks_server_port)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/siosocks-0.1.0/tests/test_trio.py 
new/siosocks-0.2.0/tests/test_trio.py
--- old/siosocks-0.1.0/tests/test_trio.py       2019-08-02 02:10:24.000000000 
+0200
+++ new/siosocks-0.2.0/tests/test_trio.py       2020-09-01 02:34:02.000000000 
+0200
@@ -3,6 +3,7 @@
 import trio
 import pytest
 
+from siosocks.exceptions import SocksException
 from siosocks.io.trio import socks_server_handler, open_tcp_stream
 
 
@@ -59,6 +60,6 @@
 async def test_connection_partly_passed_error(nursery):
     endpoint_port = await endpoint(nursery)
     socks_server_port = await socks(nursery)
-    with pytest.raises(ValueError):
+    with pytest.raises(SocksException):
         await open_tcp_stream(HOST, endpoint_port,
                               socks_host=HOST, socks_port=socks_server_port)

Reply via email to