From 734600d0f611aee74f79931acf6dd766cd3e01c7 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 1 Jan 2022 22:00:49 -0600 Subject: [PATCH] Update: Add socket functions and improve existing ones. It is very clear to me that I had stopped working on the socket code. Much of the code appears incomplete, including some comments that weren't updated after they were copy and pasted. This is only preliminary work for only the functionality needed or preceived needed by the Controller program or other existing programs. There will likely be major work in the future during the 0.7.x development release series. --- level_0/f_socket/c/socket-common.h | 121 +++++++++++++- level_0/f_socket/c/socket.c | 252 ++++++++++++++++++++++++---- level_0/f_socket/c/socket.h | 328 +++++++++++++++++++++++++++++++++---- 3 files changed, 636 insertions(+), 65 deletions(-) diff --git a/level_0/f_socket/c/socket-common.h b/level_0/f_socket/c/socket-common.h index 205e04a..bc91a3b 100644 --- a/level_0/f_socket/c/socket-common.h +++ b/level_0/f_socket/c/socket-common.h @@ -17,7 +17,19 @@ extern "C" { #endif /** - * Socket Types. + * Provide socket defaults. + * + * F_file_default_*: + * - read_size: Default read size in bytes. + * - write_size: Default write size in bytes. + */ +#ifndef _di_f_socket_defaults_ + #define F_socket_default_read_size_d 8192 + #define F_socket_default_write_size_d 8192 +#endif // _di_f_socket_defaults_ + +/** + * Socket Closes. * * f_socket_close_*: * - fast: Fast Socket close, as in close(). @@ -25,15 +37,120 @@ extern "C" { * - write: Write close, as in shutdown(, SHUT_WR). * - read_write: Read/Write close, as in shutdown(, SHUT_RDWR). */ -#ifndef _di_f_socket_types_ +#ifndef _di_f_socket_closes_ enum { f_socket_close_fast_e = 1, f_socket_close_read_e, f_socket_close_write_e, f_socket_close_read_write_e, }; +#endif // _di_f_socket_closes_ + +/** + * Socket protocol families, referred to as a domain. + * + * f_socket_domain_*: + * - atm: Raw ATM PVC. + * - apple_talk: Apple Talk. + * - cryptographic: Kernel cryptographic API. + * - file: Unix/Local file. + * - ipv4: Internet Protocol v4. + * - ipv6: Internet Protocol v6. + * - ipx: Novell IPX. + * - kernel: Kernel user interface device. + * - radio: Amateur Radio. + * - x25: ITU-T X.25 / ISO-8208 protocol + */ +#ifndef _di_f_socket_domains_ + #define f_socket_domain_apple_talk_d AF_APPLETALK + #define f_socket_domain_atm_d AF_ATMPVC + #define f_socket_domain_cryptographic_d AF_ALG + #define f_socket_domain_file_d AF_UNIX + #define f_socket_domain_ipv4_d AF_INET + #define f_socket_domain_ipv6_d AF_INET6 + #define f_socket_domain_ipx_d AF_IPX + #define f_socket_domain_kernel_d AF_NETLINK + #define f_socket_domain_radio_d AF_AX25 + #define f_socket_domain_x25_d AF_X25 +#endif // _di_f_socket_domains_ + +/** + * Socket types. + * + * f_socket_type_*: + * - close_on_execute: Close on execute. + * - datagram: Datagram (connectionless, unreliable, fixed length). + * - datagram_reliable: Reliable Datagram (reliable variant of datagram, unordered) + * - datagram_sequence: Sequenced Datagram. + * - nonblocking: Non-blocking. + * - raw: Raw access. + * - stream: Stream. + */ +#ifndef _di_f_socket_types_ + #define f_socket_type_close_on_execute_d SOCK_CLOEXEC + #define f_socket_type_datagram_d SOCK_DGRAM + #define f_socket_type_datagram_reliable_d SOCK_RDM + #define f_socket_type_datagram_sequence_d SOCK_SEQPACKET + #define f_socket_type_nonblocking_d SOCK_NONBLOCK + #define f_socket_type_raw_d SOCK_RAW + #define f_socket_type_stream_d SOCK_STREAM #endif // _di_f_socket_types_ +/** + * Commonly used socket related properties, loosely based off of f_file_t. + * + * address: Pointer to the socket address (stored as "struct sockaddr" but may represent other types such as "struct sockaddr_un" or "struct sockaddr_in"). + * domain: The socket domain (protocol family). + * flag: Flags used for opening the file. + * id: File descriptor, with a value of -1 represents a closed file. + * name: The name of the socket, if a name is given (for UNIX sockets this represents the path). + * protocol: The socket protocol. + * size_read: The default number of 1-byte characters to read at a time and is often used for the read buffer size. + * size_write: The default number of 1-byte characters to read at a time and is often used for the write buffer size. + * type: The socket type. + */ +#ifndef _di_f_socket_t_ + typedef struct { + int id; + int domain; + int protocol; + int type; + + size_t size_read; + size_t size_write; + + socklen_t length; + + struct sockaddr *address; + + f_string_t name; + } f_socket_t; + + #define f_socket_t_initialize { -1, 0, 0, 0, F_socket_default_read_size_d, F_socket_default_write_size_d, 0, 0 } + + #define macro_f_socket_t_initialize(address) { -1, 0, 0, 0, F_socket_default_read_size_d, F_socket_default_write_size_d, address, 0 } + + #define macro_f_socket_t_clear(file) \ + file.id = -1; \ + file.domain = 0; \ + file.protocol = 0; \ + file.type = 0; \ + file.size_read = 0; \ + file.size_write = 0; \ + file.length = 0; \ + file.name = 0; + + #define macro_f_socket_t_reset(file) \ + file.id = -1; \ + file.domain = 0; \ + file.protocol = 0; \ + file.type = 0; \ + file.size_read = F_socket_default_read_size_d; \ + file.size_write = F_socket_default_write_size_d; \ + file.length = 0; \ + file.name = 0; +#endif // _di_f_socket_t_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_0/f_socket/c/socket.c b/level_0/f_socket/c/socket.c index 3b64774..18bcade 100644 --- a/level_0/f_socket/c/socket.c +++ b/level_0/f_socket/c/socket.c @@ -4,85 +4,281 @@ extern "C" { #endif -#ifndef _di_f_socket_file_bind_ - f_status_t f_socket_file_bind(const f_string_t path, const int id, struct sockaddr_un *address) { +#ifndef _di_f_socket_accept_ + f_status_t f_socket_accept(f_socket_t * const socket) { #ifndef _di_level_0_parameter_checking_ - if (!address) return F_status_set_error(F_parameter); + if (!socket) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ - memset(address, 0, sizeof(struct sockaddr_un)); - address->sun_family = AF_UNIX; + if (accept(socket->id, socket->address, &socket->length) < 0) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); + if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == EINTR) return F_status_set_error(F_interrupt); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max); + if (errno == ENFILE) return F_status_set_error(F_file_open_max); + if (errno == ENOBUFS) return F_status_set_error(F_buffer_not); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); + if (errno == EOPNOTSUPP) return F_status_set_error(F_stream_not); + if (errno == EPROTO) return F_status_set_error(F_protocol); + if (errno == EPERM) return F_status_set_error(F_prohibited); + if (errno == ESOCKTNOSUPPORT) return F_status_set_error(F_supported_not); + if (errno == EPROTONOSUPPORT) return F_status_set_error(F_protocol_not); + if (errno == ETIMEDOUT) return F_status_set_error(F_time_out); - strncpy(address->sun_path, path, sizeof(address->sun_path) - 1); + return F_status_set_error(F_failure); + } - if (bind(id, (struct sockaddr *) address, sizeof(struct sockaddr_un)) < 0) { + return F_none; + } +#endif // _di_f_socket_accept_ + +#ifndef _di_f_socket_bind_ + f_status_t f_socket_bind(const f_socket_t socket) { + + if (bind(socket.id, socket.address, socket.length) < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EADDRINUSE) return F_status_set_error(F_busy_address); if (errno == EADDRNOTAVAIL) return F_status_set_error(F_available_not_address); if (errno == EFAULT) return F_status_set_error(F_buffer); - if (errno == EINVAL) return F_status_set_error(F_busy_socket); + if (errno == EINVAL) return F_status_set_error(F_parameter); if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == ENAMETOOLONG) return F_status_set_error(F_string_too_large); if (errno == ENOENT) return F_status_set_error(F_file_found_not); if (errno == ENOMEM) return F_status_set_error(F_memory_not); if (errno == ENOTDIR) return F_status_set_error(F_directory_found_not); - if (errno == ENOTSOCK) return F_status_set_error(F_descriptor); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); return F_status_set_error(F_failure); } return F_none; } -#endif // _di_f_socket_file_bind_ +#endif // _di_f_socket_bind_ -#ifndef _di_f_socket_listen_ - f_status_t f_socket_listen(const int id, const unsigned int max_backlog) { +#ifndef _di_f_socket_bind_file_ + f_status_t f_socket_bind_file(const f_socket_t socket) { + #ifndef _di_level_0_parameter_checking_ + if (socket.domain != f_socket_domain_file_d) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + memset(socket.address, 0, sizeof(struct sockaddr_un)); + ((struct sockaddr_un *) socket.address)->sun_family = f_socket_domain_file_d; - if (listen(id, max_backlog) < 0) { + strncpy(((struct sockaddr_un *) socket.address)->sun_path, socket.name, sizeof(((struct sockaddr_un *) socket.address)->sun_path) - 1); + + if (bind(socket.id, socket.address, sizeof(struct sockaddr_un)) < 0) { + if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EADDRINUSE) return F_status_set_error(F_busy_address); + if (errno == EADDRNOTAVAIL) return F_status_set_error(F_available_not_address); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == ENAMETOOLONG) return F_status_set_error(F_string_too_large); + if (errno == ENOENT) return F_status_set_error(F_file_found_not); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + if (errno == ENOTDIR) return F_status_set_error(F_directory_found_not); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); + + return F_status_set_error(F_failure); + } + + return F_none; + } +#endif // _di_f_socket_bind_file_ + +#ifndef _di_f_socket_connect_ + f_status_t f_socket_connect(const f_socket_t socket) { + + if (connect(socket.id, socket.address, socket.length) == -1) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EPERM) return F_status_set_error(F_prohibited); + if (errno == EADDRINUSE) return F_status_set_error(F_busy_address); + if (errno == EADDRNOTAVAIL) return F_status_set_error(F_available_not_address); + if (errno == EAFNOSUPPORT) return F_status_set_error(F_domain_not); + if (errno == EAGAIN) return F_status_set_error(F_block); + if (errno == EALREADY) return F_status_set_error(F_complete_not); if (errno == EBADF) return F_status_set_error(F_file_descriptor); - if (errno == ENOTSOCK) return F_status_set_error(F_descriptor); - if (errno == EOPNOTSUPP) return F_status_set_error(F_supported_not); + if (errno == ECONNREFUSED) return F_status_set_error(F_connect_refuse); + if (errno == EINPROGRESS) return F_status_set_error(F_progress); + if (errno == EINTR) return F_status_set_error(F_interrupt); + if (errno == EISCONN) return F_status_set_error(F_connect); + if (errno == ENETUNREACH) return F_status_set_error(F_network_reach_not); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); + if (errno == EPROTONOSUPPORT) return F_status_set_error(F_protocol_not); + if (errno == ETIMEDOUT) return F_status_set_error(F_time_out); return F_status_set_error(F_failure); } return F_none; } -#endif // _di_f_socket_listen_ +#endif // _di_f_socket_connect_ + +#ifndef _di_f_socket_create_ + f_status_t f_socket_create(f_socket_t * const socket_structure) { + #ifndef _di_level_0_parameter_checking_ + if (!socket_structure) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + const int result = socket(socket_structure->domain, socket_structure->type, socket_structure->protocol); + + if (result == -1) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EAFNOSUPPORT) return F_status_set_error(F_domain_not); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max); + if (errno == ENFILE) return F_status_set_error(F_file_open_max); + if (errno == ENOBUFS) return F_status_set_error(F_buffer_not); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + if (errno == EPROTONOSUPPORT) return F_status_set_error(F_protocol_not); + if (errno == ESOCKTNOSUPPORT) return F_status_set_error(F_type_not); + + return F_status_set_error(F_failure); + } + + socket_structure->id = result; + + return F_none; + } +#endif // _di_f_socket_create_ + +#ifndef _di_f_socket_create_pair_ + f_status_t f_socket_create_pair(const int domain, const int protocol, const int type, int *id_1, int *id_2) { + #ifndef _di_level_0_parameter_checking_ + if (!id_1) return F_status_set_error(F_parameter); + if (!id_2) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + int pair[2] = { 0, 0 }; + + if (socketpair(domain, type, protocol, pair) == -1) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == EAFNOSUPPORT) return F_status_set_error(F_domain_not); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max); + if (errno == ENFILE) return F_status_set_error(F_file_open_max); + if (errno == ENOBUFS) return F_status_set_error(F_buffer_not); + if (errno == ENOMEM) return F_status_set_error(F_memory_not); + if (errno == EPROTONOSUPPORT) return F_status_set_error(F_protocol_not); + + return F_status_set_error(F_failure); + } + + *id_1 = pair[0]; + *id_2 = pair[1]; + + return F_none; + } +#endif // _di_f_socket_create_pair_ + +#ifndef _di_f_socket_disconnect_ + f_status_t f_socket_disconnect(f_socket_t * const socket, const unsigned short action) { + #ifndef _di_level_0_parameter_checking_ + if (!socket) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ -#ifndef _di_f_socket_close_client_ - f_status_t f_socket_close_client(const int id, const unsigned short action) { int result = 0; if (action == f_socket_close_fast_e) { - result = close(id); + result = close(socket->id); + } + else if (action == f_socket_close_read_e || action == f_socket_close_write_e || action == f_socket_close_read_write_e) { + result = shutdown(socket->id, action); } else { - if (action == f_socket_close_read_e || action == f_socket_close_write_e || action == f_socket_close_read_write_e) { - result = shutdown(id, action); - } - else { - return F_status_set_error(F_supported_not); - } + return F_status_set_error(F_supported_not); } if (result < 0) { + + // According to man pages, retrying close() after another close on error is invalid on Linux because Linux releases the descriptor before stages that cause failures. + if (errno != EBADF && errno != EINTR) { + socket->id = -1; + } + if (errno == EBADF) return F_status_set_error(F_file_descriptor); if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block); if (errno == EINTR) return F_status_set_error(F_interrupt); if (errno == EINVAL) return F_status_set_error(F_value); if (errno == EIO) return F_status_set_error(F_input_output); - if (errno == ENOTCONN) return F_connected_not; - if (errno == ENOTSOCK) return F_status_set_error(F_descriptor); + if (errno == ENOTCONN) return F_connect_not; + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); if (errno == ENOSPC) return F_status_set_error(F_parameter); return F_status_set_error(F_failure); } + socket->id = -1; + + return F_none; + } +#endif // _di_f_socket_disconnect_ + +#ifndef _di_f_socket_listen_ + f_status_t f_socket_listen(f_socket_t * const socket, const unsigned int max_backlog) { + #ifndef _di_level_0_parameter_checking_ + if (!socket) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (listen(socket->id, max_backlog) < 0) { + if (errno == EADDRINUSE) return F_status_set_error(F_busy_address); + if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); + if (errno == EOPNOTSUPP) return F_status_set_error(F_supported_not); + + return F_status_set_error(F_failure); + } + + return F_none; + } +#endif // _di_f_socket_listen_ + +#ifndef _di_f_socket_option_get_ + f_status_t f_socket_option_get(f_socket_t * const socket, const int level, const int type, void *value, socklen_t *length) { + #ifndef _di_level_0_parameter_checking_ + if (!socket) return F_status_set_error(F_parameter); + if (!value) return F_status_set_error(F_parameter); + if (!length) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (getsockopt(socket->id, level, type, value, length) < 0) { + if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == EINVAL) return F_status_set_error(F_value); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); + if (errno == ENOPROTOOPT) return F_status_set_error(F_option_not); + + return F_status_set_error(F_failure); + } + + return F_none; + } +#endif // _di_f_socket_option_get_ + +#ifndef _di_f_socket_option_set_ + f_status_t f_socket_option_set(f_socket_t * const socket, const int level, const int type, const void *value, const socklen_t length) { + #ifndef _di_level_0_parameter_checking_ + if (!socket) return F_status_set_error(F_parameter); + if (!value) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + if (setsockopt(socket->id, level, type, value, length) < 0) { + if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == EINVAL) return F_status_set_error(F_value); + if (errno == ENOTSOCK) return F_status_set_error(F_socket_not); + if (errno == ENOPROTOOPT) return F_status_set_error(F_option_not); + + return F_status_set_error(F_failure); + } + return F_none; } -#endif // _di_f_socket_close_client_ +#endif // _di_f_socket_option_set_ #ifdef __cplusplus } // extern "C" diff --git a/level_0/f_socket/c/socket.h b/level_0/f_socket/c/socket.h index 4de7fda..3772fb4 100644 --- a/level_0/f_socket/c/socket.h +++ b/level_0/f_socket/c/socket.h @@ -5,7 +5,7 @@ * API Version: 0.5 * Licenses: lgpl-2.1-or-later * - * Provide means to connect to and use sockets. + * Provide means to interact with sockets. */ #ifndef _F_socket_h #define _F_socket_h @@ -33,89 +33,347 @@ extern "C" { #endif /** - * Bind a UNIX socket. + * Accept a connection on a socket. * - * @param path - * The path to a socket file to bind to. - * @param id - * The ID of a socket. - * @param address - * The socket address information. + * @param socket + * The socket structure. + * The socket.length must represent the full size of the address structure. + * The socket.length is updated with the populated size of the address structure. + * The socket.id must refer to a valid socket file descriptor. * * @return * F_none on success. + * + * F_access_denied (with error bit) on access denied. + * F_block (with error bit) if socket is blocked. + * F_buffer (with error bit) if the buffer is invalid. + * F_buffer_not (with error bit) if unable to create socket due to resource restrictions (maps to ENOBUFS). + * F_file_descriptor (with error bit) if id is an invalid descriptor. + * F_file_descriptor_max (with error bit) if max file descriptors is reached. + * F_file_open_max (with error bit) too many open files. + * F_interrupt (with error bit) if interrupt is received. + * F_memory_not (with error bit) if out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_prohibited (with error bit) if the file system does not permit this operation. + * F_protocol (with error bit) if a protocol error occurred. + * F_protocol_not (with error bit) if the given protocol is unknown or is unsupported. + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_stream_not (with error bit) the socket type is not a stream. + * F_supported_not (with error bit) if this socket type is not supported. + * F_time_out (with error bit) if a timeout occurred. + * + * F_failure (with error bit) for any other error. + * + * @see accept() + */ +#ifndef _di_f_socket_accept_ + extern f_status_t f_socket_accept(f_socket_t * const socket); +#endif // _di_f_socket_accept_ + +/** + * Bind a socket to a name. + * + * This does not initialize or otherwise memset() the address. + * + * @param socket + * The socket structure. + * The socket.address may point to any valid structure, like "struct sockaddr", "struct sockaddr_un", or "struct sockaddr_in". + * The caller must appropriately initialize and configure the socket.address. + * The socket.length must represent the full size of the address structure. + * The socket.id must refer to a valid socket file descriptor. + * + * @return + * F_none on success. + * * F_address (with error bit) if address is already in use (therefore unavailable). + * F_available_not_address (with error bit) if address is unavailable (is non-existent or not local). * F_buffer (with error bit) if the buffer is invalid. * F_busy_address (with error bit) if address is already in use (therefore unavailable). - * F_busy_socket (with error bit) if socket defined by id is already bound (therefore unavailable). - * F_descriptor (with error bit) if the id is not a socket descriptor. * F_directory_found_not (with error bit) if directory was not found. * F_file_found_not (with error bit) if file not found. * F_memory_not (with error bit) if out of memory. * F_name (with error bit) on path name error. * F_parameter (with error bit) if a parameter is invalid. + * F_socket_not (with error bit) if the id is not a socket descriptor. * F_string_too_large (with error bit) if string is too large to store in the buffer. + * + * F_failure (with error bit) for any other error. + * + * @see bind() + */ +#ifndef _di_f_socket_bind_ + extern f_status_t f_socket_bind(const f_socket_t socket); +#endif // _di_f_socket_bind_ + +/** + * Bind a socket to a UNIX socket file. + * + * This does initialize and memset() the address with the address set to a UNIX socket (struct sockaddr_un). + * + * @param socket + * The socket structure. + * The socket.address must point to a "struct sockaddr_un". + * The socket.name must be assigned to a path. + * The socket.type must be assigned to f_socket_domain_file_d. + * + * @return + * F_none on success. + * + * F_address (with error bit) if address is already in use (therefore unavailable). * F_available_not_address (with error bit) if address is unavailable (is non-existent or not local). + * F_buffer (with error bit) if the buffer is invalid. + * F_busy_address (with error bit) if address is already in use (therefore unavailable). + * F_directory_found_not (with error bit) if directory was not found. + * F_file_found_not (with error bit) if file not found. + * F_memory_not (with error bit) if out of memory. + * F_name (with error bit) on path name error. + * F_parameter (with error bit) if a parameter is invalid. + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_string_too_large (with error bit) if string is too large to store in the buffer. + * * F_failure (with error bit) for any other error. * * @see bind() + * @see memset() + * @see strncpy() */ -#ifndef _di_f_socket_file_bind_ - extern f_status_t f_socket_file_bind(const f_string_t path, const int id, struct sockaddr_un *address); -#endif // _di_f_socket_file_bind_ +#ifndef _di_f_socket_bind_file_ + extern f_status_t f_socket_bind_file(const f_socket_t socket); +#endif // _di_f_socket_bind_file_ /** - * Terminate a socket connection. + * Connect to a socket. * - * @param id - * The ID of a socket. - * @param max_backlog - * The max length of the pending connections queue. - * Suggested default setting: 8. + * @param socket + * The socket structure. + * The socket.address may point to any valid structure, like "struct sockaddr", "struct sockaddr_un", or "struct sockaddr_in". * * @return * F_none on success. + * + * F_access_denied (with error bit) on access denied. + * F_available_not_address (with error bit) if address is unavailable (is non-existent or not local). + * F_block (with error bit) if socket is blocked. * F_busy_address (with error bit) if address is already in use (therefore unavailable). - * F_descriptor (with error bit) if the id is not a socket descriptor. + * F_complete_not (with error bit) if a non-blocking connection attempt is not yet completed. + * F_connect (with error bit) if already connected. + * F_connect_refuse (with error bit) if connection is refused because there is nothing listening. + * F_domain_not (with error bit) if the given domain is unknown or is unsupported. * F_file_descriptor (with error bit) if id is an invalid descriptor. - * F_supported_not (with error bit) if this socket does not support the listen() operation. + * F_interrupt (with error bit) if interrupt is received. + * F_network_reach_not (with error bit) if the network is unreachable. + * F_progress (with error bit) if if a non-blocking connection cannot be completed immediately. + * F_prohibited (with error bit) if the file system does not permit this operation. + * F_protocol_not (with error bit) if the given protocol is unknown or is unsupported. + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_time_out (with error bit) if a timeout occurred. + * * F_failure (with error bit) for any other error. * - * @see listen() + * @see connect() */ -#ifndef _di_f_socket_listen_ - extern f_status_t f_socket_listen(const int id, const unsigned int max_backlog); -#endif // _di_f_socket_listen_ +#ifndef _di_f_socket_connect_ + extern f_status_t f_socket_connect(const f_socket_t socket); +#endif // _di_f_socket_connect_ /** - * Terminate a client socket connection. + * Create a new socket. + * + * @param socket_structure + * The socket structure. + * The socket.address may point to any valid structure, like "struct sockaddr", "struct sockaddr_un", or "struct sockaddr_in". + * The socket.domain must be assigned the desired domain. + * The socket.type must be assigned the desired type. + * The socket.protocol must be assigned the desired protocol. + * The socket.id will be updated with a file descriptor representing the created socket. + * + * This is named "socket_structure" rather than "socket" due to a conflict with the function "socket()". + * + * @return + * F_none on success. * - * @param id - * The ID of a socket. + * F_access_denied (with error bit) on access denied. + * F_buffer_not (with error bit) if unable to create socket due to resource restrictions (maps to ENOBUFS). + * F_domain_not (with error bit) if the given domain is unknown or is unsupported. + * F_file_descriptor_max (with error bit) if max file descriptors is reached. + * F_file_open_max (with error bit) too many open files. + * F_memory_not (with error bit) if out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_protocol_not (with error bit) if the given protocol is unknown or is unsupported. + * F_type_not (with error bit) if the given type is unknown or is unsupported. + * + * F_failure (with error bit) for any other error. + * + * @see socket() + */ +#ifndef _di_f_socket_create_ + extern f_status_t f_socket_create(f_socket_t * const socket_structure); +#endif // _di_f_socket_create_ + +/** + * Create a new pair of identical sockets. + * + * This is generally intended to be used for pipes. + * + * @param domain + * The protocol family. + * @param type + * The communication type. + * @param protocol + * The protocol to use. + * @param id_1 + * The first of the pair of socket file descriptors. + * @param id_2 + * The second of the pair of socket file descriptors. + * + * This socket is supposed to be identical to the one specified by id_1. + * + * @return + * F_none on success. + * + * F_access_denied (with error bit) on access denied. + * F_buffer_not (with error bit) if unable to create socket due to resource restrictions (maps to ENOBUFS). + * F_domain_not (with error bit) if the given domain is unknown or is unsupported. + * F_file_descriptor_max (with error bit) if max file descriptors is reached. + * F_file_open_max (with error bit) too many open files. + * F_memory_not (with error bit) if out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_protocol_not (with error bit) if the given protocol is unknown or is unsupported. + * + * F_failure (with error bit) for any other error. + * + * @see socketpair() + */ +#ifndef _di_f_socket_create_pair_ + extern f_status_t f_socket_create_pair(const int domain, const int protocol, const int type, int *id_1, int *id_2); +#endif // _di_f_socket_create_pair_ + +/** + * Terminate a socket connection. + * + * To properly close a UNIX socket, call f_file_close() and f_file_remove(). + * + * @param socket + * The socket structure. + * The socket.id must represent a valid socket file descriptor. * @param action * The action to perform on close. * f_socket_close_fast_e calls close(). * * @return * F_none on success. - * F_connected_not if the socket is not connected. + * F_connect_not if the socket is not connected. + * * F_busy_address (with error bit) if address is already in use (therefore unavailable). - * F_descriptor (with error bit) if the id is not a socket descriptor. * F_file_descriptor (with error bit) if id is an invalid descriptor. - * F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted. + * F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted. * F_input_output (with error bit) if an I/O error occurred. * F_interrupt (with error bit) when program received an interrupt signal, halting operation. * F_parameter (with error bit) if a parameter is invalid. - * F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached). + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_space_not (with error bit) if file system is out of space (or file system quota is reached). * F_supported_not (with error bit) if this socket does not support the listen() operation. + * * F_failure (with error bit) for any other error. * * @see close() * @see shutdown() */ -#ifndef _di_f_socket_close_client_ - extern f_status_t f_socket_close_client(const int id, const unsigned short action); -#endif // _di_f_socket_close_client_ +#ifndef _di_f_socket_disconnect_ + extern f_status_t f_socket_disconnect(f_socket_t * const socket, const unsigned short action); +#endif // _di_f_socket_disconnect_ + +/** + * Set the socket to listen mode (passive socket). + * + * @param socket + * The socket structure. + * The socket.id must represent a valid socket file descriptor. + * @param max_backlog + * The max length of the pending connections queue. + * Suggested default setting: 8. + * + * @return + * F_none on success. + * + * F_busy_address (with error bit) if address is already in use (therefore unavailable). + * F_file_descriptor (with error bit) if id is an invalid descriptor. + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_supported_not (with error bit) if this socket does not support the listen() operation. + * + * F_failure (with error bit) for any other error. + * + * @see listen() + */ +#ifndef _di_f_socket_listen_ + extern f_status_t f_socket_listen(f_socket_t * const socket, const unsigned int max_backlog); +#endif // _di_f_socket_listen_ + +/** + * Get a socket option value. + * + * @param socket + * The socket structure. + * The socket.id must represent a valid socket file descriptor. + * @param level + * The level in which the socket option is located. + * This may be synonymous with "layer". + * @param type + * The type code used to represent the option name. + * @param value + * The value to assign. + * @param length + * The length of the value (often derived from a sizeof() call). + * + * @return + * F_none on success. + * + * F_buffer (with error bit) if the given value is out of scope. + * F_file_descriptor (with error bit) if id is an invalid descriptor. + * F_option_not (with error bit) if the type is not valid for the given level. + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_value (with error bit) if either the value or the length is invalid. + * + * F_failure (with error bit) for any other error. + * + * @see getsockopt() + */ +#ifndef _di_f_socket_option_get_ + extern f_status_t f_socket_option_get(f_socket_t * const socket, const int level, const int type, void *value, socklen_t *length); +#endif // _di_f_socket_option_get_ + +/** + * Set a socket option value. + * + * @param socket + * The socket structure. + * The socket.id must represent a valid socket file descriptor. + * @param level + * The level in which the socket option is located. + * This may be synonymous with "layer". + * @param type + * The type code used to represent the option name. + * @param value + * The value to assign. + * @param length + * The length of the value (often derived from a sizeof() call). + * + * @return + * F_none on success. + * + * F_buffer (with error bit) if the given value is out of scope. + * F_file_descriptor (with error bit) if id is an invalid descriptor. + * F_option_not (with error bit) if the type is not valid for the given level. + * F_socket_not (with error bit) if the id is not a socket descriptor. + * F_value (with error bit) if either the value or the length is invalid. + * + * F_failure (with error bit) for any other error. + * + * @see setsockopt() + */ +#ifndef _di_f_socket_option_set_ + extern f_status_t f_socket_option_set(f_socket_t * const socket, const int level, const int type, const void *value, const socklen_t length); +#endif // _di_f_socket_option_set_ #ifdef __cplusplus } // extern "C" -- 1.8.3.1