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 + -
显示快捷键?