From: quzar <qu...@us...> - 2024-09-18 00:54:24
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via fd9f323eeddea8970ec595ca49cb40e68b208520 (commit) from 8e783b8ae5c54b510efa7f958aa37fa6fb17041b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit fd9f323eeddea8970ec595ca49cb40e68b208520 Author: Andy Barajas <and...@gm...> Date: Tue Sep 17 17:46:30 2024 -0700 Add getpeername() (#718) Added getpeername to sockets to help with cURL kos-port ----------------------------------------------------------------------- Summary of changes: include/kos/fs_socket.h | 33 ++++++++++++++----- include/sys/socket.h | 32 ++++++++++++++++++ kernel/fs/fs_socket.c | 24 ++++++++++++++ kernel/net/net_tcp.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/net/net_udp.c | 76 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+), 8 deletions(-) diff --git a/include/kos/fs_socket.h b/include/kos/fs_socket.h index 46285cfc..bd58ea2d 100644 --- a/include/kos/fs_socket.h +++ b/include/kos/fs_socket.h @@ -325,17 +325,34 @@ typedef struct fs_socket_proto { Currently all options (regardless of level) are passed onto the protocol handler. - \param s The socket to get the name of. - \param name Pointer to a sockaddr structure which will hold - the resulting address information. - \param name_len The amount of space pointed to by name, in - bytes. On return, this is set to the actual size - of the returned address information. - \retval -1 On error (set errno appropriately). - \retval 0 On success. + \param s The socket to get the name of. + \param name Pointer to a sockaddr structure which will hold + the resulting address information. + \param name_len The amount of space pointed to by name, in + bytes. On return, this is set to the actual size + of the returned address information. + \retval -1 On error (with errno set appropriately). + \retval 0 On success. */ int (*getsockname)(net_socket_t *s, struct sockaddr *name, socklen_t *name_len); + /** \brief Get the name of the peer connected to a socket created with the + protocol. + + This function should implement the ::getpeername() system call for the + protocol. The semantics are exactly as expected for that function. + + \param s The socket from which to get the peer address. + \param name Pointer to a sockaddr structure which will hold + the resulting address information. + \param name_len The amount of space pointed to by name, in + bytes. On return, this is set to the actual size + of the returned address information. + \retval -1 On error (with errno set appropriately). + \retval 0 On success. + */ + int (*getpeername)(net_socket_t *s, struct sockaddr *name, socklen_t *name_len); + /** \brief Manipulate file options. This function should implement the fcntl() system call for the given diff --git a/include/sys/socket.h b/include/sys/socket.h index 40744199..da174d27 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -387,6 +387,38 @@ int socket(int domain, int type, int protocol); */ int getsockname(int socket, struct sockaddr *name, socklen_t *name_len); +/** + \brief Get the name of the connected peer socket. + + This function retrieves the address of the peer connected to the socket + specified by the socket descriptor. The address is returned in the buffer + pointed to by the name parameter, and the actual length of the address is + returned in the name_len parameter. + + \param socket A socket that is already connected to a peer. + \param name A pointer to a sockaddr structure where the peer + address will be stored. + \param name_len A pointer to a socklen_t variable that specifies the + length of the address structure. + On return, it will contain the actual size of the + address returned. + + \retval 0 On success. + \retval -1 On error, sets errno as appropriate, such as: + - EBADF: The socket argument is not a valid file + descriptor. + - EFAULT: The addr argument points to memory not in a + valid part of the process address space. + - ENOBUFS: Insufficient resources were available in the + system to perform the operation. + - ENOTCONN: The socket is not connected. + - ENOTSOCK: The socket argument does not refer to a + socket. + - EOPNOTSUPP: The socket does not support getpeername. +*/ +int getpeername(int socket, struct sockaddr *__RESTRICT name, + socklen_t *__RESTRICT name_len); + /** \brief Get socket options. This function retrieves options associated with a socket. This function diff --git a/kernel/fs/fs_socket.c b/kernel/fs/fs_socket.c index 7465e890..8f766811 100644 --- a/kernel/fs/fs_socket.c +++ b/kernel/fs/fs_socket.c @@ -542,6 +542,30 @@ int getsockname(int sock, struct sockaddr *name, socklen_t *name_len) { return hnd->protocol->getsockname(hnd, name, name_len); } +int getpeername(int sock, struct sockaddr *__RESTRICT name, socklen_t *__RESTRICT name_len) { + net_socket_t *hnd; + + hnd = (net_socket_t *)fs_get_handle(sock); + + if(hnd == NULL) { + errno = EBADF; + return -1; + } + + /* Make sure this is actually a socket. */ + if(fs_get_handler(sock) != &vh) { + errno = ENOTSOCK; + return -1; + } + + if(!hnd->protocol->getpeername) { + errno = EOPNOTSUPP; + return -1; + } + + return hnd->protocol->getpeername(hnd, name, name_len); +} + int getsockopt(int sock, int level, int option_name, void *option_value, socklen_t *option_len) { net_socket_t *hnd; diff --git a/kernel/net/net_tcp.c b/kernel/net/net_tcp.c index 9e0fe06b..f4902d61 100644 --- a/kernel/net/net_tcp.c +++ b/kernel/net/net_tcp.c @@ -1797,6 +1797,92 @@ ret_success: return 0; } +static int net_tcp_getpeername(net_socket_t *hnd, struct sockaddr *name, socklen_t *name_len) { + struct tcp_sock *sock; + struct sockaddr_in realaddr; + struct sockaddr_in6 realaddr6; + + if(!name || !name_len) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(rwsem_read_trylock(&tcp_sem)) { + errno = EWOULDBLOCK; + return -1; + } + } else { + rwsem_read_lock(&tcp_sem); + } + + if(!(sock = (struct tcp_sock *)hnd->data)) { + rwsem_read_unlock(&tcp_sem); + errno = EBADF; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(&sock->mutex)) { + rwsem_read_unlock(&tcp_sem); + errno = EWOULDBLOCK; + return -1; + } + } else { + mutex_lock(&sock->mutex); + } + + if(sock->state == TCP_STATE_CLOSED) { + mutex_unlock(&sock->mutex); + rwsem_read_unlock(&tcp_sem); + errno = ENOTCONN; + return -1; + } + + if(sock->domain == AF_INET) { + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = + sock->remote_addr.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = sock->remote_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in)) { + /* Passed in a structure not big enough so truncate*/ + memcpy(name, &realaddr, *name_len); + errno = ENOBUFS; + } else { + memcpy(name, &realaddr, sizeof(struct sockaddr_in)); + *name_len = sizeof(struct sockaddr_in); + goto ret_success; + } + } else if(sock->domain == AF_INET6) { + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_addr = sock->remote_addr.sin6_addr; + realaddr6.sin6_port = sock->remote_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in6)) { + /* Passed in a structure not big enough */ + memcpy(name, &realaddr6, *name_len); + errno = ENOBUFS; + } else { + memcpy(name, &realaddr6, sizeof(struct sockaddr_in6)); + *name_len = sizeof(struct sockaddr_in6); + goto ret_success; + } + } + + mutex_unlock(&sock->mutex); + rwsem_read_unlock(&tcp_sem); + errno = ENOTSOCK; + return -1; + +ret_success: + mutex_unlock(&sock->mutex); + rwsem_read_unlock(&tcp_sem); + return 0; +} + static int net_tcp_fcntl(net_socket_t *hnd, int cmd, va_list ap) { struct tcp_sock *sock; @@ -2871,6 +2957,7 @@ static fs_socket_proto_t proto = { net_tcp_getsockopt, /* getsockopt */ net_tcp_setsockopt, /* setsockopt */ net_tcp_getsockname, /* getsockname */ + net_tcp_getpeername, /* getpeername */ net_tcp_fcntl, /* fcntl */ net_tcp_poll /* poll */ }; diff --git a/kernel/net/net_udp.c b/kernel/net/net_udp.c index 9a7e5fc8..6e812680 100644 --- a/kernel/net/net_udp.c +++ b/kernel/net/net_udp.c @@ -960,6 +960,80 @@ ret_success: return 0; } +static int net_udp_getpeername(net_socket_t *hnd, struct sockaddr *name, socklen_t *name_len) { + struct udp_sock *sock; + struct sockaddr_in realaddr; + struct sockaddr_in6 realaddr6; + + if(!name || !name_len) { + errno = EFAULT; + return -1; + } + + if(irq_inside_int()) { + if(mutex_trylock(&udp_mutex) == -1) { + errno = EWOULDBLOCK; + return -1; + } + } else { + mutex_lock(&udp_mutex); + } + + if(!(sock = (struct udp_sock *)hnd->data)) { + mutex_unlock(&udp_mutex); + errno = EBADF; + return -1; + } + + /* If the socket is not connected, return an error */ + if(IN6_IS_ADDR_UNSPECIFIED(&sock->remote_addr.sin6_addr) || sock->remote_addr.sin6_port == 0) { + mutex_unlock(&udp_mutex); + errno = ENOTCONN; + return -1; + } + + /* Depending on the socket domain, return the appropriate address structure */ + if(sock->domain == AF_INET) { + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = sock->remote_addr.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = sock->remote_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in)) { + /* Passed in a structure not big enough so truncate*/ + memcpy(name, &realaddr, *name_len); + errno = ENOBUFS; + } else { + memcpy(name, &realaddr, sizeof(struct sockaddr_in)); + *name_len = sizeof(struct sockaddr_in); + goto ret_success; + } + } else if(sock->domain == AF_INET6) { + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_addr = sock->remote_addr.sin6_addr; + realaddr6.sin6_port = sock->remote_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in6)) { + /* Passed in a structure not big enough */ + memcpy(name, &realaddr6, *name_len); + errno = ENOBUFS; + } else { + memcpy(name, &realaddr6, sizeof(struct sockaddr_in6)); + *name_len = sizeof(struct sockaddr_in6); + goto ret_success; + } + } + + mutex_unlock(&udp_mutex); + errno = ENOTSOCK; + return -1; + +ret_success: + mutex_unlock(&udp_mutex); + return 0; +} + static int net_udp_fcntl(net_socket_t *hnd, int cmd, va_list ap) { struct udp_sock *sock; long val; @@ -1433,6 +1507,7 @@ static fs_socket_proto_t proto = { net_udp_getsockopt, net_udp_setsockopt, net_udp_getsockname, + net_udp_getpeername, net_udp_fcntl, net_udp_poll }; @@ -1455,6 +1530,7 @@ static fs_socket_proto_t proto_lite = { net_udp_getsockopt, net_udp_setsockopt, net_udp_getsockname, + net_udp_getpeername, net_udp_fcntl, net_udp_poll }; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |