libcom_tcp.c

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

C
2,071
字号
        StringTermSender* sts;

        /*
        printf("libcom_tcp com_Connect() using ascii format\n");
        */
        connection = tcpConnect(icl_Str(host), (int)icl_Int(port));
        realTr = termReader_create();
        str = stringTermReader_create(realTr, connection);
#ifdef NORMAL_GC
        printf("created str (%p) from realTr(%p)\n", str, realTr);
#endif
        CHECK_LEAKS();
        realTs = termSender_create();
        sts = stringTermSender_create(realTs, connection);
        CHECK_LEAKS();
      }
      CHECK_LEAKS();

      icl_Free(reply);
      CHECK_LEAKS();

      close(oldConnection);
      termReader_free(initialTr);
      termSender_free(initialTs);
      CHECK_LEAKS();
#ifdef NORMAL_GC
      /* so we don't lose the pointer */
      /*
      if(termReaders == NULL) {
        termReaders = g_ptr_array_new();
      }
      g_ptr_array_add(termReaders, realTr);
      */
      termReaders[++termReadersIdx] = realTr;
      CHECK_LEAKS();
#endif
      CHECK_LEAKS();
      readerPtr = pointerToString(realTr);
      readerInfoBuf = (char*)malloc(strlen(readerPtr) + 10 + 1);
      CHECK_LEAKS();
      strncpy(readerInfoBuf, "reader('", 8);
      strncpy(readerInfoBuf + 8, readerPtr, strlen(readerPtr));
      readerInfoBuf[strlen(readerPtr) + 8] = '\'';
      readerInfoBuf[strlen(readerPtr) + 9] = ')';
      readerInfoBuf[strlen(readerPtr) + 10] = '\0';
      CHECK_LEAKS();
      readerInfo = icl_NewTermFromString(readerInfoBuf);
      free(readerPtr);
      free(readerInfoBuf);
      senderPtr = pointerToString(realTs);
#ifdef NORMAL_GC
      /* so we don't lose the pointer */
      /*
      if(termSenders == NULL) {
        termSenders = g_ptr_array_new();
      }
      g_ptr_array_add(termSenders, realTs);
      */
      termSenders[++termSendersIdx] = realTs;
#endif
      senderInfoBuf = (char*)malloc(strlen(senderPtr) + 10 + 1);
      strncpy(senderInfoBuf, "sender('", 8);
      strncpy(senderInfoBuf + 8, senderPtr, strlen(senderPtr));
      senderInfoBuf[strlen(senderPtr) + 8] = '\'';
      senderInfoBuf[strlen(senderPtr) + 9] = ')';
      senderInfoBuf[strlen(senderPtr) + 10] = '\0';
      senderInfo = icl_NewTermFromString(senderInfoBuf);
      free(senderPtr);
      free(senderInfoBuf);
    }

    if (connection>0) {
      ICLTerm *canonicalOtherAddress = NULL;
      ICLTerm *newConnectionInfo = NULL;
      ICLTerm *tempList = icl_NewList(NULL);
      ICLTerm *atmp;
      ICLTerm *templateTcpAddr = icl_NewStruct("tcp", 2, host, port);

      icl_AddToList(tempList, readerInfo, FALSE);
      icl_AddToList(tempList, senderInfo, FALSE);

      cnx_CanonicalAddress(templateTcpAddr, connection, &canonicalOtherAddress);

      icl_AddToList(tempList, icl_NewStruct("other_address", 1, canonicalOtherAddress), FALSE);
      icl_AddToList(tempList, icl_NewStruct("connection", 1, icl_NewInt(connection)),FALSE);

      // params added to call for direct_connect so that we
      // could get the "correct" other_address into the com_connection_info...
      {
      ICLTerm *tmp1;
      ICLTerm *tmp2;
      tmp1 = icl_NewStruct("other_address", 1, icl_NewVar("_"));
      if (icl_GetParamValue(tmp1, Params, &tmp2)) {
        icl_AddToList(tempList, tmp2, TRUE);
      }
      icl_Free(tmp1);
      }

      cHost = icl_CopyTerm(host);
      cPort = icl_CopyTerm(port);
      atmp = icl_NewStruct("tcp", 2, cHost, cPort);
      newConnectionInfo = icl_NewStruct("com_connection_info", 5,
					icl_NewStr(ConnectionId),
					atmp, /*
						icl_NewStruct("tcp", 2, cHost, cPort),*/
					icl_NewStr("client"),
					tempList,
					icl_NewStr("connected"));

      printf("libcom_tcp com_Connect() Connected to %s %lld.\n",
	     icl_Str(host), icl_Int(port));

      if (newConnectionInfo) {
	db_Assert(commdb, newConnectionInfo, ICL_EMPTY);
	/* DEBUG */
	/* db_PrintDB(commdb);*/
	icl_Free(newConnectionInfo);
      }
      else {
	fprintf(stderr, "Error! com_connection_info could not be constructed.\n");
      }
      icl_Free(templateTcpAddr);
    }
    else
      fprintf(stderr, "com_Connect: failed to connect to %s %lld.\n",
              icl_Str(host), icl_Int(port));
    if (!host && !port)
      fprintf(stderr, "Make sure you have a valid setup.pl file\n");
  }
  else {
    fprintf(stderr, "Error!  Bad arguments to com_Connect()\n");
  }

  icl_Free(t1);
