mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-03 23:45:27 +00:00
Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10
This commit is contained in:
@@ -904,9 +904,10 @@ AC_OUTPUT([doc/version.ent
|
|||||||
src/bin/zonemgr/run_b10-zonemgr.sh
|
src/bin/zonemgr/run_b10-zonemgr.sh
|
||||||
src/bin/stats/stats.py
|
src/bin/stats/stats.py
|
||||||
src/bin/stats/stats_httpd.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/run_bind10.sh
|
||||||
src/bin/bind10/tests/bind10_test.py
|
src/bin/bind10/tests/bind10_test.py
|
||||||
|
src/bin/bind10/tests/sockcreator_test.py
|
||||||
src/bin/bindctl/run_bindctl.sh
|
src/bin/bindctl/run_bindctl.sh
|
||||||
src/bin/bindctl/bindctl_main.py
|
src/bin/bindctl/bindctl_main.py
|
||||||
src/bin/bindctl/tests/bindctl_test
|
src/bin/bindctl/tests/bindctl_test
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
SUBDIRS = . tests
|
SUBDIRS = . tests
|
||||||
|
|
||||||
sbin_SCRIPTS = bind10
|
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@
|
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||||
pyexec_DATA = bind10_messages.py
|
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
|
$(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
|
# 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@|" \
|
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
|
||||||
-e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bind10.py >$@
|
-e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bind10_src.py >$@
|
||||||
chmod a+x $@
|
chmod a+x $@
|
||||||
|
|
||||||
pytest:
|
pytest:
|
||||||
|
0
src/bin/bind10/__init__.py
Normal file
0
src/bin/bind10/__init__.py
Normal file
@@ -32,15 +32,15 @@ started according to the configuration.
|
|||||||
The boss process was started with the -u option, to drop root privileges
|
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.
|
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
|
% BIND10_KILL_PROCESS killing process %1
|
||||||
The boss module is sending a kill signal to process with the given name,
|
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
|
as part of the process of killing all started processes during a failed
|
||||||
startup, as described for BIND10_KILLING_ALL_PROCESSES
|
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
|
% BIND10_MSGQ_ALREADY_RUNNING msgq daemon already running, cannot start
|
||||||
There already appears to be a message bus daemon running. Either an
|
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
|
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
|
All child processes have been stopped, and the boss process will now
|
||||||
stop itself.
|
stop itself.
|
||||||
|
|
||||||
% BIND10_START_AS_NON_ROOT starting %1 as a user, not root. This might fail.
|
% BIND10_SOCKCREATOR_BAD_CAUSE unknown error cause from socket creator: %1
|
||||||
The given module is being started or restarted without root privileges.
|
The socket creator reported an error when creating a socket. But the function
|
||||||
If the module needs these privileges, it may have problems starting.
|
which failed is unknown (not one of 'S' for socket or 'B' for bind).
|
||||||
Note that this issue should be resolved by the pending 'socket-creator'
|
|
||||||
process; once that has been implemented, modules should not need root
|
% BIND10_SOCKCREATOR_BAD_RESPONSE unknown response for socket request: %1
|
||||||
privileges anymore. See tickets #800 and #801 for more information.
|
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
|
% BIND10_STARTED_PROCESS started %1
|
||||||
The given process has successfully been started.
|
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
|
There was a fatal error when BIND10 was trying to start. The error is
|
||||||
shown, and BIND10 will now shut down.
|
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
|
% BIND10_STOP_PROCESS asking %1 to shut down
|
||||||
The boss module is sending a shutdown command to the given module over
|
The boss module is sending a shutdown command to the given module over
|
||||||
the message channel.
|
the message channel.
|
||||||
@@ -154,4 +198,3 @@ the message channel.
|
|||||||
% BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited
|
% BIND10_UNKNOWN_CHILD_PROCESS_ENDED unknown child pid %1 exited
|
||||||
An unknown child process has exited. The PID is printed, but no further
|
An unknown child process has exited. The PID is printed, but no further
|
||||||
action will be taken by the boss process.
|
action will be taken by the boss process.
|
||||||
|
|
||||||
|
@@ -67,6 +67,7 @@ import isc.util.process
|
|||||||
import isc.net.parse
|
import isc.net.parse
|
||||||
import isc.log
|
import isc.log
|
||||||
from bind10_messages import *
|
from bind10_messages import *
|
||||||
|
import bind10.sockcreator
|
||||||
|
|
||||||
isc.log.init("b10-boss")
|
isc.log.init("b10-boss")
|
||||||
logger = isc.log.Logger("boss")
|
logger = isc.log.Logger("boss")
|
||||||
@@ -248,6 +249,7 @@ class BoB:
|
|||||||
self.config_filename = config_filename
|
self.config_filename = config_filename
|
||||||
self.cmdctl_port = cmdctl_port
|
self.cmdctl_port = cmdctl_port
|
||||||
self.brittle = brittle
|
self.brittle = brittle
|
||||||
|
self.sockcreator = None
|
||||||
|
|
||||||
def config_handler(self, new_config):
|
def config_handler(self, new_config):
|
||||||
# If this is initial update, don't do anything now, leave it to startup
|
# If this is initial update, don't do anything now, leave it to startup
|
||||||
@@ -333,6 +335,20 @@ class BoB:
|
|||||||
"Unknown command")
|
"Unknown command")
|
||||||
return answer
|
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):
|
def kill_started_processes(self):
|
||||||
"""
|
"""
|
||||||
Called as part of the exception handling when a process fails to
|
Called as part of the exception handling when a process fails to
|
||||||
@@ -341,6 +357,8 @@ class BoB:
|
|||||||
"""
|
"""
|
||||||
logger.info(BIND10_KILLING_ALL_PROCESSES)
|
logger.info(BIND10_KILLING_ALL_PROCESSES)
|
||||||
|
|
||||||
|
self.stop_creator(True)
|
||||||
|
|
||||||
for pid in self.processes:
|
for pid in self.processes:
|
||||||
logger.info(BIND10_KILL_PROCESS, self.processes[pid].name)
|
logger.info(BIND10_KILL_PROCESS, self.processes[pid].name)
|
||||||
self.processes[pid].process.kill()
|
self.processes[pid].process.kill()
|
||||||
@@ -571,6 +589,11 @@ class BoB:
|
|||||||
Starts up all the processes. Any exception generated during the
|
Starts up all the processes. Any exception generated during the
|
||||||
starting of the processes is handled by the caller.
|
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
|
c_channel_env = self.c_channel_env
|
||||||
self.start_msgq(c_channel_env)
|
self.start_msgq(c_channel_env)
|
||||||
self.start_cfgmgr(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, "Zonemgr", "Zonemgr")
|
||||||
self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
|
self.cc_session.group_sendmsg(cmd, "Stats", "Stats")
|
||||||
self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
|
self.cc_session.group_sendmsg(cmd, "StatsHttpd", "StatsHttpd")
|
||||||
|
# Terminate the creator last
|
||||||
|
self.stop_creator()
|
||||||
|
|
||||||
def stop_process(self, process, recipient):
|
def stop_process(self, process, recipient):
|
||||||
"""
|
"""
|
||||||
@@ -746,7 +771,14 @@ class BoB:
|
|||||||
# XXX: should be impossible to get any other error here
|
# XXX: should be impossible to get any other error here
|
||||||
raise
|
raise
|
||||||
if pid == 0: break
|
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.
|
# One of the processes we know about. Get information on it.
|
||||||
proc_info = self.processes.pop(pid)
|
proc_info = self.processes.pop(pid)
|
||||||
proc_info.restart_schedule.set_run_stop_time()
|
proc_info.restart_schedule.set_run_stop_time()
|
226
src/bin/bind10/sockcreator.py
Normal file
226
src/bin/bind10/sockcreator.py
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from bind10_messages import *
|
||||||
|
from libutil_io_python import recv_fd
|
||||||
|
|
||||||
|
logger = isc.log.Logger("boss")
|
||||||
|
|
||||||
|
"""
|
||||||
|
Module that comunicates with the privileged 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
|
||||||
|
occasions 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 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)
|
||||||
|
|
||||||
|
def terminate(self):
|
||||||
|
"""
|
||||||
|
Asks the creator process to terminate and waits for it to close the
|
||||||
|
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)
|
||||||
|
logger.info(BIND10_SOCKCREATOR_TERMINATE)
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
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'
|
||||||
|
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!
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
Keeps reading until length data is read or EOF or error happens.
|
||||||
|
|
||||||
|
EOF is considered error as well and throws a CreatorError.
|
||||||
|
"""
|
||||||
|
result = b''
|
||||||
|
while len(result) < length:
|
||||||
|
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
|
||||||
|
|
||||||
|
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 its 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())
|
||||||
|
|
||||||
|
# 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
|
@@ -1,8 +1,7 @@
|
|||||||
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
|
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
|
||||||
#PYTESTS = args_test.py bind10_test.py
|
#PYTESTS = args_test.py bind10_test.py
|
||||||
# NOTE: this has a generated test found in the builddir
|
# 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
|
# If necessary (rare cases), explicitly specify paths to dynamic libraries
|
||||||
# required by loadable python modules.
|
# required by loadable python modules.
|
||||||
@@ -21,7 +20,7 @@ endif
|
|||||||
for pytest in $(PYTESTS) ; do \
|
for pytest in $(PYTESTS) ; do \
|
||||||
echo Running test: $$pytest ; \
|
echo Running test: $$pytest ; \
|
||||||
$(LIBRARY_PATH_PLACEHOLDER) \
|
$(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:$(abs_top_builddir)/src/lib/util/io/.libs \
|
||||||
BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
|
BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
|
||||||
$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
|
$(PYCOVERAGE_RUN) $(abs_builddir)/$$pytest || exit ; \
|
||||||
done
|
done
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
# 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
|
# XXX: environment tests are currently disabled, due to the preprocessor
|
||||||
# setup that we have now complicating the environment
|
# setup that we have now complicating the environment
|
||||||
@@ -193,6 +193,13 @@ class MockBob(BoB):
|
|||||||
self.cmdctl = False
|
self.cmdctl = False
|
||||||
self.c_channel_env = {}
|
self.c_channel_env = {}
|
||||||
self.processes = { }
|
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):
|
def read_bind10_config(self):
|
||||||
# Configuration options are set directly
|
# Configuration options are set directly
|
||||||
@@ -337,6 +344,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|||||||
self.assertEqual(bob.msgq, core)
|
self.assertEqual(bob.msgq, core)
|
||||||
self.assertEqual(bob.cfgmgr, core)
|
self.assertEqual(bob.cfgmgr, core)
|
||||||
self.assertEqual(bob.ccsession, core)
|
self.assertEqual(bob.ccsession, core)
|
||||||
|
self.assertEqual(bob.creator, core)
|
||||||
self.assertEqual(bob.auth, auth)
|
self.assertEqual(bob.auth, auth)
|
||||||
self.assertEqual(bob.resolver, resolver)
|
self.assertEqual(bob.resolver, resolver)
|
||||||
self.assertEqual(bob.xfrout, auth)
|
self.assertEqual(bob.xfrout, auth)
|
||||||
|
315
src/bin/bind10/tests/sockcreator_test.py.in
Normal file
315
src/bin/bind10/tests/sockcreator_test.py.in
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import struct
|
||||||
|
import socket
|
||||||
|
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:
|
||||||
|
"""
|
||||||
|
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':
|
||||||
|
self.__plan.pop(0)
|
||||||
|
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 __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.
|
||||||
|
"""
|
||||||
|
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)
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
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')
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
# 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 = 42
|
||||||
|
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()
|
||||||
|
unittest.main()
|
@@ -15,7 +15,7 @@ endif
|
|||||||
check-local:
|
check-local:
|
||||||
for pytest in $(PYTESTS) ; do \
|
for pytest in $(PYTESTS) ; do \
|
||||||
echo Running test: $$pytest ; \
|
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) \
|
$(LIBRARY_PATH_PLACEHOLDER) \
|
||||||
BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
|
BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
|
||||||
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
|
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
# 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 unittest
|
||||||
import sys
|
import sys
|
||||||
|
@@ -3,7 +3,7 @@ The socket creator
|
|||||||
|
|
||||||
The only thing we need higher rights than standard user is binding sockets to
|
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
|
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
|
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
|
and to contain as little code as possible to minimise the amount of code
|
||||||
|
Reference in New Issue
Block a user