static wi_boolean_t _wi_settings_set_port(wi_settings_t *settings, wi_uinteger_t index, wi_string_t *name, wi_string_t *value) { struct servent *servent; wi_uinteger_t port; port = wi_string_uinteger(value); if(port > 65535) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_INVALIDPORT); return false; } if(port == 0) { servent = getservbyname(wi_string_cstring(value), "tcp"); if(!servent) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_NOSUCHSERVICE); return false; } port = servent->s_port; } *(wi_uinteger_t *) settings->spec[index].setting = port; return true; }
wi_terminal_t * wi_terminal_init_with_type(wi_terminal_t *terminal, wi_string_t *type) { char *env; int err, co, li; err = tgetent(NULL, wi_string_cstring(type)); if(err <= 0) { if(err == 0) wi_error_set_libwired_error(WI_ERROR_TERMCAP_NOSUCHENTRY); else wi_error_set_libwired_error(WI_ERROR_TERMCAP_TERMINFONOTFOUND); wi_release(terminal); return NULL; } env = getenv("COLUMNS"); co = env ? strtol(env, NULL, 10) : tgetnum("co"); terminal->co = (co <= 0) ? 80 : co; env = getenv("LINES"); li = env ? strtol(env, NULL, 10) : tgetnum("li"); terminal->li = (li <= 0) ? 24 : li; terminal->ce = (char *) tgetstr("ce", NULL); terminal->cl = (char *) tgetstr("cl", NULL); terminal->cm = (char *) tgetstr("cm", NULL); terminal->cs = (char *) tgetstr("cs", NULL); terminal->scroll = wi_make_range(0, terminal->li); terminal->buffers = wi_array_init_with_capacity(wi_mutable_array_alloc(), 10); return terminal; }
int wi_log_syslog_facility_with_name(wi_string_t *name) { #if HAVE_SYSLOG_FACILITYNAMES const char *cstring; int i; cstring = wi_string_cstring(name); for(i = 0; facilitynames[i].c_name != NULL; i++) { if(strcmp(cstring, facilitynames[i].c_name) == 0) break; } if(!facilitynames[i].c_name) { wi_error_set_libwired_error(WI_ERROR_LOG_NOSUCHFACILITY); return -1; } return facilitynames[i].c_val; #else wi_error_set_errno(ENOTSUP); return -1; #endif }
void wi_error_set_openssl_ssl_error_with_result(void *ssl, int result) { wi_error_t *error; int code; code = SSL_get_error(ssl, result); if(code == SSL_ERROR_SYSCALL) { if(ERR_peek_error() == 0) { if(result == 0) wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); else wi_error_set_errno(errno); } else { wi_error_set_openssl_error(); } } else if(code == SSL_ERROR_SSL) { wi_error_set_openssl_error(); } else { error = _wi_error_get_error(); error->domain = WI_ERROR_DOMAIN_OPENSSL_SSL; error->code = code; wi_release(error->string); switch(error->code) { case SSL_ERROR_NONE: error->string = wi_retain(WI_STR("SSL: No error")); break; case SSL_ERROR_ZERO_RETURN: error->string = wi_retain(WI_STR("SSL: Zero return")); break; case SSL_ERROR_WANT_READ: error->string = wi_retain(WI_STR("SSL: Want read")); break; case SSL_ERROR_WANT_WRITE: error->string = wi_retain(WI_STR("SSL: Want write")); break; case SSL_ERROR_WANT_CONNECT: error->string = wi_retain(WI_STR("SSL: Want connect")); break; case SSL_ERROR_WANT_ACCEPT: error->string = wi_retain(WI_STR("SSL: Want accept")); break; case SSL_ERROR_WANT_X509_LOOKUP: error->string = wi_retain(WI_STR("SSL: Want X509 lookup")); break; } } ERR_clear_error(); }
void wi_error_set_openssl_ssl_error_with_result(void *ssl, int result) { wi_string_t *string; int code; code = SSL_get_error(ssl, result); if(code == SSL_ERROR_SYSCALL) { if(ERR_peek_error() == 0) { if(result == 0) wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); else wi_error_set_errno(errno); } else { wi_error_set_openssl_error(); } } else if(code == SSL_ERROR_SSL) { wi_error_set_openssl_error(); } else { switch(code) { case SSL_ERROR_NONE: string = WI_STR("SSL: No error"); break; case SSL_ERROR_ZERO_RETURN: string = WI_STR("SSL: Zero return"); break; case SSL_ERROR_WANT_READ: string = WI_STR("SSL: Want read"); break; case SSL_ERROR_WANT_WRITE: string = WI_STR("SSL: Want write"); break; case SSL_ERROR_WANT_CONNECT: string = WI_STR("SSL: Want connect"); break; case SSL_ERROR_WANT_ACCEPT: string = WI_STR("SSL: Want accept"); break; case SSL_ERROR_WANT_X509_LOOKUP: string = WI_STR("SSL: Want X509 lookup"); break; default: string = NULL; break; } wi_error_set_error_with_string(WI_ERROR_DOMAIN_OPENSSL_SSL, code, string); } ERR_clear_error(); }
static wi_boolean_t _wi_settings_set_value(wi_settings_t *settings, wi_string_t *name, wi_string_t *value) { wi_uinteger_t index; wi_boolean_t result = false; index = _wi_settings_index_of_name(settings, name); if(index == WI_NOT_FOUND) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_UNKNOWNSETTING); return false; } wi_log_debug(WI_STR(" %@ = %@"), name, value); switch(settings->spec[index].type) { case WI_SETTINGS_NUMBER: result = _wi_settings_set_number(settings, index, name, value); break; case WI_SETTINGS_BOOL: result = _wi_settings_set_bool(settings, index, name, value); break; case WI_SETTINGS_STRING: result = _wi_settings_set_string(settings, index, name, value); break; case WI_SETTINGS_STRING_ARRAY: result = _wi_settings_set_string_array(settings, index, name, value); break; case WI_SETTINGS_PATH: result = _wi_settings_set_path(settings, index, name, value); break; case WI_SETTINGS_USER: result = _wi_settings_set_user(settings, index, name, value); break; case WI_SETTINGS_GROUP: result = _wi_settings_set_group(settings, index, name, value); break; case WI_SETTINGS_PORT: result = _wi_settings_set_port(settings, index, name, value); break; case WI_SETTINGS_REGEXP: result = _wi_settings_set_regexp(settings, index, name, value); break; case WI_SETTINGS_TIME_INTERVAL: result = _wi_settings_set_time_interval(settings, index, name, value); break; } return result; }
wi_boolean_t wi_socket_tls_set_ciphers(wi_socket_tls_t *tls, wi_string_t *ciphers) { if(SSL_CTX_set_cipher_list(tls->ssl_ctx, wi_string_cstring(ciphers)) != 1) { wi_error_set_libwired_error(WI_ERROR_SOCKET_NOVALIDCIPHER); return false; } return true; }
static wi_integer_t _wi_socket_read_buffer(wi_socket_t *socket, wi_time_interval_t timeout, void *buffer, size_t length) { wi_socket_state_t state; wi_integer_t bytes; #ifdef HAVE_OPENSSL_SSL_H if(socket->ssl) { if(timeout > 0.0 && SSL_pending(socket->ssl) == 0) { state = wi_socket_wait_descriptor(socket->sd, timeout, true, false); if(state != WI_SOCKET_READY) { if(state == WI_SOCKET_TIMEOUT) wi_error_set_errno(ETIMEDOUT); return -1; } } ERR_clear_error(); bytes = SSL_read(socket->ssl, buffer, length); if(bytes <= 0) { wi_error_set_openssl_ssl_error_with_result(socket->ssl, bytes); ERR_clear_error(); } return bytes; } else { #endif if(timeout > 0.0) { state = wi_socket_wait_descriptor(socket->sd, timeout, true, false); if(state != WI_SOCKET_READY) { if(state == WI_SOCKET_TIMEOUT) wi_error_set_errno(ETIMEDOUT); return -1; } } bytes = read(socket->sd, buffer, length); if(bytes <= 0) { if(bytes < 0) wi_error_set_errno(errno); else wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); } return bytes; #ifdef HAVE_OPENSSL_SSL_H } #endif return 0; }
wi_cipher_t * wi_cipher_init_with_key(wi_cipher_t *cipher, wi_cipher_type_t type, wi_data_t *key, wi_data_t *iv) { if(!_wi_cipher_set_type(cipher, type)) { wi_error_set_libwired_error(WI_ERROR_CIPHER_CIPHERNOTSUPP); wi_release(cipher); return NULL; } return _wi_cipher_init_with_key(cipher, key, iv); }
wi_cipher_t * wi_cipher_init_with_random_key(wi_cipher_t *cipher, wi_cipher_type_t type) { wi_data_t *key, *iv; if(!_wi_cipher_set_type(cipher, type)) { wi_error_set_libwired_error(WI_ERROR_CIPHER_CIPHERNOTSUPP); wi_release(cipher); return NULL; } key = wi_data_with_random_bytes(wi_cipher_bits(cipher) / 8); iv = wi_data_with_random_bytes(wi_cipher_block_size(cipher)); return _wi_cipher_init_with_key(cipher, key, iv); }
wi_p7_message_t * wi_p7_message_init_with_bytes(wi_p7_message_t *p7_message, const void *bytes, wi_uinteger_t length, wi_p7_serialization_t serialization, wi_p7_spec_t *p7_spec) { p7_message->spec = wi_retain(p7_spec); p7_message->binary_size = length; p7_message->binary_capacity = p7_message->binary_size; p7_message->binary_buffer = wi_malloc(p7_message->binary_capacity); memcpy(p7_message->binary_buffer, bytes, p7_message->binary_size); wi_p7_message_deserialize(p7_message, WI_P7_BINARY); if(!p7_message->name) { wi_error_set_libwired_error(WI_ERROR_P7_UNKNOWNMESSAGE); wi_release(p7_message); return NULL; } return p7_message; }
wi_boolean_t _wi_settings_set_group(wi_settings_t *settings, wi_uinteger_t index, wi_string_t *name, wi_string_t *value) { struct group *group; uint32_t gid; group = getgrnam(wi_string_cstring(value)); if(!group) { gid = wi_string_uint32(value); if(gid != 0 || wi_is_equal(value, WI_STR("0"))) group = getgrgid(wi_string_uint32(value)); } if(!group) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_NOSUCHGROUP); return false; } *(gid_t *) settings->spec[index].setting = group->gr_gid; return true; }
wi_boolean_t _wi_settings_set_user(wi_settings_t *settings, wi_uinteger_t index, wi_string_t *name, wi_string_t *value) { struct passwd *user; uint32_t uid; user = getpwnam(wi_string_cstring(value)); if(!user) { uid = wi_string_uint32(value); if(uid != 0 || wi_is_equal(value, WI_STR("0"))) user = getpwuid(uid); } if(!user) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_NOSUCHUSER); return false; } *(uid_t *) settings->spec[index].setting = user->pw_uid; return true; }
static wi_boolean_t _wi_settings_parse_setting(wi_settings_t *settings, wi_string_t *string) { wi_array_t *array; wi_string_t *name, *value; wi_boolean_t result = false; array = wi_string_components_separated_by_string(string, WI_STR("=")); if(wi_array_count(array) != 2) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_SYNTAXERROR); _wi_settings_log_error(settings, string); return false; } name = wi_string_by_deleting_surrounding_whitespace(WI_ARRAY(array, 0)); value = wi_string_by_deleting_surrounding_whitespace(WI_ARRAY(array, 1)); result = _wi_settings_set_value(settings, name, value); if(!result) _wi_settings_log_error(settings, name); return result; }
wi_boolean_t wi_config_read_file(wi_config_t *config) { wi_enumerator_t *enumerator; wi_runtime_instance_t *instance; wi_file_t *file; wi_mutable_array_t *array; wi_mutable_dictionary_t *previous_values; wi_string_t *string, *name, *value; wi_config_type_t type; file = wi_file_for_reading(config->path); if(!file) { wi_log_err(WI_STR("Could not open %@: %m"), config->path); return false; } wi_log_info(WI_STR("Reading %@"), config->path); config->line = 0; wi_lock_lock(config->lock); previous_values = config->values; config->values = wi_dictionary_init(wi_mutable_dictionary_alloc()); if(config->defaults) { enumerator = wi_dictionary_key_enumerator(config->defaults); while((name = wi_enumerator_next_data(enumerator))) { // instance = wi_mutable_copy(wi_dictionary_data_for_key(config->defaults, name)); instance = wi_dictionary_data_for_key(config->defaults, name); if(wi_runtime_id(instance) == wi_array_runtime_id()) instance = wi_autorelease(wi_mutable_copy(instance)); wi_mutable_dictionary_set_data_for_key(config->values, instance, name); // wi_release(instance); } } while((string = wi_file_read_line(file))) { config->line++; if(wi_string_length(string) > 0 && !wi_string_has_prefix(string, WI_STR("#"))) { if(_wi_config_parse_string(config, string, &name, &value)) { instance = _wi_config_instance_for_setting(config, name, value, &type); if(instance) { wi_log_debug(WI_STR(" %@ = %@"), name, value); if(type == WI_CONFIG_STRINGLIST) { array = wi_dictionary_data_for_key(config->values, name); if(!array) { array = wi_mutable_array(); wi_mutable_dictionary_set_data_for_key(config->values, array, name); } wi_mutable_array_add_data(array, instance); } else { wi_mutable_dictionary_set_data_for_key(config->values, instance, name); } } else { _wi_config_log_error(config, name); } } else { wi_error_set_libwired_error(WI_ERROR_SETTINGS_SYNTAXERROR); _wi_config_log_error(config, string); } } } enumerator = wi_dictionary_key_enumerator(config->values); while((name = wi_enumerator_next_data(enumerator))) { instance = wi_dictionary_data_for_key(config->values, name); if(!previous_values || !wi_is_equal(instance, wi_dictionary_data_for_key(previous_values, name))) wi_mutable_set_add_data(config->changes, name); } wi_release(previous_values); wi_lock_unlock(config->lock); return true; }
static wi_runtime_instance_t * _wi_config_instance_for_setting(wi_config_t *config, wi_string_t *name, wi_string_t *value, wi_config_type_t *type) { struct passwd *user; struct group *group; struct servent *servent; wi_uinteger_t port; uint32_t uid, gid; if(!wi_dictionary_contains_key(config->types, name)) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_UNKNOWNSETTING); return NULL; } *type = wi_number_int32(wi_dictionary_data_for_key(config->types, name)); switch(*type) { case WI_CONFIG_INTEGER: return wi_number_with_integer(wi_string_integer(value)); break; case WI_CONFIG_BOOL: return wi_number_with_bool(wi_string_bool(value)); break; case WI_CONFIG_STRING: case WI_CONFIG_STRINGLIST: case WI_CONFIG_PATH: return value; break; case WI_CONFIG_USER: user = getpwnam(wi_string_cstring(value)); if(!user) { uid = wi_string_uint32(value); if(uid != 0 || wi_is_equal(value, WI_STR("0"))) user = getpwuid(uid); } if(!user) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_NOSUCHUSER); return NULL; } return wi_number_with_int32(user->pw_uid); break; case WI_CONFIG_GROUP: group = getgrnam(wi_string_cstring(value)); if(!group) { gid = wi_string_uint32(value); if(gid != 0 || wi_is_equal(value, WI_STR("0"))) group = getgrgid(gid); } if(!group) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_NOSUCHGROUP); return NULL; } return wi_number_with_int32(group->gr_gid); break; case WI_CONFIG_PORT: port = wi_string_uinteger(value); if(port > 65535) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_INVALIDPORT); return NULL; } if(port == 0) { servent = getservbyname(wi_string_cstring(value), "tcp"); if(!servent) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_NOSUCHSERVICE); return NULL; } port = servent->s_port; } return wi_number_with_int32(port); break; case WI_CONFIG_REGEXP: return wi_autorelease(wi_regexp_init_with_string(wi_regexp_alloc(), value)); break; case WI_CONFIG_TIME_INTERVAL: return wi_number_with_double(wi_string_double(value)); break; } return NULL; }
static wi_boolean_t _wi_config_write_setting_to_file(wi_config_t *config, wi_string_t *name, wi_file_t *file) { wi_runtime_instance_t *value; wi_config_type_t type; struct passwd *user; struct group *group; wi_uinteger_t i, count; if(!wi_dictionary_contains_key(config->types, name)) { wi_error_set_libwired_error(WI_ERROR_SETTINGS_UNKNOWNSETTING); return false; } type = wi_number_int32(wi_dictionary_data_for_key(config->types, name)); value = wi_dictionary_data_for_key(config->values, name); if(!value) return false; switch(type) { case WI_CONFIG_INTEGER: wi_file_write_format(file, WI_STR("%@ = %d\n"), name, wi_number_integer(value)); break; case WI_CONFIG_BOOL: wi_file_write_format(file, WI_STR("%@ = %@\n"), name, wi_number_bool(value) ? WI_STR("yes") : WI_STR("no")); break; case WI_CONFIG_STRING: wi_file_write_format(file, WI_STR("%@ = %@\n"), name, value); break; case WI_CONFIG_STRINGLIST: count = wi_array_count(value); for(i = 0; i < count; i++) wi_file_write_format(file, WI_STR("%@ = %@\n"), name, WI_ARRAY(value, i)); break; case WI_CONFIG_PATH: wi_file_write_format(file, WI_STR("%@ = %@\n"), name, value); break; case WI_CONFIG_USER: user = getpwuid(wi_number_int32(value)); if(user) wi_file_write_format(file, WI_STR("%@ = %s\n"), name, user->pw_name); else wi_file_write_format(file, WI_STR("%@ = %d\n"), name, wi_number_int32(value)); break; case WI_CONFIG_GROUP: group = getgrgid(wi_number_int32(value)); if(group) wi_file_write_format(file, WI_STR("%@ = %s\n"), name, group->gr_name); else wi_file_write_format(file, WI_STR("%@ = %d\n"), name, wi_number_int32(value)); break; case WI_CONFIG_PORT: wi_file_write_format(file, WI_STR("%@ = %d\n"), name, wi_number_int32(value)); break; case WI_CONFIG_REGEXP: wi_file_write_format(file, WI_STR("%@ = %@\n"), name, wi_regexp_string(value)); break; case WI_CONFIG_TIME_INTERVAL: wi_file_write_format(file, WI_STR("%@ = %.2f\n"), name, wi_number_double(value)); break; } return true; }
wi_integer_t wi_socket_read_buffer(wi_socket_t *socket, wi_time_interval_t timeout, void *buffer, size_t length) { wi_time_interval_t interval; wi_socket_state_t state; wi_uinteger_t offset; wi_integer_t bytes; WI_ASSERT(buffer != NULL, "buffer of length %u should not be NULL", length); if(timeout > 0.0) { #ifdef HAVE_OPENSSL_SSL_H if(!socket->ssl || (socket->ssl && SSL_pending(socket->ssl) == 0)) { #endif state = wi_socket_wait_descriptor(socket->sd, timeout, true, false); if(state != WI_SOCKET_READY) { if(state == WI_SOCKET_TIMEOUT) wi_error_set_errno(ETIMEDOUT); return -1; } #ifdef HAVE_OPENSSL_SSL_H } #endif } interval = 0.0; #ifdef HAVE_OPENSSL_SSL_H if(socket->ssl) { do { bytes = SSL_read(socket->ssl, buffer, length); if(bytes <= 0) { if(bytes < 0 && SSL_get_error(socket->ssl, bytes) == SSL_ERROR_WANT_READ) { wi_thread_sleep(0.1); if(timeout > 0.0) { interval += 0.1; if(interval >= timeout) { wi_error_set_errno(ETIMEDOUT); break; } } } else { wi_error_set_openssl_ssl_error_with_result(socket->ssl, bytes); socket->broken = true; break; } } } while(bytes <= 0); return bytes; } else { #endif offset = 0; do { bytes = read(socket->sd, buffer + offset, length - offset); if(bytes <= 0) { if(bytes < 0) wi_error_set_errno(errno); else wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); return bytes; } offset += bytes; if(offset < length) { wi_thread_sleep(0.1); if(timeout > 0.0) { interval += 0.1; if(interval >= timeout) { wi_error_set_errno(ETIMEDOUT); return -1; } } } } while(offset < length); return offset; #ifdef HAVE_OPENSSL_SSL_H } #endif return 0; }
wi_integer_t wi_socket_write_buffer(wi_socket_t *socket, wi_time_interval_t timeout, const void *buffer, size_t length) { wi_socket_state_t state; wi_uinteger_t offset; wi_integer_t bytes; WI_ASSERT(buffer != NULL, "buffer of length %u should not be NULL", length); WI_ASSERT(socket->sd >= 0, "socket %@ should be valid", socket); #ifdef HAVE_OPENSSL_SSL_H if(socket->ssl) { while(true) { if(timeout > 0.0) { state = wi_socket_wait_descriptor(socket->sd, timeout, false, true); if(state != WI_SOCKET_READY) { if(state == WI_SOCKET_TIMEOUT) wi_error_set_errno(ETIMEDOUT); return -1; } } ERR_clear_error(); bytes = SSL_write(socket->ssl, buffer, length); if(bytes > 0) { break; } else { if(bytes < 0 && SSL_get_error(socket->ssl, bytes) == SSL_ERROR_WANT_WRITE) continue; wi_error_set_openssl_ssl_error_with_result(socket->ssl, bytes); break; } } ERR_clear_error(); return bytes; } else { #endif offset = 0; while(offset < length) { if(timeout > 0.0) { state = wi_socket_wait_descriptor(socket->sd, timeout, false, true); if(state != WI_SOCKET_READY) { if(state == WI_SOCKET_TIMEOUT) wi_error_set_errno(ETIMEDOUT); return -1; } } bytes = write(socket->sd, buffer + offset, length - offset); if(bytes > 0) { offset += bytes; } else { if(bytes < 0) wi_error_set_errno(errno); else wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); return bytes; } } return offset; #ifdef HAVE_OPENSSL_SSL_H } #endif return 0; }