summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngelos Evripiotis <jevripiotis@bloomberg.net>2019-10-11 13:25:11 +0100
committerAngelos Evripiotis <jevripiotis@bloomberg.net>2019-10-15 15:37:59 +0100
commit739753bbb54ac958d1762f95992cbc7b4ec8d3fe (patch)
treedd7838d66d242cfd123eb2903ab9f3b390567c05
parent7d0bff1ff0b9e32bf9555ed8b68f8e1caed677a2 (diff)
downloadbuildstream-aevri/win32_receive_signals.tar.gz
cas: localhost tcp/ip connection when on win32aevri/win32_receive_signals
To support Windows, add the possibility of connecting to buildbox-casd via a localhost connection, instead of a UNIX socket.
-rw-r--r--src/buildstream/_cas/cascache.py11
-rw-r--r--src/buildstream/_cas/casdprocessmanager.py45
2 files changed, 52 insertions, 4 deletions
diff --git a/src/buildstream/_cas/cascache.py b/src/buildstream/_cas/cascache.py
index 4114d9fff..8638e4d01 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 fb6caf807..40f945f24 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