diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index 3da6f3546b829920ba6ea664b6fefc737129f5c1..234f7091c1fd7541f23b39af96054d91c57dd0f8 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -95,7 +95,7 @@ StringXString MeshOptions_String[] = { StringXString SolverOptions_String[] = { { F|O, "SocketName" , opt_solver_socket_name , #if defined(WIN32) && !defined(__CYGWIN__) - "127.0.0.1:44122" , // use TCP/IP sockets by default on "pure" Windows + ":44122" , // use TCP/IP sockets by default on Windows #else ".gmshsock" , // otherwise use Unix sockets by default #endif diff --git a/Common/OS.cpp b/Common/OS.cpp index b8fd20a55fe376adefb09686ab5f74832376b30f..5f9ca684ca9b2ccae48615eb0faa720c28da4e2b 100644 --- a/Common/OS.cpp +++ b/Common/OS.cpp @@ -110,6 +110,13 @@ int GetProcessId() #endif } +std::string GetHostName() +{ + char host[256]; + gethostname(host, sizeof(host)); + return std::string(host); +} + int UnlinkFile(const char *filename) { #if !defined(WIN32) || defined(__CYGWIN__) diff --git a/Common/OS.h b/Common/OS.h index 93cc1155aee6f1fcbc57340c9c8a6545bd403fed..d9840b3eb4905a4e9562b061885577d8cd072d2b 100644 --- a/Common/OS.h +++ b/Common/OS.h @@ -6,12 +6,15 @@ #ifndef _OS_H_ #define _OS_H_ +#include <string> + double GetTimeInSeconds(); void SleepInSeconds(double s); void GetResources(double *s, long *mem); void CheckResources(); double Cpu(); int GetProcessId(); +std::string GetHostName(); int UnlinkFile(const char *name); int StatFile(const char *filename); int KillProcess(int pid); diff --git a/Fltk/GmshServer.h b/Fltk/GmshServer.h deleted file mode 100644 index 8b776c537968e80dfcab5c5fd3f4fe8a6b5fdebf..0000000000000000000000000000000000000000 --- a/Fltk/GmshServer.h +++ /dev/null @@ -1,274 +0,0 @@ -// Gmsh - Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle -// -// See the LICENSE.txt file for license information. Please report all -// bugs and problems to <gmsh@geuz.org>. - -#ifndef _GMSH_SERVER_H_ -#define _GMSH_SERVER_H_ - -int SystemCall(const char *str); -int WaitForData(int socket, int num, double waitint); - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#if defined(_AIX) -#include <strings.h> -#endif - -#if !defined(WIN32) || defined(__CYGWIN__) - -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <sys/time.h> -#include <netinet/in.h> - -#else // pure windows - -#include <winsock.h> - -#endif - -static int myselect(int socket, int seconds) -{ - struct timeval tv; - tv.tv_sec = seconds; - tv.tv_usec = 0; - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(socket, &rfds); - return select(socket + 1, &rfds, NULL, NULL, &tv); -} - -class GmshServer { - public: - // This should match what's in GmshClient.h (Do not use values - // greater that 65535: if we receive types > 65535 we assume that we - // receive data from a machine with a different byte ordering, and - // we just swap the bytes) - typedef enum{ CLIENT_START = 1, - CLIENT_STOP = 2, - CLIENT_INFO = 10, - CLIENT_WARNING = 11, - CLIENT_ERROR = 12, - CLIENT_PROGRESS = 13, - CLIENT_MERGE_FILE = 20, // old name: CLIENT_VIEW - CLIENT_PARSE_STRING = 21, - CLIENT_OPTION_1 = 100, - CLIENT_OPTION_2 = 101, - CLIENT_OPTION_3 = 102, - CLIENT_OPTION_4 = 103, - CLIENT_OPTION_5 = 104 } MessageType; - static int init, s; - - private: - int _maxdelay, _portno, _sock; - const char *_sockname; - int _ReceiveData(void *buffer, int bytes) - { - char *buf = (char *)buffer; - int sofar = 0; - int remaining = bytes; - do { - int len = recv(_sock, buf + sofar, remaining, 0); - if(len <= 0) - return 0; - sofar += len; - remaining -= len; - } while(remaining > 0); - return bytes; - } - void _SwapBytes(char *array, int size, int n) - { - char *x = new char[size]; - for(int i = 0; i < n; i++) { - char *a = &array[i * size]; - memcpy(x, a, size); - for(int c = 0; c < size; c++) - a[size - 1 - c] = x[c]; - } - delete [] x; - } - int _AcceptConnection(int s) - { -#if defined(HAVE_NO_SOCKLEN_T) - int len; -#else - socklen_t len; -#endif - if(_portno < 0){ -#if !defined(WIN32) || defined(__CYGWIN__) - struct sockaddr_un from_un; - len = sizeof(from_un); - return accept(s, (struct sockaddr *)&from_un, &len); -#else - return -7; // Unix sockets not available on Windows without Cygwin -#endif - } - else{ - struct sockaddr_in from_in; - len = sizeof(from_in); - return accept(s, (struct sockaddr *)&from_in, &len); - } - } - - public: - GmshServer(int maxdelay = 4) - : _maxdelay(maxdelay), _portno(-1), _sock(0), _sockname(NULL) {} - ~GmshServer(){} - int StartClient(const char *command, const char *sockname = NULL) - { - int justwait = 0; - - if(!command || !strlen(command)) - justwait = 1; - - _sockname = sockname; - - // no socket? launch the command directly - if(!_sockname) { - SystemCall(command); - return 1; - } - - if(strstr(_sockname, "/") || strstr(_sockname, "\\") || !strstr(_sockname, ":")){ - // UNIX socket (testing ":" is not enough with Windows paths) - _portno = -1; - } - else{ - // TCP/IP socket - const char *port = strstr(_sockname, ":"); - _portno = atoi(port + 1); - } - - if(_portno < 0){ - // delete the file if it already exists -#if !defined(WIN32) || defined(__CYGWIN__) - unlink(_sockname); - - // make the socket - s = socket(PF_UNIX, SOCK_STREAM, 0); - if(s < 0) - return -1; // Error: Couldn't create socket - - // bind the socket to its name - struct sockaddr_un addr_un; - memset((char *) &addr_un, 0, sizeof(addr_un)); - strcpy(addr_un.sun_path, _sockname); - addr_un.sun_family = AF_UNIX; - if(bind(s, (struct sockaddr *)&addr_un, sizeof(addr_un)) < 0) - return -2; // Error: Couldn't bind socket to name - - // change permissions on the socket name in case it has to be rm'd later - chmod(_sockname, 0666); -#else - return -7; // Unix sockets not available on Windows without Cygwin -#endif - } - else{ -#if defined(WIN32) && !defined(__CYGWIN__) - if(!init){ - WSADATA wsaData; - int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); - if(iResult != NO_ERROR) - return -8; // Error: Couldn't initialize Windows sockets - } -#endif - if(init != _portno){ - // We need a better solution to deal with addresses that have - // already been bound... - init = _portno; - - // make the socket - s = socket(AF_INET, SOCK_STREAM, 0); -#if !defined(WIN32) || defined(__CYGWIN__) - if(s < 0) -#else - if(s == INVALID_SOCKET) -#endif - return -1; // Error: Couldn't create socket - - // bind the socket to its name - struct sockaddr_in addr_in; - memset((char *) &addr_in, 0, sizeof(addr_in)); - addr_in.sin_family = AF_INET; - addr_in.sin_addr.s_addr = INADDR_ANY; - addr_in.sin_port = htons(_portno); - if(bind(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0) - return -2; // Error: Couldn't bind socket to name - } - } - - if(!justwait) - SystemCall(command); // Start the solver - - // listen on socket (queue up to 20 connections before having - // them automatically rejected) - if(listen(s, 20)) - return -3; // Error: Socket listen failed - - if(justwait){ - // wait indefinitely until we get data - if(WaitForData(s, -1, 0.5)) - return -6; // not an actual error: we just stopped listening - } - else{ - // Wait at most _maxdelay seconds for data, issue error if no - // connection in that amount of time - if(!myselect(s, _maxdelay)) - return -4; // Error: Socket listening timeout - } - - // accept connection request - if((_sock = _AcceptConnection(s)) < 0) - return -5; // Error: Socket accept failed - - return _sock; - } - int ReceiveMessageHeader(int *type, int *len) - { - bool swap = false; - if(_ReceiveData(type, sizeof(int))){ - if(*type < 0) return 0; - if(*type > 65535){ - // the data comes from a machine with different endianness and - // we must swap the bytes - swap = true; - _SwapBytes((char*)type, sizeof(int), 1); - } - if(_ReceiveData(len, sizeof(int))){ - if(*len < 0) return 0; - if(swap) _SwapBytes((char*)len, sizeof(int), 1); - return 1; - } - } - return 0; - } - int ReceiveMessageBody(int len, char *str) - { - if(_ReceiveData(str, len) == len) { - str[len] = '\0'; - return 1; - } - return 0; - } - int StopClient() - { -#if !defined(WIN32) || defined(__CYGWIN__) - if(_portno < 0){ - // UNIX socket - if(unlink(_sockname) == -1) - return -1; // Impossible to unlink the socket - } - close(_sock); -#else - closesocket(_sock); -#endif - return 0; - } -}; - -#endif diff --git a/Fltk/GmshSocket.h b/Fltk/GmshSocket.h new file mode 100644 index 0000000000000000000000000000000000000000..549185a193320e34d7b47850d1444879c5265cfe --- /dev/null +++ b/Fltk/GmshSocket.h @@ -0,0 +1,451 @@ +// Gmsh - Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#ifndef _GMSH_SOCKET_H_ +#define _GMSH_SOCKET_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(_AIX) +#include <strings.h> +#endif + +#if !defined(WIN32) || defined(__CYGWIN__) +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <netdb.h> +#else +#include <winsock.h> +#include <process.h> +#endif + +class GmshSocket{ + public: + // types of messages that can be exchanged (never use values greater + // that 65535: if we receive a type > 65535 we assume that we + // receive data from a machine with a different byte ordering, and + // we swap the bytes in the payload) + enum MessageType{ + CLIENT_START = 1, + CLIENT_STOP = 2, + CLIENT_INFO = 10, + CLIENT_WARNING = 11, + CLIENT_ERROR = 12, + CLIENT_PROGRESS = 13, + CLIENT_MERGE_FILE = 20, // old name: CLIENT_VIEW + CLIENT_PARSE_STRING = 21, + CLIENT_SPEED_TEST = 30, + CLIENT_OPTION_1 = 100, + CLIENT_OPTION_2 = 101, + CLIENT_OPTION_3 = 102, + CLIENT_OPTION_4 = 103, + CLIENT_OPTION_5 = 104}; + protected: + // the socket descriptor + int _sock; + // the socket name + const char *_sockname; + // send some data over the socket + void _SendData(const void *buffer, int bytes) + { + const char *buf = (const char *)buffer; + int sofar = 0; + int remaining = bytes; + do { + ssize_t len = send(_sock, buf + sofar, remaining, 0); + sofar += len; + remaining -= len; + } while(remaining > 0); + } + // receive some data over the socket + int _ReceiveData(void *buffer, int bytes) + { + char *buf = (char *)buffer; + int sofar = 0; + int remaining = bytes; + do { + int len = recv(_sock, buf + sofar, remaining, 0); + if(len <= 0) + return 0; + sofar += len; + remaining -= len; + } while(remaining > 0); + return bytes; + } + // utility function to swap bytes in an array + void _SwapBytes(char *array, int size, int n) + { + char *x = new char[size]; + for(int i = 0; i < n; i++) { + char *a = &array[i * size]; + memcpy(x, a, size); + for(int c = 0; c < size; c++) + a[size - 1 - c] = x[c]; + } + delete [] x; + } + // sleep for some milliseconds + void _Sleep(int ms) + { +#if !defined(WIN32) || defined(__CYGWIN__) + usleep(1000 * ms); +#else + Sleep(ms); +#endif + } + public: + GmshSocket() : _sock(0), _sockname(0) + { +#if defined(WIN32) && !defined(__CYGWIN__) + static bool first = true; + if(first){ + first = false; + WSADATA wsaData; + int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if(iResult != NO_ERROR){ + // Error: Couldn't initialize Windows sockets... + } + } +#endif + } + ~GmshSocket() + { +#if defined(WIN32) && !defined(__CYGWIN__) + WSACleanup(); +#endif + } + // utility function to wait for some data to read on a socket (if + // seconds==0 we check for available data and return immediately, + // i.e., we do polling) + int Select(int socket, int seconds) + { + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(socket, &rfds); + // select checks all IO descriptors between 0 and its first arg, + // minus 1... hence the +1 below + return select(socket + 1, &rfds, NULL, NULL, &tv); + } + void SendString(int type, const char *str) + { + // send header (type + length) + _SendData(&type, sizeof(int)); + int len = strlen(str); + _SendData(&len, sizeof(int)); + // send body + _SendData(str, len); + } + int ReceiveHeader(int *type, int *len) + { + bool swap = false; + if(_ReceiveData(type, sizeof(int))){ + if(*type < 0) return 0; + if(*type > 65535){ + // the data comes from a machine with different endianness and + // we must swap the bytes + swap = true; + _SwapBytes((char*)type, sizeof(int), 1); + } + if(_ReceiveData(len, sizeof(int))){ + if(*len < 0) return 0; + if(swap) _SwapBytes((char*)len, sizeof(int), 1); + return 1; + } + } + return 0; + } + int ReceiveString(int len, char *str) + { + if(_ReceiveData(str, len) == len) { + str[len] = '\0'; + return 1; + } + return 0; + } +}; + +class GmshClient : public GmshSocket { + public: + GmshClient() : GmshSocket() {} + ~GmshClient(){} + int Connect(const char *sockname) + { + // slight delay to be sure that the socket is bound by the + // server before we attempt to connect to it... + _Sleep(100); + + int portno; + char remote[256]; + if(strstr(sockname, "/") || strstr(sockname, "\\") || !strstr(sockname, ":")){ + // UNIX socket (testing ":" is not enough with Windows paths) + portno = -1; + } + else{ + // INET socket + char *port = strstr(sockname, ":"); + portno = atoi(port + 1); + int remotelen = strlen(sockname) - strlen(port); + if(remotelen > 0) + strncpy(remote, sockname, remotelen); + remote[remotelen] = '\0'; + } + + // create socket + + if(portno < 0){ +#if !defined(WIN32) || defined(__CYGWIN__) + _sock = socket(PF_UNIX, SOCK_STREAM, 0); + if(_sock < 0) + return -1; // Error: Couldn't create socket + // try to connect socket to given name + struct sockaddr_un addr_un; + memset((char *) &addr_un, 0, sizeof(addr_un)); + addr_un.sun_family = AF_UNIX; + strcpy(addr_un.sun_path, sockname); + for(int tries = 0; tries < 5; tries++) { + if(connect(_sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) >= 0) + return _sock; + _Sleep(100); + } +#else + // Unix sockets are not available on Windows without Cygwin + return -1; +#endif + } + else{ + _sock = socket(AF_INET, SOCK_STREAM, 0); + if(_sock < 0) + return -1; // Error: Couldn't create socket + struct hostent *server; + if(!(server = gethostbyname(remote))) + return -3; // Error: No such host + // try to connect socket to given name + struct sockaddr_in addr_in; + memset((char *) &addr_in, 0, sizeof(addr_in)); + addr_in.sin_family = AF_INET; + memcpy((char *)&addr_in.sin_addr.s_addr, (char *)server->h_addr, server->h_length); + addr_in.sin_port = htons(portno); + for(int tries = 0; tries < 5; tries++) { + if(connect(_sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0) + return _sock; + _Sleep(100); + } + } + return -2; // Error: Couldn't connect + } + void Start() + { + char tmp[256]; +#if !defined(WIN32) || defined(__CYGWIN__) + sprintf(tmp, "%d", getpid()); +#else + sprintf(tmp, "%d", _getpid()); +#endif + SendString(CLIENT_START, tmp); + } + void Stop() + { + SendString(CLIENT_STOP, "Goodbye!"); + } + void Info(const char *str) + { + SendString(CLIENT_INFO, str); + } + void Warning(const char *str) + { + SendString(CLIENT_WARNING, str); + } + void Error(const char *str) + { + SendString(CLIENT_ERROR, str); + } + void Progress(const char *str) + { + SendString(CLIENT_PROGRESS, str); + } + void View(const char *str) + { + // deprecated: use MergeFile(str) instead + SendString(CLIENT_MERGE_FILE, str); + } + void MergeFile(const char *str) + { + SendString(CLIENT_MERGE_FILE, str); + } + void ParseString(const char *str) + { + SendString(CLIENT_PARSE_STRING, str); + } + void Option(int num, const char *str) + { + if(num < 1) num = 1; + if(num > 5) num = 5; + SendString(CLIENT_OPTION_1 + num - 1, str); + } + void Disconnect() + { +#if !defined(WIN32) || defined(__CYGWIN__) + close(_sock); +#else + closesocket(_sock); +#endif + } + +}; + +class GmshServer : public GmshSocket{ + private: + int _portno; + public: + GmshServer() : GmshSocket(), _portno(-1) {} + ~GmshServer(){} + virtual int SystemCall(const char *str) = 0; + virtual int WaitForData(int socket, int num, double waitint) = 0; + int StartClient(const char *command, const char *sockname=0, int maxdelay=4) + { + static int init = 0; + static int tmpsock = 0; + + int justwait = (!command || !strlen(command)); + _sockname = sockname; + + // no socket? launch the command directly + if(!_sockname) { + SystemCall(command); + return 1; + } + + if(strstr(_sockname, "/") || strstr(_sockname, "\\") || !strstr(_sockname, ":")){ + // UNIX socket (testing ":" is not enough with Windows paths) + _portno = -1; + } + else{ + // TCP/IP socket + const char *port = strstr(_sockname, ":"); + _portno = atoi(port + 1); + } + + if(_portno < 0){ +#if !defined(WIN32) || defined(__CYGWIN__) + // delete the file if it already exists + unlink(_sockname); + + // create a socket + tmpsock = socket(PF_UNIX, SOCK_STREAM, 0); + if(tmpsock < 0) + return -1; // Error: Couldn't create socket + + // bind the socket to its name + struct sockaddr_un addr_un; + memset((char *) &addr_un, 0, sizeof(addr_un)); + strcpy(addr_un.sun_path, _sockname); + addr_un.sun_family = AF_UNIX; + if(bind(tmpsock, (struct sockaddr *)&addr_un, sizeof(addr_un)) < 0) + return -2; // Error: Couldn't bind socket to name + + // change permissions on the socket name in case it has to be rm'd later + chmod(_sockname, 0666); +#else + return -7; // Unix sockets not available on Windows without Cygwin +#endif + } + else{ + if(init != _portno){ + // We should be able to use setsockopt to allow reusing the + // same address, but I could not make it work... hence this + // horrible hack to avoid binding the name multiple times + init = _portno; + + // create a socket + tmpsock = socket(AF_INET, SOCK_STREAM, 0); +#if !defined(WIN32) || defined(__CYGWIN__) + if(tmpsock < 0) +#else + if(tmpsock == INVALID_SOCKET) +#endif + return -1; // Error: Couldn't create socket + + // bind the socket to its name + struct sockaddr_in addr_in; + memset((char *) &addr_in, 0, sizeof(addr_in)); + addr_in.sin_family = AF_INET; + addr_in.sin_addr.s_addr = INADDR_ANY; + addr_in.sin_port = htons(_portno); + if(bind(tmpsock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0) + return -2; // Error: Couldn't bind socket to name + } + } + + if(!justwait) + SystemCall(command); // Start the solver + + // listen on socket (queue up to 20 connections before having + // them automatically rejected) + if(listen(tmpsock, 20)) + return -3; // Error: Socket listen failed + + if(justwait){ + // wait indefinitely until we get data + if(WaitForData(tmpsock, -1, 0.5)) + return -6; // not an actual error: we just stopped listening + } + else{ + // Wait at most maxdelay seconds for data, issue error if no + // connection in that amount of time + if(!Select(tmpsock, maxdelay)) + return -4; // Error: Socket listening timeout + } + + // accept connection request +#if defined(HAVE_NO_SOCKLEN_T) + int len; +#else + socklen_t len; +#endif + if(_portno < 0){ +#if !defined(WIN32) || defined(__CYGWIN__) + struct sockaddr_un from_un; + len = sizeof(from_un); + _sock = accept(tmpsock, (struct sockaddr *)&from_un, &len); +#else + _sock = -7; // Unix sockets not available on Windows without Cygwin +#endif + } + else{ + struct sockaddr_in from_in; + len = sizeof(from_in); + _sock = accept(tmpsock, (struct sockaddr *)&from_in, &len); + } + if(_sock < 0) return -5; // Error: Socket accept failed + + return _sock; + } + int StopClient() + { +#if !defined(WIN32) || defined(__CYGWIN__) + if(_portno < 0){ + // UNIX socket + if(unlink(_sockname) == -1) + return -1; // Impossible to unlink the socket + } + close(_sock); +#else + closesocket(_sock); +#endif + return 0; + } +}; + +#endif diff --git a/Fltk/Makefile b/Fltk/Makefile index 8d0f3dc81e74dfcf80d8b3b8e1b9adcf5a3c4d91..7d13c83248e475032ed850cb08d6df894eb3496d 100644 --- a/Fltk/Makefile +++ b/Fltk/Makefile @@ -207,9 +207,9 @@ Colorbar_Window.o: Colorbar_Window.cpp ../Common/GmshUI.h GUI.h \ ../Geo/SPoint3.h ../Common/Context.h ../Geo/CGNSOptions.h \ ../Mesh/PartitionOptions.h Solvers.o: Solvers.cpp ../Common/Message.h ../Common/StringUtils.h \ - Solvers.h GmshServer.h ../Common/OpenFile.h ../Common/GmshUI.h GUI.h \ + Solvers.h GmshSocket.h ../Common/OpenFile.h ../Common/GmshUI.h GUI.h \ Opengl_Window.h Colorbar_Window.h ../Post/ColorTable.h Popup_Button.h \ SpherePosition_Widget.h ../Mesh/Field.h ../Post/PView.h \ ../Geo/SPoint3.h ../Graphics/Draw.h ../Geo/SBoundingBox3d.h \ ../Geo/SPoint3.h ../Common/Context.h ../Geo/CGNSOptions.h \ - ../Mesh/PartitionOptions.h + ../Mesh/PartitionOptions.h ../Common/OS.h diff --git a/Fltk/Solvers.cpp b/Fltk/Solvers.cpp index 3b884081e55d19a7f47347d53f7c80bc45d72849..3a6f9b4848aca1583dd95ada3f94ba0976fddd74 100644 --- a/Fltk/Solvers.cpp +++ b/Fltk/Solvers.cpp @@ -8,57 +8,60 @@ #include "Message.h" #include "StringUtils.h" #include "Solvers.h" -#include "GmshServer.h" +#include "GmshSocket.h" #include "OpenFile.h" #include "GmshUI.h" #include "GUI.h" #include "PView.h" #include "Draw.h" #include "Context.h" +#include "OS.h" extern Context_T CTX; extern GUI *WID; SolverInfo SINFO[MAXSOLVERS]; -int GmshServer::init = 0; -int GmshServer::s; - -// This routine polls the socket at least every 'waitint' seconds and -// returns 0 if data is available or 1 if there was en error or if the -// process was killed. Otherwise it just tends to current GUI events -// (this is easier to manage than non-blocking IO, and simpler than -// using the "real" solution, i.e., threads. Another possibility would -// be to use Fl::add_fd()) - -int WaitForData(int socket, int num, double waitint) -{ - while(1){ - if((num >= 0 && SINFO[num].pid < 0) || (num < 0 && !CTX.solver.listen)){ - // process has been killed or we stopped listening - return 1; - } +class myGmshServer : public GmshServer{ + public: + myGmshServer() : GmshServer() {} + ~myGmshServer() {} + int SystemCall(const char *str){ return ::SystemCall(str); } + int WaitForData(int socket, int num, double waitint) + { + // This routine polls the socket at least every 'waitint' seconds and + // returns 0 if data is available or 1 if there was en error or if the + // process was killed. Otherwise it just tends to current GUI events + // (this is easier to manage than non-blocking IO, and simpler than + // using the "real" solution, i.e., threads. Another possibility would + // be to use Fl::add_fd()) + while(1){ + if((num >= 0 && SINFO[num].pid < 0) || (num < 0 && !CTX.solver.listen)){ + // process has been killed or we stopped listening + return 1; + } - // check if there is data (call select with a zero timeout to - // return immediately, i.e., do polling) - int ret = myselect(socket, 0); + // check if there is data (call select with a zero timeout to + // return immediately, i.e., do polling) + int ret = Select(socket, 0); - if(ret == 0){ - // nothing available: wait at most waitint seconds - WID->wait(waitint); - } - else if(ret > 0){ - // data is there - return 0; - } - else{ - // an error happened - if(num >= 0) - SINFO[num].pid = -1; - return 1; + if(ret == 0){ + // nothing available: wait at most waitint seconds + WID->wait(waitint); + } + else if(ret > 0){ + // data is there + return 0; + } + else{ + // an error happened + if(num >= 0) + SINFO[num].pid = -1; + return 1; + } } } -} +}; // This routine either launches a solver and waits for some answer (if // num >= 0), or simply waits for messages (if num < 0) @@ -69,7 +72,7 @@ int Solver(int num, const char *args) new_connection: - GmshServer server(CTX.solver.max_delay); + GmshServer *server = new myGmshServer; if(num >= 0){ prog = FixWindowsPath(SINFO[num].executable_name); @@ -78,7 +81,7 @@ int Solver(int num, const char *args) #if !defined(WIN32) command += " &"; #endif - server.StartClient(command.c_str()); + server->StartClient(command.c_str(), 0, CTX.solver.max_delay); return 1; } } @@ -103,6 +106,9 @@ int Solver(int num, const char *args) else{ // TCP/IP socket sockname = CTX.solver.socket_name; + // if only the port is given, prepend the host name + if(sockname.size() && sockname[0] == ':') + sockname = GetHostName() + sockname; } if(num >= 0){ @@ -115,7 +121,7 @@ int Solver(int num, const char *args) #endif } - int sock = server.StartClient(command.c_str(), sockname.c_str()); + int sock = server->StartClient(command.c_str(), sockname.c_str(), CTX.solver.max_delay); if(sock < 0) { switch (sock) { @@ -137,7 +143,7 @@ int Solver(int num, const char *args) break; case -6: Msg::Info("Stopped listening for solver connections"); - server.StopClient(); + server->StopClient(); break; case -7: Msg::Error("Unix sockets not available on Windows without Cygwin"); @@ -169,15 +175,16 @@ int Solver(int num, const char *args) if(stop || (num >= 0 && SINFO[num].pid < 0)) break; - stop = WaitForData(sock, num, 0.1); + stop = server->WaitForData(sock, num, 0.1); if(stop || (num >= 0 && SINFO[num].pid < 0)) break; int type, length; - if(server.ReceiveMessageHeader(&type, &length)){ + if(server->ReceiveHeader(&type, &length)){ + double timer = GetTimeInSeconds(); char *message = new char[length + 1]; - if(server.ReceiveMessageBody(length, message)){ + if(server->ReceiveString(length, message)){ switch (type) { case GmshServer::CLIENT_START: if(num >= 0) @@ -236,6 +243,10 @@ int Solver(int num, const char *args) case GmshServer::CLIENT_ERROR: Msg::Direct(1, "%-8.8s: %s", num >= 0 ? SINFO[num].name : "Client", message); break; + case GmshServer::CLIENT_SPEED_TEST: + Msg::Info("got %d Mb message in %g seconds", strlen(message) / 1024 / 1024, + GetTimeInSeconds() - timer); + break; default: Msg::Warning("Unknown type of message received from %s", num >= 0 ? SINFO[num].name : "client"); @@ -267,7 +278,7 @@ int Solver(int num, const char *args) } } - if(server.StopClient() < 0) + if(server->StopClient() < 0) Msg::Warning("Impossible to unlink the socket '%s'", sockname.c_str()); if(num >= 0){ @@ -275,6 +286,7 @@ int Solver(int num, const char *args) } else{ Msg::Info("Client disconnected: starting new connection"); + delete server; goto new_connection; } diff --git a/Mesh/Makefile b/Mesh/Makefile index afc7c89c556620c950acb4e2ab4e1d37cff97b13..af73417385bc1dd697c36c30a69109f56b079b4c 100644 --- a/Mesh/Makefile +++ b/Mesh/Makefile @@ -105,7 +105,8 @@ Field.o: Field.cpp ../Common/Context.h ../Geo/CGNSOptions.h \ ../Geo/SPoint2.h ../Geo/SVector3.h ../Geo/Pair.h ../Geo/GRegion.h \ ../Geo/GEntity.h ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h \ ../Common/Message.h ../Post/OctreePost.h ../Common/Octree.h \ - ../Common/OctreeInternals.h ../Post/PViewDataList.h ../Post/PViewData.h + ../Common/OctreeInternals.h ../Post/PViewDataList.h ../Post/PViewData.h \ + ../Geo/MVertex.h ../Geo/SPoint3.h meshGEdge.o: meshGEdge.cpp ../Geo/GModel.h ../Geo/GVertex.h \ ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \ ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Geo/GPoint.h \