Logo Search packages:      
Sourcecode: malaga version File versions  Download package

transmit.c

/* Copyright (C) 1995 Bjoern Beutel. */

/* Description. =============================================================*/

/* This module invokes and manages the transmit process from malaga. */

/* Includes. ================================================================*/

#define _XOPEN_SOURCE
#define _XOPEN_SOURCE_EXTENDED 1
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <setjmp.h>
#include "basic.h"
#include "pools.h"
#include "values.h"
#include "files.h"
#include "input.h"
#include "symbols.h"
#include "commands.h"
#include "value_parser.h"
#include "scanner.h"
#include "options.h"
#include "rule_type.h"
#include "rules.h"
#include "transmit.h"
#ifdef UNIX
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/wait.h>
#endif
#ifdef WINDOWS
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#endif

/* Variables. ===============================================================*/

static string_t transmit_command_line; /* Command line for transmit process. */
static FILE *transmit_input_stream; /* To read data from transmit process. */
static FILE *transmit_output_stream; /* To write data to transmit process. */
#ifdef UNIX
static pid_t process_id; /* ID of transmit process. */
#endif
#ifdef WINDOWS
static HANDLE process_handle; /* Handle of transmit process. */
#endif

/* Functions. ===============================================================*/

static void 
start_transmit_process( void )
/* Start the Malaga transmit process by executing TRANSMIT_COMMAND_LINE
 * if it is not already running. */
{
#ifdef UNIX
  int to_transmit_fd[2];
  int from_transmit_fd[2];
  string_t arguments, argument;
  string_t *args;
  int_t arg_count, i;

  if (process_id != 0) 
  { 
    if (waitpid( process_id, NULL, WNOHANG ) == 0) 
      return;
    process_id = 0;
    close_stream( &transmit_input_stream, NULL );
    close_stream( &transmit_output_stream, NULL );
  }

  if (transmit_command_line == NULL) 
    complain( "Missing transmit command line." );
  if (pipe( to_transmit_fd ) == -1 || pipe( from_transmit_fd ) == -1) 
  {
    complain( "Can't create pipe to transmit process: %s.", 
            strerror( errno ) );
  }
  signal( SIGPIPE, SIG_IGN );
  switch (process_id = fork()) 
  {
  case -1:
    complain( "Can't create transmit process: %s.", strerror( errno ) );
    break;
  case 0:
    dup2( to_transmit_fd[0], STDIN_FILENO );
    close( to_transmit_fd[0] );
    close( to_transmit_fd[1] );
    dup2( from_transmit_fd[1], STDOUT_FILENO );
    close( from_transmit_fd[0] );
    close( from_transmit_fd[1] );
    signal( SIGINT, SIG_IGN );

    /* Count arguments. */
    arg_count = 0;
    arguments = transmit_command_line;
    while (*arguments != EOS) 
    { 
      argument = parse_word( &arguments );
      free_mem( &argument );
      arg_count++;
    }

    /* Create argument vector. */
    args = new_vector( sizeof( string_t ), arg_count + 1 );
    arguments = transmit_command_line;
    for (i = 0; i < arg_count; i++) 
      args[i] = parse_word( &arguments );
    args[i] = NULL;

    /* Start transmit program. */
    execvp( args[0], (char **) args );
    fprintf( stderr, "Can't start transmit process \"%s\": %s.\n", 
             args[0], strerror( errno ) );
    exit(1);
  default:
    close( to_transmit_fd[0] );
    transmit_output_stream = fdopen( to_transmit_fd[1], "w" );
    close( from_transmit_fd[1] );
    transmit_input_stream = fdopen( from_transmit_fd[0], "r" );
    if (transmit_input_stream == NULL || transmit_output_stream == NULL) 
      complain( "Can't open data stream: %s.", strerror( errno ) );
  }
#endif

#ifdef WINDOWS
  HANDLE parent_read, parent_write, parent_read_local, parent_write_local;
  HANDLE child_read, child_write, old_stdin, old_stdout;
  SECURITY_ATTRIBUTES security;
  STARTUPINFO startup_info;
  PROCESS_INFORMATION process_info;
  DWORD status;
  int fd;

  /* Check if the process is still running. */
  if (process_handle != NULL) 
  {
    if (GetExitCodeProcess( process_handle, &status ) 
      && status == STILL_ACTIVE)
    {
      return;
    }
    CloseHandle( process_handle );
    process_handle = NULL;
    close_stream( &transmit_input_stream, NULL );
    close_stream( &transmit_output_stream, NULL );
  }
  
  /* Check command line. */
  if (transmit_command_line == NULL) 
    complain( "Missing transmit command line." );

  /* Create two pipes with inherited handles. */
  security.nLength = sizeof( SECURITY_ATTRIBUTES );
  security.bInheritHandle = TRUE;
  security.lpSecurityDescriptor = NULL;
  if (! CreatePipe( &child_read, &parent_write, &security, 0 ))
    complain( "Can't create pipe to transmit process." );
  if (! CreatePipe( &parent_read, &child_write, &security, 0 )) 
    complain( "Can't create pipe from transmit process." );
  
  /* Change STDIN and STDOUT for the child process. */
  old_stdout = GetStdHandle( STD_OUTPUT_HANDLE );
  SetStdHandle( STD_OUTPUT_HANDLE, child_write );
  old_stdin = GetStdHandle( STD_INPUT_HANDLE );
  SetStdHandle( STD_INPUT_HANDLE, child_read );

  /* Make sure the parent's handles are not inherited. */
  DuplicateHandle( GetCurrentProcess(), parent_read,
               GetCurrentProcess(), &parent_read_local,
               0, FALSE, DUPLICATE_SAME_ACCESS );
  CloseHandle( parent_read );
  DuplicateHandle( GetCurrentProcess(), parent_write, 
               GetCurrentProcess(), &parent_write_local,
               0, FALSE, DUPLICATE_SAME_ACCESS );
  CloseHandle( parent_write );

  /* Start the transmit process as child. */
  ZeroMemory( &startup_info, sizeof( startup_info ) );
  startup_info.cb = sizeof( startup_info );
  if (! CreateProcess( NULL, transmit_command_line, NULL, NULL, TRUE, 
                   CREATE_NEW_PROCESS_GROUP, 
                   NULL, NULL, &startup_info, &process_info ))
  {
    complain( "Can't create the transmit process." );
  }
  process_handle = process_info.hProcess;
  CloseHandle( process_info.hThread );

  /* Reset stdin and stdout. */
  SetStdHandle( STD_OUTPUT_HANDLE, old_stdout );
  CloseHandle( child_write );
  SetStdHandle( STD_INPUT_HANDLE, old_stdin );
  CloseHandle( child_read );

  /* Open pipes to send and receive. */         
  fd = _open_osfhandle( (long) parent_write_local, O_TEXT );
  transmit_output_stream = _fdopen( fd, "w" );
  fd = _open_osfhandle( (long) parent_read_local, O_TEXT );
  transmit_input_stream = _fdopen( fd, "r" );
  if (transmit_input_stream == NULL || transmit_output_stream == NULL) 
    complain( "Can't open data stream: %s.", strerror( errno ) );
#endif
}

