libcom_tcp.c

来自「SRI international 发布的OAA框架软件」· C语言 代码 · 共 2,071 行 · 第 1/5 页

C
2,071
字号
/******************************************************************************
%   File    : libcom_tcp.c
%   Primary Authors  : Adam Cheyer, Didier Guzzoni
%   Purpose : TCP instantiation of lowlevel communication primitives for OAA
%         Works for both Microsoft Windows (1st half) and UNIX (2nd half)
%   Updated : 01/98
%
%   ------------------------------------------------------------------------
%   Unpublished-rights reserved under the copyright laws of the United States.
%
%      This data and information is proprietary to, and a valuable trade
%      secret of, SRI International.  It is given in confidence by SRI
%      International. Its use, duplication, or disclosure is subject to the
%      restrictions set forth in the License Agreement under which it has
%      been distributed.
%
%   Unpublished Copyright (c) 1993-98, SRI International.
%   "Open Agent Architecture" and "OAA" are Trademarks of SRI International.
%   ------------------------------------------------------------------------
%
%*/

#define EXPORT_BORLAND

#ifdef IS_DLL
#define EXPORT_MSCPP __declspec(dllexport)
#else
#define EXPORT_MSCPP
#endif

#define OAA_BINARY_PORT_OFFSET 10

/****************************************************************************
 * Include files
 ****************************************************************************/
#ifndef _WINDOWS
#include <sys/param.h>	// used by com_get_localhost_ip_address()
#endif
#include <stdio.h>
#include <stdarg.h>  	/* Variable length argument lists */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include "libcom_tcp.h"
#include "libdb.h"
#include "libutils.h"
#include "libicl_private.h"
#include "libicl.h"
#include "libicl_depr.h"
#include "termreader.h"
#include "stringtermreader.h"
#include "binarytermreader.h"
#include "termsender.h"
#include "stringtermsender.h"
#include "binarytermsender.h"
#include "liboaa.h"

extern char* oaa_library_version_str;

/****************************************************************************
 * Global variables and forward declarations
 ****************************************************************************/
#ifndef STREQ
#define STREQ(str1, str2) (strcmp((str1), (str2)) == 0)
#endif

int COM_BEST_FORMAT = 100;
int COM_STRING_FORMAT = 1;
int COM_BINARY_FORMAT = 2;

#ifdef NORMAL_GC
static void* termReaders[128];
static void* termSenders[128];
static int termReadersIdx = -1;
static int termSendersIdx = -1;
/*
static GPtrArray* termReaders = NULL;
static GPtrArray* termSenders = NULL;
*/
#endif

/* Communication database */
ICLDatabase *commdb = NULL;

/**
 * Eventbuffer to hold events incoming from all sockets.
 * Reading all events each time through the select loop
 * Helps prevent any one socket from overflowing its buffer.
 */
static ICLTerm *eventBuffer = NULL;

/**
 * stringListener is used for "classic" OAA communications.
 * A negative value means listening has not been
 * set up.
 */
static int stringListener = -1;

/**
 * binaryListener is used for binary communications.
 * A negative value means listening has not been
 * set up.
 */
static int binaryListener = -1;

/**
 * stringPort is used for "classic" OAA communications.
 * A negative value means listening has not been
 * set up.
 */
static int stringPort = -1;

/**
 * binaryPort is used for binary communications.
 * A negative value means listening has not been
 * set up.
 */
static int binaryPort = -1;

/* Forward definitions */
int com_ask_about_tcp_exception(int Port, char *Host);
void    tcpShutdown(SOCKET connection);
SOCKET  tcpConnect(char *hostName, int port);
// Timeout given in seconds
int tcpSelect(SOCKET socket, double timeout);
EXTERN void comPrintError(char *str, ...);

// new functions for direct_connect
static void checkEventBuffer(void);
static void com_accept_new_connection(int listenersocket);
static int com_add_event_to_buffer(ICLTerm *event);
static int com_disconnect_all_connection_ids();
static int com_find_all_connected_sockets(ICLTerm *ids, ICLTerm **sockets);
static int com_find_all_connection_ids(ICLTerm **ids);
static char *com_get_connection_id_from_socket(int socket);
static char *com_get_localhost_ip_address(void);
static int com_is_binary_listener(int socket);
static int com_is_listening(void);
static int com_read_events_into_buffer(double timeout);
static int com_select_event_from_buffer(ICLTerm **event);
static int com_select_event_from_socket(int socketNumber, double timeout, ICLTerm **event);
static char* new_direct_client_id(void);
static int opentcpport(int port);
static int tcpListenAtPort(int port);

#ifdef _WINDOWS
/****************************************************************************
 * Definitions for MICROSOFT WINDOWS (Unix follows)
 ****************************************************************************/
