From 4c485d0b112721d3a2b2939ab61db14b7608c98c Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 10:52:14 +0200 Subject: [PATCH 1/9] [trac800] Interface and tests for the sockcreator parser --- configure.ac | 2 +- src/bin/bind10/Makefile.am | 10 +- src/bin/bind10/__init__.py | 0 .../bind10/{bind10.py.in => bind10_src.py.in} | 0 src/bin/bind10/sockcreator.py | 78 +++++++ src/bin/bind10/tests/Makefile.am | 4 +- src/bin/bind10/tests/bind10_test.py.in | 2 +- src/bin/bind10/tests/sockcreator_test.py | 193 ++++++++++++++++++ 8 files changed, 282 insertions(+), 7 deletions(-) create mode 100644 src/bin/bind10/__init__.py rename src/bin/bind10/{bind10.py.in => bind10_src.py.in} (100%) create mode 100644 src/bin/bind10/sockcreator.py create mode 100644 src/bin/bind10/tests/sockcreator_test.py diff --git a/configure.ac b/configure.ac index 48a79d262c..9ee534829e 100644 --- a/configure.ac +++ b/configure.ac @@ -902,7 +902,7 @@ AC_OUTPUT([doc/version.ent src/bin/zonemgr/run_b10-zonemgr.sh src/bin/stats/stats.py src/bin/stats/stats_httpd.py - src/bin/bind10/bind10.py + src/bin/bind10/bind10_src.py src/bin/bind10/run_bind10.sh src/bin/bind10/tests/bind10_test.py src/bin/bindctl/run_bindctl.sh diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am index 126c429e44..1a5ce64a54 100644 --- a/src/bin/bind10/Makefile.am +++ b/src/bin/bind10/Makefile.am @@ -1,7 +1,11 @@ SUBDIRS = . tests sbin_SCRIPTS = bind10 -CLEANFILES = bind10 bind10.pyc bind10_messages.py bind10_messages.pyc +CLEANFILES = bind10 bind10_src.pyc bind10_messages.py bind10_messages.pyc \ + sockcreator.pyc + +python_PYTHON = __init__.py sockcreator.py +pythondir = $(pyexecdir)/bind10 pkglibexecdir = $(libexecdir)/@PACKAGE@ pyexec_DATA = bind10_messages.py @@ -24,9 +28,9 @@ bind10_messages.py: bind10_messages.mes $(top_builddir)/src/lib/log/compiler/message -p $(top_srcdir)/src/bin/bind10/bind10_messages.mes # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix -bind10: bind10.py +bind10: bind10_src.py $(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \ - -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bind10.py >$@ + -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bind10_src.py >$@ chmod a+x $@ pytest: diff --git a/src/bin/bind10/__init__.py b/src/bin/bind10/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10_src.py.in similarity index 100% rename from src/bin/bind10/bind10.py.in rename to src/bin/bind10/bind10_src.py.in diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py new file mode 100644 index 0000000000..667c22f293 --- /dev/null +++ b/src/bin/bind10/sockcreator.py @@ -0,0 +1,78 @@ +# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +""" +Module that comunicates with the priviledget socket creator (b10-sockcreator). +""" + +class CreatorError(Exception): + """ + Exception for socket creator related errors. + + It has two members: fatal and errno and they are just holding the values + passed to the __init__ function. + """ + + def __init__(self, message, fatal, errno=None): + """ + Creates the exception. The message argument is the usual string. + The fatal one tells if the error is fatal (eg. the creator crashed) + and errno is the errno value returned from socket creator, if + applicable. + """ + Exception.__init__(self, message) + self.fatal = fatal + self.errno = errno + +class Parser: + """ + This class knows the sockcreator language. It creates commands, sends them + and receives the answers and parses them. + + It does not start it, the communication channel must be provided. + + In theory, anything here can throw a fatal CreatorError exception, but it + happens only in case something like the creator process crashes. Any other + occations are mentioned explicitly. + """ + + def __init__(self, creator_socket): + """ + Creates the parser. The creator_socket is socket to the socket creator + process that will be used for communication. However, the object must + have a read_fd() method to read the file descriptor. This slightly + unusual modification of socket object is used to easy up testing. + """ + pass # TODO Implement + + def terminate(self): + """ + Asks the creator process to terminate and waits for it to close the + socket. Does not return anything. + """ + pass # TODO Implement + + def get_socket(self, address, port, socktype): + """ + Asks the socket creator process to create a socket. Pass an address + (the isc.net.IPaddr object), port number and socket type (either + string "UDP", "TCP" or constant socket.SOCK_DGRAM or + socket.SOCK_STREAM. + + Blocks until it is provided by the socket creator process (which + should be fast, as it is on localhost) and returns the file descriptor + number. It raises a CreatorError exception if the creation fails. + """ + pass # TODO Implement diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am index 3d8d57a195..3fe357e264 100644 --- a/src/bin/bind10/tests/Makefile.am +++ b/src/bin/bind10/tests/Makefile.am @@ -1,7 +1,7 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ #PYTESTS = args_test.py bind10_test.py # NOTE: this has a generated test found in the builddir -PYTESTS = bind10_test.py +PYTESTS = bind10_test.py sockcreator_test.py EXTRA_DIST = $(PYTESTS) # If necessary (rare cases), explicitly specify paths to dynamic libraries @@ -21,7 +21,7 @@ endif for pytest in $(PYTESTS) ; do \ echo Running test: $$pytest ; \ $(LIBRARY_PATH_PLACEHOLDER) \ - env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \ + env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin:$(abs_top_builddir)/src/bin/bind10 \ BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \ $(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \ done diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in index 9d794a6a08..6b871334b8 100644 --- a/src/bin/bind10/tests/bind10_test.py.in +++ b/src/bin/bind10/tests/bind10_test.py.in @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from bind10 import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file, _BASETIME +from bind10_src import ProcessInfo, BoB, parse_args, dump_pid, unlink_pid_file, _BASETIME # XXX: environment tests are currently disabled, due to the preprocessor # setup that we have now complicating the environment diff --git a/src/bin/bind10/tests/sockcreator_test.py b/src/bin/bind10/tests/sockcreator_test.py new file mode 100644 index 0000000000..4e9390387a --- /dev/null +++ b/src/bin/bind10/tests/sockcreator_test.py @@ -0,0 +1,193 @@ +# Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM +# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +""" +Tests for the bind10.sockcreator module. +""" + +import unittest +import struct +import socket +from bind10.sockcreator import Parser, CreatorError +from isc.net.addr import IPAddr + +class FakeCreator: + """ + Class emulating the socket to the socket creator. It can be given expected + data to receive (and check) and responses to give to the Parser class + during testing. + """ + + class InvalidPlan(Exception): + """ + Raised when someone wants to recv when sending is planned or vice + versa. + """ + pass + + class InvalidData(Exception): + """ + Raises when the data passed to sendall are not the same as expected. + """ + pass + + def __init__(self, plan): + """ + Create the object. The plan variable contains list of expected actions, + in form: + + [('r', 'Data to return from recv'), ('s', 'Data expected on sendall'), + , ('d', 'File descriptor number to return from read_sock'), ('e', + None), ...] + + It modifies the array as it goes. + """ + self.__plan = plan + + def __get_plan(self, expected): + if len(self.__plan) == 0: + raise InvalidPlan('Nothing more planned') + (kind, data) = self.__plan[0] + if kind == 'e': + raise socket.error('False socket error') + if kind != expected: + raise InvalidPlan('Planned ' + kind + ', but ' + expected + + 'requested') + return data + + def recv(self, maxsize): + """ + Emulate recv. Returs maxsize bytes from the current recv plan. If + there are data left from previous recv call, it is used first. + + If no recv is planned, raises InvalidPlan. + """ + data = self.__get_plan('r') + result, rest = data[:maxsize], data[maxsize:] + if len(rest) > 0: + self.__plan[0] = ('r', rest) + else: + self.__plan.pop(0) + return result + + def read_fd(self): + """ + Emulate the reading of file descriptor. Returns one from a plan. + + It raises InvalidPlan if no socket is planned now. + """ + fd = self.__get_plan('f') + self.__plan.pop(0) + return fd + + def sendall(self, data): + """ + Checks that the data passed are correct according to plan. It raises + InvalidData if the data differs or InvalidPlan when sendall is not + expected. + """ + planned = self.__get_plan('s') + dlen = len(data) + prefix, rest = planned[:dlen], planned[dlen:] + if prefix != data: + raise InvalidData('Expected "' + str(prefix)+ '", got "' + + str(data) + '"') + if len(rest) > 0: + self.__plan[0] = ('s', rest) + else: + self.__plan.pop(0) + def all_used(self): + """ + Returns if the whole plan was consumed. + """ + return len(self.__plan) == 0 + +class ParserTests(unittest.TestCase): + """ + Testcases for the Parser class. + """ + def test_terminate(self): + """ + Test if the command to terminate is correct and it waits for reading the + EOF. + """ + creator = FakeCreator([('s', b'T'), ('r', b'')]) + parser = Parser(creator) + self.assertEqual(None, parser.terminate()) + self.assertTrue(creator.all_used()) + + def test_crash(self): + """ + Tests that the parser correctly raises exception when it crashes + unexpectedly. + """ + creator = FakeCreator([('s', b'SU4\0\0\0\0\0\0'), ('r', b'')]) + parser = Parser(creator) + with self.assertRaises(CreatorError) as cm: + parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP') + self.assertTrue(creator.all_used()) + # Is the exception correct? + self.assertTrue(cm.exception.fatal) + self.assertEqual(None, cm.exception.errno) + + def test_error(self): + """ + Tests that the parser correctly raises non-fatal exception when + the socket can not be created. + """ + # We split the int to see if it can cope with data coming in + # different packets + intpart = struct.pack('@i', 42) + creator = FakeCreator([('s', b'SU4\0\0\0\0\0\0'), ('r', b'ES' + + intpart[:1]), ('r', intpart[1:])]) + parser = Parser(creator) + with self.assertRaises(CreatorError) as cm: + parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP') + self.assertTrue(creator.all_used()) + # Is the exception correct? + self.assertFalse(cm.exception.fatal) + self.assertEqual(42, cm.exception.errno) + + def __error(self, plan): + creator = FakeCreator(plan) + parser = Parser(creator) + with self.assertRaises(CreatorError) as cm: + parser.get_socket(IPAddr('0.0.0.0'), 0, socket.SOCK_DGRAM) + self.assertTrue(creator.all_used()) + self.assertTrue(cm.exception.fatal) + + def test_error_send(self): + self.__error([('e', None)]) + + def test_error_recv(self): + self.__error([('s', b'SU4\0\0\0\0\0\0'), ('e', None)]) + + def test_error_read_fd(self): + self.__error([('s', b'SU4\0\0\0\0\0\0'), ('r', b'S'), ('e', None)]) + + def __create(self, addr, socktype, encoded): + creator = FakeCreator([('s', b'S' + encoded), ('r', b'S'), ('f', 42)]) + parser = Parser(creator) + self.assertEqual(42, parser.get_socket(IPAddr(addr), 42, socktype)) + + def test_create1(self): + self.__create('192.0.2.0', 'UDP', b'U4\0\x2A\xC0\0\x02\0') + + def test_create2(self): + self.__create('2001:db8::', socket.SOCK_STREAM, + b'T6\0\x2A\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\0\0') + +if __name__ == '__main__': + unittest.main() From 517c31a58af1f7b97f308e77caeb8cbe9ef99cf1 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 12:44:09 +0200 Subject: [PATCH 2/9] [trac800] The parser --- src/bin/bind10/sockcreator.py | 81 ++++++++++++++++++++++- src/bin/bind10/tests/sockcreator_test.py | 84 +++++++++++++++++++++++- src/bin/sockcreator/README | 2 +- 3 files changed, 160 insertions(+), 7 deletions(-) diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py index 667c22f293..44e1d8e8ef 100644 --- a/src/bin/bind10/sockcreator.py +++ b/src/bin/bind10/sockcreator.py @@ -13,6 +13,9 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +import socket +import struct + """ Module that comunicates with the priviledget socket creator (b10-sockcreator). """ @@ -55,14 +58,26 @@ class Parser: have a read_fd() method to read the file descriptor. This slightly unusual modification of socket object is used to easy up testing. """ - pass # TODO Implement + self.__socket = creator_socket def terminate(self): """ Asks the creator process to terminate and waits for it to close the socket. Does not return anything. """ - pass # TODO Implement + if self.__socket is None: + raise CreatorError('Terminated already', True) + try: + self.__socket.sendall(b'T') + # Wait for an EOF - it will return empty data + eof = self.__socket.recv(1) + if len(eof) != 0: + raise CreatorError('Protocol error - data after terminated', + True) + self.__socket = None + except socket.error as se: + self.__socket = None + raise CreatorError(str(se), True) def get_socket(self, address, port, socktype): """ @@ -75,4 +90,64 @@ class Parser: should be fast, as it is on localhost) and returns the file descriptor number. It raises a CreatorError exception if the creation fails. """ - pass # TODO Implement + if self.__socket is None: + raise CreatorError('Socket requested on terminated creator', True) + # First, assemble the request from parts + data = b'S' + if socktype == 'UDP' or socktype == socket.SOCK_DGRAM: + data += b'U' + elif socktype == 'TCP' or socktype == socket.SOCK_STREAM: + data += b'T' + else: + raise ValueError('Unknown socket type: ' + str(socktype)) + if address.family == socket.AF_INET: + data += b'4' + elif address.family == socket.AF_INET6: + data += b'6' + else: + raise ValueError('Unknown address family in address') + data += struct.pack('!H', port) + data += address.addr + try: + # Send the request + self.__socket.sendall(data) + answer = self.__socket.recv(1) + if answer == b'S': + # Success! + return self.__socket.read_fd() + elif answer == b'E': + # There was an error, read the error as well + error = self.__socket.recv(1) + errno = struct.unpack('i', + self.__read_all(len(struct.pack('i', + 0)))) + if error == b'S': + cause = 'socket' + elif error == b'B': + cause = 'bind' + else: + self.__socket = None + raise CreatorError('Unknown error cause' + str(answer), True) + raise CreatorError('Error creating socket on ' + cause, False, + errno[0]) + else: + self.__socket = None + raise CreatorError('Unknown response ' + str(answer), True) + except socket.error as se: + self.__socket = None + raise CreatorError(str(se), True) + + def __read_all(self, length): + """ + Keeps reading until length data is read or EOF or error happens. + + EOF is considered error as well and throws. + """ + result = b'' + while len(result) < length: + data = self.__socket.recv(length - len(result)) + if len(data) == 0: + self.__socket = None + raise CreatorError('Unexpected EOF', True) + result += data + return result diff --git a/src/bin/bind10/tests/sockcreator_test.py b/src/bin/bind10/tests/sockcreator_test.py index 4e9390387a..fee691fc25 100644 --- a/src/bin/bind10/tests/sockcreator_test.py +++ b/src/bin/bind10/tests/sockcreator_test.py @@ -61,6 +61,7 @@ class FakeCreator: raise InvalidPlan('Nothing more planned') (kind, data) = self.__plan[0] if kind == 'e': + self.__plan.pop(0) raise socket.error('False socket error') if kind != expected: raise InvalidPlan('Planned ' + kind + ', but ' + expected + @@ -108,6 +109,7 @@ class FakeCreator: self.__plan[0] = ('s', rest) else: self.__plan.pop(0) + def all_used(self): """ Returns if the whole plan was consumed. @@ -118,15 +120,65 @@ class ParserTests(unittest.TestCase): """ Testcases for the Parser class. """ + def __terminate(self): + creator = FakeCreator([('s', b'T'), ('r', b'')]) + parser = Parser(creator) + self.assertEqual(None, parser.terminate()) + self.assertTrue(creator.all_used()) + return parser + def test_terminate(self): """ Test if the command to terminate is correct and it waits for reading the EOF. """ - creator = FakeCreator([('s', b'T'), ('r', b'')]) + self.__terminate() + + def test_terminate_error1(self): + """ + Test it reports an exception when there's error terminating the creator. + This one raises an error when receiving the EOF. + """ + creator = FakeCreator([('s', b'T'), ('e', None)]) parser = Parser(creator) - self.assertEqual(None, parser.terminate()) - self.assertTrue(creator.all_used()) + with self.assertRaises(CreatorError) as cm: + parser.terminate() + self.assertTrue(cm.exception.fatal) + self.assertEqual(None, cm.exception.errno) + + def test_terminate_error2(self): + """ + Test it reports an exception when there's error terminating the creator. + This one raises an error when sending data. + """ + creator = FakeCreator([('e', None)]) + parser = Parser(creator) + with self.assertRaises(CreatorError) as cm: + parser.terminate() + self.assertTrue(cm.exception.fatal) + self.assertEqual(None, cm.exception.errno) + + def test_terminate_twice(self): + """ + Test we can't terminate twice. + """ + parser = self.__terminate() + with self.assertRaises(CreatorError) as cm: + parser.terminate() + self.assertTrue(cm.exception.fatal) + self.assertEqual(None, cm.exception.errno) + + def test_terminate_error3(self): + """ + Test it reports an exception when there's error terminating the creator. + This one sends data when it should have terminated. + """ + creator = FakeCreator([('s', b'T'), ('r', b'Extra data')]) + parser = Parser(creator) + with self.assertRaises(CreatorError) as cm: + parser.terminate() + self.assertTrue(cm.exception.fatal) + self.assertEqual(None, cm.exception.errno) def test_crash(self): """ @@ -189,5 +241,31 @@ class ParserTests(unittest.TestCase): self.__create('2001:db8::', socket.SOCK_STREAM, b'T6\0\x2A\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\0\0') + def test_create_terminated(self): + """ + Test we can't request sockets after it was terminated. + """ + parser = self.__terminate() + with self.assertRaises(CreatorError) as cm: + parser.get_socket(IPAddr('0.0.0.0'), 0, 'UDP') + self.assertTrue(cm.exception.fatal) + self.assertEqual(None, cm.exception.errno) + + def test_invalid_socktype(self): + """ + Test invalid socket type is rejected + """ + self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket, + IPAddr('0.0.0.0'), 42, 'RAW') + + def test_invalid_family(self): + """ + Test it rejects invalid address family. + """ + addr = IPAddr('0.0.0.0') + addr.family = 'Nonsense' + self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket, + addr, 42, socket.SOCK_DGRAM) + if __name__ == '__main__': unittest.main() diff --git a/src/bin/sockcreator/README b/src/bin/sockcreator/README index 4dbbee726e..e142d191d7 100644 --- a/src/bin/sockcreator/README +++ b/src/bin/sockcreator/README @@ -3,7 +3,7 @@ The socket creator The only thing we need higher rights than standard user is binding sockets to ports lower than 1024. So we will have a separate process that keeps the -rights, while the rests drop them for security reasons. +rights, while the rest drops them for security reasons. This process is the socket creator. Its goal is to be as simple as possible and to contain as little code as possible to minimise the amount of code From d9e757fb15b711464cfc8ba344f2563f3e2b9195 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 13:48:15 +0200 Subject: [PATCH 3/9] [trac800] Provide logging for the sockcreator parser --- src/bin/bind10/bind10_messages.mes | 34 ++++++++++++++++++++++++ src/bin/bind10/sockcreator.py | 17 +++++++++++- src/bin/bind10/tests/sockcreator_test.py | 9 ++++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes index 3f5f637415..392b6c7057 100644 --- a/src/bin/bind10/bind10_messages.mes +++ b/src/bin/bind10/bind10_messages.mes @@ -155,3 +155,37 @@ the message channel. An unknown child process has exited. The PID is printed, but no further action will be taken by the boss process. +% BIND10_SOCKCREATOR_INIT initializing socket creator parser +The boss module initializes routines for parsing the socket creator +protocol. + +% BIND10_SOCKCREATOR_TERMINATE terminating socket creator +The boss module sends a request to terminate to the socket creator. + +% BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator +The boss forwards a request for a socket to the socket creator. + +% BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator +There should be more data from the socket creator, but it closed the socket. +It probably crashed. + +% BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1 +The boss requested a socket from the creator, but the answer is unknown. This +looks like programmer error. + +% BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3 +The socket creator failed to create the requested socket. It failed on the +indicated OS API function with given error. + +% BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1 +The socket creator reported an error when creating a socket. But the function +which failed is unknown (not one of 'S' for socket or 'B' for bind). + +% BIND10_SOCKET_CREATED successfully created socket %1 +The socket creator successfully created and sent a requested socket, it has +the given file number. + +% BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1 +Either sending or receiving data from the socket creator failed with the given +error. The creator probably crashed or some serious OS-level problem happened, +as the communication happens only on local host. diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py index 44e1d8e8ef..36815efdb8 100644 --- a/src/bin/bind10/sockcreator.py +++ b/src/bin/bind10/sockcreator.py @@ -15,6 +15,10 @@ import socket import struct +import os +from bind10_messages import * + +logger = isc.log.Logger("boss") """ Module that comunicates with the priviledget socket creator (b10-sockcreator). @@ -59,6 +63,7 @@ class Parser: unusual modification of socket object is used to easy up testing. """ self.__socket = creator_socket + logger.info(BIND10_SOCKCREATOR_INIT) def terminate(self): """ @@ -67,6 +72,7 @@ class Parser: """ if self.__socket is None: raise CreatorError('Terminated already', True) + logger.info(BIND10_SOCKCREATOR_TERMINATE) try: self.__socket.sendall(b'T') # Wait for an EOF - it will return empty data @@ -93,6 +99,7 @@ class Parser: if self.__socket is None: raise CreatorError('Socket requested on terminated creator', True) # First, assemble the request from parts + logger.info(BIND10_SOCKET_GET, address, port, socktype) data = b'S' if socktype == 'UDP' or socktype == socket.SOCK_DGRAM: data += b'U' @@ -114,7 +121,9 @@ class Parser: answer = self.__socket.recv(1) if answer == b'S': # Success! - return self.__socket.read_fd() + result = self.__socket.read_fd() + logger.info(BIND10_SOCKET_CREATED, result) + return result elif answer == b'E': # There was an error, read the error as well error = self.__socket.recv(1) @@ -127,14 +136,19 @@ class Parser: cause = 'bind' else: self.__socket = None + logger.fatal(BIND10_SOCKCREATOR_BAD_CAUSE, error) raise CreatorError('Unknown error cause' + str(answer), True) + logger.error(BIND10_SOCKET_ERROR, cause, errno[0], + os.strerror(errno[0])) raise CreatorError('Error creating socket on ' + cause, False, errno[0]) else: self.__socket = None + logger.fatal(BIND10_SOCKCREATOR_BAD_RESPONSE, answer) raise CreatorError('Unknown response ' + str(answer), True) except socket.error as se: self.__socket = None + logger.fatal(BIND10_SOCKCREATOR_TRANSPORT_ERROR, str(se)) raise CreatorError(str(se), True) def __read_all(self, length): @@ -148,6 +162,7 @@ class Parser: data = self.__socket.recv(length - len(result)) if len(data) == 0: self.__socket = None + logger.fatal(BIND10_SOCKCREATOR_EOF) raise CreatorError('Unexpected EOF', True) result += data return result diff --git a/src/bin/bind10/tests/sockcreator_test.py b/src/bin/bind10/tests/sockcreator_test.py index fee691fc25..d61254a8bb 100644 --- a/src/bin/bind10/tests/sockcreator_test.py +++ b/src/bin/bind10/tests/sockcreator_test.py @@ -22,6 +22,7 @@ import struct import socket from bind10.sockcreator import Parser, CreatorError from isc.net.addr import IPAddr +import isc.log class FakeCreator: """ @@ -262,10 +263,16 @@ class ParserTests(unittest.TestCase): """ Test it rejects invalid address family. """ + # Note: this produces a bad logger output, since this address + # can not be converted to string, so the original message with + # placeholders is output. This should not happen in practice, so + # it is harmless. addr = IPAddr('0.0.0.0') - addr.family = 'Nonsense' + addr.family = 42 self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket, addr, 42, socket.SOCK_DGRAM) if __name__ == '__main__': + isc.log.init("bind10") # FIXME Should this be needed? + isc.log.resetUnitTestRootLogger() unittest.main() From 3da7e8747dcea9b45c8bc4c17b946be7d5ff9576 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 14:40:06 +0200 Subject: [PATCH 4/9] [trac800] WrappedSocket --- src/bin/bind10/sockcreator.py | 27 +++++++++++++++++- src/bin/bind10/tests/Makefile.am | 2 +- src/bin/bind10/tests/sockcreator_test.py | 36 +++++++++++++++++++++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py index 36815efdb8..0bf750fa26 100644 --- a/src/bin/bind10/sockcreator.py +++ b/src/bin/bind10/sockcreator.py @@ -17,6 +17,7 @@ import socket import struct import os from bind10_messages import * +from libutil_io_python import recv_fd logger = isc.log.Logger("boss") @@ -60,7 +61,10 @@ class Parser: Creates the parser. The creator_socket is socket to the socket creator process that will be used for communication. However, the object must have a read_fd() method to read the file descriptor. This slightly - unusual modification of socket object is used to easy up testing. + unusual trick with modifying an object is used to easy up testing. + + You can use WrappedSocket in production code to add the method to any + ordinary socket. """ self.__socket = creator_socket logger.info(BIND10_SOCKCREATOR_INIT) @@ -166,3 +170,24 @@ class Parser: raise CreatorError('Unexpected EOF', True) result += data return result + +class WrappedSocket: + """ + This class wraps a socket and adds a read_fd method, so it can be used + for the Parser class conveniently. It simply copies all it's guts into + itself and implements the method. + """ + def __init__(self, socket): + # Copy whatever can be copied from the socket + for name in dir(socket): + if name not in ['__class__', '__weakref__']: + setattr(self, name, getattr(socket, name)) + # Keep the socket, so we can prevent it from being garbage-collected + # and closed before we are removed ourself + self.__orig_socket = socket + + def read_fd(self): + """ + Read the file descriptor from the socket. + """ + return recv_fd(self.fileno()) diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am index 3fe357e264..1cbd841012 100644 --- a/src/bin/bind10/tests/Makefile.am +++ b/src/bin/bind10/tests/Makefile.am @@ -21,7 +21,7 @@ endif for pytest in $(PYTESTS) ; do \ echo Running test: $$pytest ; \ $(LIBRARY_PATH_PLACEHOLDER) \ - env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin:$(abs_top_builddir)/src/bin/bind10 \ + env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin:$(abs_top_builddir)/src/bin/bind10:$(abs_top_builddir)/src/lib/util/io/.libs \ BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \ $(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \ done diff --git a/src/bin/bind10/tests/sockcreator_test.py b/src/bin/bind10/tests/sockcreator_test.py index d61254a8bb..c863034392 100644 --- a/src/bin/bind10/tests/sockcreator_test.py +++ b/src/bin/bind10/tests/sockcreator_test.py @@ -20,9 +20,10 @@ Tests for the bind10.sockcreator module. import unittest import struct import socket -from bind10.sockcreator import Parser, CreatorError from isc.net.addr import IPAddr import isc.log +from libutil_io_python import send_fd +from bind10.sockcreator import Parser, CreatorError, WrappedSocket class FakeCreator: """ @@ -272,6 +273,39 @@ class ParserTests(unittest.TestCase): self.assertRaises(ValueError, Parser(FakeCreator([])).get_socket, addr, 42, socket.SOCK_DGRAM) +class WrapTests(unittest.TestCase): + """ + Tests for the wrap_socket function. + """ + def test_wrap(self): + # We construct two pairs of socket. The receiving side of one pair will + # be wrapped. Then we send one of the other pair through this pair and + # check the received one can be used as a socket + + # The transport socket + (t1, t2) = socket.socketpair() + # The payload socket + (p1, p2) = socket.socketpair() + + t2 = WrappedSocket(t2) + + # Transfer the descriptor + send_fd(t1.fileno(), p1.fileno()) + p1 = socket.fromfd(t2.read_fd(), socket.AF_UNIX, socket.SOCK_STREAM) + + # Now, pass some data trough the socket + p1.send(b'A') + data = p2.recv(1) + self.assertEqual(b'A', data) + + # Test the wrapping didn't hurt the socket's usual methods + t1.send(b'B') + data = t2.recv(1) + self.assertEqual(b'B', data) + t2.send(b'C') + data = t1.recv(1) + self.assertEqual(b'C', data) + if __name__ == '__main__': isc.log.init("bind10") # FIXME Should this be needed? isc.log.resetUnitTestRootLogger() From 9517f61cb8ad4f8074b5e6e33c663ca9ed581908 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 18:02:06 +0200 Subject: [PATCH 5/9] [trac800] Actually starting the creator --- src/bin/bind10/bind10_messages.mes | 9 +++++++ src/bin/bind10/bind10_src.py.in | 34 +++++++++++++++++++++++++- src/bin/bind10/sockcreator.py | 31 +++++++++++++++++++++++ src/bin/bind10/tests/bind10_test.py.in | 8 ++++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes index 392b6c7057..a596147a08 100644 --- a/src/bin/bind10/bind10_messages.mes +++ b/src/bin/bind10/bind10_messages.mes @@ -189,3 +189,12 @@ the given file number. Either sending or receiving data from the socket creator failed with the given error. The creator probably crashed or some serious OS-level problem happened, as the communication happens only on local host. + +% BIND10_SOCKCREATOR_CRASHED the socket creator crashed +The socket creator terminated unexpectadly. It is not possible to restart it +(because the boss already gave up root privileges), so the system is going +to terminate. + +% BIND10_SOCKCREATOR_KILL killing the socket creator +The socket creator is being terminated the aggressive way, by sending it +sigkill. This should not happen usually. diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in index a624383da6..bbb17a2347 100755 --- a/src/bin/bind10/bind10_src.py.in +++ b/src/bin/bind10/bind10_src.py.in @@ -67,6 +67,7 @@ import isc.util.process import isc.net.parse import isc.log from bind10_messages import * +import bind10.sockcreator isc.log.init("b10-boss") logger = isc.log.Logger("boss") @@ -248,6 +249,7 @@ class BoB: self.config_filename = config_filename self.cmdctl_port = cmdctl_port self.brittle = brittle + self.sockcreator = None def config_handler(self, new_config): # If this is initial update, don't do anything now, leave it to startup @@ -333,6 +335,20 @@ class BoB: "Unknown command") return answer + def start_creator(self): + self.curproc = 'b10-sockcreator' + self.sockcreator = bind10.sockcreator.Creator("@@LIBEXECDIR@@:" + + os.environ['PATH']) + + def stop_creator(self, kill=False): + if self.sockcreator is None: + return + if kill: + self.sockcreator.kill() + else: + self.sockcreator.terminate() + self.sockcreator = None + def kill_started_processes(self): """ Called as part of the exception handling when a process fails to @@ -341,6 +357,8 @@ class BoB: """ logger.info(BIND10_KILLING_ALL_PROCESSES) + self.stop_creator(True) + for pid in self.processes: logger.info(BIND10_KILL_PROCESS, self.processes[pid].name) self.processes[pid].process.kill() @@ -571,6 +589,11 @@ class BoB: Starts up all the processes. Any exception generated during the starting of the processes is handled by the caller. """ + # The socket creator first, as it is the only thing that needs root + self.start_creator() + # TODO: Once everything uses the socket creator, we can drop root + # privileges right now + c_channel_env = self.c_channel_env self.start_msgq(c_channel_env) self.start_cfgmgr(c_channel_env) @@ -660,6 +683,8 @@ class BoB: self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr") self.cc_session.group_sendmsg(cmd, "Stats", "Stats") self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd") + # Terminate the creator last + self.stop_creator() def stop_process(self, process, recipient): """ @@ -746,7 +771,14 @@ class BoB: # XXX: should be impossible to get any other error here raise if pid == 0: break - if pid in self.processes: + if self.sockcreator is not None and self.sockcreator.pid() == pid: + # This is the socket creator, started and terminated + # differently. This can't be restarted. + if self.runnable: + logger.fatal(BIND10_SOCKCREATOR_CRASHED) + self.sockcreator = None + self.runnable = False + elif pid in self.processes: # One of the processes we know about. Get information on it. proc_info = self.processes.pop(pid) proc_info.restart_schedule.set_run_stop_time() diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py index 0bf750fa26..baccc95ed9 100644 --- a/src/bin/bind10/sockcreator.py +++ b/src/bin/bind10/sockcreator.py @@ -16,6 +16,7 @@ import socket import struct import os +import subprocess from bind10_messages import * from libutil_io_python import recv_fd @@ -191,3 +192,33 @@ class WrappedSocket: Read the file descriptor from the socket. """ return recv_fd(self.fileno()) + +# FIXME: Any idea how to test this? Starting an external process doesn't sound +# OK +class Creator(Parser): + """ + This starts the socket creator and allows asking for the sockets. + """ + def __init__(self, path): + (local, remote) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM) + # Popen does not like, for some reason, having the same socket for + # stdin as well as stdout, so we dup it before passing it there. + remote2 = socket.fromfd(remote.fileno(), socket.AF_UNIX, + socket.SOCK_STREAM) + env = os.environ + env['PATH'] = path + self.__process = subprocess.Popen(['b10-sockcreator'], env=env, + stdin=remote.fileno(), + stdout=remote2.fileno()) + remote.close() + remote2.close() + Parser.__init__(self, WrappedSocket(local)) + + def pid(self): + return self.__process.pid + + def kill(self): + logger.warn(BIND10_SOCKCREATOR_KILL) + if self.__process is not None: + self.__process.kill() + self.__process = None diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in index 6b871334b8..077190c865 100644 --- a/src/bin/bind10/tests/bind10_test.py.in +++ b/src/bin/bind10/tests/bind10_test.py.in @@ -193,6 +193,13 @@ class MockBob(BoB): self.cmdctl = False self.c_channel_env = {} self.processes = { } + self.creator = False + + def start_creator(self): + self.creator = True + + def stop_creator(self, kill=False): + self.creator = False def read_bind10_config(self): # Configuration options are set directly @@ -337,6 +344,7 @@ class TestStartStopProcessesBob(unittest.TestCase): self.assertEqual(bob.msgq, core) self.assertEqual(bob.cfgmgr, core) self.assertEqual(bob.ccsession, core) + self.assertEqual(bob.creator, core) self.assertEqual(bob.auth, auth) self.assertEqual(bob.resolver, resolver) self.assertEqual(bob.xfrout, auth) From 0710846d8d7a38079b9570aeec9abfb94341af79 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 18:15:43 +0200 Subject: [PATCH 6/9] [trac800] Fix tests depending on boss Why do they include boss? --- src/bin/dhcp6/tests/Makefile.am | 2 +- src/bin/dhcp6/tests/dhcp6_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index a35284fbb4..219dcff42a 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/src/bin/dhcp6/tests/Makefile.am @@ -15,7 +15,7 @@ endif check-local: for pytest in $(PYTESTS) ; do \ echo Running test: $$pytest ; \ - env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \ + env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin:$(abs_top_builddir)/src/bin/bind10:$(abs_top_builddir)/src/lib/util/io/.libs \ $(LIBRARY_PATH_PLACEHOLDER) \ BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \ $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \ diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py index 61ec009606..5ae1f5eba5 100644 --- a/src/bin/dhcp6/tests/dhcp6_test.py +++ b/src/bin/dhcp6/tests/dhcp6_test.py @@ -13,7 +13,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -from bind10 import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME +from bind10_src import ProcessInfo, parse_args, dump_pid, unlink_pid_file, _BASETIME import unittest import sys From c62810c526d75363ed4d668bbdb6b21a5a294a7b Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Mon, 25 Jul 2011 18:38:53 +0200 Subject: [PATCH 7/9] [trac800] Makefile fixes --- configure.ac | 1 + src/bin/bind10/tests/Makefile.am | 1 - .../tests/{sockcreator_test.py => sockcreator_test.py.in} | 3 +++ 3 files changed, 4 insertions(+), 1 deletion(-) rename src/bin/bind10/tests/{sockcreator_test.py => sockcreator_test.py.in} (98%) diff --git a/configure.ac b/configure.ac index 9ee534829e..a554db11a5 100644 --- a/configure.ac +++ b/configure.ac @@ -905,6 +905,7 @@ AC_OUTPUT([doc/version.ent src/bin/bind10/bind10_src.py src/bin/bind10/run_bind10.sh src/bin/bind10/tests/bind10_test.py + src/bin/bind10/tests/sockcreator_test.py src/bin/bindctl/run_bindctl.sh src/bin/bindctl/bindctl_main.py src/bin/bindctl/tests/bindctl_test diff --git a/src/bin/bind10/tests/Makefile.am b/src/bin/bind10/tests/Makefile.am index 1cbd841012..4a40ec89d2 100644 --- a/src/bin/bind10/tests/Makefile.am +++ b/src/bin/bind10/tests/Makefile.am @@ -2,7 +2,6 @@ PYCOVERAGE_RUN = @PYCOVERAGE_RUN@ #PYTESTS = args_test.py bind10_test.py # NOTE: this has a generated test found in the builddir PYTESTS = bind10_test.py sockcreator_test.py -EXTRA_DIST = $(PYTESTS) # If necessary (rare cases), explicitly specify paths to dynamic libraries # required by loadable python modules. diff --git a/src/bin/bind10/tests/sockcreator_test.py b/src/bin/bind10/tests/sockcreator_test.py.in similarity index 98% rename from src/bin/bind10/tests/sockcreator_test.py rename to src/bin/bind10/tests/sockcreator_test.py.in index c863034392..7fb522fd91 100644 --- a/src/bin/bind10/tests/sockcreator_test.py +++ b/src/bin/bind10/tests/sockcreator_test.py.in @@ -13,6 +13,9 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# This test file is generated .py.in -> .py just to be in the build dir, +# same as the rest of the tests. Saves a lot of stuff in makefile. + """ Tests for the bind10.sockcreator module. """ From 12186e267fb75a77027dc046f78db6ace99b8571 Mon Sep 17 00:00:00 2001 From: Jelte Jansen Date: Tue, 26 Jul 2011 15:00:33 +0200 Subject: [PATCH 8/9] [trac800] fix a few typos --- src/bin/bind10/bind10_messages.mes | 2 +- src/bin/bind10/sockcreator.py | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes index a596147a08..bad17022c0 100644 --- a/src/bin/bind10/bind10_messages.mes +++ b/src/bin/bind10/bind10_messages.mes @@ -171,7 +171,7 @@ It probably crashed. % BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1 The boss requested a socket from the creator, but the answer is unknown. This -looks like programmer error. +looks like a programmer error. % BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3 The socket creator failed to create the requested socket. It failed on the diff --git a/src/bin/bind10/sockcreator.py b/src/bin/bind10/sockcreator.py index baccc95ed9..9fcc74e74c 100644 --- a/src/bin/bind10/sockcreator.py +++ b/src/bin/bind10/sockcreator.py @@ -23,7 +23,7 @@ from libutil_io_python import recv_fd logger = isc.log.Logger("boss") """ -Module that comunicates with the priviledget socket creator (b10-sockcreator). +Module that comunicates with the privileged socket creator (b10-sockcreator). """ class CreatorError(Exception): @@ -54,7 +54,7 @@ class Parser: In theory, anything here can throw a fatal CreatorError exception, but it happens only in case something like the creator process crashes. Any other - occations are mentioned explicitly. + occasions are mentioned explicitly. """ def __init__(self, creator_socket): @@ -73,7 +73,9 @@ class Parser: def terminate(self): """ Asks the creator process to terminate and waits for it to close the - socket. Does not return anything. + socket. Does not return anything. Raises a CreatorError if there is + still data on the socket, if there is an error closing the socket, + or if the socket had already been closed. """ if self.__socket is None: raise CreatorError('Terminated already', True) @@ -160,7 +162,7 @@ class Parser: """ Keeps reading until length data is read or EOF or error happens. - EOF is considered error as well and throws. + EOF is considered error as well and throws a CreatorError. """ result = b'' while len(result) < length: @@ -175,7 +177,7 @@ class Parser: class WrappedSocket: """ This class wraps a socket and adds a read_fd method, so it can be used - for the Parser class conveniently. It simply copies all it's guts into + for the Parser class conveniently. It simply copies all its guts into itself and implements the method. """ def __init__(self, socket): From 69336de84b2ae1b5b6a59fa8d817daa1108cea27 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 26 Jul 2011 16:19:51 +0200 Subject: [PATCH 9/9] [trac800] Sort the message definitions --- src/bin/bind10/bind10_messages.mes | 108 ++++++++++++++--------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/bin/bind10/bind10_messages.mes b/src/bin/bind10/bind10_messages.mes index bad17022c0..e10bc7c7b7 100644 --- a/src/bin/bind10/bind10_messages.mes +++ b/src/bin/bind10/bind10_messages.mes @@ -32,15 +32,15 @@ started according to the configuration. The boss process was started with the -u option, to drop root privileges and continue running as the specified user, but the user is unknown. +% BIND10_KILLING_ALL_PROCESSES killing all started processes +The boss module was not able to start every process it needed to start +during startup, and will now kill the processes that did get started. + % BIND10_KILL_PROCESS killing process %1 The boss module is sending a kill signal to process with the given name, as part of the process of killing all started processes during a failed startup, as described for BIND10_KILLING_ALL_PROCESSES -% BIND10_KILLING_ALL_PROCESSES killing all started processes -The boss module was not able to start every process it needed to start -during startup, and will now kill the processes that did get started. - % BIND10_MSGQ_ALREADY_RUNNING msgq daemon already running, cannot start There already appears to be a message bus daemon running. Either an old process was not shut down correctly, and needs to be killed, or @@ -113,12 +113,49 @@ it shall send SIGKILL signals to the processes still alive. All child processes have been stopped, and the boss process will now stop itself. -% BIND10_START_AS_NON_ROOT starting %1 as a user, not root. This might fail. -The given module is being started or restarted without root privileges. -If the module needs these privileges, it may have problems starting. -Note that this issue should be resolved by the pending 'socket-creator' -process; once that has been implemented, modules should not need root -privileges anymore. See tickets #800 and #801 for more information. +% BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1 +The socket creator reported an error when creating a socket. But the function +which failed is unknown (not one of 'S' for socket or 'B' for bind). + +% BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1 +The boss requested a socket from the creator, but the answer is unknown. This +looks like a programmer error. + +% BIND10_SOCKCREATOR_CRASHED the socket creator crashed +The socket creator terminated unexpectadly. It is not possible to restart it +(because the boss already gave up root privileges), so the system is going +to terminate. + +% BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator +There should be more data from the socket creator, but it closed the socket. +It probably crashed. + +% BIND10_SOCKCREATOR_INIT initializing socket creator parser +The boss module initializes routines for parsing the socket creator +protocol. + +% BIND10_SOCKCREATOR_KILL killing the socket creator +The socket creator is being terminated the aggressive way, by sending it +sigkill. This should not happen usually. + +% BIND10_SOCKCREATOR_TERMINATE terminating socket creator +The boss module sends a request to terminate to the socket creator. + +% BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1 +Either sending or receiving data from the socket creator failed with the given +error. The creator probably crashed or some serious OS-level problem happened, +as the communication happens only on local host. + +% BIND10_SOCKET_CREATED successfully created socket %1 +The socket creator successfully created and sent a requested socket, it has +the given file number. + +% BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3 +The socket creator failed to create the requested socket. It failed on the +indicated OS API function with given error. + +% BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator +The boss forwards a request for a socket to the socket creator. % BIND10_STARTED_PROCESS started %1 The given process has successfully been started. @@ -147,6 +184,13 @@ All modules have been successfully started, and BIND 10 is now running. There was a fatal error when BIND10 was trying to start. The error is shown, and BIND10 will now shut down. +% BIND10_START_AS_NON_ROOT starting %1 as a user, not root. This might fail. +The given module is being started or restarted without root privileges. +If the module needs these privileges, it may have problems starting. +Note that this issue should be resolved by the pending 'socket-creator' +process; once that has been implemented, modules should not need root +privileges anymore. See tickets #800 and #801 for more information. + % BIND10_STOP_PROCESS asking %1 to shut down The boss module is sending a shutdown command to the given module over the message channel. @@ -154,47 +198,3 @@ the message channel. % BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited An unknown child process has exited. The PID is printed, but no further action will be taken by the boss process. - -% BIND10_SOCKCREATOR_INIT initializing socket creator parser -The boss module initializes routines for parsing the socket creator -protocol. - -% BIND10_SOCKCREATOR_TERMINATE terminating socket creator -The boss module sends a request to terminate to the socket creator. - -% BIND10_SOCKET_GET requesting socket [%1]:%2 of type %3 from the creator -The boss forwards a request for a socket to the socket creator. - -% BIND10_SOCKCREATOR_EOF eof while expecting data from socket creator -There should be more data from the socket creator, but it closed the socket. -It probably crashed. - -% BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1 -The boss requested a socket from the creator, but the answer is unknown. This -looks like a programmer error. - -% BIND10_SOCKET_ERROR error on %1 call in the creator: %2/%3 -The socket creator failed to create the requested socket. It failed on the -indicated OS API function with given error. - -% BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1 -The socket creator reported an error when creating a socket. But the function -which failed is unknown (not one of 'S' for socket or 'B' for bind). - -% BIND10_SOCKET_CREATED successfully created socket %1 -The socket creator successfully created and sent a requested socket, it has -the given file number. - -% BIND10_SOCKCREATOR_TRANSPORT_ERROR transport error when talking to the socket creator: %1 -Either sending or receiving data from the socket creator failed with the given -error. The creator probably crashed or some serious OS-level problem happened, -as the communication happens only on local host. - -% BIND10_SOCKCREATOR_CRASHED the socket creator crashed -The socket creator terminated unexpectadly. It is not possible to restart it -(because the boss already gave up root privileges), so the system is going -to terminate. - -% BIND10_SOCKCREATOR_KILL killing the socket creator -The socket creator is being terminated the aggressive way, by sending it -sigkill. This should not happen usually.