Logo Search packages:      
Sourcecode: ldtp version File versions

ldtp.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * Linux Desktop Testing Project http://ldtp.freedesktop.org
 *
 * Author:
 *    Veerapuram Varadhan <v.varadhan@gmail.com>
 *
 * Copyright 2004 - 2006 Novell, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "ldtp.h"
#include "ldtp-gui.h"
#include "ldtp-appmap.h"
#include "remap.h"
#include "ldtp-server.h"
#include "ldtp-utils.h"
#include "client-handler.h"
#include "ldtp-error.h"
#include "ldtp-logger.h"

gint ldtp_script_port = 0;
gint ldtp_gui_timeout = 0;
gint ldtp_obj_timeout = 0;
gboolean ldtp_debug   = FALSE;
static gboolean ldtp_usage   = FALSE;
static gboolean ldtp_version = FALSE;
gboolean ldtp_script_service = FALSE;
GHashTable *event_notifier  = NULL;
static GHashTable *client_thread_pool = NULL;
static AccessibleEventListener *window_listener;
pthread_mutex_t cb_mutex = PTHREAD_MUTEX_INITIALIZER;

static GOptionEntry entries[] = 
      {
            { "gui-timeout", 'g', 0, G_OPTION_ARG_INT, &ldtp_gui_timeout, "Wait gui to appear / disappear till N seconds", "N" },
            { "obj-timeout", 'o', 0, G_OPTION_ARG_INT, &ldtp_obj_timeout, "Wait object to appear till N seconds", "N" },
            { "port", 'p', 0, G_OPTION_ARG_INT, &ldtp_script_port, "Start LDTP scripting engine on TCP port", "N" },
            { "script-engine", 's', 0, G_OPTION_ARG_NONE, &ldtp_script_service, "Start LDTP script execution engine as TCP service", NULL },
            { "usage", 'u', 0, G_OPTION_ARG_NONE, &ldtp_usage, "LDTP engine usage", NULL },
            { "verbose", 'v', 0, G_OPTION_ARG_NONE, &ldtp_debug, "Verbose mode", NULL },
            { "version", 'V', 0, G_OPTION_ARG_NONE, &ldtp_version, "LDTP engine version", NULL },
            { NULL }
      };

static LDTPClientContext*
is_window_reg_for_events (char *context)
{
      LDTPClientContext *cctxt = NULL;
      if (event_notifier) {
            cctxt = g_hash_table_find (event_notifier, search_title_based, context);
            if (cctxt && context && cctxt->req && cctxt->req->context)
                  g_print ("Registered window title: %s - %s\n", context, cctxt->req->context);
      }
      return cctxt;
}

static void
report_window_event  (const AccessibleEvent *event, void *user_data)
{
      char *title, *context = Accessible_getName (event->source);
      title = AccessibleWindowEvent_getTitleString (event);

      if (title && event_notifier) {
            uint32_t resp_size = 0;
            LDTPErrorCode status;
            char *resp_pckt = NULL;
            char *window_name = NULL;
            LDTPClientContext *cctxt = NULL;
            pthread_mutex_lock (&cb_mutex);
            if ((cctxt = is_window_reg_for_events (title))) {
                  /*
                    Notify to client
                  */
                  if (!cctxt || !cctxt->resp) {
                        g_print ("CCTXT is lost\n");
                        pthread_mutex_unlock (&cb_mutex);
                        return;
                  }
                  cctxt->resp->data = g_strdup (title);
                  cctxt->resp->data_len = g_utf8_strlen (title, -1);
                  cctxt->resp->resp_status = LDTP_ERROR_SUCCESS;

                  generate_notification_packet (cctxt, &status, &resp_pckt, &resp_size);
                  if (status != LDTP_ERROR_SUCCESS) {
                        g_print ("Error generating notification\n");
                        pthread_mutex_unlock (&cb_mutex);
                        return;
                  }
                  if (resp_pckt)
                        g_print ("Notification: %s - Len - %d", resp_pckt, resp_size);
                  send_response (cctxt->sock_fd, resp_pckt, resp_size, &status);
                  g_free (cctxt->resp->data);
                  cctxt->resp->data = NULL;
                  pthread_mutex_unlock (&cb_mutex);
                  return;
            }
            /*
              If window title is used in old appmap format (like dlgFind), then use the following approach
            */
            window_name = get_window_text_in_appmap_format (title, Accessible_getRole (event->source));
            if (window_name && is_window_reg_for_events (window_name)) {
                  /*
                    Notify to client
                  */
                  if (window_name)
                        g_free (window_name);
                  cctxt->resp->resp_status = LDTP_ERROR_SUCCESS;

                  generate_notification_packet (cctxt, &status, &resp_pckt, &resp_size);
                  if (status != LDTP_ERROR_SUCCESS) {
                        g_print ("Error generating notification\n");
                        pthread_mutex_unlock (&cb_mutex);
                        return;
                  }

                  g_print ("Notification: %s - Len - %d", resp_pckt, resp_size);
                  send_response (cctxt->sock_fd, resp_pckt, resp_size, &status);
                  pthread_mutex_unlock (&cb_mutex);
                  return;
            }
            if (window_name)
                  g_free (window_name);
            pthread_mutex_unlock (&cb_mutex);
      }
      SPI_freeString (context);
      SPI_freeString (title);
}

