home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / k95d.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  16KB  |  550 lines

  1. #include <stdio.h>
  2.  
  3. #ifdef NT
  4. #include <windows.h>
  5. #include <winsock.h>
  6. #define strdup _strdup
  7. #define ltoa   _ltoa
  8. #define CONFIG_FILE "k95d.cfg"
  9. #else
  10.  
  11. #define CONFIG_FILE "k2d.cfg"
  12. #endif
  13.  
  14.  
  15. #define bzero(x,y) memset(x,0,y)
  16. #define BSDSELECT
  17.  
  18. #define MAXPORTS 32
  19. struct PORT
  20. {
  21.     short id ;
  22.     int   lsocket ;
  23.     int   asocket ;
  24.     char  * k95cmd ;
  25.     int   showcmd;
  26.     int   rdns;
  27. } ports[MAXPORTS] ;
  28. int portcount = 0 ;
  29.  
  30. #define MAXCHILDREN 256
  31. struct CHILDREN
  32. {
  33.     HANDLE hProcess;
  34.     int    socket;
  35. } children[MAXCHILDREN];
  36. int childcount = 0;
  37.  
  38. void
  39. init_children(void)
  40. {       
  41.     int i;
  42.     for ( i=0 ;i<MAXCHILDREN;i++ ) {
  43.         children[i].hProcess = INVALID_HANDLE_VALUE;
  44.         children[i].socket = (int)INVALID_HANDLE_VALUE;
  45.     }   
  46. }
  47.  
  48. void
  49. check_children(void)
  50. {
  51.     int i,found;
  52.     DWORD dwExit;
  53.  
  54.     for (i=0, found=0; i<MAXCHILDREN && found<childcount; i++) {
  55.         if ( children[i].hProcess != INVALID_HANDLE_VALUE ) {
  56.             if (GetExitCodeProcess(children[i].hProcess, &dwExit)) {
  57.                 if ( dwExit != STILL_ACTIVE ) {
  58.                     closesocket(children[i].socket);
  59.                     CloseHandle(children[i].hProcess);
  60.                     children[i].socket = (int)INVALID_HANDLE_VALUE;
  61.                     children[i].hProcess = INVALID_HANDLE_VALUE;
  62.                     childcount--;       
  63.                     /* Do not increase found if we reduce childcount */
  64.                     continue;
  65.                 }
  66.             }
  67.             found++;
  68.         }
  69.     }
  70. }
  71.  
  72. void
  73. add_child(HANDLE hProcess, int socket)
  74. {
  75.     int i;
  76.     for ( i=0;i<MAXCHILDREN;i++ ) {
  77.         if ( children[i].hProcess == INVALID_HANDLE_VALUE ) {
  78.             children[i].hProcess = hProcess;
  79.             children[i].socket = socket;
  80.             childcount++;
  81.             return;
  82.         }
  83.     }
  84. }
  85.  
  86. int
  87. ParseCmdLine( int argc, char * argv[] )
  88. {
  89.     int len = 0, i ;
  90.     char * p = NULL ;
  91.     static struct servent *service, servrec;
  92.     int arg = 1;
  93.  
  94.    if ( argc < 3 )
  95.       return 0;
  96.  
  97.     ports[portcount].showcmd = SW_SHOWNORMAL;
  98.     ports[portcount].rdns = 1;
  99.  
  100.     for ( arg = 1; argv[arg][0] == '-' && argv[arg][1] == '-' ; arg++ ) {
  101.         if ( !_stricmp("--maximized",argv[arg]) )
  102.              ports[portcount].showcmd = SW_SHOWMAXIMIZED;
  103.         else if ( !_stricmp("--minimized",argv[arg]) )
  104.              ports[portcount].showcmd = SW_SHOWMINIMIZED;
  105.         else if ( !_stricmp("--normal",argv[arg]) )
  106.              ports[portcount].showcmd = SW_NORMAL;
  107.         else if ( !_stricmp("--minnoactive",argv[arg]) )
  108.              ports[portcount].showcmd = SW_SHOWMINNOACTIVE;
  109.         else if ( !_stricmp("--nodns",argv[arg]) )
  110.              ports[portcount].rdns = 0;
  111.     }
  112.  
  113.     p = argv[arg];                      /* Was a service requested? */
  114.  
  115.     if (isdigit(*p)) {                  /* Use socket number without lookup */
  116.       service = &servrec;
  117.       service->s_port = htons((unsigned short)atoi(p));
  118.    } else {                             /* Otherwise lookup the service name */
  119.       service = getservbyname(p, "tcp");
  120.    }
  121.  
  122.    if ( service )
  123.    {
  124.       ports[portcount].id = service->s_port ;
  125.    }
  126.    else if ( !strcmp( "kermit", p ) )
  127.    {  /* use now assigned Kermit Service Port */
  128.       service = &servrec ;
  129.       service->s_port = htons( 1649 ) ;
  130.    }
  131.    else /* !service */
  132.    {
  133.       fprintf(stderr, "Cannot find port for service %s\n", p);
  134.       exit(2);
  135.    }
  136.  
  137.     arg++;
  138.  
  139.    for ( i = arg ; i < argc ; i++ )
  140.    {
  141.       len += strlen( argv[i] ) + 1 ;
  142.    }
  143.  
  144.    ports[portcount].k95cmd = (char *) malloc( len ) ;
  145.    if ( !ports[portcount].k95cmd )
  146.    {
  147.       fprintf( stderr, "memory allocation error\n" ) ;
  148.       exit(1) ;
  149.    }
  150.  
  151.    ports[portcount].k95cmd[0] = '\0' ;
  152.    for ( i=arg ; i<argc ; i++ )
  153.    {
  154.       strcat( ports[portcount].k95cmd, argv[i] ) ;
  155.    }
  156.    portcount++ ;
  157.    return portcount ;
  158. }
  159.  
  160. int
  161. ParseCfgFile( void )
  162. {
  163.    FILE * cfgfd = NULL ;
  164.    static struct servent *service, servrec;
  165.    char cmdbuf[256], *p ;
  166.    int i ;
  167.  
  168.    p = cmdbuf;
  169.  
  170.    /* try and open file in local directory */
  171.     cfgfd = fopen( CONFIG_FILE, "r" ) ;
  172.    if ( !cfgfd )
  173.       return 0;
  174.  
  175.    while ( !feof(cfgfd) && portcount < MAXPORTS )
  176.    {
  177.        ports[portcount].showcmd = SW_SHOWNORMAL;
  178.        ports[portcount].rdns = 1;
  179.        service = NULL ;
  180.  
  181.       /* read and parse the first white space delimited string */
  182.       switch ( fscanf( cfgfd, "%s ", &cmdbuf ) )
  183.       {
  184.       case EOF:
  185.          fclose( cfgfd ) ;
  186.          return portcount ;
  187.  
  188.       case 0:
  189.          /* lets assume we should just skip this line */
  190.          fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
  191.          break;
  192.  
  193.       default:
  194.          {
  195.            flag:
  196.              /* look for an optional show flag */
  197.              if ( p[0] == '-' && p[1] == '-' ) {
  198.                  if ( !_stricmp("--maximized",p) )
  199.                      ports[portcount].showcmd = SW_SHOWMAXIMIZED;
  200.                  else if ( !_stricmp("--minimized",p) )
  201.                      ports[portcount].showcmd = SW_SHOWMINIMIZED;
  202.                  else if ( !_stricmp("--normal",p) )
  203.                      ports[portcount].showcmd = SW_NORMAL;
  204.                  else if ( !_stricmp("--minnoactive",p) )
  205.                      ports[portcount].showcmd = SW_SHOWMINNOACTIVE;
  206.                  else if ( !_stricmp("--nodns",p) )
  207.                      ports[portcount].rdns = 0;
  208.  
  209.                  p = cmdbuf;
  210.                  *p = '\0';
  211.  
  212.                  /* now read the service */
  213.                  switch ( fscanf( cfgfd, "%s ", &cmdbuf ) )
  214.                  {
  215.                  case EOF:
  216.                      fclose( cfgfd ) ;
  217.                      return portcount ;
  218.  
  219.                  case 0:
  220.                      /* lets assume we should just skip this line */
  221.                      fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
  222.                      break;
  223.  
  224.                  default:
  225.                      if ( p[0] == '-' && p[1] == '-' )
  226.                          goto flag;
  227.                      break;
  228.                  }
  229.  
  230.              }
  231.  
  232.              if (isdigit(*p)) {                 /* Use socket number without lookup */
  233.                service = &servrec;
  234.                service->s_port = htons((unsigned short)atoi(p));
  235.             } else {                            /* Otherwise lookup the service name */
  236.                service = getservbyname(p, "tcp");
  237.             }
  238.  
  239.             if ( service )
  240.             {
  241.                ports[portcount].id = service->s_port ;
  242.             }
  243.             else if ( !strcmp( "kermit", p ) )
  244.             {  /* use now assigned Kermit Service Port */
  245.                service = &servrec ;
  246.                ports[portcount].id = service->s_port = htons( 1649 ) ;
  247.             }
  248.             else /* ( !service ) */
  249.             {
  250.                if ( cmdbuf[0] != ';' )
  251.                   fprintf( stderr, "WARNING: invalid service or port \"%s\"\n",
  252.                            cmdbuf ) ;
  253.                fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
  254.                break;
  255.             }
  256.  
  257.             for ( i=0 ; i<portcount ; i++ )
  258.             {
  259.                if ( ports[i].id == ports[portcount].id )
  260.                {
  261.                   fprintf( stderr, "WARNING: ignoring duplicate entry for port \"%s\"\n",
  262.                            cmdbuf ) ;
  263.                   fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
  264.                   break;
  265.                }
  266.             }
  267.  
  268.             /* Parse the rest of the line or up to a comment */
  269.             switch ( fscanf( cfgfd, "%[^;\n]", cmdbuf ) )
  270.             {
  271.             case EOF:
  272.             case 0:
  273.                fclose( cfgfd ) ;
  274.                return portcount;
  275.  
  276.             default:
  277.                ports[portcount].k95cmd = strdup(cmdbuf) ;
  278.                ports[portcount].lsocket = -1 ;
  279.                ports[portcount].asocket = -1 ;
  280.                portcount++ ;
  281.             }
  282.          }
  283.       }
  284.    }
  285.    fclose( cfgfd ) ;
  286.    return portcount ;
  287. }
  288.  
  289. HANDLE
  290. StartKermit( int socket, char * scriptfile, int ShowCmd, int * psockdup )
  291. {
  292. #ifdef NT
  293.    PROCESS_INFORMATION StartKermitProcessInfo ;
  294.    OSVERSIONINFO osverinfo ;
  295.    STARTUPINFO si ;
  296.    HANDLE sockdup = INVALID_HANDLE_VALUE ;
  297.    static char buf[512] ;
  298.  
  299.     *psockdup = (int)INVALID_HANDLE_VALUE;
  300.  
  301.    osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
  302.    GetVersionEx( &osverinfo ) ;
  303.  
  304.    memset( &si, 0, sizeof(STARTUPINFO) ) ;
  305.    si.cb = sizeof(STARTUPINFO);
  306.    si.dwFlags = STARTF_USESHOWWINDOW;
  307.    si.wShowWindow = ShowCmd;
  308.  
  309.    if (!DuplicateHandle( GetCurrentProcess(), (HANDLE) socket,
  310.                     GetCurrentProcess(), &sockdup,
  311.                     DUPLICATE_SAME_ACCESS, TRUE,
  312.                     DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ))
  313.    {
  314.       closesocket( (int) socket ) ;
  315.       fprintf( stderr, "\nKERMIT DAEMON FATAL ERROR:\n" );
  316.       fprintf( stderr, " You are using a WinSOCK which does not allow socket handles\n");
  317.       fprintf( stderr, " to be duplicated or shared with child processes.\n\n");
  318.       fprintf( stderr, " If you are attempting to start Kermit 95 Host Mode,\n");
  319.       fprintf( stderr, " please change SESSIONS to 1 in your configuration.\n");
  320.       fprintf( stderr, "\n Press ENTER to exit...\n");
  321.       fscanf( stdin, "" ) ;
  322.       exit( 2 ) ;
  323.    }
  324.    strcpy( buf, "k95.exe -j $" ) ;
  325.    ltoa( (LONG) sockdup, buf+strlen(buf), 10 ) ;
  326.    strcat( buf, " -C \"" ) ;
  327.    strcat( buf, scriptfile ) ;
  328.    strcat( buf, "\"" ) ;
  329.  
  330.    printf("Executing: %s\n",buf ) ;
  331.    if (!CreateProcess(
  332.                        (LPSTR)NULL,          /* start K-95  */
  333.                        (LPSTR)buf, /* give it the file */
  334.                        (LPSECURITY_ATTRIBUTES)NULL, /* fix if necessary */
  335.                        (LPSECURITY_ATTRIBUTES)NULL, /* fix if necessary */
  336.                         TRUE,                      /* fix if necessary */
  337.                        (DWORD) CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
  338.                        (LPVOID)NULL,                /* fix if necessary */
  339.                        (LPSTR)NULL,               /* Current directory */
  340.                        &si,                     /* Startup info, fix */
  341.                        &StartKermitProcessInfo  /* Process info */
  342.                       ))
  343.     {
  344.         CloseHandle(StartKermitProcessInfo.hThread);
  345.         *psockdup = (int)sockdup;
  346.         return (StartKermitProcessInfo.hProcess);
  347.     }
  348.     else
  349.     {
  350.         closesocket( (int) sockdup ) ;
  351.         CloseHandle(StartKermitProcessInfo.hProcess);
  352.         CloseHandle(StartKermitProcessInfo.hThread);
  353.         return(INVALID_HANDLE_VALUE);
  354.     }
  355. #else /* NT */
  356.  
  357. #endif /* NT */
  358. }
  359.  
  360. int
  361. main( int argc, char * argv[] ) {
  362.    char *p;
  363.    int i, x;
  364.    int on = 1, rc = 0;
  365.    int ready_to_accept = 0 ;
  366.    static struct servent *service, servrec;
  367.    static struct hostent *host;
  368.    static struct sockaddr_in saddr;
  369.    static int saddrlen ;
  370. #ifdef BSDSELECT
  371.     fd_set rfds;
  372.     struct timeval tv;
  373. #endif /* BSDSELECT */
  374.    int tcpsrv_fd = -1, ttyfd = -1 ;
  375. #ifdef NT
  376.     WSADATA data ;
  377.     HANDLE hProcess;
  378.     int sockdup = (int)INVALID_HANDLE_VALUE;
  379.  
  380.    printf("Kermit-95 Daemon\n");
  381.    rc = WSAStartup( MAKEWORD( 2, 0 ), &data ) ;
  382.    if ( rc == WSAVERNOTSUPPORTED )
  383.    {
  384.  
  385.       WSACleanup() ;
  386.       rc = WSAStartup( MAKEWORD( 1, 1 ), &data ) ;
  387.    }
  388. #else /* NT */
  389.  
  390. #endif /* NT */
  391.  
  392.     init_children();
  393.  
  394.    ParseCmdLine( argc, argv ) ;
  395.  
  396.    if ( !portcount ) /* Only use k95.cfg if there was no command line */
  397.       ParseCfgFile() ;
  398.  
  399.    if ( !portcount )
  400.    {
  401.       fprintf( stderr, "Nothing to do." ) ;
  402.       exit(8) ;
  403.    }
  404.  
  405.  
  406.    for ( i=0; i<portcount; i++)
  407.    {
  408.       /* Set up socket structure and get host address */
  409.  
  410.       bzero((char *)&saddr, sizeof(saddr));
  411.       saddr.sin_family = AF_INET ;
  412.       saddr.sin_addr.s_addr = INADDR_ANY ;
  413.  
  414.       /* Get a file descriptor for the connection. */
  415.  
  416.       saddr.sin_port = ports[i].id;
  417.  
  418.       if ((ports[i].lsocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  419.       {
  420.          perror("TCP socket error");
  421.          exit (3);
  422.       }
  423.       errno = 0;
  424.  
  425.       /* Specify the Port may be reused */
  426.       setsockopt(ports[i].lsocket, SOL_SOCKET, SO_REUSEADDR,(char *) &on, sizeof on);
  427.  
  428.       /* Now bind to the socket */
  429. #ifdef DEBUG
  430.       printf("Binding socket to port %d ... ",
  431.               ntohs((unsigned short)ports[i].id)) ;
  432. #endif
  433.       if (bind(ports[i].lsocket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
  434.       {
  435.          i = errno;                     /* save error code */
  436.          closesocket(ports[i].lsocket) ;
  437.          ports[i].lsocket = -1 ;
  438.          ports[i].asocket = -1;
  439.          errno = i;                     /* and report this error */
  440.          fprintf(stderr,"tcpsrv_open bind errno","",errno);
  441.          exit(4);
  442.       }
  443. #ifdef DEBUG
  444.       printf("Listening ...\n");
  445. #endif
  446.       if (listen(ports[i].lsocket, 15) < 0)
  447.       {
  448.          i = errno;                     /* save error code */
  449.          closesocket(ports[i].lsocket) ;
  450.          ports[i].lsocket = -1 ;
  451.          ports[i].asocket = -1;
  452.          errno = i;                     /* and report this error */
  453.          fprintf(stderr,"tcpsrv_open listen errno","",errno);
  454.          exit(5);
  455.       }
  456.    }
  457.  
  458.    printf("Servicing ports:\n");
  459.    for ( i=0;i<portcount ;i++ )
  460.    {
  461.       printf("  %d\n", ntohs((unsigned short)ports[i].id) ) ;
  462.    }
  463.     printf("Press Ctrl-C to cancel...\n");
  464.  
  465.    saddrlen = sizeof(saddr) ;
  466.  
  467. #ifdef BSDSELECT
  468.    tv.tv_sec  = 1L;
  469.    tv.tv_usec = 0L;
  470. #endif /* BSDSELECT */
  471.  
  472.    for ( ;; )
  473.    {
  474.       while ( !ready_to_accept )
  475.       {
  476.           check_children();
  477.  
  478. #ifdef BSDSELECT
  479.          FD_ZERO(&rfds);
  480.          for ( i=0; i<portcount;i++ )
  481.             FD_SET(ports[i].lsocket, &rfds);
  482.          if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv ) > 0)
  483.          {
  484.             for ( i=0; i<portcount ; i++ )
  485.             {
  486.                if ( ready_to_accept = FD_ISSET(ports[i].lsocket, &rfds) )
  487.                   break;
  488.             }
  489.          }
  490. #else /* BSDSELECT */
  491. #ifdef IBMSELECT
  492. ???      /* in order to make this work, we need to create an array of socket values */
  493.          ready_to_accept = (( select(&tcpsrv_fd, 1, 0, 0,1 )) == 1) ;
  494. #endif /* IBMSELECT */
  495. #endif /* BSDSELECT */
  496.       }
  497.  
  498.       if ( ready_to_accept )
  499.       {
  500.          if ((ports[i].asocket = accept(ports[i].lsocket, (struct sockaddr *)&saddr,&saddrlen)) < 0)
  501.          {
  502.             i = errno;                  /* save error code */
  503.             closesocket(ports[i].lsocket) ;
  504.             ports[i].asocket = -1;
  505.             ports[i].lsocket = -1 ;
  506.             errno = i;                  /* and report this error */
  507.             fprintf(stderr,"tcpsrv_open accept errno","",errno);
  508.             exit(6);
  509.          }
  510.  
  511.          setsockopt(ports[i].asocket, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
  512.  
  513.          if (ports[i].rdns &&
  514.              (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) != NULL)
  515.          {
  516.             printf("%s [%s] connected on port %d\n",host->h_name,
  517.                     (char *)inet_ntoa(saddr.sin_addr),ntohs(ports[i].id));
  518.          } else {
  519.             printf("%s connected on port %d\n",(char *)inet_ntoa(saddr.sin_addr),
  520.                    ntohs(ports[i].id));
  521.          }
  522.  
  523.          /* Now start subprocess */
  524.          printf("Starting Kermit with socket %d and command %s\n",ports[i].asocket,ports[i].k95cmd);
  525.           hProcess = StartKermit(ports[i].asocket,ports[i].k95cmd, ports[i].showcmd, &sockdup);
  526.           if ( hProcess != INVALID_HANDLE_VALUE ) 
  527.               add_child(hProcess, sockdup);
  528.           else
  529.               closesocket(ports[i].asocket);      /* we use CLOSE_SOURCE when duplicating */
  530.          continue;                              /* Go get the next one */
  531.       }
  532.       else
  533.       {
  534.          i = errno;                     /* save error code */
  535.          closesocket(ports[i].lsocket) ;
  536.          ports[i].lsocket = -1;
  537.          ports[i].asocket = -1;
  538.          errno = i;                     /* and report this error */
  539.          fprintf(stderr,"tcpsrv_open accept errno","",errno);
  540.          exit(7);
  541.       }
  542.    }
  543.  
  544. #ifdef NT
  545.    WSACleanup() ;
  546. #else
  547.  
  548. #endif /* NT */
  549. }
  550.