#ifdef NORMAL_GC
  printf("Leaving comConnectFormat\n");
#endif

  return connection;
}

/**
 * Given a connection ID, shuts down the connection. If Id is NULL,
 * shuts down all connections.
 * <p>Note: Succeeds silently if there is not an open connection having the
 *           given id.</p>
 */
EXPORT_MSCPP
int EXPORT_BORLAND
com_Disconnect(char *ConnectionId)
{
  ICLTerm *t1, *info = NULL;

  if (ConnectionId == NULL) {
    return com_disconnect_all_connection_ids();
  }

  if (ConnectionId && *ConnectionId && commdb) {
    if (com_GetInfo(ConnectionId,
                    (t1 = icl_NewStruct("connection", 1,
                                        icl_NewVar("_"))), &info)) {

      tcpShutdown(icl_Int(icl_NthTerm(info, 1)));
      icl_Free(info);
      icl_Free(t1);
      db_Retract(commdb,
                 (t1 = icl_NewStruct("com_connection_info", 5,
                                     icl_NewStr(ConnectionId),
                                     icl_NewVar("TCP"),
                                     icl_NewVar("_Type"),
                                     icl_NewVar("_Info"),
                                     icl_NewStr("connected"))),
                 ICL_EMPTY);
    }
    icl_Free(t1);
    return TRUE;
  }
  else return FALSE;
}

/**
 * Return TRUE if the TCP connection is established
 */
EXPORT_MSCPP
SOCKET EXPORT_BORLAND
com_Connected(char* ConnectionId)
{
  ICLTerm *t1;

  /* Make sure there's a valid connection id */
  if (ConnectionId && *ConnectionId) {
    ICLTerm *currentStatus = NULL;
    com_GetInfo(ConnectionId,
                (t1 = icl_NewStruct("status", 1,
                                    icl_NewStr("connected"))),&currentStatus);
    icl_Free(t1);
    if (currentStatus && STREQ(icl_Str(currentStatus),"connected")) {
      icl_Free(currentStatus);
      return TRUE;
    }
  }
  return FALSE;
}

/****************************************************************************
 * name:    com_GetAllValidConnections
 * purpose:
 * remarks:
 ****************************************************************************/
EXPORT_MSCPP
int EXPORT_BORLAND
com_GetAllValidConnections(ICLTerm** result)
{
  int index;
  ICLTerm *resultFromDb = (ICLTerm *)NULL;
  static ICLTerm* info = NULL;

  if (!icl_IsValid(info)) {
    info = icl_NewTermFromData("com_connection_info(Id,Protocol,Type,InfoList,connected)",56);
  }

  *result = icl_NewList(NULL);

  if (db_Solve(commdb, info, ICL_EMPTY, &resultFromDb)) {
    /*
      Retreives all Id from the list of connected connections.
      Not the best optimized way to to it (n^2 order), but lists of connections
      are not going to be huge.
    */

    ICLTerm *item = NULL;

    /* DEBUG */
    /*
      printf("Result from db_Solve %s\n", icl_NewStringFromTerm(resultFromDb));
    */

    for (index = 1; index <= icl_ListLen(resultFromDb) ; index ++) {
      item = icl_NthTerm(resultFromDb, index);
      icl_AddToList(*result, icl_CopyTerm(icl_NthTerm(item, 1)), TRUE);
    }
    icl_Free(resultFromDb);
    return TRUE;
  }
  icl_Free(resultFromDb);
  return FALSE;
};

/**
 * Looks up a connection that contains a given information.
 * @return NULL if fail, an IclTerm if success.
 */
int com_GetConnectionFromInfo(ICLTerm *Info, char** connectionName)
{
  ICLTerm *resultFromDb = (ICLTerm *)NULL;
  int      res = FALSE;
  static ICLTerm* info = NULL;

  if (!icl_IsValid(info)) {
    info = icl_NewTermFromData("com_connection_info(Conn,Protocol,Type,InfoList,Status)",55);
  }

  (void)Info;

  if (db_Solve(commdb, info, ICL_EMPTY, &resultFromDb)) {
    *connectionName =
      strdup(icl_Str(icl_NthTerm(icl_NthTerm(resultFromDb, 1),1)));
    res = TRUE;
    icl_Free(resultFromDb);
  }
  return res;
}