#include <windows.h>
#include <winsock.h>
int tcp_started = 0;
int EXPORT_MSCPP tcpStartup();
#include "oaa-windows.h"
#else
/****************************************************************************
 * Definitions for UNIX (Windows above)
 ****************************************************************************/
#include <stdio.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>  /* inet_addr        */
#include <netdb.h>
#include <strings.h>    /* bzero, bcopy     */
#include <unistd.h>     /* close        */
#include <sys/time.h>   /* For polling time */
#include <string.h>

#endif

char* pointerToString(void* p)
{
  int sizeToAlloc = 0;
  char* ret = NULL;

  sizeToAlloc = snprintf(ret, 0, "%p", p);
  if(sizeToAlloc < 0) {
    sizeToAlloc = 16;
  }
  ret = (char*)malloc((sizeToAlloc + 1) * sizeof(char));
  snprintf(ret, (sizeToAlloc + 1), "%p", p);
  return ret;
}

void* stringToPointer(char* s)
{
  void* p = NULL;
  int res;
  res = sscanf(s, "%p", &p);
  return p;
}

/**
 * Given a connection ID and an address, initiates a client connection.
 * <p>Remarks:</p>
 * <ul>
 *  <li>if Address is a variable, instantiates the Address by using
 *     oaa_ResolveVariables, which looks in a setup file, command line, and
 *     environment variables for the required info.</li>
 *  <li>stores the connection info for connection ID in com_connection_info/5.
 * returns: socket connection or <= 0 if connection can't be made.</li>
 * </ul>
 */
EXPORT_MSCPP
SOCKET EXPORT_BORLAND
com_Connect(char *ConnectionId, ICLTerm *Address)
{
  return comConnectFormat(ConnectionId, ICL_EMPTY, Address, COM_BEST_FORMAT);
}

