phunix/minix/lib/libc/sys/setsockopt.c
David van Moolenbroek 84ed480ef7 libc: fix local from-source upgrades
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
2016-03-09 12:11:57 +00:00

295 lines
5.6 KiB
C

#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.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>
#define DEBUG 0
static int _tcp_setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len);
static int _udp_setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len);
static int _uds_setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len);
/*
* Set socket options.
*/
static int
__setsockopt(int fd, int level, int option_name, const void * option_value,
socklen_t option_len)
{
message m;
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;
return _syscall(VFS_PROC_NR, VFS_SETSOCKOPT, &m);
}
int setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len)
{
int r;
nwio_tcpopt_t tcpopt;
nwio_udpopt_t udpopt;
struct sockaddr_un uds_addr;
r = __setsockopt(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_setsockopt(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_setsockopt(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_setsockopt(sock, level, option_name,
option_value, option_len);
}
errno = ENOTSOCK;
return -1;
}
static int _tcp_setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len)
{
int i;
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (!i)
{
/* At the moment there is no way to turn off
* reusing addresses.
*/
errno= ENOSYS;
return -1;
}
return 0;
}
if (level == SOL_SOCKET && option_name == SO_KEEPALIVE)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (!i)
{
/* At the moment there is no way to turn off
* keepalives.
*/
errno= ENOSYS;
return -1;
}
return 0;
}
if (level == SOL_SOCKET && option_name == SO_RCVBUF)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (i > 32*1024)
{
/* The receive buffer is limited to 32K at the moment.
*/
errno= ENOSYS;
return -1;
}
/* There is no way to reduce the receive buffer, do we have to
* let this call fail for smaller buffers?
*/
return 0;
}
if (level == SOL_SOCKET && option_name == SO_SNDBUF)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (i > 32*1024)
{
/* The send buffer is limited to 32K at the moment.
*/
errno= ENOSYS;
return -1;
}
/* There is no way to reduce the send buffer, do we have to
* let this call fail for smaller buffers?
*/
return 0;
}
if (level == IPPROTO_TCP && option_name == TCP_NODELAY)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (i)
{
/* At the moment there is no way to turn on
* nodelay.
*/
errno= ENOSYS;
return -1;
}
return 0;
}
#if DEBUG
fprintf(stderr, "_tcp_setsocketopt: level %d, name %d\n",
level, option_name);
#endif
errno= ENOSYS;
return -1;
}
static int _udp_setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len)
{
#if DEBUG
fprintf(stderr, "_udp_setsocketopt: level %d, name %d\n",
level, option_name);
#endif
errno= ENOSYS;
return -1;
}
static int _uds_setsockopt(int sock, int level, int option_name,
const void *option_value, socklen_t option_len)
{
int i;
size_t size;
if (level == SOL_SOCKET && option_name == SO_RCVBUF)
{
if (option_len != sizeof(size))
{
errno= EINVAL;
return -1;
}
size= *(const size_t *)option_value;
return ioctl(sock, NWIOSUDSRCVBUF, &size);
}
if (level == SOL_SOCKET && option_name == SO_SNDBUF)
{
if (option_len != sizeof(size))
{
errno= EINVAL;
return -1;
}
size= *(const size_t *)option_value;
return ioctl(sock, NWIOSUDSSNDBUF, &size);
}
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (!i)
{
/* At the moment there is no way to turn off
* reusing addresses.
*/
errno= ENOSYS;
return -1;
}
return 0;
}
if (level == SOL_SOCKET && option_name == SO_PASSCRED)
{
if (option_len != sizeof(i))
{
errno= EINVAL;
return -1;
}
i= *(const int *)option_value;
if (!i)
{
/* credentials can always be received. */
errno= ENOSYS;
return -1;
}
return 0;
}
#if DEBUG
fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n",
level, option_name);
#endif
errno= ENOSYS;
return -1;
}