| 295 | return stream |
| 296 | |
| 297 | def _create_stream( |
| 298 | self, |
| 299 | max_buffer_size: int, |
| 300 | af: socket.AddressFamily, |
| 301 | addr: Tuple, |
| 302 | source_ip: Optional[str] = None, |
| 303 | source_port: Optional[int] = None, |
| 304 | ) -> Tuple[IOStream, "Future[IOStream]"]: |
| 305 | # Always connect in plaintext; we'll convert to ssl if necessary |
| 306 | # after one connection has completed. |
| 307 | source_port_bind = source_port if isinstance(source_port, int) else 0 |
| 308 | source_ip_bind = source_ip |
| 309 | if source_port_bind and not source_ip: |
| 310 | # User required a specific port, but did not specify |
| 311 | # a certain source IP, will bind to the default loopback. |
| 312 | source_ip_bind = "::1" if af == socket.AF_INET6 else "127.0.0.1" |
| 313 | # Trying to use the same address family as the requested af socket: |
| 314 | # - 127.0.0.1 for IPv4 |
| 315 | # - ::1 for IPv6 |
| 316 | socket_obj = socket.socket(af) |
| 317 | if source_port_bind or source_ip_bind: |
| 318 | # If the user requires binding also to a specific IP/port. |
| 319 | try: |
| 320 | socket_obj.bind((source_ip_bind, source_port_bind)) |
| 321 | except OSError: |
| 322 | socket_obj.close() |
| 323 | # Fail loudly if unable to use the IP/port. |
| 324 | raise |
| 325 | try: |
| 326 | stream = IOStream(socket_obj, max_buffer_size=max_buffer_size) |
| 327 | except OSError as e: |
| 328 | fu = Future() # type: Future[IOStream] |
| 329 | fu.set_exception(e) |
| 330 | return stream, fu |
| 331 | else: |
| 332 | return stream, stream.connect(addr) |