/**
 * Given a connection ID and an address, initiate a server 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>Even if RequestedAddress is fully instantiated, the actual listener
 *     address could be different, because of user input.  Thus, ActualAddress
 *     should always be used as the return value (and should be a variable
 *     when called)
 *     <strong>UNLESS</strong> Params includes resolve_vars(false)</li>
 *  <li>stores the connection info for connection ID in com_connection_info/5.</li>
 *  <li>fails if connection can't be made</li>
 * </ul>
 */
EXPORT_MSCPP
int EXPORT_BORLAND
com_ListenAt(char *ConnectionId, ICLTerm *Params, ICLTerm *Address)
{
  ICLTerm *connectionInfo = NULL, *host = NULL, *port = NULL;
  ICLTerm *info = NULL, *t1 = NULL;
  ICLTerm *resolve_vars_false = icl_NewTermFromData("resolve_vars(false)",19);
  int do_resolve_vars = TRUE;
  char cmd[600];
  char *addressString = NULL;
  char *hostString = NULL;
  int res = FALSE;
  ICLTerm* addrFromCmdLine = NULL;
  ICLTerm* addrFromSetup = NULL;
  ICLTerm* addrFromEnv = NULL;

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

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

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

    // if variable address, look it up...
    do_resolve_vars = !icl_GetParamValue(resolve_vars_false, Params, NULL);
    icl_Free(resolve_vars_false);
    if (do_resolve_vars && (icl_IsVar(host) || icl_IsVar(port))) {
        oaa_ResolveVariable("oaa_connect", &addrFromSetup);   // setup file
        Address = addrFromSetup;
        addressString = getenv("OAA_CONNECT");         // env var
        if (addressString) {
          icl_Free(Address);
          addrFromEnv = icl_NewTermFromString(addressString);
          Address = addrFromEnv;
        }
        if(oaa_ResolveVariable("-oaa_connect", &addrFromCmdLine)) {  // cmd line
          icl_Free(Address);
          Address = addrFromCmdLine;
        }
    }

    icl_Free(connectionInfo);

    // by now, host and port should be known
    icl_Unify(Address, t1, &connectionInfo);

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

    if (!icl_IsVar(host) && !icl_IsVar(port))

      do {
        //
        hostString = strdup(icl_Str(host));
        if (!strcmp("localhost", hostString)) {
          icl_stFree(hostString);
          hostString = com_get_localhost_ip_address();
        }
        // stringPort, binaryPort, stringListener, and binaryListener
        // have file scope
        stringPort = icl_Int(port);
        binaryPort = stringPort + OAA_BINARY_PORT_OFFSET;
        stringListener = tcpListenAtPort(stringPort);
        binaryListener = tcpListenAtPort(binaryPort);
        if ( (stringListener > 0) && (binaryListener > 0) ) {
          sprintf(cmd, "com_connection_info('%s', tcp, server, \
            [oaa_address(addr(tcp('%s',%d))), oaa_host('%s'), oaa_port(%d)], \
            connected)",
                  ConnectionId, hostString, stringPort,
                  hostString, stringPort);
          info = icl_NewTermFromString(cmd);

          if (info) {
            db_Assert(commdb, info, ICL_EMPTY);
            icl_Free(info);
          }
          else {
            printf("Error! com_connection_info could not be constructed.\n");
          }
          res = TRUE;
        }
        else {
          if (!com_ask_about_tcp_exception(icl_Int(port),
                                           icl_NewStringFromTerm(host))) {
            icl_Free(connectionInfo);
            icl_Free(t1);
            icl_stFree(hostString);
            return FALSE;
          }
        }
      } while (!res);
    icl_Free(connectionInfo);
  }
  else {
    printf("Error! Bad arguments to com_ListenAt()\n");
            db_Assert(commdb, info, ICL_EMPTY);
  }
  icl_Free(t1);
  icl_stFree(hostString);
  return res;
} // end of com_ListenAt

/****************************************************************************
 * Utility functions for com_ListenAt
 ****************************************************************************/

void
com_print_tcp_exception_help() {
#ifdef _WINDOWS
#else
  printf("I've just attempted to listen on the specified port, but was unable\n");
  printf("to gain control of it.  This could be because there's already a\n");
  printf("Facilitator, or some other program, making use of that port.  Or, it\n");
  printf("could be that a Facilitator using that port was just terminated.  In\n");
  printf("such cases, the port may be inaccessible for a brief period (usually\n");
  printf("only a few seconds, but sometimes more).  It may help to kill any\n");
  printf("client agents which may still be connected to the defunct Facilitator.\n");

  printf("If you think the specified port may now be accessible, enter \"y\" and\n");
  printf("I'll try again.  You may request retry any number of times.\n");

⌨️ 快捷键说明

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