/* Notes: One of the reason we do not create the threads in this * function, is that it would make it more difficult to properly * "cleanup" on an error. We wouldn't know how many threads were * created, flags for setup completion may not be set yet, etc. * * Therefore ipmiconsole_engine_thread_create() is done outside of * this function and is done elsewhere. */ int ipmiconsole_engine_setup (unsigned int thread_count) { unsigned int i; int perr; assert (!console_engine_thread_count); assert (thread_count && thread_count <= IPMICONSOLE_THREAD_COUNT_MAX); if ((perr = pthread_mutex_lock (&console_engine_is_setup_mutex))) { IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr))); errno = perr; return (-1); } memset (console_engine_ctxs, '\0', IPMICONSOLE_THREAD_COUNT_MAX * sizeof (List)); memset (console_engine_ctxs_count, '\0', IPMICONSOLE_THREAD_COUNT_MAX * sizeof (unsigned int)); memset (console_engine_ctxs_mutex, '\0', IPMICONSOLE_THREAD_COUNT_MAX * sizeof (pthread_mutex_t)); for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++) { console_engine_ctxs_notifier[i][0] = -1; console_engine_ctxs_notifier[i][1] = -1; } garbage_collector_notifier[0] = -1; garbage_collector_notifier[1] = -1; if (ipmi_rmcpplus_init () < 0) { if (errno == EPERM) IPMICONSOLE_DEBUG (("ipmi_rmcpplus_init: incompatible crypto library")); else IPMICONSOLE_DEBUG (("ipmi_rmcpplus_init: %s", strerror (errno))); goto cleanup; } for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++) { if (!(console_engine_ctxs[i] = list_create ((ListDelF)ipmiconsole_ctx_connection_cleanup_session_submitted))) { IPMICONSOLE_DEBUG (("list_create: %s", strerror (errno))); goto cleanup; } console_engine_ctxs_count[i] = 0; if ((perr = pthread_mutex_init (&console_engine_ctxs_mutex[i], NULL)) != 0) { IPMICONSOLE_DEBUG (("pthread_mutex_init: %s", strerror (perr))); goto cleanup; } } /* Don't create fds for all ctxs_notifier to limit fd creation */ console_engine_ctxs_notifier_num = thread_count; for (i = 0; i < console_engine_ctxs_notifier_num; i++) { if (pipe (console_engine_ctxs_notifier[i]) < 0) { IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno))); goto cleanup; } if (ipmiconsole_set_closeonexec (NULL, console_engine_ctxs_notifier[i][0]) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } if (ipmiconsole_set_closeonexec (NULL, console_engine_ctxs_notifier[i][1]) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } } if (pipe (garbage_collector_notifier) < 0) { IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno))); goto cleanup; } if (ipmiconsole_set_closeonexec (NULL, garbage_collector_notifier[0]) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } if (ipmiconsole_set_closeonexec (NULL, garbage_collector_notifier[1]) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } if (!(console_engine_ctxs_to_destroy = list_create ((ListDelF)ipmiconsole_ctx_list_cleanup))) { IPMICONSOLE_DEBUG (("list_create: %s", strerror (errno))); goto cleanup; } if ((dummy_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { IPMICONSOLE_DEBUG (("socket: %s", strerror (errno))); goto cleanup; } if (_ipmiconsole_garbage_collector_create () < 0) goto cleanup; console_engine_is_setup++; console_engine_teardown = 0; console_engine_teardown_immediate = 0; if ((perr = pthread_mutex_unlock (&console_engine_is_setup_mutex))) { IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr))); errno = perr; goto cleanup; } return (0); cleanup: for (i = 0; i < IPMICONSOLE_THREAD_COUNT_MAX; i++) { if (console_engine_ctxs[i]) { list_destroy (console_engine_ctxs[i]); pthread_mutex_destroy (&console_engine_ctxs_mutex[i]); } console_engine_ctxs[i] = NULL; /* ignore potential error, cleanup path */ close (console_engine_ctxs_notifier[i][0]); /* ignore potential error, cleanup path */ close (console_engine_ctxs_notifier[i][1]); } if (console_engine_ctxs_to_destroy) list_destroy (console_engine_ctxs_to_destroy); console_engine_ctxs_to_destroy = NULL; garbage_collector_notifier[0] = -1; garbage_collector_notifier[1] = -1; /* ignore potential error, cleanup path */ close (dummy_fd); dummy_fd = -1; if ((perr = pthread_mutex_unlock (&console_engine_is_setup_mutex))) IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr))); return (-1); }
int ipmiconsole_ctx_connection_setup (ipmiconsole_ctx_t c) { struct sockaddr_in srcaddr; int sv[2]; int secure_malloc_flag; assert (c); assert (c->magic == IPMICONSOLE_CTX_MAGIC); assert (!(c->session_submitted)); _ipmiconsole_ctx_connection_init (c); /* File Descriptor User Interface */ if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0) { IPMICONSOLE_DEBUG (("socketpair: %s", strerror (errno))); if (errno == EMFILE) ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES); else ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR); goto cleanup; } c->connection.user_fd = sv[0]; c->connection.ipmiconsole_fd = sv[1]; if (ipmiconsole_set_closeonexec (c, c->connection.user_fd) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } if (ipmiconsole_set_closeonexec (c, c->connection.ipmiconsole_fd) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } /* Copy for API level */ c->fds.user_fd = c->connection.user_fd; secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0; if (!(c->connection.console_remote_console_to_bmc = scbuf_create (CONSOLE_REMOTE_CONSOLE_TO_BMC_BUF_MIN, CONSOLE_REMOTE_CONSOLE_TO_BMC_BUF_MAX, secure_malloc_flag))) { IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.console_bmc_to_remote_console = scbuf_create (CONSOLE_BMC_TO_REMOTE_CONSOLE_BUF_MIN, CONSOLE_BMC_TO_REMOTE_CONSOLE_BUF_MAX, secure_malloc_flag))) { IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } /* Connection Data */ if ((c->connection.ipmi_fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { IPMICONSOLE_DEBUG (("socket: %s", strerror (errno))); if (errno == EMFILE) ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES); else ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR); goto cleanup; } if (ipmiconsole_set_closeonexec (c, c->connection.ipmi_fd) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } memset (&srcaddr, '\0', sizeof (struct sockaddr_in)); srcaddr.sin_family = AF_INET; srcaddr.sin_port = htons (0); srcaddr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (c->connection.ipmi_fd, (struct sockaddr *)&srcaddr, sizeof (struct sockaddr_in)) < 0) { IPMICONSOLE_DEBUG (("bind: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR); goto cleanup; } if (!(c->connection.ipmi_from_bmc = scbuf_create (IPMI_FROM_BMC_BUF_MIN, IPMI_FROM_BMC_BUF_MAX, secure_malloc_flag))) { IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.ipmi_to_bmc = scbuf_create (IPMI_TO_BMC_BUF_MIN, IPMI_TO_BMC_BUF_MAX, secure_malloc_flag))) { IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } /* Pipe for non-fd communication */ if (pipe (c->connection.asynccomm) < 0) { IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno))); if (errno == EMFILE) ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES); else ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR); goto cleanup; } if (ipmiconsole_set_closeonexec (c, c->connection.asynccomm[0]) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } if (ipmiconsole_set_closeonexec (c, c->connection.asynccomm[1]) < 0) { IPMICONSOLE_DEBUG (("closeonexec error")); goto cleanup; } /* Copy for API level */ c->fds.asynccomm[0] = c->connection.asynccomm[0]; c->fds.asynccomm[1] = c->connection.asynccomm[1]; /* Fiid Objects */ if (!(c->connection.obj_rmcp_hdr_rq = fiid_obj_create (tmpl_rmcp_hdr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rmcp_hdr_rs = fiid_obj_create (tmpl_rmcp_hdr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_lan_session_hdr_rq = fiid_obj_create (tmpl_lan_session_hdr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_lan_session_hdr_rs = fiid_obj_create (tmpl_lan_session_hdr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_lan_msg_hdr_rq = fiid_obj_create (tmpl_lan_msg_hdr_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_lan_msg_hdr_rs = fiid_obj_create (tmpl_lan_msg_hdr_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_lan_msg_trlr_rs = fiid_obj_create (tmpl_lan_msg_trlr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rmcpplus_session_hdr_rq = fiid_obj_create (tmpl_rmcpplus_session_hdr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rmcpplus_session_hdr_rs = fiid_obj_create (tmpl_rmcpplus_session_hdr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rmcpplus_payload_rs = fiid_obj_create (tmpl_rmcpplus_payload))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rmcpplus_session_trlr_rq = fiid_obj_create (tmpl_rmcpplus_session_trlr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rmcpplus_session_trlr_rs = fiid_obj_create (tmpl_rmcpplus_session_trlr))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_authentication_capabilities_rq = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_authentication_capabilities_rs = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_open_session_request = fiid_obj_create (tmpl_rmcpplus_open_session_request))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_open_session_response = fiid_obj_create (tmpl_rmcpplus_open_session_response))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rakp_message_1 = fiid_obj_create (tmpl_rmcpplus_rakp_message_1))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rakp_message_2 = fiid_obj_create (tmpl_rmcpplus_rakp_message_2))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rakp_message_3 = fiid_obj_create (tmpl_rmcpplus_rakp_message_3))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_rakp_message_4 = fiid_obj_create (tmpl_rmcpplus_rakp_message_4))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_set_session_privilege_level_rq = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_set_session_privilege_level_rs = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_get_channel_payload_support_rq = fiid_obj_create (tmpl_cmd_get_channel_payload_support_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_get_channel_payload_support_rs = fiid_obj_create (tmpl_cmd_get_channel_payload_support_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_get_payload_activation_status_rq = fiid_obj_create (tmpl_cmd_get_payload_activation_status_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_get_payload_activation_status_rs = fiid_obj_create (tmpl_cmd_get_payload_activation_status_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_activate_payload_rq = fiid_obj_create (tmpl_cmd_activate_payload_sol_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_activate_payload_rs = fiid_obj_create (tmpl_cmd_activate_payload_sol_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_sol_payload_data_rq = fiid_obj_create (tmpl_sol_payload_data_remote_console_to_bmc))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_sol_payload_data_rs = fiid_obj_create (tmpl_sol_payload_data_bmc_to_remote_console))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_get_channel_payload_version_rq = fiid_obj_create (tmpl_cmd_get_channel_payload_version_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_get_channel_payload_version_rs = fiid_obj_create (tmpl_cmd_get_channel_payload_version_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_deactivate_payload_rq = fiid_obj_create (tmpl_cmd_deactivate_payload_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_deactivate_payload_rs = fiid_obj_create (tmpl_cmd_deactivate_payload_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_close_session_rq = fiid_obj_create (tmpl_cmd_close_session_rq))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } if (!(c->connection.obj_close_session_rs = fiid_obj_create (tmpl_cmd_close_session_rs))) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno))); ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY); goto cleanup; } return (0); cleanup: /* Previously called here, but this is now supposed to be handled in API land */ /* ipmiconsole_ctx_connection_cleanup(c) */ /* _ipmiconsole_ctx_fds_cleanup(c); */ /* _ipmiconsole_ctx_fds_setup(c); */ return (-1); }