/*---------------------------------------------------------------------------*/

static void 
stop_transmit_process( void )
/* Stop the Malaga transmit process. */
{
#ifdef UNIX
  close_stream( &transmit_input_stream, NULL );
  close_stream( &transmit_output_stream, NULL );
  free_mem( &transmit_command_line );
  if (process_id != 0) 
  { 
    kill( process_id, SIGTERM );
    waitpid( process_id, NULL, 0 );
    process_id = 0;
  }
#endif

#ifdef WINDOWS
  close_stream( &transmit_input_stream, NULL );
  close_stream( &transmit_output_stream, NULL );
  free_mem( &transmit_command_line );
  if (process_handle != 0) 
  { 
    TerminateProcess( process_handle, 0 ); 
    CloseHandle( process_handle );
    process_handle = NULL;
  }
#endif
}

/*---------------------------------------------------------------------------*/

static void 
transmit_local( void )
/* Stack effects: VALUE -> NEW_VALUE
 * Start the Malaga transmit process by executing TRANSMIT_COMMAND_LINE
 * if it is not already running.
 * Send VALUE, in text format, to the transmit process and receive an answer
 * value in text format, convert it into internal format as NEW_VALUE. */
{
  string_t input_line, value_string;

  start_transmit_process();

  /* Send top value to transmit process. */
  value_string = value_to_readable( value_stack[ --top ], TRUE, -1 );
  fprintf( transmit_output_stream, "%s\n", value_string );
  fflush( transmit_output_stream );
  free_mem( &value_string );

  /* Read result and convert it to value format. */
  input_line = read_line( transmit_input_stream );
  if (input_line == NULL) 
    complain( "Transmit process doesn't answer." );
  set_scanner_input( input_line );
  TRY 
  { 
    parse_a_value();
    parse_token( EOF );
  } 
  FINALLY 
  { 
    free_mem( &input_line );
    set_scanner_input( NULL );
  }
  END_TRY;
}

/*---------------------------------------------------------------------------*/

void 
init_transmit( void )
/* Initialise this module. */
{
  transmit = transmit_local;
}

/*---------------------------------------------------------------------------*/

void 
terminate_transmit( void )
/* Terminate this module. */
{
  stop_transmit_process();
  transmit = NULL;
}

/*---------------------------------------------------------------------------*/

static void 
do_transmit_line_option( string_t arguments )
/* Set the command line to start the transmit process. */
{
  if (*arguments == EOS) 
  { 
    printf( "transmit-line: \"%s\"\n", 
            (transmit_command_line == NULL ? "" : transmit_command_line) );
  } 
  else 
  { 
    stop_transmit_process();
    transmit_command_line = parse_word( &arguments );
  }

  parse_end( &arguments );
}

command_t transmit_line_option = 
{ 
  "transmit-line transmit", do_transmit_line_option,
  "Usage: set transmit-line \"TRANSMIT_COMMAND_LINE\"\n"
  "Set the command line that is used to start the transmit process.\n"
};

/*---------------------------------------------------------------------------*/

static void 
do_transmit( string_t arguments )
/* Communicate with the transmit process. */
{
  string_t result;

  set_scanner_input( arguments );
  TRY 
  {
    parse_a_value(); 
    test_token( EOF );
  }
  FINALLY 
    set_scanner_input( NULL );
  END_TRY;
  transmit_local();
  result = value_to_readable( value_stack[ --top ], FALSE, 0 );
  printf( "%s\n", result );
  free_mem( &result );
}

command_t transmit_command = 
{ 
  "transmit", do_transmit,
  "Usage: transmit VALUE\n"
  "Send VALUE to the transmit process and display the result.\n"
};

/* End of file. =============================================================*/

Generated by  Doxygen 1.6.0   Back to index