/* * init.c - initialization and finalization of the library * * This file is part of the SSH Library * * Copyright (c) 2003-2009 by Aris Adamantiadis * * The SSH Library 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.1 of the License, or (at your * option) any later version. * * The SSH Library 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 the SSH Library; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ #include "config.h" #include "libssh/priv.h" #include "libssh/socket.h" #include "libssh/dh.h" #include "libssh/poll.h" #include "libssh/threads.h" #ifdef _WIN32 #include #endif #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE #define CONSTRUCTOR_ATTRIBUTE __attribute__((constructor)) #else #define CONSTRUCTOR_ATTRIBUTE #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */ #ifdef HAVE_DESTRUCTOR_ATTRIBUTE #define DESTRUCTOR_ATTRIBUTE __attribute__((destructor)) #else #define DESTRUCTOR_ATTRIBUTE #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */ /* Declare static mutex */ static SSH_MUTEX ssh_init_mutex = SSH_MUTEX_STATIC_INIT; /* Counter for initializations */ static int _ssh_initialized = 0; /* Cache the returned value */ static int _ssh_init_ret = 0; void libssh_constructor(void) CONSTRUCTOR_ATTRIBUTE; void libssh_destructor(void) DESTRUCTOR_ATTRIBUTE; static int _ssh_init(unsigned constructor) { int rc = 0; if (!constructor) { ssh_mutex_lock(&ssh_init_mutex); } _ssh_initialized++; if (_ssh_initialized > 1) { rc = _ssh_init_ret; goto _ret; } rc = ssh_threads_init(); if (rc) { goto _ret; } rc = ssh_crypto_init(); if (rc) { goto _ret; } rc = ssh_dh_init(); if (rc) { goto _ret; } rc = ssh_socket_init(); if (rc) { goto _ret; } _ret: _ssh_init_ret = rc; if (!constructor) { ssh_mutex_unlock(&ssh_init_mutex); } return rc; } /** * @brief Initialize global cryptographic data structures. * * This function is automatically called when the library is loaded. * */ void libssh_constructor(void) { int rc; rc = _ssh_init(1); if (rc < 0) { fprintf(stderr, "Error in auto_init()\n"); } return; } /** * @defgroup libssh The libssh API * * The libssh library is implementing the SSH protocols and some of its * extensions. This group of functions is mostly used to implement an SSH * client. * Some functions are needed to implement an SSH server too. * * @{ */ /** * @brief Initialize global cryptographic data structures. * * Since version 0.8.0, when libssh is dynamically linked, it is not necessary * to call this function on systems that fully support threading (that is, * systems with pthreads available). * * If libssh is statically linked, it is necessary to explicitly call ssh_init() * before calling any other provided API, and it is necessary to explicitly call * ssh_finalize() to free the allocated resources before exiting. * * If the library is already initialized, increments the _ssh_initialized * counter and return the error code cached in _ssh_init_ret. * * @returns SSH_OK on success, SSH_ERROR if an error occurred. * * @see ssh_finalize() */ int ssh_init(void) { return _ssh_init(0); } static int _ssh_finalize(unsigned destructor) { if (!destructor) { ssh_mutex_lock(&ssh_init_mutex); if (_ssh_initialized > 1) { _ssh_initialized--; ssh_mutex_unlock(&ssh_init_mutex); return 0; } if (_ssh_initialized == 1) { if (_ssh_init_ret < 0) { ssh_mutex_unlock(&ssh_init_mutex); return 0; } } } /* If the counter reaches zero or it is the destructor calling, finalize */ ssh_dh_finalize(); ssh_crypto_finalize(); ssh_socket_cleanup(); /* It is important to finalize threading after CRYPTO because * it still depends on it */ ssh_threads_finalize(); _ssh_initialized = 0; if (!destructor) { ssh_mutex_unlock(&ssh_init_mutex); } #if (defined(_WIN32) && !defined(HAVE_PTHREAD)) if (ssh_init_mutex != NULL) { DeleteCriticalSection(ssh_init_mutex); SAFE_FREE(ssh_init_mutex); } #endif return 0; } /** * @brief Finalize and clean up all libssh and cryptographic data structures. * * This function is automatically called when the library is unloaded. * */ void libssh_destructor(void) { int rc; rc = _ssh_finalize(1); if (rc < 0) { fprintf(stderr, "Error in libssh_destructor()\n"); } } /** * @brief Finalize and clean up all libssh and cryptographic data structures. * * Since version 0.8.0, when libssh is dynamically linked, it is not necessary * to call this function, since it is automatically called when the library is * unloaded. * * If libssh is statically linked, it is necessary to explicitly call ssh_init() * before calling any other provided API, and it is necessary to explicitly call * ssh_finalize() to free the allocated resources before exiting. * * If ssh_init() is called explicitly, then ssh_finalize() must be called * explicitly. * * When called, decrements the counter _ssh_initialized. If the counter reaches * zero, then the libssh and cryptographic data structures are cleaned up. * * @returns 0 on success, -1 if an error occurred. * * @see ssh_init() */ int ssh_finalize(void) { return _ssh_finalize(0); } #ifdef _WIN32 #if defined(_MSC_VER) && !defined(LIBSSH_STATIC) /* Library constructor and destructor */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { int rc = 0; switch(fdwReason) { case DLL_PROCESS_ATTACH: rc = _ssh_init(1); if (rc != 0) { fprintf(stderr, "DllMain: ssh_init failed!"); return FALSE; } break; case DLL_PROCESS_DETACH: _ssh_finalize(1); break; default: break; } return TRUE; } #endif /* _MSC_VER && !LIBSSH_STATIC */ #endif /* _WIN32 */ /** * @internal * @brief Return whether the library is initialized * * @returns true if the library is initialized; false otherwise. * * @see ssh_init() */ bool is_ssh_initialized() { bool is_initialized = false; ssh_mutex_lock(&ssh_init_mutex); is_initialized = _ssh_initialized > 0; ssh_mutex_unlock(&ssh_init_mutex); return is_initialized; } /** @} */