EXPORT_MSCPP
SOCKET EXPORT_BORLAND
comConnectFormat(char* ConnectionId, ICLTerm* Params,
                 ICLTerm* Address, int format)
{
  ICLTerm *connectionInfo = NULL, *host = NULL, *port = NULL;
  ICLTerm *cHost = NULL;
  ICLTerm *cPort = NULL;
  ICLTerm *t1;
  SOCKET connection = 0;
  SOCKET oldConnection = 0;
  ICLTerm *readerInfo = NULL;
  ICLTerm *senderInfo = NULL;
  int res;
  ICLTerm* usePassword = NULL;
  ICLTerm* passwordTerm = NULL;
  char* password = NULL;

#ifdef _WINDOWS
  if (!tcp_started)
    tcp_started = tcpStartup();
#endif

  /* DEBUG */
  /* printf("Address %s\n", icl_NewStringFromTerm(Address)); */

  /* Make sure database is initialized */
  if (!commdb) {
    commdb = db_NewDB();
  }

  t1 = icl_NewStruct("tcp", 2, icl_NewVar("Host"), icl_NewVar("Port"));
  res = icl_Unify(Address, t1 ,&connectionInfo);
  if (ConnectionId && *ConnectionId && res) {

    /* connectionInfo = tcp(Host,Port) */
    host = icl_CopyTerm(icl_NthTerm(connectionInfo, 1));
    port = icl_CopyTerm(icl_NthTerm(connectionInfo, 2));
    icl_Free(connectionInfo);

    /* if variable address, look it up... */
    if (icl_IsVar(host) || icl_IsVar(port)) {
      ICLTerm* resolved_var = NULL;

      oaa_ResolveVariable("default_facilitator", &resolved_var);
      if (icl_IsVar(host)) {
	icl_Free(host);
	host = icl_CopyTerm(icl_NthTerm(resolved_var, 1));
      }
      if (icl_IsVar(port)) {
	icl_Free(port);
	port = icl_CopyTerm(icl_NthTerm(resolved_var, 2));
      }
      icl_Free(resolved_var);
    }

    /* by now, host and port should be known */
    if (host && port && !icl_IsVar(host) && !icl_IsVar(port))
      connection = tcpConnect(icl_Str(host), icl_Int(port));

    oaa_ResolveVariable("use_password", &usePassword);

    if(usePassword != NULL) {
      if(icl_IsStr(usePassword) && 
         (strlen(icl_Str(usePassword)) == 4) &&
         (strncmp(icl_Str(usePassword), "true", 4) == 0)) {
        oaa_ResolveVariable("client_password", &passwordTerm);
        if(passwordTerm != NULL) {
          password = icl_NewStringFromTerm(passwordTerm);
        }
        else {
          password = strdup("_");
        }
      }
    }

    if(connection > 0) {
      // create an initial connection to determine what formats are supported
      TermReader* initialTr = termReader_create();
      StringTermReader* str;
      TermSender* initialTs = termSender_create();
      StringTermSender* sts;
      ICLTerm* whatFormats = NULL;
      ICLTerm* reply = NULL;
      ICLTerm* resultList = NULL;
      gint64 realPort = icl_Int(port);
      TermReader* realTr = NULL;
      TermSender* realTs = NULL;
      char* readerPtr;
      char* readerInfoBuf;
      char* senderPtr;
      char* senderInfoBuf;
      if(password != NULL) {
        char* tempString;
        char* ts1 = "event(ev_connect([other_version(";
        char* ts2 = "),password(";
        char* ts3 = "),query_formats(_),other_name('libcom_tcp_formatRequest_shouldDisconnect'),other_type(client)]),[])";
        int tempStringLen = strlen(ts1) + strlen(oaa_library_version_str) + strlen(ts2) + strlen(password) + strlen(ts3);
        
        tempString = (char*)malloc(tempStringLen + 1);
        strcpy(tempString, ts1);
        strcat(tempString, oaa_library_version_str);
        strcat(tempString, ts2);
        strcat(tempString, password);
        strcat(tempString, ts3);
        whatFormats = icl_NewTermFromString(tempString);
        
        icl_stFree(password);
        password = NULL;
        free(tempString);
      }
      else {
        char* tempString;
        char* ts1 = "event(ev_connect([other_version(";
        char* ts2 = "),query_formats(_),other_name('libcom_tcp_formatRequest_shouldDisconnect'),other_type(client)]),[])";
        int tempStringLen = strlen(ts1) + strlen(oaa_library_version_str) + strlen(ts2);
        
        tempString = (char*)malloc(tempStringLen + 1);
        strcpy(tempString, ts1);
        strcat(tempString, oaa_library_version_str);
        strcat(tempString, ts2);
        whatFormats = icl_NewTermFromString(tempString);

        free(tempString);
      }

      str = stringTermReader_create(initialTr, connection);
      sts = stringTermSender_create(initialTs, connection);
      /*
      printf("libcom_tcp.c sending whatFormats message sending...\n");
      */
      termSender_sendTerm(initialTs, whatFormats);
      icl_Free(whatFormats);
      /*
      printf("libcom_tcp.c sending whatFormats message sent\n");
      */
      if(termSender_getError(initialTs) != TERMSENDER_OKAY) {
        fprintf(stderr, "libcom_tcp com_Connect could not send formatRequest message: %i\n", termSender_getError(initialTs));
        close(termSender_getSocket(initialTs));
        termSender_free(initialTs);
        termReader_free(initialTr);
        return -1;
      }
      reply = NULL;
      do {
        /*
        printf("libcom_tcp.c sending whatFormats waiting for reply...\n");
        */
        if(reply != NULL) {
          icl_Free(reply);
        }
        reply = termReader_getNextTerm(initialTr, 0);
        /*
        printf("libcom_tcp.c sending whatFormats waiting got a reply\n");
        */
      } while(termReader_getError(initialTr) == TERMREADER_TIMEOUT);

      if(termReader_getError(initialTr) != TERMREADER_OKAY) {
        fprintf(stderr, "libcom_tcp com_Connect could not read next term: %i\n", termReader_getError(initialTr));
        close(termReader_getSocket(initialTr));
        termReader_free(initialTr);
        termSender_free(initialTs);
        return -1;
      }

      if(icl_IsStruct(icl_NthTerm(icl_NthTerm(icl_NthTerm(reply, 1), 1), 1))) {
        ICLTerm* resStruct = icl_NthTerm(icl_NthTerm(icl_NthTerm(reply, 1), 1), 1);
        char* functor = icl_Functor(resStruct);
        if(functor != NULL) {
          if((strlen(functor) == 9) &&
             (strncmp(functor, "exception", 9) == 0)) {
            char* exceptionData = icl_NewStringFromTerm(icl_NthTerm(resStruct, 1));
            fprintf(stderr, "Exception in comConnectFormat: %s\n", exceptionData);
            icl_stFree(exceptionData);
            return -1;
          }
        }
      }

      /*
       * save old socket so we can close it later--this is only done because the Prolog
       * facilitator gets mixed up if we close this connection before opening the new
       * one.
       */
      oldConnection = connection;
      resultList = icl_NthTerm(icl_NthTerm(icl_NthTerm(reply, 1), 1), 1);
      if(((format == COM_BEST_FORMAT) || (format == COM_BINARY_FORMAT))  &&
         (icl_ParamValueAsInt("binary", resultList, &realPort) == TRUE)) {
        BinaryTermReader* btr;
        BinaryTermSender* bts;


        printf("libcom_tcp com_Connect() using binary format\n");

        connection = tcpConnect(icl_Str(host), (int)realPort);
        realTr = termReader_create();
        btr = binaryTermReader_create(realTr, connection);
        realTs = termSender_create();
        bts = binaryTermSender_create(realTs, connection);
      }
      else { /* if(icl_ParamValueAsInt("ascii", resultList, &realPort)) */
        StringTermReader* str;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?