wi_boolean_t wi_socket_listen(wi_socket_t *_socket, uint32_t backlog) { struct sockaddr *sa; uint32_t length; sa = wi_address_sa(_socket->address); length = wi_address_sa_length(_socket->address); if(bind(_socket->sd, sa, length) < 0) { wi_error_set_errno(errno); return false; } if(_socket->type == WI_SOCKET_TCP) { if(listen(_socket->sd, backlog) < 0) { wi_error_set_errno(errno); return false; } } _socket->direction = WI_SOCKET_READ; return true; }
wi_boolean_t wi_socket_wait_descriptor(int sd, wi_time_interval_t timeout, wi_boolean_t read, wi_boolean_t write) { struct timeval tv; fd_set rfds, wfds; int state; tv = wi_dtotv(timeout); FD_ZERO(&rfds); FD_ZERO(&wfds); if(read) FD_SET(sd, &rfds); if(write) FD_SET(sd, &wfds); state = select(sd + 1, &rfds, &wfds, NULL, (timeout > 0.0) ? &tv : NULL); if(state < 0) wi_error_set_errno(errno); else if(state == 0) wi_error_set_errno(ETIMEDOUT); return (state > 0); }
wi_boolean_t wi_switch_user(uid_t uid, gid_t gid) { struct passwd *user; if(gid != getegid()) { user = getpwuid(uid); if(user) { if(initgroups(user->pw_name, gid) < 0) { wi_error_set_errno(errno); return false; } } if(setgid(gid) < 0) { wi_error_set_errno(errno); return false; } } if(uid != geteuid()) { if(setuid(uid) < 0) { wi_error_set_errno(errno); 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_boolean_t wi_thread_create_thread_with_priority(wi_thread_func_t *function, wi_runtime_instance_t *argument, double priority) { #ifdef WI_PTHREADS #if defined(HAVE_PTHREAD_ATTR_SETSCHEDPOLICY) && defined(HAVE_SCHED_GET_PRIORITY_MIN) && defined(HAVE_SCHED_GET_PRIORITY_MAX) struct sched_param param; int min, max; #endif pthread_t thread; pthread_attr_t attr; void **vector; int err; vector = wi_malloc(2 * sizeof(void *)); vector[0] = function; vector[1] = wi_retain(argument); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #if defined(HAVE_PTHREAD_ATTR_SETSCHEDPOLICY) && defined(HAVE_SCHED_GET_PRIORITY_MIN) && defined(HAVE_SCHED_GET_PRIORITY_MAX) min = sched_get_priority_min(SCHED_OTHER); max = sched_get_priority_max(SCHED_OTHER); if(min > 0 && max > 0) param.sched_priority = min + ((max - min) * priority); else param.sched_priority = 0; pthread_attr_setschedpolicy(&attr, SCHED_OTHER); pthread_attr_setschedparam(&attr, ¶m); #endif err = pthread_create(&thread, &attr, _wi_thread_trampoline, vector); pthread_attr_destroy(&attr); if(err != 0) { wi_error_set_errno(err); wi_release(vector[1]); wi_free(vector); return false; } return true; #else wi_error_set_errno(WI_ERROR_THREADS_NOTSUPP); return false; #endif }
int32_t wi_socket_recvfrom(wi_socket_t *socket, wi_socket_context_t *context, char *buffer, size_t length, wi_address_t **address) { struct sockaddr_storage ss; char *inbuffer = NULL; socklen_t sslength; int bytes; sslength = sizeof(ss); #ifdef WI_SSL if(context && context->priv_rsa) { inbuffer = wi_malloc(length); bytes = recvfrom(socket->sd, inbuffer, length, 0, (struct sockaddr *) &ss, &sslength); if(bytes < 0) { wi_error_set_errno(errno); goto end; } bytes = RSA_private_decrypt(bytes, (unsigned char *) inbuffer, (unsigned char *) buffer, context->priv_rsa, RSA_PKCS1_OAEP_PADDING); if(bytes < 0) { wi_error_set_ssl_error(); goto end; } } else { #endif bytes = recvfrom(socket->sd, buffer, length, 0, (struct sockaddr *) &ss, &sslength); if(bytes < 0) { wi_error_set_errno(errno); goto end; } #ifdef WI_SSL } #endif end: *address = (sslength > 0) ? wi_autorelease(wi_address_init_with_sa(wi_address_alloc(), (struct sockaddr *) &ss)) : NULL; if(inbuffer) wi_free(inbuffer); return bytes; }
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 }
wi_file_t * wi_file_init_with_path(wi_file_t *file, wi_string_t *path, wi_file_mode_t mode) { int flags; if(mode & WI_FILE_WRITING) flags = O_CREAT; else flags = 0; if((mode & WI_FILE_READING) && (mode & WI_FILE_WRITING)) flags |= O_RDWR; else if(mode & WI_FILE_READING) flags |= O_RDONLY; else if(mode & WI_FILE_WRITING) flags |= O_WRONLY; if(mode & WI_FILE_WRITING) { if(mode & WI_FILE_UPDATING) flags |= O_APPEND; else flags |= O_TRUNC; } file->fd = open(wi_string_cstring(path), flags, 0666); if(file->fd < 0) { wi_error_set_errno(errno); wi_release(file); return NULL; } return file; }
wi_array_t * wi_file_directory_contents_at_path(wi_string_t *path) { wi_array_t *contents; wi_string_t *name; DIR *dir; struct dirent de, *dep; dir = opendir(wi_string_cstring(path)); if(!dir) { wi_error_set_errno(errno); return NULL; } contents = wi_array_init_with_capacity(wi_array_alloc(), 100); while(readdir_r(dir, &de, &dep) == 0 && dep) { if(strcmp(dep->d_name, ".") != 0 && strcmp(dep->d_name, "..") != 0) { name = wi_string_init_with_cstring(wi_string_alloc(), dep->d_name); wi_array_add_data(contents, name); wi_release(name); } } closedir(dir); return wi_autorelease(contents); }
wi_socket_t * wi_socket_init_with_address(wi_socket_t *_socket, wi_address_t *address, wi_socket_type_t type) { _socket->address = wi_copy(address); _socket->close = true; _socket->buffer = wi_string_init_with_capacity(wi_string_alloc(), WI_SOCKET_BUFFER_SIZE); _socket->type = type; _socket->sd = socket(wi_address_family(_socket->address), _socket->type, 0); if(_socket->sd < 0) { wi_error_set_errno(errno); wi_release(_socket); return NULL; } if(!_wi_socket_set_option_int(_socket, SOL_SOCKET, SO_REUSEADDR, 1)) { wi_release(_socket); return NULL; } #ifdef SO_REUSEPORT if(!_wi_socket_set_option_int(_socket, SOL_SOCKET, SO_REUSEPORT, 1)) { wi_release(_socket); return NULL; } #endif return _socket; }
wi_socket_state_t wi_socket_wait_descriptor(int sd, wi_time_interval_t timeout, wi_boolean_t read, wi_boolean_t write) { struct timeval tv; fd_set rfds, wfds; int state; tv = wi_dtotv(timeout); FD_ZERO(&rfds); FD_ZERO(&wfds); WI_ASSERT(sd >= 0, "%d should be positive", sd); WI_ASSERT(sd < (int) FD_SETSIZE, "%d should be less than %d", sd, FD_SETSIZE); WI_ASSERT(read || write, "read and write can't both be false"); if(read) FD_SET(sd, &rfds); if(write) FD_SET(sd, &wfds); state = select(sd + 1, &rfds, &wfds, NULL, (timeout > 0.0) ? &tv : NULL); if(state < 0) { wi_error_set_errno(errno); return WI_SOCKET_ERROR; } if(state == 0) return WI_SOCKET_TIMEOUT; return WI_SOCKET_READY; }
wi_socket_state_t wi_socket_wait_descriptor(int sd, wi_time_interval_t timeout, wi_boolean_t read, wi_boolean_t write) { struct timeval tv; fd_set rfds, wfds; int state; tv = wi_dtotv(timeout); FD_ZERO(&rfds); FD_ZERO(&wfds); if(read) FD_SET(sd, &rfds); if(write) FD_SET(sd, &wfds); state = select(sd + 1, &rfds, &wfds, NULL, (timeout > 0.0) ? &tv : NULL); if(state < 0) { wi_error_set_errno(errno); return WI_SOCKET_ERROR; } if(state == 0) return WI_SOCKET_TIMEOUT; return WI_SOCKET_READY; }
wi_boolean_t wi_file_copy(wi_string_t *frompath, wi_string_t *topath) { struct stat sb; int err; wi_boolean_t result; if(!wi_file_lstat(frompath, &sb)) return false; if(wi_file_lstat(topath, &sb)) return false; if(S_ISDIR(sb.st_mode)) result = _wi_file_copy_directory(frompath, topath); else result = _wi_file_copy_file(frompath, topath); if(!result) { err = errno; wi_file_delete(topath); wi_error_set_errno(err); } return result; }
wi_x509_t * wi_x509_init_with_pem_file(wi_x509_t *x509, wi_string_t *path) { FILE *fp; fp = fopen(wi_string_cstring(path), "r"); if(!fp) { wi_error_set_errno(errno); wi_release(x509); return NULL; } x509->x509 = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if(!x509->x509) { wi_error_set_openssl_error(); wi_release(x509); return NULL; } return x509; }
wi_rsa_t * wi_rsa_init_with_pem_file(wi_rsa_t *rsa, wi_string_t *path) { FILE *fp; fp = fopen(wi_string_cstring(path), "r"); if(!fp) { wi_error_set_errno(errno); wi_release(rsa); return NULL; } rsa->rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); fclose(fp); if(!rsa->rsa) { wi_error_set_openssl_error(); wi_release(rsa); return NULL; } return rsa; }
wi_socket_t * wi_socket_accept(wi_socket_t *accept_socket, wi_time_interval_t timeout, wi_address_t **address) { wi_socket_t *socket; struct sockaddr_storage ss; socklen_t length; int sd, err = 0; length = sizeof(ss); sd = accept(accept_socket->sd, (struct sockaddr *) &ss, &length); if(sd < 0) err = errno; *address = (length > 0) ? wi_autorelease(wi_address_init_with_sa(wi_address_alloc(), (struct sockaddr *) &ss)) : NULL; if(sd < 0) { wi_error_set_errno(err); return NULL; } socket = wi_socket_init_with_descriptor(wi_socket_alloc(), sd); socket->close = true; socket->address = wi_retain(*address); socket->type = accept_socket->type; socket->direction = WI_SOCKET_READ; socket->interactive = accept_socket->interactive; return wi_autorelease(socket); }
wi_integer_t wi_file_write_bytes(wi_file_t *file, const void *buffer, wi_uinteger_t length) { wi_uinteger_t offset; wi_integer_t bytes; _WI_FILE_ASSERT_OPEN(file); offset = 0; while(offset < length) { bytes = write(file->fd, buffer + offset, length - offset); if(bytes > 0) { offset += bytes; file->offset += bytes; } else { if(bytes == 0) { return offset; } else { if(errno == EINTR) { continue; } else { wi_error_set_errno(errno); return -1; } } } } return offset; }
wi_boolean_t wi_data_write_to_file(wi_data_t *data, wi_string_t *path) { FILE *fp; wi_string_t *fullpath; fullpath = wi_string_by_appending_string(path, WI_STR("~")); fp = fopen(wi_string_cstring(fullpath), "w"); if(!fp) { wi_error_set_errno(errno); return false; } fwrite(data->bytes, 1, data->length, fp); fclose(fp); if(!wi_fs_rename_path(fullpath, path)) { wi_fs_delete_path(fullpath); return false; } return true; }
int32_t wi_socket_write_buffer(wi_socket_t *socket, wi_time_interval_t timeout, const void *buffer, size_t length) { int bytes; if(timeout > 0.0) { if(wi_socket_wait_descriptor(socket->sd, timeout, false, true) <= 0) return -1; } #ifdef WI_SSL if(socket->ssl) { bytes = SSL_write(socket->ssl, buffer, length); if(bytes < 0) { wi_error_set_ssl_error(); socket->broken = true; } } else { #endif bytes = write(socket->sd, buffer, length); if(bytes < 0) wi_error_set_errno(errno); #ifdef WI_SSL } #endif return bytes; }
wi_boolean_t wi_socket_context_set_ssl_privkey(wi_socket_context_t *context, wi_string_t *path) { #ifdef WI_SSL FILE *fp; fp = fopen(wi_string_cstring(path), "r"); if(!fp) { wi_error_set_errno(errno); return false; } context->priv_rsa = PEM_read_RSAPrivateKey(fp, NULL, 0, NULL); if(!context->priv_rsa) wi_error_set_ssl_error(); fclose(fp); return (context->priv_rsa != NULL); #else wi_error_set_lib_error(WI_ERROR_SOCKET_NOSSL); return false; #endif }
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(); }
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(); }
wi_boolean_t wi_file_statfs(wi_string_t *path, wi_file_statfs_t *sfp) { #ifdef HAVE_STATVFS struct statvfs sfvb; if(statvfs(wi_string_cstring(path), &sfvb) < 0) { wi_error_set_errno(errno); return false; } sfp->f_bsize = sfvb.f_bsize; sfp->f_frsize = sfvb.f_frsize; sfp->f_blocks = sfvb.f_blocks; sfp->f_bfree = sfvb.f_bfree; sfp->f_bavail = sfvb.f_bavail; sfp->f_files = sfvb.f_files; sfp->f_ffree = sfvb.f_ffree; sfp->f_favail = sfvb.f_favail; sfp->f_fsid = sfvb.f_fsid; sfp->f_flag = sfvb.f_flag; sfp->f_namemax = sfvb.f_namemax; #else struct statfs sfb; if(statfs(wi_string_cstring(path), &sfb) < 0) { wi_error_set_errno(errno); return false; } sfp->f_bsize = sfb.f_iosize; sfp->f_frsize = sfb.f_bsize; sfp->f_blocks = sfb.f_blocks; sfp->f_bfree = sfb.f_bfree; sfp->f_bavail = sfb.f_bavail; sfp->f_files = sfb.f_files; sfp->f_ffree = sfb.f_ffree; sfp->f_favail = sfb.f_ffree; sfp->f_fsid = sfb.f_fsid.val[0]; sfp->f_flag = 0; sfp->f_namemax = 0; #endif return true; }
wi_boolean_t wi_file_lstat(wi_string_t *path, struct stat *sp) { if(lstat(wi_string_cstring(path), sp) < 0) { wi_error_set_errno(errno); return false; } return true; }
static wi_boolean_t _wi_file_delete_file(wi_string_t *path) { if(unlink(wi_string_cstring(path)) < 0) { wi_error_set_errno(errno); return false; } return true; }
wi_boolean_t wi_file_clear(wi_string_t *path) { if(truncate(wi_string_cstring(path), 0) < 0) { wi_error_set_errno(errno); return false; } return true; }
wi_boolean_t wi_file_rename(wi_string_t *path, wi_string_t *newpath) { if(rename(wi_string_cstring(path), wi_string_cstring(newpath)) < 0) { wi_error_set_errno(errno); return false; } return true; }
wi_boolean_t wi_process_set_hostname(wi_process_t *process, wi_string_t *hostname) { if(sethostname((char *) wi_string_cstring(hostname), (int)wi_string_length(hostname))) { wi_error_set_errno(errno); return false; } return true; }
wi_boolean_t wi_file_create_directory(wi_string_t *path, mode_t mode) { if(mkdir(wi_string_cstring(path), mode) < 0) { wi_error_set_errno(errno); return false; } return true; }
static wi_boolean_t _wi_socket_set_option_int(wi_socket_t *socket, int level, int name, int option) { if(setsockopt(socket->sd, level, name, &option, sizeof(option)) < 0) { wi_error_set_errno(errno); return false; } return true; }