From: Lawrence S. <ljs...@us...> - 2022-02-23 14:18:00
|
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 6ce15aff975014867f1e9b8aa80b840b1db85714 (commit) via 75cfc550e361752fec8dd3c5fa79e232b2afe03c (commit) from d96e864b4d49addd9a1465eee99d9f881a856ab3 (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 6ce15aff975014867f1e9b8aa80b840b1db85714 Merge: d96e864 75cfc55 Author: Luke Benstead <ka...@gm...> Date: Sat Jan 29 14:12:20 2022 +0000 Merge pull request #68 from Kazade/master Implement getsockopt for TCP and UDP commit 75cfc550e361752fec8dd3c5fa79e232b2afe03c Author: Luke Benstead <ka...@gm...> Date: Sat Jan 29 14:11:08 2022 +0000 Implement getsockopt for TCP and UDP ----------------------------------------------------------------------- Summary of changes: include/kos/fs_socket.h | 19 +++++++++++ include/sys/socket.h | 16 +++++++++ kernel/fs/fs_socket.c | 19 +++++++++++ kernel/net/net_tcp.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel/net/net_udp.c | 74 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 214 insertions(+) diff --git a/include/kos/fs_socket.h b/include/kos/fs_socket.h index 1c97cf4..03e7448 100644 --- a/include/kos/fs_socket.h +++ b/include/kos/fs_socket.h @@ -309,6 +309,25 @@ typedef struct fs_socket_proto { int (*setsockopt)(net_socket_t *s, int level, int option_name, const void *option_value, socklen_t option_len); + /** \brief Get socket name. + + This function should implement the ::getsockname() system call for the + given protocol. The semantics are exactly as defined for that function. + + 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. + */ + int (*getsockname)(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 e1f642b..682c866 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -340,6 +340,22 @@ int shutdown(int socket, int how); */ int socket(int domain, int type, int protocol); +/** \brief Get socket name. + + This function returns the locally bound address information for a specified + socket. + + \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, sets errno as appropriate. + \retval 0 On success. +*/ +int getsockname(int socket, struct sockaddr *name, socklen_t *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 e35a8cc..ed93080 100644 --- a/kernel/fs/fs_socket.c +++ b/kernel/fs/fs_socket.c @@ -567,6 +567,25 @@ int shutdown(int sock, int how) { return hnd->protocol->shutdownsock(hnd, how); } +int getsockname(int sock, struct sockaddr *name, socklen_t *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; + } + + return hnd->protocol->getsockname(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 f16305b..ca86731 100644 --- a/kernel/net/net_tcp.c +++ b/kernel/net/net_tcp.c @@ -1890,6 +1890,91 @@ ret_success: return 0; } +static int net_tcp_getsockname(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->domain == AF_INET) { + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = + sock->local_addr.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = sock->local_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in)) { + /* Passed in a structure not big enough so truncate*/ + memcpy(name, &realaddr, *name_len); + } 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->local_addr.sin6_addr; + realaddr6.sin6_port = sock->local_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in6)) { + /* Passed in a structure not big enough */ + memcpy(name, &realaddr6, *name_len); + } 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; @@ -3013,6 +3098,7 @@ static fs_socket_proto_t proto = { net_tcp_input, /* input */ net_tcp_getsockopt, /* getsockopt */ net_tcp_setsockopt, /* setsockopt */ + net_tcp_getsockname, /* getsockname */ net_tcp_fcntl, /* fcntl */ net_tcp_poll /* poll */ }; diff --git a/kernel/net/net_udp.c b/kernel/net/net_udp.c index d806e20..dcc38a5 100644 --- a/kernel/net/net_udp.c +++ b/kernel/net/net_udp.c @@ -944,6 +944,78 @@ ret_success: return 0; } +static int net_udp_getsockname(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(sock->domain == AF_INET) { + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = + sock->local_addr.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = sock->local_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in)) { + /* Passed in a structure not big enough so truncate*/ + memcpy(name, &realaddr, *name_len); + } 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->local_addr.sin6_addr; + realaddr6.sin6_port = sock->local_addr.sin6_port; + + if(*name_len <= sizeof(struct sockaddr_in6)) { + /* Passed in a structure not big enough */ + memcpy(name, &realaddr6, *name_len); + } 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; @@ -1436,6 +1508,7 @@ static fs_socket_proto_t proto = { net_udp_input, net_udp_getsockopt, net_udp_setsockopt, + net_udp_getsockname, net_udp_fcntl, net_udp_poll }; @@ -1457,6 +1530,7 @@ static fs_socket_proto_t proto_lite = { net_udp_input, net_udp_getsockopt, net_udp_setsockopt, + net_udp_getsockname, net_udp_fcntl, net_udp_poll }; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |