/*___INFO__MARK_BEGIN__*/ /************************************************************************* * * The Contents of this file are made available subject to the terms of * the Sun Industry Standards Source License Version 1.2 * * Sun Microsystems Inc., March, 2001 * * * Sun Industry Standards Source License Version 1.2 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.2 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2001 by Sun Microsystems, Inc. * * All Rights Reserved. * ************************************************************************/ /*___INFO__MARK_END__*/ #include #include #include #include #include #if defined(DARWIN) # include # include # include #elif defined(HP11) || defined(HP1164) # include #elif defined(INTERIX) # include # include #elif defined(FREEBSD) || defined(NETBSD) # include # include #else # include #endif #include #include "sgermon.h" #include "sge_io.h" #include "sge_utility.h" #include "sge_pty.h" #include "sge_ijs_comm.h" #include "sge_ijs_threads.h" #include "sge_client_ijs.h" /* module variables */ static char *g_hostname = NULL; static int g_exit_status = 0; /* set by worker thread, read by main thread */ static int g_nostdin = 0; /* set by main thread, read by worker thread */ static int g_noshell = 0; /* set by main thread, read by worker thread */ static COMM_HANDLE *g_comm_handle = NULL; /* * static volatile sig_atomic_t received_window_change_signal = 1; * Flag to indicate that we have received a window change signal which has * not yet been processed. This will cause a message indicating the new * window size to be sent to the server a little later. This is volatile * because this is updated in a signal handler. */ static volatile sig_atomic_t received_window_change_signal = 1; static volatile sig_atomic_t received_broken_pipe_signal = 0; static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ volatile sig_atomic_t received_signal = 0; /****** window_change_handler ************************************************** * NAME * window_change_handler() -- handler for the window changed signal * * SYNOPSIS * static void window_change_handler(int sig) * * FUNCTION * Signal handler for the window change signal (SIGWINCH). This just sets a * flag indicating that the window has changed. * * INPUTS * int sig - number of the received signal * * RESULT * void - no result * * NOTES * MT-NOTE: window_change_handler() is not MT safe, because it uses * received_window_change_signal * * SEE ALSO *******************************************************************************/ static void window_change_handler(int sig) { /* Do not use DPRINTF in a signal handler! */ received_window_change_signal = 1; signal(SIGWINCH, window_change_handler); } /****** broken_pipe_handler **************************************************** * NAME * broken_pipe_handler() -- handler for the broken pipe signal * * SYNOPSIS * static void broken_pipe_handler(int sig) * * FUNCTION * Handler for the SIGPIPE signal. * * INPUTS * int sig - number of the received signal * * RESULT * void - no result * * NOTES * * SEE ALSO *******************************************************************************/ static void broken_pipe_handler(int sig) { received_broken_pipe_signal = 1; signal(SIGPIPE, broken_pipe_handler); } /****** signal_handler() ******************************************************* * NAME * signal_handler() -- handler for quit signals * * SYNOPSIS * static void signal_handler(int sig) * * FUNCTION * Handler for all signals that quit the program. These signals are trapped * in order to restore the terminal modes. * * INPUTS * int sig - number of the received signal * * RESULT * void - no result * * NOTES * * SEE ALSO *******************************************************************************/ void signal_handler(int sig) { received_signal = sig; quit_pending = 1; } /****** set_signal_handlers() ************************************************** * NAME * set_signal_handlers() -- set all signal handlers * * SYNOPSIS * static void set_signal_handlers(void) * * FUNCTION * Sets all signal handlers. Doesn't overwrite SIG_IGN and therefore * matches the behaviour of rsh. * * RESULT * void - no result * * NOTES * * SEE ALSO *******************************************************************************/ void set_signal_handlers(void) { struct sigaction old_handler, new_handler; /* Is SIGHUP necessary? * Yes: termio(7I) says: * "When a modem disconnect is detected, a SIGHUP signal is sent * to the terminal's controlling process. * Unless other arrangements have been made, these signals * cause the process to terminate. If SIGHUP is ignored or * caught, any subsequent read returns with an end-of-file * indication until the terminal is closed." */ sigaction(SIGHUP, NULL, &old_handler); if (old_handler.sa_handler != SIG_IGN) { new_handler.sa_handler = signal_handler; sigaddset(&new_handler.sa_mask, SIGHUP); new_handler.sa_flags = SA_RESTART; sigaction(SIGHUP, &new_handler, NULL); } sigaction(SIGINT, NULL, &old_handler); if (old_handler.sa_handler != SIG_IGN) { new_handler.sa_handler = signal_handler; sigaddset(&new_handler.sa_mask, SIGINT); new_handler.sa_flags = SA_RESTART; sigaction(SIGINT, &new_handler, NULL); } sigaction(SIGQUIT, NULL, &old_handler); if (old_handler.sa_handler != SIG_IGN) { new_handler.sa_handler = signal_handler; sigaddset(&new_handler.sa_mask, SIGQUIT); new_handler.sa_flags = SA_RESTART; sigaction(SIGQUIT, &new_handler, NULL); } sigaction(SIGTERM, NULL, &old_handler); if (old_handler.sa_handler != SIG_IGN) { new_handler.sa_handler = signal_handler; sigaddset(&new_handler.sa_mask, SIGTERM); new_handler.sa_flags = SA_RESTART; sigaction(SIGTERM, &new_handler, NULL); } new_handler.sa_handler = window_change_handler; sigaddset(&new_handler.sa_mask, SIGWINCH); new_handler.sa_flags = SA_RESTART; sigaction(SIGWINCH, &new_handler, NULL); new_handler.sa_handler = broken_pipe_handler; sigaddset(&new_handler.sa_mask, SIGPIPE); new_handler.sa_flags = SA_RESTART; sigaction(SIGPIPE, &new_handler, NULL); } /****** client_check_window_change() ******************************************* * NAME * client_check_window_change() -- check if window size was change and * submit changes to pty * * SYNOPSIS * static void client_check_window_change(COMM_HANDLE *handle) * * FUNCTION * Checks if the window size of the terminal window was changed. * If the size was changed, submits the new window size to the * pty. * The actual change is detected by a signal (on Unix), this function * just checks the according flag. * * INPUTS * COMM_HANDLE *handle - pointer to the commlib handle * * RESULT * void - no result * * NOTES * MT-NOTE: client_check_window_change() is MT-safe (see comment in code) * * SEE ALSO * window_change_handler() *******************************************************************************/ static void client_check_window_change(COMM_HANDLE *handle) { struct winsize ws; char buf[200]; dstring err_msg = DSTRING_INIT; DENTER(TOP_LAYER, "client_check_window_change"); if (received_window_change_signal) { /* * here we can have a race condition between the two working threads, * but it doesn't matter - in the worst case, the new window size gets * submitted two times. */ received_window_change_signal = 0; if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) { DPRINTF(("sendig WINDOW_SIZE_CTRL_MSG with new window size: " "%d, %d, %d, %d to shepherd\n", ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel)); sprintf(buf, "WS %d %d %d %d", ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel); comm_write_message(handle, g_hostname, COMM_CLIENT, 1, (unsigned char*)buf, strlen(buf), WINDOW_SIZE_CTRL_MSG, &err_msg); } else { DPRINTF(("client_check_windows_change: ioctl() failed! " "sending dummy WINDOW_SIZE_CTRL_MSG to fullfill protocol.\n")); sprintf(buf, "WS 60 80 480 640"); comm_write_message(handle, g_hostname, COMM_CLIENT, 1, (unsigned char*)buf, strlen(buf), WINDOW_SIZE_CTRL_MSG, &err_msg); } } sge_dstring_free(&err_msg); DEXIT; } /****** tty_to_commlib() ******************************************************* * NAME * tty_to_commlib() -- tty_to_commlib thread entry point and main loop * * SYNOPSIS * void* tty_to_commlib(void *t_conf) * * FUNCTION * Entry point and main loop of the tty_to_commlib thread. * Reads data from the tty and writes it to the commlib. * * INPUTS * void *t_conf - pointer to cl_thread_settings_t struct of the thread * * RESULT * void* - always NULL * * NOTES * MT-NOTE: tty_to_commlib is MT-safe ? * * SEE ALSO *******************************************************************************/ void* tty_to_commlib(void *t_conf) { char *pbuf; fd_set read_fds; struct timeval timeout; dstring err_msg = DSTRING_INIT; int ret, nread, do_exit = 0; DENTER(TOP_LAYER, "tty_to_commlib"); thread_func_startup(t_conf); /* * allocate working buffer */ pbuf = (char*)malloc(BUFSIZE); if (pbuf == NULL) { DPRINTF(("tty_to_commlib can't allocate working buffer: %s (%d)\n", strerror(errno), errno)); do_exit = 1; } while (do_exit == 0) { FD_ZERO(&read_fds); if (g_nostdin == 0) { /* wait for input on tty */ FD_SET(STDIN_FILENO, &read_fds); } timeout.tv_sec = 1; timeout.tv_usec = 0; DPRINTF(("tty_to_commlib: Waiting in select() for data\n")); ret = select(STDIN_FILENO+1, &read_fds, NULL, NULL, &timeout); thread_testcancel(t_conf); client_check_window_change(g_comm_handle); if (received_signal == SIGHUP || received_signal == SIGINT || received_signal == SIGQUIT || received_signal == SIGTERM) { /* If we receive one of these signals, we must terminate */ do_exit = 1; continue; } if (ret > 0) { if (g_nostdin == 1) { /* We should never get here if STDIN is closed */ DPRINTF(("tty_to_commlib: STDIN ready to read while it should be closed!!!\n")); } DPRINTF(("tty_to_commlib: trying to read() from stdin\n")); nread = read(STDIN_FILENO, pbuf, BUFSIZE-1); DPRINTF(("tty_to_commlib: nread = %d\n", nread)); if (nread < 0 && (errno == EINTR || errno == EAGAIN)) { DPRINTF(("tty_to_commlib: EINTR or EAGAIN\n")); /* do nothing */ } else if (nread <= 0) { do_exit = 1; } else { DPRINTF(("tty_to_commlib: writing to commlib: %d bytes\n", nread)); if (comm_write_message(g_comm_handle, g_hostname, COMM_CLIENT, 1, (unsigned char*)pbuf, (unsigned long)nread, STDIN_DATA_MSG, &err_msg) != nread) { DPRINTF(("tty_to_commlib: couldn't write all data\n")); } else { DPRINTF(("tty_to_commlib: data successfully written\n")); } comm_flush_write_messages(g_comm_handle, &err_msg); } } else { /* * We got either a select timeout or a select error. In both cases, * it's a good chance to check if our client is still alive. */ DPRINTF(("tty_to_commlib: Checking if client is still alive\n")); if (comm_get_connection_count(g_comm_handle, &err_msg) == 0) { DPRINTF(("tty_to_commlib: Client is not alive! -> exiting.\n")); do_exit = 1; } else { DPRINTF(("tty_to_commlib: Client is still alive\n")); } } } /* while (do_exit == 0) */ /* clean up */ FREE(pbuf); thread_func_cleanup(t_conf); sge_dstring_free(&err_msg); DPRINTF(("tty_to_commlib: exiting tty_to_commlib thread!\n")); DEXIT; return NULL; } /****** commlib_to_tty() ******************************************************* * NAME * commlib_to_tty() -- commlib_to_tty thread entry point and main loop * * SYNOPSIS * void* commlib_to_tty(void *t_conf) * * FUNCTION * Entry point and main loop of the commlib_to_tty thread. * Reads data from the commlib and writes it to the tty. * * INPUTS * void *t_conf - pointer to cl_thread_settings_t struct of the thread * * RESULT * void* - always NULL * * NOTES * MT-NOTE: commlib_to_tty is MT-safe ? * * SEE ALSO *******************************************************************************/ void* commlib_to_tty(void *t_conf) { recv_message_t recv_mess; dstring err_msg = DSTRING_INIT; int ret = 0, do_exit = 0; DENTER(TOP_LAYER, "commlib_to_tty"); thread_func_startup(t_conf); while (do_exit == 0) { /* * wait blocking for a message from commlib */ recv_mess.cl_message = NULL; recv_mess.data = NULL; DPRINTF(("commlib_to_tty: recv_message()\n")); ret = comm_recv_message(g_comm_handle, CL_TRUE, &recv_mess, &err_msg); if (ret != COMM_RETVAL_OK) { /* check if we are still connected to anybody. */ /* if not - exit. */ DPRINTF(("commlib_to_tty: error receiving message: %s\n", sge_dstring_get_string(&err_msg))); if (comm_get_connection_count(g_comm_handle, &err_msg) == 0) { DPRINTF(("commlib_to_tty: no endpoint found\n")); do_exit = 1; continue; } } DPRINTF(("commlib_to_tty: received a message\n")); thread_testcancel(t_conf); client_check_window_change(g_comm_handle); if (received_signal == SIGHUP || received_signal == SIGINT || received_signal == SIGQUIT || received_signal == SIGTERM) { /* If we receive one of these signals, we must terminate */ DPRINTF(("commlib_to_tty: shutting down because of signal %d\n", received_signal)); do_exit = 1; continue; } DPRINTF(("'parsing' message\n")); /* * 'parse' message * A 1 byte prefix tells us what kind of message it is. * See sge_ijs_comm.h for message types. */ if (recv_mess.cl_message != NULL) { char buf[100]; switch (recv_mess.type) { case STDOUT_DATA_MSG: /* copy recv_mess.data to buf to append '\0' */ memcpy(buf, recv_mess.data, MIN(99, recv_mess.cl_message->message_length - 1)); buf[MIN(99, recv_mess.cl_message->message_length - 1)] = 0; DPRINTF(("commlib_to_tty: received stdout message, writing to tty.\n")); DPRINTF(("commlib_to_tty: message is: %s\n", buf)); /* TODO: If it's not possible to write all data to the tty, retry blocking * until all data was written. The commlib must block then, too. */ if (sge_writenbytes(STDOUT_FILENO, recv_mess.data, (int)(recv_mess.cl_message->message_length-1)) != (int)(recv_mess.cl_message->message_length-1)) { DPRINTF(("commlib_to_tty: sge_writenbytes() error\n")); } break; case STDERR_DATA_MSG: DPRINTF(("commlib_to_tty: received stderr message, writing to tty.\n")); /* TODO: If it's not possible to write all data to the tty, retry blocking * until all data was written. The commlib must block then, too. */ if (sge_writenbytes(STDERR_FILENO, recv_mess.data, (int)(recv_mess.cl_message->message_length-1)) != (int)(recv_mess.cl_message->message_length-1)) { DPRINTF(("commlib_to_tty: sge_writenbytes() error\n")); } break; case WINDOW_SIZE_CTRL_MSG: /* control message */ /* we don't expect a control message */ DPRINTF(("commlib_to_tty: received window size message! " "This was unexpected!\n")); break; case REGISTER_CTRL_MSG: /* control message */ /* a client registered with us. With the next loop, the * cl_commlib_trigger function will send the WINDOW_SIZE_CTRL_MSG * (and perhaps some data messages), which is already in the * send_messages list of the connection, to the client. */ DPRINTF(("commlib_to_tty: received register message!\n")); /* Send the settings in response */ sprintf(buf, "noshell = %d", g_noshell); ret = (int)comm_write_message(g_comm_handle, g_hostname, COMM_CLIENT, 1, (unsigned char*)buf, strlen(buf)+1, SETTINGS_CTRL_MSG, &err_msg); DPRINTF(("commlib_to_tty: sent SETTINGS_CTRL_MSG, ret = %d\n", ret)); break; case UNREGISTER_CTRL_MSG: /* control message */ /* the client wants to quit, as this is the last message the client * sends, we can be sure to have received all messages from the * client. We answer with a UNREGISTER_RESPONSE_CTRL_MSG so * the client knows that it can quit now. We can quit, also. */ DPRINTF(("commlib_to_tty: received unregister message!\n")); DPRINTF(("commlib_to_tty: writing UNREGISTER_RESPONSE_CTRL_MSG\n")); /* copy recv_mess.data to buf to append '\0' */ memcpy(buf, recv_mess.data, MIN(99, recv_mess.cl_message->message_length - 1)); buf[MIN(99, recv_mess.cl_message->message_length - 1)] = 0; /* the UNREGISTER_CTRL_MSG contains the exit status of the * qrsh_starter in case of qrsh and the exit status * of the shell for qlogin/qrsh . * If the job was signalled, the exit code is 128+signal. */ sscanf(buf, "%d", &g_exit_status); comm_write_message(g_comm_handle, g_hostname, COMM_CLIENT, 1, (unsigned char*)" ", 1, UNREGISTER_RESPONSE_CTRL_MSG, &err_msg); DPRINTF(("commlib_to_tty: received exit_status from shepherd: %d\n", g_exit_status)); comm_flush_write_messages(g_comm_handle, &err_msg); do_exit = 1; #if 0 cl_log_list_set_log_level(cl_com_get_log_list(), CL_LOG_OFF); cl_com_set_error_func(NULL); #endif break; } } comm_free_message(&recv_mess, &err_msg); } thread_func_cleanup(t_conf); DPRINTF(("commlib_to_tty: exiting commlib_to_tty thread!\n")); sge_dstring_free(&err_msg); DEXIT; return NULL; } /****** run_ijs_server() ******************************************************* * NAME * run_ijs_server() -- The servers main loop * * SYNOPSIS * int run_ijs_server(u_long32 job_id, int nostdin, int noshell, * int is_rsh, int is_qlogin, int force_pty, * int *p_exit_status) * * FUNCTION * The main loop of the commlib server, handling the data transfer from * and to the client. * * INPUTS * COMM_HANDLE *handle - Handle of the COMM server * u_long32 job_id - SGE job id of this job * int nostdin - The "-nostdin" switch * int noshell - The "-noshell" switch * int is_rsh - Is it a qrsh with commandline? * int is_qlogin - Is it a qlogin or qrsh without commandline? * int force_pty - The user forced use of pty by the "-pty yes" switch * * OUTPUTS * int *p_exit_status - The exit status of qrsh_starter in case of * "qrsh " or the exit status of the shell in * case of "qrsh "/"qlogin". * If the job was signalled, the exit code is 128+signal. * * RESULT * int - 0: Ok. * 1: Invalid parameter * 2: Log list not initialized * 3: Error setting terminal mode * 4: Can't create tty_to_commlib thread * 5: Can't create commlib_to_tty thread * 6: Error shutting down commlib connection * 7: Error resetting terminal mode * * NOTES * MT-NOTE: run_ijs_server is not MT-safe *******************************************************************************/ int run_ijs_server(COMM_HANDLE *handle, const char *remote_host, u_long32 job_id, int nostdin, int noshell, int is_rsh, int is_qlogin, ternary_t force_pty, int *p_exit_status, dstring *p_err_msg) { int ret = 0, ret_val = 0; THREAD_HANDLE *pthread_tty_to_commlib = NULL; THREAD_HANDLE *pthread_commlib_to_tty = NULL; THREAD_LIB_HANDLE *thread_lib_handle = NULL; cl_raw_list_t *cl_com_log_list = NULL; DENTER(TOP_LAYER, "run_ijs_server"); if (handle == NULL || p_err_msg == NULL || p_exit_status == NULL || remote_host == NULL) { return 1; } g_comm_handle = handle; g_hostname = strdup(remote_host); cl_com_log_list = cl_com_get_log_list(); if (cl_com_log_list == NULL) { return 2; } g_nostdin = nostdin; g_noshell = noshell; /* * qrsh without command and qlogin both have is_rsh == 0 and is_qlogin == 1 * qrsh with command and qsh don't need to set terminal mode. * If the user requested a pty we also have to set terminal mode. * But only if stdout is still connected to a tty and not redirected * to a file or a pipe. */ if (isatty(STDOUT_FILENO) == 1 && ((force_pty == UNSET && is_rsh == 0 && is_qlogin == 1) || force_pty == YES)) { /* * Set this terminal to raw mode, just output everything, don't interpret * it. Let the pty on the client side interpret the characters. */ ret = terminal_enter_raw_mode(); if (ret != 0) { sge_dstring_sprintf(p_err_msg, "can't set terminal to raw mode: %s (%d)", strerror(ret), ret); return 3; } } /* * Setup thread list and create two worker threads */ thread_init_lib(&thread_lib_handle); /* * From here on, we have to cleanup the list in case of errors, this is * why we "goto cleanup" in case of error. */ DPRINTF(("creating worker threads\n")); DPRINTF(("creating tty_to_commlib thread\n")); ret = create_thread(thread_lib_handle, &pthread_tty_to_commlib, cl_com_log_list, "tty_to_commlib thread", 1, tty_to_commlib); if (ret != CL_RETVAL_OK) { sge_dstring_sprintf(p_err_msg, "can't create tty_to_commlib thread: %s", cl_get_error_text(ret)); ret_val = 4; goto cleanup; } DPRINTF(("creating commlib_to_tty thread\n")); ret = create_thread(thread_lib_handle, &pthread_commlib_to_tty, cl_com_log_list, "commlib_to_tty thread", 1, commlib_to_tty); if (ret != CL_RETVAL_OK) { sge_dstring_sprintf(p_err_msg, "can't create commlib_to_tty thread: %s", cl_get_error_text(ret)); ret_val = 5; goto cleanup; } /* * From here on, the two worker threads are doing all the work. * This main thread is just waiting until the client closes the * connection to us, which causes the commlib_to_tty thread to * exit. Then it closes the tty_to_commlib thread, too, and * cleans up everything. */ DPRINTF(("waiting for end of commlib_to_tty thread\n")); thread_join(pthread_commlib_to_tty); DPRINTF(("shutting down tty_to_commlib thread\n")); thread_shutdown(pthread_tty_to_commlib); /* * Close stdin to awake the tty_to_commlib-thread from the select() call. * thread_shutdown() doesn't work on all architectures. */ close(STDIN_FILENO); DPRINTF(("waiting for end of tty_to_commlib thread\n")); thread_join(pthread_tty_to_commlib); cleanup: /* * Set our terminal back to 'unraw' mode. Should be done automatically * by OS on process end, but we want to be sure. */ ret = terminal_leave_raw_mode(); DPRINTF(("terminal_leave_raw_mode() returned %s (%d)\n", strerror(ret), ret)); if (ret != 0) { sge_dstring_sprintf(p_err_msg, "error resetting terminal mode: %s (%d)", strerror(ret)); ret_val = 7; } *p_exit_status = g_exit_status; thread_cleanup_lib(&thread_lib_handle); DRETURN(ret_val); } /****** sge_client_ijs/start_ijs_server() ************************************** * NAME * start_ijs_server() -- starts the commlib server for the builtin * interactive job support * * SYNOPSIS * int start_ijs_server(const char* username, int csp_mode, * COMM_HANDLE **phandle, dstring *p_err_msg) * * FUNCTION * Starts the commlib server for the commlib connection between the shepherd * of the interactive job (qrsh/qlogin) and the qrsh/qlogin command. * Over this connection the stdin/stdout/stderr input/output is transferred. * * INPUTS * bool csp_mode - If false, the server uses unsecured communications, * otherwise it uses secured communictions. * const char* username - The owner of the certificates that are used to * secure the connection. * Used only in CSP mode, otherwise ignored. * OUTPUTS * COMM_HANDLE **handle - Pointer to the COMM server handle. * Gets initialized in this function. * dstring *p_err_msg - Contains the error reason in case of error. * * RESULT * int - 0: OK * 1: Can't open connection * 2: Can't set connection parameters * * NOTES * MT-NOTE: start_builtin_ijs_server() is not MT safe * * SEE ALSO * sge_client_ijs/run_ijs_server() * sge_client_ijs/stop_ijs_server() * sge_client_ijs/force_ijs_server_shutdown() *******************************************************************************/ int start_ijs_server(bool csp_mode, const char* username, COMM_HANDLE **phandle, dstring *p_err_msg) { int ret, ret_val = 0; DENTER(TOP_LAYER, "start_ijs_server"); /* we must copy the hostname here to a global variable, because the * worker threads need it later. * It gets freed in force_ijs_server_shutdown(). * TODO: Cleaner solution for this! */ DPRINTF(("starting commlib server\n")); ret = comm_open_connection(true, csp_mode, COMM_SERVER, 0, COMM_CLIENT, NULL, username, phandle, p_err_msg); if (ret != 0 || *phandle == NULL) { ret_val = 1; } else { ret = comm_set_connection_param(*phandle, HEARD_FROM_TIMEOUT, 0, p_err_msg); if (ret != 0) { ret_val = 2; } } DRETURN(ret_val); } /****** sge_client_ijs/stop_ijs_server() *************************************** * NAME * stop_ijs_server() -- stops the commlib server for the builtin * interactive job support * * SYNOPSIS * int stop_ijs_server(COMM_HANDLE **phandle, dstring *p_err_msg) * * FUNCTION * Stops the commlib server for the commlib connection between the shepherd * of the interactive job (qrsh/qlogin) and the qrsh/qlogin command. * Over this connectin the stdin/stdout/stderr input/output is transferred. * * INPUTS * COMM_HANDLE **phandle - Pointer to the COMM server handle. Gets set to * NULL in this function. * dstring *p_err_msg - Contains the error reason in case of error. * * RESULT * int - 0: OK * 1: Invalid Parameter: phandle = NULL * 2: General error shutting down the COMM server, * see p_err_msg for details * * NOTES * MT-NOTE: stop_ijs_server() is not MT safe * * SEE ALSO * sge_client_ijs/start_ijs_server() * sge_client_ijs/run_ijs_server() * sge_client_ijs/force_ijs_server_shutdown() *******************************************************************************/ int stop_ijs_server(COMM_HANDLE **phandle, dstring *p_err_msg) { int ret = 0; DENTER(TOP_LAYER, "stop_ijs_server"); if (phandle == NULL) { ret = 1; } else if (*phandle != NULL) { cl_com_set_error_func(NULL); #if 0 cl_log_list_set_log_level(cl_com_get_log_list(), CL_LOG_OFF); #endif cl_com_ignore_timeouts(CL_TRUE); DPRINTF(("shut down the connection from our side\n")); ret = cl_commlib_shutdown_handle(*phandle, CL_FALSE); if (ret != CL_RETVAL_OK) { sge_dstring_sprintf(p_err_msg, "error shutting down the connection: %s", cl_get_error_text(ret)); ret = 2; } *phandle = NULL; } DRETURN(ret); } /****** sge_client_ijs/force_ijs_server_shutdown() ***************************** * NAME * force_ijs_server_shutdown() -- forces the commlib server for the builtin * interactive job support to shut down * * SYNOPSIS * int force_ijs_server_shutdown(COMM_HANDLE **phandle, const char * *this_component, dstring *p_err_msg) * * FUNCTION * Forces the commlib server for the builtin interactive job support to shut * down immediately and ensures it is shut down. * * INPUTS * COMM_HANDLE **phandle - Handle of the COMM connection, gets set to * NULL in this function. * const char *this_component - Name of this component. * dstring *p_err_msg - Contains the error reason in case of error. * * RESULT * int - 0: OK * 1: Invalid parameter: phandle == NULL or *phandle == NULL * 2: Can't shut down connection, see p_err_msg for details * * NOTES * MT-NOTE: force_ijs_server_shutdown() is not MT safe * * SEE ALSO * sge_client_ijs/start_ijs_server() * sge_client_ijs/run_ijs_server() * sge_client_ijs/stop_ijs_server_shutdown() *******************************************************************************/ int force_ijs_server_shutdown(COMM_HANDLE **phandle, const char *this_component, dstring *p_err_msg) { int ret; DENTER(TOP_LAYER, "force_ijs_server_shutdown"); if (phandle == NULL || *phandle == NULL) { sge_dstring_sprintf(p_err_msg, "invalid connection handle"); DPRINTF(("invalid connection handle - nothing to shut down\n")); DRETURN(1); } DPRINTF(("connection is still alive\n")); /* This will remove the handle */ ret = comm_shutdown_connection(*phandle, COMM_CLIENT, g_hostname, p_err_msg); FREE(g_hostname); if (ret != COMM_RETVAL_OK) { DPRINTF(("comm_shutdown_connection() failed: %s (%d)\n", sge_dstring_get_string(p_err_msg), ret)); ret = 2; } else { DPRINTF(("successfully shut down the connection\n")); } *phandle = NULL; DRETURN(ret); }