diff --git a/.gitignore b/.gitignore index 3b06daa..be51429 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ perf.data.old # Valgrind reports callgrind.* +# GDB temp files +.gdb_history + # Git hash file githash.txt diff --git a/build.bat b/build.bat index 732acad..35933ca 100644 --- a/build.bat +++ b/build.bat @@ -23,6 +23,7 @@ dmd^ src\client\client.d^ src\common\messages.d^ src\common\dcd_version.d^ + src\common\socket.d^ msgpack-d\src\msgpack.d^ -Imsgpack-d\src^ -release -inline -O -wi^ diff --git a/src/client/client.d b/src/client/client.d index 515baae..7511d9f 100644 --- a/src/client/client.d +++ b/src/client/client.d @@ -30,13 +30,14 @@ import std.conv; import std.string; import std.experimental.logger; -import msgpack; import common.messages; import common.dcd_version; import common.socket; int main(string[] args) { + sharedLog.fatalHandler = () {}; + size_t cursorPos = size_t.max; string[] importPaths; ushort port = 9166; @@ -106,24 +107,12 @@ int main(string[] args) if (query) { - try + if (serverIsRunning(useTCP, socketFile, port)) { - Socket socket = createSocket(socketFile, port); - scope (exit) { socket.shutdown(SocketShutdown.BOTH); socket.close(); } - request.kind = RequestKind.query; - if (sendRequest(socket, request)) - { - const AutocompleteResponse response = getResponse(socket); - if (response.completionType == "ack") - { - writeln("Server is running"); - return 0; - } - else - throw new Exception(""); - } + writeln("Server is running"); + return 0; } - catch (Exception ex) + else { writeln("Server is not running"); return 1; @@ -312,47 +301,26 @@ Socket createSocket(string socketFile, ushort port) } else { - socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); - socket.connect(new UnixAddress(socketFile)); + version(Windows) + { + // should never be called with non-null socketFile on Windows + assert(false); + } + else + { + socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); + socket.connect(new UnixAddress(socketFile)); + } } socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5)); socket.blocking = true; return socket; } -/** - * Returns: true on success - */ -bool sendRequest(Socket socket, AutocompleteRequest request) -{ - ubyte[] message = msgpack.pack(request); - ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof]; - auto messageLength = message.length; - messageBuffer[0 .. size_t.sizeof] = (cast(ubyte*) &messageLength)[0 .. size_t.sizeof]; - messageBuffer[size_t.sizeof .. $] = message[]; - return socket.send(messageBuffer) == messageBuffer.length; -} - -/** - * Gets the response from the server - */ -AutocompleteResponse getResponse(Socket socket) -{ - ubyte[1024 * 16] buffer; - auto bytesReceived = socket.receive(buffer); - if (bytesReceived == Socket.ERROR) - throw new Exception("Incorrect number of bytes received"); - if (bytesReceived == 0) - throw new Exception("Server closed the connection, 0 bytes received"); - AutocompleteResponse response; - msgpack.unpack(buffer[0..bytesReceived], response); - return response; -} - void printDocResponse(AutocompleteResponse response) { import std.array: join; - response.docComments.join(r"\n\n").writeln; + response.docComments.join(r"\n\n").writeln; } void printLocationResponse(AutocompleteResponse response) diff --git a/src/common/dcd_version.d b/src/common/dcd_version.d index 01ca019..ac7c229 100644 --- a/src/common/dcd_version.d +++ b/src/common/dcd_version.d @@ -21,7 +21,7 @@ module common.dcd_version; /** * Human-readable version number */ -enum DCD_VERSION = "v0.8.0-alpha1"; +enum DCD_VERSION = "v0.8.0-beta2"; version (Windows) {} else version (built_with_dub) {} diff --git a/src/common/messages.d b/src/common/messages.d index f1b0d95..a3d07de 100644 --- a/src/common/messages.d +++ b/src/common/messages.d @@ -18,6 +18,9 @@ module common.messages; +import std.socket; +import msgpack; + /** * The type of completion list being returned */ @@ -157,3 +160,69 @@ struct AutocompleteResponse */ string[] importPaths; } + +/** + * Returns: true on success + */ +bool sendRequest(Socket socket, AutocompleteRequest request) +{ + ubyte[] message = msgpack.pack(request); + ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof]; + auto messageLength = message.length; + messageBuffer[0 .. size_t.sizeof] = (cast(ubyte*) &messageLength)[0 .. size_t.sizeof]; + messageBuffer[size_t.sizeof .. $] = message[]; + return socket.send(messageBuffer) == messageBuffer.length; +} + +/** + * Gets the response from the server + */ +AutocompleteResponse getResponse(Socket socket) +{ + ubyte[1024 * 16] buffer; + auto bytesReceived = socket.receive(buffer); + if (bytesReceived == Socket.ERROR) + throw new Exception("Incorrect number of bytes received"); + if (bytesReceived == 0) + throw new Exception("Server closed the connection, 0 bytes received"); + AutocompleteResponse response; + msgpack.unpack(buffer[0..bytesReceived], response); + return response; +} + +/** + * Returns: true if a server instance is running + * Params: + * useTCP = `true` to check a TCP port, `false` for UNIX domain socket + * socketFile = the file name for the UNIX domain socket + * port = the TCP port + */ +bool serverIsRunning(bool useTCP, string socketFile, ushort port) +{ + scope (failure) + return false; + AutocompleteRequest request; + request.kind = RequestKind.query; + Socket socket; + scope (exit) + { + socket.shutdown(SocketShutdown.BOTH); + socket.close(); + } + if (useTCP) + { + socket = new TcpSocket(AddressFamily.INET); + socket.connect(new InternetAddress("localhost", port)); + } + else + { + socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); + socket.connect(new UnixAddress(socketFile)); + } + socket.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(5)); + socket.blocking = true; + if (sendRequest(socket, request)) + return getResponse(socket).completionType == "ack"; + else + return false; +} diff --git a/src/common/socket.d b/src/common/socket.d index 05623f6..eed6b40 100644 --- a/src/common/socket.d +++ b/src/common/socket.d @@ -42,4 +42,8 @@ string generateSocketName() "dcd.socket"); } } + else + { + assert(0); + } } diff --git a/src/server/server.d b/src/server/server.d index 406dc32..fa7a32f 100644 --- a/src/server/server.d +++ b/src/server/server.d @@ -73,6 +73,8 @@ int main(string[] args) string socketFile = generateSocketName(); } + sharedLog.fatalHandler = () {}; + try { getopt(args, "port|p", &port, "I", &importPaths, "help|h", &help, @@ -86,6 +88,8 @@ int main(string[] args) return 1; } + globalLogLevel = level; + if (printVersion) { version (Windows) @@ -109,7 +113,11 @@ int main(string[] args) return 1; } - globalLogLevel = level; + if (serverIsRunning(useTCP, socketFile, port)) + { + fatal("Another instance of DCD-server is already running"); + return 1; + } info("Starting up..."); StopWatch sw = StopWatch(AutoStart.yes); @@ -128,17 +136,25 @@ int main(string[] args) } else { - socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); - if (exists(socketFile)) + version(Windows) { - info("Cleaning up old socket file at ", socketFile); - remove(socketFile); + fatal("UNIX domain sockets not supported on Windows"); + return 1; + } + else + { + socket = new Socket(AddressFamily.UNIX, SocketType.STREAM); + if (exists(socketFile)) + { + info("Cleaning up old socket file at ", socketFile); + remove(socketFile); + } + socket.blocking = true; + socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); + socket.bind(new UnixAddress(socketFile)); + setAttributes(socketFile, S_IRUSR | S_IWUSR); + info("Listening at ", socketFile); } - socket.blocking = true; - socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); - socket.bind(new UnixAddress(socketFile)); - setAttributes(socketFile, S_IRUSR | S_IWUSR); - info("Listening at ", socketFile); } socket.listen(0); diff --git a/tests/actual.txt b/tests/actual.txt deleted file mode 100644 index e69de29..0000000 diff --git a/tests/tc027/expected1.txt b/tests/tc027/expected1.txt new file mode 100644 index 0000000..a1254f5 --- /dev/null +++ b/tests/tc027/expected1.txt @@ -0,0 +1,9 @@ +identifiers +C l +alignof k +i v +init k +mangleof k +sizeof k +stringof k +tupleof k diff --git a/tests/tc027/file.d b/tests/tc027/file.d new file mode 100644 index 0000000..ed2da0d --- /dev/null +++ b/tests/tc027/file.d @@ -0,0 +1,10 @@ +struct Foo(C) +{ + int i; +} + +unittest +{ + auto foo = Foo!int(); + foo. +} diff --git a/tests/tc027/run.sh b/tests/tc027/run.sh new file mode 100755 index 0000000..d9fe1a8 --- /dev/null +++ b/tests/tc027/run.sh @@ -0,0 +1,5 @@ +set -e +set -u + +../../bin/dcd-client $1 file.d -c66 > actual1.txt +diff actual1.txt expected1.txt