static SilcThreadPoolThread silc_thread_pool_new_thread(SilcThreadPool tp) { SilcThreadPoolThread t; t = silc_scalloc(tp->stack, 1, sizeof(*t)); if (!t) return NULL; if (!silc_mutex_alloc(&t->lock)) { silc_sfree(tp->stack, t); return NULL; } if (!silc_cond_alloc(&t->thread_signal)) { silc_mutex_free(t->lock); silc_sfree(tp->stack, t); return NULL; } t->tp = tp; silc_list_init(t->queue, struct SilcThreadPoolThreadStruct, next); silc_list_init(t->free_queue, struct SilcThreadPoolThreadStruct, next); /* Add to thread pool */ silc_list_add(tp->threads, t); silc_list_add(tp->free_threads, t); silc_thread_pool_ref(tp); SILC_LOG_DEBUG(("Start thread %p", t)); /* Start the thread */ silc_thread_create(silc_thread_pool_run_thread, t, FALSE); return t; }
SilcThreadPool silc_thread_pool_alloc(SilcStack stack, SilcUInt32 min_threads, SilcUInt32 max_threads, SilcBool start_min_threads) { SilcThreadPool tp; int i; if (max_threads < min_threads) { silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT, "Max threads is smaller than min threads (%d < %d)", max_threads, min_threads); return NULL; } if (!max_threads) { silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT, "Max threads is 0"); return NULL; } if (stack) stack = silc_stack_alloc(0, stack); tp = silc_scalloc(stack, 1, sizeof(*tp)); if (!tp) { silc_stack_free(stack); return NULL; } SILC_LOG_DEBUG(("Starting thread pool %p, min threads %d, max threads %d", tp, min_threads, max_threads)); tp->stack = stack; tp->min_threads = min_threads; tp->max_threads = max_threads; tp->refcnt++; if (!silc_mutex_alloc(&tp->lock)) { silc_sfree(stack, tp); silc_stack_free(stack); return NULL; } if (!silc_cond_alloc(&tp->pool_signal)) { silc_mutex_free(tp->lock); silc_sfree(stack, tp); silc_stack_free(stack); return NULL; } silc_list_init(tp->threads, struct SilcThreadPoolThreadStruct, next); silc_list_init(tp->free_threads, struct SilcThreadPoolThreadStruct, next2); for (i = 0; i < tp->min_threads && start_min_threads; i++) silc_thread_pool_new_thread(tp); silc_list_start(tp->threads); return tp; }
SilcTls silc_thread_tls_init(void) { SilcTls tls; if (silc_thread_get_tls()) return silc_thread_get_tls(); /* Allocate Tls for the thread */ tls = (SilcTls)silc_calloc(1, sizeof(*tls)); if (!tls) return NULL; Dll::SetTls(tls); /* Allocate global lock */ silc_mutex_alloc(&tls->lock); return tls; }
SilcBool silc_rwlock_alloc(SilcRwLock *rwlock) { #ifdef SILC_THREADS *rwlock = (SilcRwLock)silc_calloc(1, sizeof(**rwlock)); if (!(*rwlock)) return FALSE; if (!silc_mutex_alloc(&(*rwlock)->mutex)) { silc_free(*rwlock); return FALSE; } if (!silc_cond_alloc(&(*rwlock)->cond)) { silc_mutex_free((*rwlock)->mutex); silc_free(*rwlock); return FALSE; } return TRUE; #else return FALSE; #endif /* SILC_THREADS */ }
SilcBool silc_client_init(SilcClient client, const char *username, const char *hostname, const char *realname, SilcClientRunning running, void *context) { SILC_LOG_DEBUG(("Initializing client")); if (!client) return FALSE; if (!username || !hostname) { SILC_LOG_ERROR(("Username and hostname must be given to " "silc_client_init")); return FALSE; } if (!realname) realname = username; /* Validate essential strings */ if (!silc_identifier_verify(username, strlen(username), SILC_STRING_UTF8, 128)) { SILC_LOG_ERROR(("Malformed username '%s'. Username must be UTF-8 string", client->username)); return FALSE; } if (!silc_identifier_verify(hostname, strlen(hostname), SILC_STRING_UTF8, 256)) { SILC_LOG_ERROR(("Malformed hostname '%s'. Hostname must be UTF-8 string", client->hostname)); return FALSE; } if (!silc_utf8_valid(realname, strlen(realname))) { SILC_LOG_ERROR(("Malformed realname '%s'. Realname must be UTF-8 string", client->realname)); return FALSE; } /* Take the name strings */ client->username = strdup(username); client->hostname = strdup(hostname); client->realname = strdup(realname); if (!username || !hostname || !realname) return FALSE; client->internal->ftp_sessions = silc_dlist_init(); if (!client->internal->ftp_sessions) return FALSE; if (!client->internal->params->dont_register_crypto_library) { /* Initialize the crypto library. If application has done this already this has no effect. Also, we will not be overriding something application might have registered earlier. */ silc_cipher_register_default(); silc_pkcs_register_default(); silc_hash_register_default(); silc_hmac_register_default(); } /* Initialize random number generator */ client->rng = silc_rng_alloc(); if (!client->rng) return FALSE; silc_rng_init(client->rng); silc_rng_global_init(client->rng); /* Initialize the scheduler */ client->schedule = silc_schedule_init(0, client); if (!client->schedule) return FALSE; /* Allocate client lock */ silc_mutex_alloc(&client->internal->lock); /* Register commands */ silc_client_commands_register(client); /* Start packet engine */ client->internal->packet_engine = silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs, client); if (!client->internal->packet_engine) return FALSE; /* Initialize and start the client FSM */ client->internal->running = running; client->internal->running_context = context; silc_fsm_init(&client->internal->fsm, client, NULL, NULL, client->schedule); silc_fsm_event_init(&client->internal->wait_event, &client->internal->fsm); silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run); /* Signal the application when we are running */ client->internal->run_callback = TRUE; SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event); return TRUE; }
SilcClientConnection silc_client_add_connection(SilcClient client, SilcConnectionType conn_type, SilcBool connect, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, char *remote_host, int port, SilcClientConnectCallback callback, void *context) { SilcClientConnection conn; SilcFSMThread thread; if (!callback) return NULL; SILC_LOG_DEBUG(("Adding new connection to %s:%d", remote_host, port)); conn = silc_calloc(1, sizeof(*conn)); if (!conn) return NULL; conn->client = client; conn->public_key = public_key; conn->private_key = private_key; conn->remote_host = strdup(remote_host); conn->remote_port = port ? port : 706; conn->type = conn_type; conn->callback = callback; conn->callback_context = context; conn->internal = silc_calloc(1, sizeof(*conn->internal)); if (!conn->internal) { silc_free(conn); return NULL; } conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN; silc_mutex_alloc(&conn->internal->lock); silc_atomic_init16(&conn->internal->cmd_ident, 0); if (!silc_hash_alloc("sha1", &conn->internal->sha1hash)) { silc_free(conn); silc_free(conn->internal); return NULL; } /* Set parameters */ if (params) { conn->internal->params = *params; conn->context = params->context; } if (!conn->internal->params.rekey_secs) conn->internal->params.rekey_secs = 3600; if (conn->internal->params.rekey_secs < 300) conn->internal->params.rekey_secs = 300; conn->internal->verbose = TRUE; silc_list_init(conn->internal->pending_commands, struct SilcClientCommandContextStruct, next); silc_list_init(conn->internal->thread_pool, SilcFSMThreadStruct, next); /* Allocate client, channel and serve caches */ if (conn_type != SILC_CONN_CLIENT) { conn->internal->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, NULL, NULL); conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, NULL); conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL, NULL); if (!conn->internal->client_cache || !conn->internal->channel_cache || !conn->internal->server_cache) { silc_client_del_connection(client, conn); return NULL; } } if (connect) { /* Initialize our async operation so that application may abort us while we're connecting. */ conn->internal->cop = silc_async_alloc(silc_client_connect_abort, NULL, conn); if (!conn->internal->cop) { silc_client_del_connection(client, conn); return NULL; } } /* Run the connection state machine. If threads are in use the connection machine is always run in a real thread. */ thread = silc_fsm_thread_alloc(&client->internal->fsm, conn, silc_client_connection_finished, NULL, client->internal->params->threads); if (!thread) { silc_client_del_connection(client, conn); return NULL; } silc_fsm_set_state_context(thread, client); silc_fsm_start(thread, silc_client_connection_st_start); SILC_LOG_DEBUG(("New connection %p", conn)); silc_atomic_add_int32(&client->internal->conns, 1); return conn; }