extern void
CommandExternal(char *sz)
{

#if !HAVE_SOCKETS
    outputl(_("This installation of GNU Backgammon was compiled without\n"
              "socket support, and does not implement external controllers."));
#else
    int h, hPeer, cb;
    struct sockaddr *psa;
    char szCommand[256];
    char *szResponse = NULL;
    struct sockaddr_in saRemote;
    socklen_t saLen;
    scancontext scanctx;
    int fExit;
    int fRestart = TRUE;
    int retval;

    sz = NextToken(&sz);

    if (!sz || !*sz) {
        outputl(_("You must specify the name of the socket to the external controller."));
        return;
    }

    memset(&scanctx, 0, sizeof(scanctx));
    ExtInitParse(&scanctx.scanner);

  listenloop:
    {
        fExit = FALSE;
        scanctx.fDebug = FALSE;
        scanctx.fNewInterface = FALSE;

        if ((h = ExternalSocket(&psa, &cb, sz)) < 0) {
            SockErr(sz);
            ExtDestroyParse(scanctx.scanner);
            return;
        }

        if (bind(h, psa, cb) < 0) {
            SockErr(sz);
            closesocket(h);
            free(psa);
            ExtDestroyParse(scanctx.scanner);
            return;
        }

        free(psa);

        if (listen(h, 1) < 0) {
            SockErr("listen");
            closesocket(h);
            ExternalUnbind(sz);
            ExtDestroyParse(scanctx.scanner);
            return;
        }
        outputf(_("Waiting for a connection from %s...\n"), sz);
        outputx();
        ProcessEvents();

        /* Must set length when using windows */
        saLen = sizeof(struct sockaddr);
        while ((hPeer = accept(h, (struct sockaddr *) &saRemote, &saLen)) < 0) {
            if (errno == EINTR) {
                ProcessEvents();

                if (fInterrupt) {
                    closesocket(h);
                    ExternalUnbind(sz);
                    ExtDestroyParse(scanctx.scanner);
                    return;
                }

                continue;
            }

            SockErr("accept");
            closesocket(h);
            ExternalUnbind(sz);
            ExtDestroyParse(scanctx.scanner);
            return;
        }

        closesocket(h);
        ExternalUnbind(sz);

        /* print info about remove client */

        outputf(_("Accepted connection from %s.\n"), inet_ntoa(saRemote.sin_addr));
        outputx();
        ProcessEvents();

        while (!fExit && !(retval = ExternalRead(hPeer, szCommand, sizeof(szCommand)))) {

            if ((ExtParse(&scanctx, szCommand)) == 0) {
                /* parse error */
                szResponse = scanctx.szError;
            } else {
                ProcessedFIBSBoard processedBoard;
                GValue *optionsmapgv;
                GValue *boarddatagv;
                GString *dbgStr;
                int anScore[2];
                int fCrawford, fJacoby;
                char *asz[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
                char szBoard[10000];
                char **aszLines;
                char **aszLinesOrig;
                char *szMatchID;
                gchar *szOptStr;

                switch (scanctx.ct) {
                case COMMAND_HELP:
                    szResponse = g_strdup("\tNo help information available\n");
                    break;

                case COMMAND_SET:
                    szOptStr = g_value_get_gstring_gchar(g_list_nth_data(scanctx.pCmdData, 0));
                    if (g_ascii_strcasecmp(szOptStr, KEY_STR_DEBUG) == 0) {
                        scanctx.fDebug = g_value_get_int(g_list_nth_data(scanctx.pCmdData, 1));
                        szResponse = g_strdup_printf("Debug output %s\n", scanctx.fDebug ? "ON" : "OFF");
                    } else if (g_ascii_strcasecmp(szOptStr, KEY_STR_NEWINTERFACE) == 0) {
                        scanctx.fNewInterface = g_value_get_int(g_list_nth_data(scanctx.pCmdData, 1));
                        szResponse = g_strdup_printf("New interface %s\n", scanctx.fNewInterface ? "ON" : "OFF");
                    } else {
                        szResponse = g_strdup_printf("Error: set option '%s' not supported\n", szOptStr);
                    }
                    g_list_gv_boxed_free(scanctx.pCmdData);

                    break;

                case COMMAND_VERSION:
                    szResponse = g_strdup("Interface: " EXTERNAL_INTERFACE_VERSION "\n"
                                          "RFBF: " RFBF_VERSION_SUPPORTED "\n"
                                          "Engine: " WEIGHTS_VERSION "\n" "Software: " VERSION "\n");

                    break;

                case COMMAND_NONE:
                    szResponse = g_strdup("Error: no command given\n");
                    break;

                case COMMAND_FIBSBOARD:
                case COMMAND_EVALUATION:
                    if (scanctx.fDebug) {
                        optionsmapgv = (GValue *) g_list_nth_data(g_value_get_boxed(scanctx.pCmdData), 1);
                        boarddatagv = (GValue *) g_list_nth_data(g_value_get_boxed(scanctx.pCmdData), 0);
                        dbgStr = g_string_new(DEBUG_PREFIX);
                        g_value_tostring(dbgStr, optionsmapgv, 0);
                        g_string_append(dbgStr, "\n" DEBUG_PREFIX);
                        g_value_tostring(dbgStr, boarddatagv, 0);
                        g_string_append(dbgStr, "\n" DEBUG_PREFIX "\n");
                        ExternalWrite(hPeer, dbgStr->str, strlen(dbgStr->str));
                        ProcessFIBSBoardInfo(&scanctx.bi, &processedBoard);

                        anScore[0] = processedBoard.nScoreOpp;
                        anScore[1] = processedBoard.nScore;
                        /* If the session isn't using Crawford rule, set crawford flag to false */
                        fCrawford = scanctx.fCrawfordRule ? processedBoard.fCrawford : FALSE;
                        /* Set the Jacoby flag appropriately from the external interface settings */
                        fJacoby = scanctx.fJacobyRule;

                        szMatchID = MatchID((unsigned int *) processedBoard.anDice, 1, processedBoard.nResignation,
                                            processedBoard.fDoubled, 1, processedBoard.fCubeOwner, fCrawford,
                                            processedBoard.nMatchTo, anScore, processedBoard.nCube, fJacoby,
                                            GAME_PLAYING);

                        DrawBoard(szBoard, (ConstTanBoard) & processedBoard.anBoard, 1, asz, szMatchID, 15);

                        aszLines = g_strsplit(&szBoard[0], "\n", 32);
                        aszLinesOrig = aszLines;
                        while (*aszLines) {
                            ExternalWrite(hPeer, DEBUG_PREFIX, strlen(DEBUG_PREFIX));
                            ExternalWrite(hPeer, *aszLines, strlen(*aszLines));
                            ExternalWrite(hPeer, "\n", 1);
                            aszLines++;
                        }

                        dbgStr = g_string_assign(dbgStr, "");
                        g_string_append_printf(dbgStr, DEBUG_PREFIX "X is %s, O is %s\n", processedBoard.szPlayer,
                                               processedBoard.szOpp);
                        if (processedBoard.nMatchTo) {
                            g_string_append_printf(dbgStr, DEBUG_PREFIX "Match Play %s Crawford Rule\n",
                                                   scanctx.fCrawfordRule ? "with" : "without");
                            g_string_append_printf(dbgStr, DEBUG_PREFIX "Score: %d-%d/%d%s, ", processedBoard.nScore,
                                                   processedBoard.nScoreOpp, processedBoard.nMatchTo,
                                                   fCrawford ? "*" : "");
                        } else {
                            g_string_append_printf(dbgStr, DEBUG_PREFIX "Money Session %s Jacoby Rule, %s Beavers\n",
                                                   scanctx.fJacobyRule ? "with" : "without",
                                                   scanctx.fBeavers ? "with" : "without");
                            g_string_append_printf(dbgStr, DEBUG_PREFIX "Score: %d-%d, ", processedBoard.nScore,
                                                   processedBoard.nScoreOpp);
                        }
                        g_string_append_printf(dbgStr, "Roll: %d%d\n",
                                               processedBoard.anDice[0], processedBoard.anDice[1]);
                        g_string_append_printf(dbgStr,
                                               DEBUG_PREFIX
                                               "CubeOwner: %d, Cube: %d, Turn: %c, Doubled: %d, Resignation: %d\n",
                                               processedBoard.fCubeOwner, processedBoard.nCube, 'X',
                                               processedBoard.fDoubled, processedBoard.nResignation);
                        g_string_append(dbgStr, DEBUG_PREFIX "\n");
                        ExternalWrite(hPeer, dbgStr->str, strlen(dbgStr->str));

                        g_string_free(dbgStr, TRUE);
                        g_strfreev(aszLinesOrig);
                    }
                    g_value_unsetfree(scanctx.pCmdData);

                    if (scanctx.ct == COMMAND_EVALUATION)
                        szResponse = ExtEvaluation(&scanctx);
                    else
                        szResponse = ExtFIBSBoard(&scanctx);

                    break;

                case COMMAND_EXIT:
                    closesocket(hPeer);
                    fExit = TRUE;
                    break;

                default:
                    szResponse = g_strdup("Unsupported Command\n");
                }
                unset_scan_context(&scanctx, FALSE);
            }

            if (szResponse) {
                if (ExternalWrite(hPeer, szResponse, strlen(szResponse)))
                    break;

                g_free(szResponse);
                szResponse = NULL;
            }

        }
        /* Interrupted : get out of listen loop */
        if (retval == -2) {
            ProcessEvents();
            fRestart = FALSE;
        }

        closesocket(hPeer);
        if (szResponse)
            g_free(szResponse);

        szResponse = NULL;
        scanctx.szError = NULL;
    }
    if (fRestart)
        goto listenloop;

    unset_scan_context(&scanctx, TRUE);
#endif
}
Example #2
0
extern void CommandExternal( char *sz ) {

#if !HAVE_SOCKETS
    outputl( _("This installation of GNU Backgammon was compiled without\n"
	     "socket support, and does not implement external controllers.") );
#else
    int h, hPeer, cb;
    struct sockaddr *psa;
    char szCommand[ 256 ];
    char *szResponse = NULL;
    struct sockaddr_in saRemote;
    socklen_t saLen;
    extcmd *pec;
    
    sz = NextToken( &sz );
    
    if( !sz || !*sz ) {
	outputl( _("You must specify the name of the socket to the external controller.") );
	return;
    }

listenloop:
	{

      if( ( h = ExternalSocket( &psa, &cb, sz ) ) < 0 ) {
	SockErr( sz );
	return;
      }
      
      if( bind( h, psa, cb ) < 0 ) {
	SockErr( sz );
	closesocket( h );
	free( psa );
	return;
      }
      
      free( psa );
      
      if( listen( h, 1 ) < 0 ) {
	SockErr( "listen" );
	closesocket( h );
	ExternalUnbind( sz );
	return;
      }
      outputf( _("Waiting for a connection from %s...\n"), sz);
      outputx();
      ProcessEvents();

      /* Must set length when using windows */
      saLen = sizeof(struct sockaddr);
      while( ( hPeer = accept( h, (struct sockaddr*)&saRemote, &saLen ) ) < 0 )
	  {
		if( errno == EINTR )
		{
			ProcessEvents();

          if( fInterrupt ) {
            closesocket( h );
            ExternalUnbind( sz );
            return;
          }
	    
          continue;
	}
	
	SockErr( "accept" );
	closesocket( h );
	ExternalUnbind( sz );
	return;
      }

      closesocket( h );
      ExternalUnbind( sz );

      /* print info about remove client */

      outputf(_("Accepted connection from %s.\n"),
                 inet_ntoa( saRemote.sin_addr ) );
      outputx();
      ProcessEvents();

      while( !ExternalRead( hPeer, szCommand, sizeof( szCommand ) ) ) {

        if ( ( pec = ExtParse( szCommand ) ) == 0 ) {
          /* parse error */
          szResponse = szError;
        }
        else {

          switch ( pec->ct ) {
          case COMMAND_NONE:
            szResponse = g_strdup( "Error: no command given\n" );
            break;
          
          case COMMAND_FIBSBOARD:
          
            szResponse = ExtFIBSBoard( pec );
            break;
          
          case COMMAND_EVALUATION:
          
            szResponse = ExtEvaluation( pec );
            break;
          
          }

        }

        if ( szResponse ) {
          if ( ExternalWrite( hPeer, szResponse, strlen( szResponse ) ) )
            break;

          g_free( szResponse );
        }

      }
      closesocket( hPeer );
    }
	goto listenloop;
#endif
}