Commit Graph

70 Commits

Author SHA1 Message Date
Jun Wu
15584f0091 commandserver: move printbanner logic to bindsocket
bindsocket now handles listen automatically. "printbanner" seems to be just
a part of "bindsocket". This simplifies the interface a bit.
2017-04-30 11:21:05 -07:00
Jun Wu
d3cc1e50f4 commandserver: move "listen" responsibility from service to handler
This enables chg to replace a server socket in an atomic way:

  1. bind to a temp address
  2. listen
  3. rename

Currently 3 happens before 2 so a client may see the socket file but fails
to connect to it.
2017-04-30 11:08:27 -07:00
Pulkit Goyal
07314d0686 py3: convert the mode argument of os.fdopen to unicodes (1 of 2)
os.fdopen() does not accepts bytes as its second argument which represent the
mode in which the file is to be opened. This patch makes sure unicodes are
passed in py3 by using pycompat.sysstr().
2017-02-13 20:06:38 +05:30
Jun Wu
863f8667b5 commandserver: handle backlog before exiting
Previously, when a chg server is exiting, it does not handle connected
clients so clients may get ECONNRESET and crash:

  1. client connect() # success
  2. server shouldexit = True and exit
  3. client recv() # ECONNRESET

297d89f2789e makes this race condition easier to reproduce if a lot of short
chg commands are started in parallel.

This patch fixes the above issue by unlinking the socket path to stop
queuing new connections and processing all pending connections before exit.
2017-02-08 14:45:30 -08:00
Jun Wu
59177ba177 commandserver: prevent unlink socket twice
This patch changes unixforkingservice so it only calls
`self._servicehandler.unlinksocket(self.address)` at most once.

This is needed by the next patch.
2017-02-08 14:37:38 -08:00
Pulkit Goyal
97f340e354 py3: use pycompat.getcwd() instead of os.getcwd()
We have pycompat.getcwd() which returns bytes path on Python 3. This patch
changes most of the occurences of the os.getcwd() with pycompat one.
2016-11-23 00:03:11 +05:30
Yuya Nishihara
e90ef2b652 server: move service table and factory from commandserver
This is necessary to solve future dependency cycle between commandserver.py
and chgserver.py.

'cmd' prefix is added to table and function names to avoid conflicts with
hgweb.
2016-10-15 13:57:17 +09:00
Yuya Nishihara
47f9c8b52e py3: bulk replace sys.stdin/out/err by util's
Almost all sys.stdin/out/err in hgext/ and mercurial/ are replaced by util's.
There are a few exceptions:

 - lsprof.py and statprof.py are untouched since they are a kind of vendor
   code and they never import mercurial modules right now.
 - ui._readline() needs to replace sys.stdin and stdout to pass them to
   raw_input(). We'll need another workaround here.
2016-10-20 23:53:36 +09:00
Yuya Nishihara
51001d7040 cmdserver: write channel header and payload by a single write() call
This makes a channeledoutput thread-safe as long as the underlying fwrite() is
thread-safe. Both POSIX and Windows implementations are documented as MT-safe.

MT-safety is necessary to use ui.fout and ui.ferr in hgweb.
2016-02-29 13:41:54 +09:00
Jun Wu
62e9dff235 commandserver: update comment about setpgid
Now setpgid has 2 main purposes: better handling for terminal-generated
SIGTSTP, SIGINT, and process-exit-generated SIGHUP. Update the comment to
explain things more clearly.
2016-07-18 15:59:08 +01:00
Yuya Nishihara
8140c5f97f commandserver: use SOMAXCONN as queue size of pending connections
The old value 5 was arbitrary chosen. Since there's no practical reason to
limit the backlog, this patch simply uses SOMAXCONN as a value large enough.
2016-07-16 14:48:58 +09:00
Yuya Nishihara
badb03f2ce commandserver: rename _serveworker() to _runworker()
"run" sounds more natural as the function does never listen for new connection.
2016-07-16 14:46:31 +09:00
Yuya Nishihara
a598675541 commandserver: separate initialization and cleanup of forked process
Separated _initworkerprocess() and _serverequest() can be reused when
implementing a prefork service.
2016-05-22 13:53:32 +09:00
Yuya Nishihara
e51719b422 commandserver: unindent superfluous "if True" blocks 2016-05-21 18:14:13 +09:00
Jun Wu
accebce9b6 commandserver: send pgid in hello message
See the next patches for why we need it.
2016-07-17 22:56:05 +01:00
Yuya Nishihara
076cc2bdc1 commandserver: drop old unixservice implementation
It's been superseded by unixforkingservice.
2016-05-22 13:45:09 +09:00
Yuya Nishihara
2857a87cb4 commandserver: add new forking server implemented without using SocketServer
SocketServer.ForkingMixIn of Python 2.x has a couple of issues, such as:

 - race condition that leads to 100% CPU usage (Python 2.6)
   https://bugs.python.org/issue21491
 - can't wait for children belonging to different process groups (Python 2.6)
 - leaves at least one zombie process (Python 2.6, 2.7)
   https://bugs.python.org/issue11109