static void
signal_all_threads (gpointer key, gpointer value, gpointer userdata)
{
      pthread_kill ((pthread_t) value, SIGKILL);
}

void
cleanup (int mysig)
{
      int leaked;
      char *tmpfile = NULL;

      leaked = SPI_exit ();
      if (leaked)
            printf ("Leaked %d SPI handles\n", leaked);

      g_hash_table_foreach (client_thread_pool, signal_all_threads, NULL);
      /*
        Close server socket
      */
      close_connection (get_server_socket (LDTP_SCRIPT_SERVER));
      close_connection (get_server_socket (LDTP_RECORD_SERVER));

      tmpfile = get_tmp_file (LDTP_RECORD_SERVER);
      if (tmpfile) {
            /*
              Remove tmp file
            */
            unlink (tmpfile);
            g_free (tmpfile);
      }

      if (ldtp_script_service || ldtp_script_port)
            goto quit;

      tmpfile = get_tmp_file (LDTP_SCRIPT_SERVER);
      if (tmpfile) {
            /*
              Remove tmp file
            */
            unlink (tmpfile);
            g_free (tmpfile);
      }
 quit:
      /*
        Quit from main SPI event loop
      */
      SPI_event_quit ();
}

static void 
accept_connection (int listener, LDTPErrorCode* err)
{
      struct sockaddr_in remoteaddr;
      socklen_t addrlen;
      int newfd;
      pthread_t client_thread = 0;
      int* newfd_dup = NULL;
      int retval;
  
      /* handle new connections */
      addrlen = sizeof (remoteaddr);
      newfd = accept (listener, (struct sockaddr *) &remoteaddr, 
                  &addrlen);
  
      if (newfd == -1) {
            ldtp_log("ERROR:accept() failed with \"%s\"\n", strerror(errno));
            *err = LDTP_ERROR_ACCEPT_FAILED;
            goto error;
      }

      ldtp_log ("Client connection: accepted\n");

      newfd_dup = malloc (sizeof (newfd));
      *newfd_dup = newfd;
      retval = pthread_create (&client_thread, NULL, (void *)&handle_client, 
                         (void *)newfd_dup);
      if (retval == EAGAIN) {
            /* unable to create threads... kindly retry... */
            ldtp_log ("%s:%d: Unable to create client_threads. "
                    "Disconnecting the client.\n", __FILE__, __LINE__);
            close_connection (newfd);
            *err = LDTP_ERROR_THREAD_CREATION_FAILED;
            goto error;
      }
      else {
            /* parent process */
            g_hash_table_insert (client_thread_pool, &newfd, &client_thread);
            *err = LDTP_ERROR_SUCCESS;
            return;
      }

 error:
      if (newfd_dup)
            free (newfd_dup);
      return;
}

void 
close_connection (int fd)
{
      close (fd);
}

static void 
init_pollfd (int fd, struct pollfd *pfd, LDTPErrorCode *err)
{
      if (pfd == NULL) {
            *err = LDTP_ERROR_ARGUMENT_NULL;
            return;
      }

      pfd->fd = fd;
      pfd->events = POLLIN;

      if (!client_thread_pool)
            client_thread_pool = g_hash_table_new (&g_int_hash, &g_int_equal);
      *err = LDTP_ERROR_SUCCESS;
}

