Skip to content
Snippets Groups Projects
Forked from gmsh / gmsh
18534 commits behind the upstream repository.
GmshClient.h 5.33 KiB
#ifndef _GMSH_CLIENT_H_
#define _GMSH_CLIENT_H_

// Copyright (C) 1997-2005 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>.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _AIX
#include <strings.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/time.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>

class GmshClient {
 private:
  typedef enum{ CLIENT_START    = 1,
		CLIENT_STOP     = 2,
		CLIENT_INFO     = 10,
		CLIENT_WARNING  = 11,
		CLIENT_ERROR    = 12,
		CLIENT_PROGRESS = 13,
		CLIENT_VIEW     = 20,
		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(void *buffer, int bytes)
  {
    char *buf = (char *)buffer;
    int sofar = 0;
    int remaining = bytes;
    do {
      int len = write(_sock, buf + sofar, remaining);
      sofar += len;
      remaining -= len;
    } while(remaining > 0);
  }
  void _SendString(int type, char str[])
  {
    int len = strlen(str);
    _SendData(&type, sizeof(int));
    _SendData(&len, sizeof(int));
    _SendData(str, len);
  }
  long _GetTime()
  {
    struct timeval tp;
    gettimeofday(&tp, (struct timezone *)0);
    return (long)tp.tv_sec * 1000000 + (long)tp.tv_usec;
  }
  void _Idle(double delay)
  {
    long t1 = _GetTime();
    while(1) {
      if(_GetTime() - t1 > 1.e6 * delay)
	break;
    }
  }
 public:
  GmshClient() : _sock(0) {}
  ~GmshClient(){}
  int Connect(char *sockname)
  {
    // slight delay to be sure that the socket is bound by the
    // server before we attempt to connect to it...
    _Idle(0.1);

    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){
      _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;
      strcpy(addr_un.sun_path, sockname);
      addr_un.sun_family = AF_UNIX;
      for(int tries = 0; tries < 5; tries++) {
	if(connect(_sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) >= 0)
	  return _sock;
	_Idle(0.1);
      }
    }
    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);
      addr_in.sin_addr.s_addr = INADDR_ANY;
      for(int tries = 0; tries < 5; tries++) {
	if(connect(_sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0)
	  return _sock;
	_Idle(0.1);
      }
    }
    return -2; // Error: Couldn't connect
  }
  void Start(int pid)
  {
    char tmp[256];
    sprintf(tmp, "%d", getpid());
    _SendString(CLIENT_START, tmp);
  }
  void Stop()
  {
    _SendString(CLIENT_STOP, "Goodbye!");
  }
  void Info(char *str)
  {
    _SendString(CLIENT_INFO, str);
  }
  void Warning(char *str)
  {
    _SendString(CLIENT_WARNING, str);
  }
  void Error(char *str)
  {
    _SendString(CLIENT_ERROR, str);
  }
  void Progress(char *str)
  {
    _SendString(CLIENT_PROGRESS, str);
  }
  void View(char *str)
  {
    _SendString(CLIENT_VIEW, str);
  }
  void Option(int num, char *str)
  {
    if(num < 1) num = 1;
    if(num > 5) num = 5;
    _SendString(CLIENT_OPTION_1 + num - 1, str);
  }
  void Disconnect()
  {
    close(_sock);
  }
};

#endif