The first two are critical because we do setpgid(0, 0) in child process to
isolate terminal signals. The last one isn't, but ForkingMixIn seems to be
doing silly. So there are two choices:

 a) backport and maintain SocketServer until we can drop support for Python 2.x
 b) replace SocketServer by simpler one and eliminate glue codes

I chose (b) because it's great time for getting rid of utterly complicated
SocketServer stuff, and preparing for future move towards prefork service.

New unixforkingservice is implemented loosely based on chg 531f8ef64be6. It
is monolithic but much simpler than SocketServer. unixservicehandler provides
customizing points for chg, and it will be shared with future prefork service.

Old unixservice class is still used by chgserver. It will be removed later.

Thanks to Jun Wu for investigating these issues.
2016-05-22 11:43:18 +09:00
Yuya Nishihara
d298dc2539 commandserver: extract function that serves for the current connection
This will be used by new server implementation.
2016-05-22 12:49:22 +09:00
Yuya Nishihara
be6319726b commandserver: manually create file objects from socket
Prepares for moving away from SocketServer. See the subsequent patches for
why.
2016-05-22 12:44:25 +09:00
Yuya Nishihara
53e19881da commandserver: extract _cleanup() hook to clarify chg is doing differently
This makes it clear that chg needs its own way to unlink closed socket file.
I made a mistake in draft patches without noting the difference.
2016-05-22 11:21:11 +09:00
Yuya Nishihara
bfbe03d5c2 commandserver: backport handling of forking server from chgserver
This is common between chg and vanilla forking server, so move it to
commandserver and unify handle().

It would be debatable whether we really need gc.collect() or not, but that
is beyond the scope of this series. Maybe we can remove gc.collect() once
all resource deallocations are switched to context manager.
2016-05-21 15:23:21 +09:00
Yuya Nishihara
b7be4fa70f commandserver: promote .cleanup() hook from chgserver
This allows us to unify _requesthandler.handle().
2016-05-21 15:18:23 +09:00
Yuya Nishihara
3f1513d0b9 commandserver: extract method to create commandserver instance per request
This is a step toward merging chgserver._requesthandler with commandserver's.
2016-05-21 15:12:19 +09:00
Pulkit Goyal
38a359ce5c py3: conditionalize SocketServer import
The SocketServer is renamed to socketserver in python 3
2016-06-27 16:48:54 +05:30
Yuya Nishihara
bed8e170aa ui: provide official way to reset internal state per command
This will allow us to clear in-memory password storage per runcommand().

I've updated commandserver to call resetstate() of both ui and repo.ui because
they may have different states in theory.
2016-06-12 14:07:26 +09:00
Yuya Nishihara
025ddf17ef cmdserver: write early exception to 'e' channel in 'unix' mode
In 'unix' mode, the server is typically detached from the console. Therefore
a client couldn't see the exception that occurred while instantiating the
server object.

This patch tries to catch the early error and send it to 'e' channel even if
the server isn't instantiated yet. This means the error may be sent before the
initial hello message. So it's up to the client implementation whether to
handle the early error message or error out as protocol violation.

The error handling code is also copied to chgserver.py. I'll factor out them
later if we manage to get chg passes the test suite.
2016-03-12 22:03:30 +09:00
Jun Wu
f4e1334a3d commandserver: use _readlist
Use _readlist introduced in previous commit to make the code shorter.
2016-02-15 14:20:41 +00:00
Jun Wu
009ee924ea commandserver: add _readstr and _readlist
Reading a string or a list are common operations for commandserver and
chgserver. This patch adds _readstr and _readlist to avoid duplication.
2016-02-16 19:11:45 +00:00
timeless
3502e556ef util: enable getpid to be replaced
This will enable tests to write stable process ids.
2016-02-03 09:11:22 +00:00
Yuya Nishihara
558df9ce0f commandserver: drop tell() and seek() from channels (issue5049)
These operations are obviously invalid for file-like channels because they
will read or write protocol headers.

This patch works around the issue that "hg archive" generates a corrupted
zip file on Windows commandserver because of unusable tell() implementation.
But the problem still occurs without using a commandserver.

  $ hg archive -R not-small-repo -t zip - | cat > invalid.zip

So, this patch cannot fix the issue5049 completely.
2016-01-20 00:08:00 +09:00
Yuya Nishihara
240828180d commandserver: reset state of progress bar per command
A progress bar is normally disabled in command-server session, but chg can
enable it. This patch makes sure the last-print time is measured per command.
Otherwise, progress.delay could be ineffective if a progbar was loaded before
forking worker process.

This patch is corresponding to the following change.

https://bitbucket.org/yuja/chg/commits/2dfe3e90b365
2015-12-14 23:50:02 +09:00
Yuya Nishihara
76486fd2e7 commandserver: do not set nontty flag if channel is replaced by a real file
This prepares for porting the chg server. In chg, a server receives client's
stdio over a UNIX domain socket to override server channels. This is because
chg should behave as if it is a normal hg command attached to tty. "nontty"
is not wanted.

This patch is corresponding to the following change. This doesn't test the
identity of "cin" object because the current version of chg reopens stdio
to apply buffering mode.

https://bitbucket.org/yuja/chg/commits/c48c7aed5fc0
2015-12-14 23:13:42 +09:00
Yuya Nishihara
f7f67c678f commandserver: implement name() to clarify channel is not a plain file
Because unknown attributes are delegated to the underlying file object,
commandserver channels said they were '<stdout>' or '<stdin>' even though
they weren't. This patch makes them say '<X-channel>'.
2015-12-13 19:32:01 +09:00
Yuya Nishihara
7b095d1256 commandserver: cut import cycle by itself
We generally make modules importable from the front-end layer, dispatch ->
commands -> x. So the import cycle to dispatch should be resolved by the
commandserver module.
2015-11-24 23:03:54 +09:00
Yuya Nishihara
a881bac864 commandserver: use absolute_import 2015-11-24 22:58:40 +09:00
Pierre-Yves David
30913031d4 error: get Abort from 'error' instead of 'util'
The home of 'Abort' is 'error' not 'util' however, a lot of code seems to be
confused about that and gives all the credit to 'util' instead of the
hardworking 'error'. In a spirit of equity, we break the cycle of injustice and
give back to 'error' the respect it deserves. And screw that 'util' poser.

For great justice.
2015-10-08 12:55:45 -07:00
Matt Mackall
da38b28f4f commandserver: mark developer-only logging option 2015-06-25 17:44:15 -05:00
Gregory Szorc
5380dea2a7 global: mass rewrite to use modern exception syntax
Python 2.6 introduced the "except type as instance" syntax, replacing
the "except type, instance" syntax that came before. Python 3 dropped
support for the latter syntax. Since we no longer support Python 2.4 or
2.5, we have no need to continue supporting the "except type, instance".

This patch mass rewrites the exception syntax to be Python 2.6+ and
Python 3 compatible.

This patch was produced by running `2to3 -f except -w -n .`.
2015-06-23 22:20:08 -07:00
Yuya Nishihara
1c7ce2bd17 cmdserver: protect pipe server streams against corruption caused by direct io
Because pipe-mode server uses stdio as IPC channel, other modules should not
touch stdio directly and use ui instead.  However, this strategy is brittle
because several Python functions read and write stdio implicitly.

    print 'hello'  # should use ui.write()
    # => ch = 'h', size = 1701604463 'ello', data = '\n'