static void
ldtp_server_thread (void *ptr)
{
      struct pollfd pfd[2];
      int record_socket;
      int server_socket;
      int client_update_flag;
      LDTPErrorCode err;

      server_socket = init_ldtp_server (LDTP_SCRIPT_SERVER);
      record_socket = init_ldtp_server (LDTP_RECORD_SERVER);

      init_pollfd (server_socket, &pfd[0], &err);
      if (err != LDTP_ERROR_SUCCESS) {
            /* 
               1) Close the server
               2) Inform SPI_Main() to close, in some way
               may be SPI_Quit()?
            */
            close_connection (server_socket);
            pthread_exit ((void *) 1);
      }

      init_pollfd (record_socket, &pfd[1], &err);
      if (err != LDTP_ERROR_SUCCESS) {
            /* 
               1) Close the server
               2) Inform SPI_Main() to close, in some way
               may be SPI_Quit()?
            */
            close_connection (server_socket);
            pthread_exit ((void *) 1);
      }

      while (1) {
            if (poll (pfd, 2, -1) == -1) {
                  if (errno == EINTR) {
                        continue;
                  }
                  else if (errno != EBADF && errno != EFAULT && errno != EINVAL && errno != ENOMEM) {
                        ldtp_log ("%d:Continuing\n", getpid ());
                        exit (1);
                  }
                  else {
                        ldtp_log ("%d:Exiting : %s\n", getpid (), strerror (errno));
                        exit (1);
                  }
            }
            client_update_flag = 0;
            if ((pfd[0].revents & POLLIN) && (pfd[0].fd == server_socket)) {
                  accept_connection (server_socket, &err);
                  if (err != LDTP_ERROR_SUCCESS)
                        ldtp_log ("******Unable to accept connection*******\n");
            } // if check for all fds
            if ((pfd[1].revents & POLLIN) && (pfd[1].fd == record_socket)) {
                  accept_connection (record_socket, &err);
                  if (err != LDTP_ERROR_SUCCESS)
                        ldtp_log ("******Unable to accept connection*******\n");
            } // if check for all fds
      } // while loop forever
      pthread_exit ((void *) 0);
}

static void
ldtp_print (const char *string) 
{
      char *env_ldtp_debug = getenv ("LDTP_DEBUG");
      if (ldtp_debug || (env_ldtp_debug != NULL && g_ascii_strcasecmp (env_ldtp_debug, "2") == 0))
            printf ("%s", string);
}

int
main (int argc, char **argv)
{
      int retval;
      int spi_init;
      LDTPErrorCode err;
      GError *error = NULL;
      char *env_sleep = NULL;
      pthread_t server_thread = 0;
      struct rlimit resource_limit;
      GOptionContext *context = NULL;

      context = g_option_context_new ("- Linux Desktop Testing Project engine");
      g_option_context_add_main_entries (context, entries, NULL);
      if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
            g_print ("%s\n", error->message);
            printf ("Usage help:\n\tldtp --help\n\tldtp --usage\n");
            g_error_free (error);
            g_option_context_free (context);
            exit (1);
      }
      g_option_context_free (context);

      if (ldtp_usage) {
            printf ("ldtp [--verbose] [--gui-timeout=N]  [--obj-timeout=N] [--version] [--help]\n");
            exit (0);
      }
      if (ldtp_version) {
            printf ("ldtp-%s\n", PACKAGE_VERSION);
            exit (0);
      }

      /* generate core dump on seg-fault */
      resource_limit.rlim_cur =
            resource_limit.rlim_max = RLIM_INFINITY;
      if (setrlimit (RLIMIT_CORE, &resource_limit) != 0) {
            perror ("setrlimit");
      }

      signal (SIGCHLD, SIG_IGN);
      signal (SIGTERM, cleanup);
      signal (SIGPIPE, SIG_IGN);
      signal (SIGINT, cleanup);

      // Register local print function
      g_set_print_handler (ldtp_print);

      if (getenv ("LDTP_DEBUG"))
            ldtp_debug = TRUE;
      if ((env_sleep = getenv ("GUI_TIMEOUT")) != NULL) {
            ldtp_gui_timeout = atoi (env_sleep);
            if (!ldtp_gui_timeout)
                  ldtp_gui_timeout = 30;
      }
      if ((env_sleep = getenv ("OBJ_TIMEOUT")) != NULL) {
            ldtp_obj_timeout = atoi (env_sleep);
            if (!ldtp_obj_timeout)
                  ldtp_obj_timeout = 5;
      }

      retval = pthread_create (&server_thread, NULL, (void *)&ldtp_server_thread, 
                         NULL);
      if (retval == EAGAIN) {
            /* unable to create threads... kindly retry... */
            err = LDTP_ERROR_THREAD_CREATION_FAILED;
            g_print ("%s\n", ldtp_error_get_message (err));
            return 1;
      }
      spi_init = SPI_init ();

      window_listener = SPI_createAccessibleEventListener (report_window_event, NULL);

      SPI_registerGlobalEventListener (window_listener,
                               "window:create");
      SPI_event_main ();
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index