You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by gi...@apache.org on 2020/12/29 13:09:19 UTC

[buildstream] 16/16: cas: localhost tcp/ip connection when on win32

This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch aevri/win32_receive_signals
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 739753bbb54ac958d1762f95992cbc7b4ec8d3fe
Author: Angelos Evripiotis <je...@bloomberg.net>
AuthorDate: Fri Oct 11 13:25:11 2019 +0100

    cas: localhost tcp/ip connection when on win32
    
    To support Windows, add the possibility of connecting to buildbox-casd
    via a localhost connection, instead of a UNIX socket.
---
 src/buildstream/_cas/cascache.py           | 11 ++++++--
 src/buildstream/_cas/casdprocessmanager.py | 45 ++++++++++++++++++++++++++++--
 2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/src/buildstream/_cas/cascache.py b/src/buildstream/_cas/cascache.py
index 4114d9f..8638e4d 100644
--- a/src/buildstream/_cas/cascache.py
+++ b/src/buildstream/_cas/cascache.py
@@ -26,6 +26,7 @@ import contextlib
 import ctypes
 import multiprocessing
 import signal
+import sys
 import time
 
 import grpc
@@ -38,7 +39,7 @@ from .. import _signals, utils
 from ..types import FastEnum
 from .._exceptions import CASCacheError
 
-from .casdprocessmanager import CASDProcessManager
+from .casdprocessmanager import CASDProcessManager, ConnectionType
 from .casremote import _CASBatchRead, _CASBatchUpdate
 
 _BUFFER_SIZE = 65536
@@ -76,8 +77,14 @@ class CASCache():
 
         if casd:
             log_dir = os.path.join(self.casdir, "logs")
+
+            if sys.platform == 'win32':
+                connection_type = ConnectionType.LOCALHOST_PORT
+            else:
+                connection_type = ConnectionType.UNIX_SOCKET
+
             self._casd_process_manager = CASDProcessManager(
-                path, log_dir, log_level, cache_quota, protect_session_blobs)
+                path, log_dir, log_level, cache_quota, protect_session_blobs, connection_type)
         else:
             self._casd_process_manager = None
 
diff --git a/src/buildstream/_cas/casdprocessmanager.py b/src/buildstream/_cas/casdprocessmanager.py
index fb6caf8..40f945f 100644
--- a/src/buildstream/_cas/casdprocessmanager.py
+++ b/src/buildstream/_cas/casdprocessmanager.py
@@ -21,6 +21,7 @@ import contextlib
 import os
 import shutil
 import signal
+import socket
 import subprocess
 import sys
 import tempfile
@@ -32,9 +33,31 @@ from ..types import FastEnum
 
 _CASD_MAX_LOGFILES = 10
 
+# Note that we want to make sure that BuildStream and buildbox-casd are on the
+# same page about what the hostname is, for that reason we may want to avoid
+# e.g. empty string as the hostname. We also don't want buildbox-casd to accept
+# connections from other machines in this use-case.
+#
+# Note that buildbox-casd will stop with an error if it fails to listen on all
+# addresses, but if it sucessfully listens on any then it will continue. For
+# this reason we don't want to choose `localhost` as the hostname, otherwise it
+# will also bind to the ipv6 address `::1`.
+#
+_HOSTNAME = "127.0.0.1"
+
 
 class ConnectionType(FastEnum):
     UNIX_SOCKET = 0
+    LOCALHOST_PORT = 1
+
+
+# Note that it's necessary to use the LOCALHOST_PORT option on Windows, because
+# grpc doesn't support AF_UNIX on win32 yet. You can verify this in the grpc
+# source by searching for 'GRPC_HAVE_UNIX_SOCKET'.
+#
+# There also isn't support in grpc for receiving a WSADuplicateSocket, so we
+# can't pass one over. You can verify this in the grpc source by searching for
+# 'WSASocket' and noting that the lpProtocolInfo parameter is always null.
 
 
 # CASDProcessManager
@@ -62,8 +85,11 @@ class CASDProcessManager:
     ):
         self._log_dir = log_dir
 
-        assert connection_type == ConnectionType.UNIX_SOCKET
-        self._connection = _UnixSocketConnection()
+        if connection_type == ConnectionType.UNIX_SOCKET:
+            self._connection = _UnixSocketConnection()
+        else:
+            assert connection_type == ConnectionType.LOCALHOST_PORT
+            self._connection = _LocalhostPortConnection()
 
         casd_args = [utils.get_host_tool('buildbox-casd')]
         casd_args.append('--bind=' + self.connection_string)
@@ -242,6 +268,21 @@ class CASDProcessManager:
         self._failure_callback()
 
 
+class _LocalhostPortConnection:
+    def __init__(self):
+        # Note that there is a race-condition between us finding an available
+        # port and buildbox-casd taking ownership of it. If another process
+        # takes the port in the mean time, we will later fail with an error.
+        with socket.socket() as s:
+            s.bind((_HOSTNAME, 0))
+            hostname, port = s.getsockname()
+        assert hostname == _HOSTNAME
+        self.connection_string = "{}:{}".format(hostname, port)
+
+    def release_resouces(self):
+        pass
+
+
 class _UnixSocketConnection:
     def __init__(self):
         # Place socket in global/user temporary directory to avoid hitting