This patch adds protection for such mistakes.  Both stdio files and low-level
file descriptors are redirected to /dev/null while command server uses them.
2014-11-15 13:50:43 +09:00
Yuya Nishihara
2808848bc1 cmdserver: postpone creation of pipe server until run()
This makes it easy to swap file descriptors while running command server.
2014-11-15 13:04:41 +09:00
Yuya Nishihara
0c88d9a994 cmdserver: use given streams as pipe channels like other commands
Because commandserver itself is an hg subcommand, it shouldn't use stdio
directly in principle.
2014-11-15 12:43:35 +09:00
Yuya Nishihara
a9b00f4522 cmdserver: include pid of server handling requests in hello message
Because unix-mode server forks child process per connection, client does not
know the pid of the server that will handle requests.  The pid is necessary
to interrupt hung process:

 1. client connects to socket server
 2. server accepts the connection, forks, and tells pid
 3. client requests "runcommand pull"
    .. hung ..
 4. client sends SIGINT to the (forked) server
 5. server returns from I/O wait

Note that getsockopt(SO_PEERCRED) of Linux cannot be used because the server
fork()s after accept().
2014-10-18 12:24:50 +09:00
Yuya Nishihara
0baf7a676d cmdserver: add service that listens on unix domain socket and forks process
Typical use case of 'unix' mode is a background hg daemon.

    $ hg serve --cmdserver unix --cwd / -a /tmp/hg-`id -u`.sock

Unlike 'pipe' mode in which parent process keeps stdio channel, 'unix' server
can be detached.  So clients can freely connect and disconnect from server,
saving Python start-up time.

It might be better to write "--cmdserver socket -a unix:/sockpath" instead
of "--cmdserver unix -a /sockpath" in case hgweb gets the ability to listen
on unix domain socket.
2014-10-04 16:46:50 +09:00
Yuya Nishihara
754a73fea4 cmdserver: make server streams switchable
In 'unix' mode, server instance will be created per connection, and fin/fout
are set to socket files.
2014-09-27 15:10:14 +09:00
Yuya Nishihara
11d619a47e cmdserver: switch service objects by mode
server class will be changed to accept fin/fout pair instead of mode string
so that it can interact with socket files.
2014-09-27 15:04:46 +09:00
Yuya Nishihara
84c7e5f2c1 cmdserver: wrap 'pipe' mode server by service object
This is the stub for new mode that will listen for connections on unix domain
socket.

Though --daemon option is not banned in 'pipe' mode, it is useless because
the detached 'pipe' mode server exits immediately due to null stdin. Should
it abort if --daemon is specified with --cmdserver pipe or --stdio?
2014-09-27 14:52:09 +09:00
Yuya Nishihara
27aa215891 cmdserver: drop useless in_ attribute from channeledoutput
The previous patch makes sure that in_ == out, so it's no longer needed
to keep in_ for __getattr__.  Also, it seems strange for channeledoutput
to have in_ stream which is actually a writable file object.
2014-09-27 12:37:53 +09:00
Yuya Nishihara
99d8be652a cmdserver: get file attributes of 'e'-channel from stdout, not from stderr
It seems wrong to get attributes from object different than the underlying
file.  In the following example, it doesn't make sense to flush stderr after
writing to stdout:

    self.ferr.write(str(a))
    if not getattr(self.ferr, 'closed', False):
        self.ferr.flush()
2014-09-27 12:27:03 +09:00
Yuya Nishihara
2e0a7a3cee cmdserver: correct doc of channeledoutput
in_ is only used as the source of file attributes.
2014-09-27 12:15:01 +09:00
Yuya Nishihara
96a8ea56df cmdserver: forcibly use L channel to read password input (issue3161)
Command server is designed to use the channel protocol even if the server
process is accessible to tty, whereas vanilla hg should be able to read
password from tty in that case.  So it isn't enough to swap sys.stdin:

    # works only if the server process is detached from the console
    sys.stdin = self.fin
    getpass.getpass('')
    sys.stdin = oldin

or test isatty:

    # vanilla hg can't talk to tty if stdin is redirected
    if self._isatty(self.fin):
        return getpass.getpass('')
    else:
        ...

Since ui.nontty flag is undocumented and command-server channels don't provide
isatty(), this change won't affect the other uses of ui._isatty().

issue3161 also suggests to provide some context of messages.  I think it can
be implemented by using the generic templating function.
2014-04-26 18:13:06 +09:00