
Commit git-c38dbb9 inadvertently broke local MINIX3-on-MINIX3 builds, since its libc changes relied on VFS being upgraded already as well. As a result, after installing the new libc, networking ceased to work, leading to curl(1) failing later on in the build process. This patch introduces transitional code that is necessary for the build process to complete, after which it is obsolete again. Change-Id: I93bf29c01d228e3d7efc7b01befeff682954f54d
287 lines
6.5 KiB
C
287 lines
6.5 KiB
C
#include <sys/cdefs.h>
|
|
#include "namespace.h"
|
|
#include <lib.h>
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ucred.h>
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <net/gen/in.h>
|
|
#include <net/gen/tcp.h>
|
|
#include <net/gen/tcp_io.h>
|
|
#include <net/gen/udp.h>
|
|
#include <net/gen/udp_io.h>
|
|
|
|
#include <minix/type.h>
|
|
|
|
#define DEBUG 0
|
|
|
|
static int _tcp_getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len);
|
|
static int _udp_getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len);
|
|
static int _uds_getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len);
|
|
static void getsockopt_copy(void *return_value, size_t return_len,
|
|
void *__restrict option_value, socklen_t *__restrict option_len);
|
|
|
|
/*
|
|
* Get socket options.
|
|
*/
|
|
static int
|
|
__getsockopt(int fd, int level, int option_name,
|
|
void * __restrict option_value, socklen_t * __restrict option_len)
|
|
{
|
|
message m;
|
|
|
|
if (option_len == NULL) {
|
|
errno = EFAULT;
|
|
return -1;
|
|
}
|
|
|
|
memset(&m, 0, sizeof(m));
|
|
m.m_lc_vfs_sockopt.fd = fd;
|
|
m.m_lc_vfs_sockopt.level = level;
|
|
m.m_lc_vfs_sockopt.name = option_name;
|
|
m.m_lc_vfs_sockopt.buf = (vir_bytes)option_value;
|
|
m.m_lc_vfs_sockopt.len = *option_len;
|
|
|
|
if (_syscall(VFS_PROC_NR, VFS_GETSOCKOPT, &m) < 0)
|
|
return -1;
|
|
|
|
*option_len = m.m_vfs_lc_socklen.len;
|
|
return 0;
|
|
}
|
|
|
|
int getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len)
|
|
{
|
|
int r;
|
|
nwio_tcpopt_t tcpopt;
|
|
nwio_udpopt_t udpopt;
|
|
struct sockaddr_un uds_addr;
|
|
|
|
r = __getsockopt(sock, level, option_name, option_value, option_len);
|
|
if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS))
|
|
return r;
|
|
|
|
r= ioctl(sock, NWIOGTCPOPT, &tcpopt);
|
|
if (r != -1 || errno != ENOTTY)
|
|
{
|
|
if (r == -1)
|
|
{
|
|
/* Bad file descriptor */
|
|
return -1;
|
|
}
|
|
return _tcp_getsockopt(sock, level, option_name,
|
|
option_value, option_len);
|
|
}
|
|
|
|
r= ioctl(sock, NWIOGUDPOPT, &udpopt);
|
|
if (r != -1 || errno != ENOTTY)
|
|
{
|
|
if (r == -1)
|
|
{
|
|
/* Bad file descriptor */
|
|
return -1;
|
|
}
|
|
return _udp_getsockopt(sock, level, option_name,
|
|
option_value, option_len);
|
|
}
|
|
|
|
r= ioctl(sock, NWIOGUDSADDR, &uds_addr);
|
|
if (r != -1 || errno != ENOTTY)
|
|
{
|
|
if (r == -1)
|
|
{
|
|
/* Bad file descriptor */
|
|
return -1;
|
|
}
|
|
return _uds_getsockopt(sock, level, option_name,
|
|
option_value, option_len);
|
|
}
|
|
|
|
errno = ENOTSOCK;
|
|
return -1;
|
|
}
|
|
|
|
static void getsockopt_copy(void *return_value, size_t return_len,
|
|
void *__restrict option_value, socklen_t *__restrict option_len)
|
|
{
|
|
/* copy as much data as possible */
|
|
if (*option_len < return_len)
|
|
memcpy(option_value, return_value, *option_len);
|
|
else
|
|
memcpy(option_value, return_value, return_len);
|
|
|
|
/* return length */
|
|
*option_len = return_len;
|
|
}
|
|
|
|
static int _tcp_getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len)
|
|
{
|
|
int i, r, err;
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
|
|
{
|
|
i = 1; /* Binds to TIME_WAIT sockets never cause errors */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
|
|
{
|
|
i = 1; /* Keepalive is always on */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
if (level == SOL_SOCKET && option_name == SO_ERROR)
|
|
{
|
|
r = ioctl(sock, NWIOTCPGERROR, &err);
|
|
if (r != 0)
|
|
return r;
|
|
|
|
getsockopt_copy(&err, sizeof(err), option_value, option_len);
|
|
return 0;
|
|
}
|
|
if (level == SOL_SOCKET && option_name == SO_RCVBUF)
|
|
{
|
|
i = 32 * 1024; /* Receive buffer in the current
|
|
* implementation
|
|
*/
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
if (level == SOL_SOCKET && option_name == SO_SNDBUF)
|
|
{
|
|
i = 32 * 1024; /* Send buffer in the current implementation */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
if (level == SOL_SOCKET && option_name == SO_TYPE)
|
|
{
|
|
i = SOCK_STREAM; /* this is a TCP socket */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
|
|
{
|
|
i = 0; /* nodelay is always off */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
#if DEBUG
|
|
fprintf(stderr, "_tcp_getsocketopt: level %d, name %d\n",
|
|
level, option_name);
|
|
#endif
|
|
|
|
errno= ENOPROTOOPT;
|
|
return -1;
|
|
}
|
|
|
|
static int _udp_getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len)
|
|
{
|
|
int i;
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_TYPE)
|
|
{
|
|
i = SOCK_DGRAM; /* this is a UDP socket */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
#if DEBUG
|
|
fprintf(stderr, "_udp_getsocketopt: level %d, name %d\n",
|
|
level, option_name);
|
|
#endif
|
|
|
|
errno= ENOSYS;
|
|
return -1;
|
|
}
|
|
|
|
static int _uds_getsockopt(int sock, int level, int option_name,
|
|
void *__restrict option_value, socklen_t *__restrict option_len)
|
|
{
|
|
int i, r;
|
|
size_t size;
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_RCVBUF)
|
|
{
|
|
r= ioctl(sock, NWIOGUDSRCVBUF, &size);
|
|
if (r == -1) {
|
|
return r;
|
|
}
|
|
|
|
getsockopt_copy(&size, sizeof(size), option_value, option_len);
|
|
return 0;
|
|
}
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_SNDBUF)
|
|
{
|
|
r= ioctl(sock, NWIOGUDSSNDBUF, &size);
|
|
if (r == -1) {
|
|
return r;
|
|
}
|
|
|
|
getsockopt_copy(&size, sizeof(size), option_value, option_len);
|
|
return 0;
|
|
}
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_TYPE)
|
|
{
|
|
r= ioctl(sock, NWIOGUDSSOTYPE, &i);
|
|
if (r == -1) {
|
|
return r;
|
|
}
|
|
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_PEERCRED)
|
|
{
|
|
struct uucred cred;
|
|
|
|
r= ioctl(sock, NWIOGUDSPEERCRED, &cred);
|
|
if (r == -1) {
|
|
return -1;
|
|
}
|
|
|
|
getsockopt_copy(&cred, sizeof(struct uucred), option_value,
|
|
option_len);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
|
|
{
|
|
i = 1; /* as long as nobody is listen()ing on the address,
|
|
* it can be reused without waiting for a
|
|
* timeout to expire.
|
|
*/
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
|
|
if (level == SOL_SOCKET && option_name == SO_PASSCRED)
|
|
{
|
|
i = 1; /* option is always 'on' */
|
|
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
|
return 0;
|
|
}
|
|
|
|
#if DEBUG
|
|
fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",
|
|
level, option_name);
|
|
#endif
|
|
|
|
errno= ENOSYS;
|
|
return -1;
|
|
}
|