diff --git a/Fltk/GmshServer.h b/Fltk/GmshServer.h new file mode 100644 index 0000000000000000000000000000000000000000..8b776c537968e80dfcab5c5fd3f4fe8a6b5fdebf --- /dev/null +++ b/Fltk/GmshServer.h @@ -0,0 +1,274 @@ +// 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/Plugin/TransformLatLon.cpp b/Plugin/TransformLatLon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c8d7545e723eb03acbb1ea2b932c526ccade71c --- /dev/null +++ b/Plugin/TransformLatLon.cpp @@ -0,0 +1,237 @@ +// 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>. + +#include "TransformLatLon.h" + +StringXNumber TransformLatLonOptions_Number[] = { + {GMSH_FULLRC, (char *)"iView", NULL, -1.}, + {GMSH_FULLRC, (char *)"Longitude0", NULL, 0.} +}; + +extern "C" +{ + GMSH_Plugin *GMSH_RegisterTransformLatLonPlugin() + { + return new GMSH_TransformLatLonPlugin(); + } +} + +GMSH_TransformLatLonPlugin::GMSH_TransformLatLonPlugin() +{ + ; +} + +void GMSH_TransformLatLonPlugin::getName(char *name) const +{ + strcpy(name, "TransformLatLon"); +} + +void GMSH_TransformLatLonPlugin::getInfos(char *author, char *copyright, + char *help_text) const +{ + strcpy(author, "J. Lambrechts"); + strcpy(copyright, "C. Geuzaine, J.-F. Remacle"); + strcpy(help_text, + "Plugin(TransformLatLon) transforms the homogeneous\n" + "node coordinates (x,y,z,1) of the elements in\n" + "the view `iView' by the matrix\n" + "[`A11' `A12' `A13' `Tx']\n" + "[`A21' `A22' `A23' `Ty']\n" + "[`A31' `A32' `A33' `Tz'].\n" + "If `SwapOrientation' is set, the orientation of the\n" + "elements is reversed. If `iView' < 0, the plugin\n" + "is run on the current view.\n" + "\n" "Plugin(TransformLatLon) is executed in-place.\n"); +} + +int GMSH_TransformLatLonPlugin::getNbOptions() const +{ + return sizeof(TransformLatLonOptions_Number) / sizeof(StringXNumber); +} + +StringXNumber *GMSH_TransformLatLonPlugin::getOption(int iopt) +{ + return &TransformLatLonOptions_Number[iopt]; +} + +void GMSH_TransformLatLonPlugin::catchErrorMessage(char *errorMessage) const +{ + strcpy(errorMessage, "TransformLatLon failed..."); +} + +// TransformLatLonation +static void vector_transform(double *vin, double *vout, double x, + double y, double z) +{ + double theta = y * M_PI / 180; + double phi = x * M_PI / 180; + vout[0] = -sin(phi) * vin[0] + cos(phi) * vin[1]; + vout[1] = + -sin(theta) * (cos(phi) * vin[0] + sin(phi) * vin[1]) + + cos(theta) * vin[2]; + vout[2] = + cos(theta) * (cos(phi) * vin[0] + sin(phi) * vin[1]) + + sin(theta) * vin[2]; +} + +static void transform_list(List_T * list, int nbList, List_T * list2, + int *nbList2, int nbVert, int nbComp, + double rotate) +{ + if(!nbList) + return; + int nb = List_Nbr(list) / nbList; + double *ll_out=new double[nbVert*3]; + double *lon=ll_out; + double *lat=ll_out+nbVert; + double *r=ll_out+nbVert*2; + double *din = new double[nbComp]; + double *dout = new double[nbComp]; + for(int i = 0; i < List_Nbr(list); i += nb) { + double *x = (double *)List_Pointer_Fast(list, i); + double *y = (double *)List_Pointer_Fast(list, i + nbVert); + double *z = (double *)List_Pointer_Fast(list, i + 2 * nbVert); + for(int j = 0; j < nbVert; j++) { + r[j] = sqrt(x[j]*x[j] + y[j]*y[j]+ z[j]*z[j]); + lat[j] = asin(z[j] / r[j]) * 180 / M_PI; + lon[j] = atan2(y[j], x[j]) * 180 / M_PI + rotate; + while(lon[j] > 180) + lon[j] -= 360; + lon[j]+=rotate; + } + // check the periodicity + bool cross = false; + for(int j = 1; j < nbVert; j++) + cross |= (fabs(lon[j] - lon[0]) > 180); + if(cross) + for(int j = 0; j < nbVert; j++) + if(lon[j] < 0) + lon[j] += 360; + for(int j = 0; j < nbVert*3; j++) + List_Add(list2, &ll_out[j]); + for(int k = 0; k < nbVert; k++) { + for(int l = 0; l < nbComp; l++) + List_Read(list, i + 3 * nbVert + nbComp * k + l, &din[l]); + if(nbComp == 1) + dout[0]=din[0]; + else if(nbComp == 3) { + vector_transform(din, dout, lon[k], lat[k], r[k]); + }else if(nbComp == 9){ + + }else{ + + } + for(int l = 0; l < nbComp; l++) + List_Add(list2, &dout[l]); + } + (*nbList2)++; + if(cross) { + for(int j = 0; j < nbVert; j++) + lon[j] -= 360; + for(int j = 0; j < nbVert*3; j++) + List_Add(list2, &ll_out[j]); + for(int k = 0; k < nbVert; k++) { + for(int l = 0; l < nbComp; l++) + List_Read(list, i + 3 * nbVert + nbComp * k + l, &din[l]); + if(nbComp == 1){ + dout[0]=din[0]; + } + else if(nbComp == 3) { + vector_transform(din, dout, lon[k], lat[k], r[k]); + }else if(nbComp == 9){ + + }else{ + + } + for(int l = 0; l < nbComp; l++) + List_Add(list2, &dout[l]); + } + (*nbList2)++; + } + } + delete[]dout; + delete[]din; + delete[]ll_out; +} + +PView *GMSH_TransformLatLonPlugin::execute(PView * v) +{ + int iView = (int)TransformLatLonOptions_Number[0].def; + double rotate = (double)TransformLatLonOptions_Number[1].def; + + PView *v1 = getView(iView, v); + if(!v1) + return v; + PView *v2 = new PView(true); + PViewDataList *data2 = getDataList(v2); + if(!data2) + return v; + + PViewDataList *data1 = getDataList(v1); + if(!data1) + return v; + // points + transform_list(data1->SP, data1->NbSP, data2->SP, &data2->NbSP, 1, 1, + rotate); + transform_list(data1->VP, data1->NbVP, data2->VP, &data2->NbVP, 1, 3, + rotate); + transform_list(data1->TP, data1->NbTP, data2->TP, &data2->NbTP, 1, 9, + rotate); + // lines + transform_list(data1->SL, data1->NbSL, data2->SL, &data2->NbSL, 2, 1, + rotate); + transform_list(data1->VL, data1->NbVL, data2->VL, &data2->NbVL, 2, 3, + rotate); + transform_list(data1->TL, data1->NbTL, data2->TL, &data2->NbTL, 2, 9, + rotate); + // triangles + transform_list(data1->ST, data1->NbST, data2->ST, &data2->NbST, 3, 1, + rotate); + transform_list(data1->VT, data1->NbVT, data2->VT, &data2->NbVT, 3, 3, + rotate); + transform_list(data1->TT, data1->NbTT, data2->TT, &data2->NbTT, 3, 9, + rotate); + // quadrangles + transform_list(data1->SQ, data1->NbSQ, data2->SQ, &data2->NbSQ, 4, 1, + rotate); + transform_list(data1->VQ, data1->NbVQ, data2->VQ, &data2->NbVQ, 4, 3, + rotate); + transform_list(data1->TQ, data1->NbTQ, data2->TQ, &data2->NbTQ, 4, 9, + rotate); + // tets + transform_list(data1->SS, data1->NbSS, data2->SS, &data2->NbSS, 4, 1, + rotate); + transform_list(data1->VS, data1->NbVS, data2->VS, &data2->NbVS, 4, 3, + rotate); + transform_list(data1->TS, data1->NbTS, data2->TS, &data2->NbTS, 4, 9, + rotate); + // hexas + transform_list(data1->SH, data1->NbSH, data2->SH, &data2->NbSH, 8, 1, + rotate); + transform_list(data1->VH, data1->NbVH, data2->VH, &data2->NbVH, 8, 3, + rotate); + transform_list(data1->TH, data1->NbTH, data2->TH, &data2->NbTH, 8, 9, + rotate); + // prisms + transform_list(data1->SI, data1->NbSI, data2->SI, &data2->NbSI, 6, 1, + rotate); + transform_list(data1->VI, data1->NbVI, data2->VI, &data2->NbVI, 6, 3, + rotate); + transform_list(data1->TI, data1->NbTI, data2->TI, &data2->NbTI, 6, 9, + rotate); + // pyramids + transform_list(data1->SY, data1->NbSY, data2->SY, &data2->NbSY, 5, 1, + rotate); + transform_list(data1->VY, data1->NbVY, data2->VY, &data2->NbVY, 5, 3, + rotate); + transform_list(data1->TY, data1->NbTY, data2->TY, &data2->NbTY, 5, 9, + rotate); + + data2->setName(data1->getName() + "_LatLon"); + data2->setFileName(data1->getName() + "_LatLon.pos"); + data2->finalize(); + + return v2; +} diff --git a/Plugin/TransformLatLon.h b/Plugin/TransformLatLon.h new file mode 100644 index 0000000000000000000000000000000000000000..e531a47422967aa8260d97c51496ef4260bb14c6 --- /dev/null +++ b/Plugin/TransformLatLon.h @@ -0,0 +1,28 @@ +// 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 _TRANSFORMLATLON_H_ +#define _TRANSFORMLATLON_H_ + +#include "Plugin.h" + +extern "C" +{ + GMSH_Plugin *GMSH_RegisterTransformLatLonPlugin(); +} + +class GMSH_TransformLatLonPlugin : public GMSH_Post_Plugin +{ +public: + GMSH_TransformLatLonPlugin(); + void getName(char *name) const; + void getInfos(char *author, char *copyright, char *help_text) const; + void catchErrorMessage(char *errorMessage) const; + int getNbOptions() const; + StringXNumber* getOption(int iopt); + PView *execute(PView *); +}; + +#endif diff --git a/demos/gen_earth_100km.geo b/demos/gen_earth_100km.geo new file mode 100644 index 0000000000000000000000000000000000000000..37de0611c03a782277dcbf77b6f9fb0cdc4c63dd --- /dev/null +++ b/demos/gen_earth_100km.geo @@ -0,0 +1,30 @@ +// you need gshhs data file, available on ftp://ftp.soest.hawaii.edu/ +Field[1] = Box; +Field[1].VIn = 2000; +Field[1].VOut = 100000; +Field[1].XMax = 6000000; +Field[1].XMin = 3000000; +Field[1].YMin = -2000000; +Field[1].YMax = 1000000; +Field[1].ZMin = 3220000; +Field[1].ZMax = 6000000; +//Field[2] = MathEval; +//Field[2].F= "1.e3"; + + +Plugin(GSHHS).iField=1; +Plugin(GSHHS).InFileName="gshhs_f.b"; +Plugin(GSHHS).OutFileName="earth_adapt.geo"; +Plugin(GSHHS).Run; +/* +Merge "earth_4km.geo"; +Field[3] = Threshold; +Field[3].LcMin = 4e3; +Field[3].LcMax = 500e3; +Field[3].DistMax = 2000e3; +Field[3].DistMin = 0e3; +Field[3].IField = 2; +Field[4]=MathEval; +Field[4].F = "80e3"; +Background Field = 3; +*/ diff --git a/examples/cube.geo b/examples/cube.geo deleted file mode 100644 index decdd4a696bb42dae6ae5bda42e91f3bb5b099e1..0000000000000000000000000000000000000000 --- a/examples/cube.geo +++ /dev/null @@ -1,83 +0,0 @@ -lcar1 = .0275; - -length = 0.25; -height = 1.0; -depth = 0.25; - -Point(newp) = {length/2,height/2,depth,lcar1}; /* Point 1 */ -Point(newp) = {length/2,height/2,0,lcar1}; /* Point 2 */ -Point(newp) = {-length/2,height/2,depth,lcar1}; /* Point 3 */ -Point(newp) = {-length/2,-height/2,depth,lcar1}; /* Point 4 */ -Point(newp) = {length/2,-height/2,depth,lcar1}; /* Point 5 */ -Point(newp) = {length/2,-height/2,0,lcar1}; /* Point 6 */ -Point(newp) = {-length/2,height/2,0,lcar1}; /* Point 7 */ -Point(newp) = {-length/2,-height/2,0,lcar1}; /* Point 8 */ -Line(1) = {3,1}; -Line(2) = {3,7}; -Line(3) = {7,2}; -Line(4) = {2,1}; -Line(5) = {1,5}; -Line(6) = {5,4}; -Line(7) = {4,8}; -Line(8) = {8,6}; -Line(9) = {6,5}; -Line(10) = {6,2}; -Line(11) = {3,4}; -Line(12) = {8,7}; -Line Loop(13) = {-6,-5,-1,11}; -Plane Surface(14) = {13}; -Line Loop(15) = {4,5,-9,10}; -Plane Surface(16) = {15}; -Line Loop(17) = {-3,-12,8,10}; -Plane Surface(18) = {17}; -Line Loop(19) = {7,12,-2,11}; -Plane Surface(20) = {19}; -Line Loop(21) = {-4,-3,-2,1}; -Plane Surface(22) = {21}; -Line Loop(23) = {8,9,6,7}; -Plane Surface(24) = {23}; - -Surface Loop(25) = {14,24,-18,22,16,-20}; -Complex Volume(26) = {25}; - -n = 21; - -/* -sizex = 4; -sizey = 6; -sizez = 4; -*/ -sizex = n*length; -sizey = n*height; -sizez = n*depth; - -sizex = 9; -sizey = 33; -sizez = 9; - - -Transfinite Line {2,4,9,7} = sizez; -Transfinite Line {11,5,10,12} = sizey; -Transfinite Line {3,1,6,8} = sizex; - -Transfinite Surface {14} = {5,4,3,1}; -Transfinite Surface {16} = {6,2,1,5}; -Transfinite Surface {18} = {6,2,7,8}; -Transfinite Surface {20} = {3,7,8,4}; -Transfinite Surface {22} = {3,7,2,1}; -Transfinite Surface {24} = {4,8,6,5}; - -Recombine Surface {14,16,18,20,22,24}; - -Transfinite Volume {26} = {3,7,2,1,4,8,6,5}; - -Physical Surface(200) = {14,16,18,20,24}; - -Physical Volume(100) = {26}; -/* -Mesh.use_cut_plane = 1; -Mesh.cut_planea = 0; -Mesh.cut_planeb = 0; -Mesh.cut_planec = 1; -Mesh.cut_planed = -0.125; -*/ \ No newline at end of file diff --git a/utils/solvers/c++/GmshClient.h b/utils/solvers/c++/GmshClient.h new file mode 100644 index 0000000000000000000000000000000000000000..ceb21908c7d9b7543fef1b569170d9106036b3f0 --- /dev/null +++ b/utils/solvers/c++/GmshClient.h @@ -0,0 +1,232 @@ +// Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, and/or sell copies of the +// Software, and to permit persons to whom the Software is furnished +// to do so, provided that the above copyright notice(s) and this +// permission notice appear in all copies of the Software and that +// both the above copyright notice(s) and this permission notice +// appear in supporting documentation. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE +// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR +// ANY CLAIM, OR ANY SPECIAL 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. +// +// Please report all bugs and problems to <gmsh@geuz.org>. + +#ifndef _GMSH_CLIENT_H_ +#define _GMSH_CLIENT_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef _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 // pure windows + +#include <winsock.h> +#include <process.h> + +#endif + +class GmshClient { + private: + 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 was 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; + int _sock; + 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); + } + void _SendString(int type, const char *str) + { + int len = strlen(str); + _SendData(&type, sizeof(int)); + _SendData(&len, sizeof(int)); + _SendData(str, len); + } + void _Idle(int ms) + { +#if !defined(WIN32) || defined(__CYGWIN__) + usleep(1000 * ms); +#else + Sleep(ms); +#endif + } + public: + GmshClient() : _sock(0) {} + ~GmshClient(){} + int Connect(const char *sockname) + { +#if defined(WIN32) && !defined(__CYGWIN__) + WSADATA wsaData; + int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if(iResult != NO_ERROR) + return -4; // Error: Couldn't initialize Windows sockets +#endif + + // slight delay to be sure that the socket is bound by the + // server before we attempt to connect to it... + _Idle(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; + _Idle(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; + _Idle(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); + WSACleanup(); +#endif + } +}; + +#endif