slirp: replace most qemu socket utilities with slirp own version

qemu_set_nonblock() is slightly more problematic and will be dealt
with in a separate patch.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
This commit is contained in:
Marc-André Lureau 2019-01-17 15:43:40 +04:00 committed by Samuel Thibault
parent 9032941640
commit 707bd47ef3
8 changed files with 274 additions and 36 deletions

View File

@ -27,6 +27,7 @@ slirp.mo-objs = \
tftp.o \ tftp.o \
udp.o \ udp.o \
udp6.o \ udp6.o \
util.o \
$(NULL) $(NULL)
slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" -DWITH_QEMU

View File

@ -83,7 +83,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
struct ip *ip = mtod(m, struct ip *); struct ip *ip = mtod(m, struct ip *);
struct sockaddr_in addr; struct sockaddr_in addr;
so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (so->s == -1) { if (so->s == -1) {
return -1; return -1;
} }
@ -114,7 +114,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
void icmp_detach(struct socket *so) void icmp_detach(struct socket *so)
{ {
closesocket(so->s); slirp_closesocket(so->s);
sofree(so); sofree(so);
} }
@ -421,7 +421,7 @@ void icmp_receive(struct socket *so)
icp = mtod(m, struct icmp *); icp = mtod(m, struct icmp *);
id = icp->icmp_id; id = icp->icmp_id;
len = qemu_recv(so->s, icp, M_ROOM(m), 0); len = slirp_recv(so->s, icp, M_ROOM(m), 0);
/* /*
* The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent * The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
* between host OSes. On Linux, only the ICMP header and payload is * between host OSes. On Linux, only the ICMP header and payload is

View File

@ -72,14 +72,14 @@ slirp_socketpair_with_oob(int sv[2])
int ret, s; int ret, s;
sv[1] = -1; sv[1] = -1;
s = qemu_socket(AF_INET, SOCK_STREAM, 0); s = slirp_socket(AF_INET, SOCK_STREAM, 0);
if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
listen(s, 1) < 0 || listen(s, 1) < 0 ||
getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) { getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
goto err; goto err;
} }
sv[1] = qemu_socket(AF_INET, SOCK_STREAM, 0); sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);
if (sv[1] < 0) { if (sv[1] < 0) {
goto err; goto err;
} }
@ -102,16 +102,16 @@ slirp_socketpair_with_oob(int sv[2])
goto err; goto err;
} }
closesocket(s); slirp_closesocket(s);
return 0; return 0;
err: err:
g_critical("slirp_socketpair(): %s", strerror(errno)); g_critical("slirp_socketpair(): %s", strerror(errno));
if (s >= 0) { if (s >= 0) {
closesocket(s); slirp_closesocket(s);
} }
if (sv[1] >= 0) { if (sv[1] >= 0) {
closesocket(sv[1]); slirp_closesocket(sv[1]);
} }
return -1; return -1;
} }
@ -153,16 +153,16 @@ fork_exec(struct socket *so, const char *ex)
if (err) { if (err) {
g_critical("fork_exec: %s", err->message); g_critical("fork_exec: %s", err->message);
g_error_free(err); g_error_free(err);
closesocket(sp[0]); slirp_closesocket(sp[0]);
closesocket(sp[1]); slirp_closesocket(sp[1]);
return 0; return 0;
} }
so->s = sp[0]; so->s = sp[0];
closesocket(sp[1]); slirp_closesocket(sp[1]);
socket_set_fast_reuse(so->s); slirp_socket_set_fast_reuse(so->s);
opt = 1; opt = 1;
qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); slirp_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
qemu_set_nonblock(so->s); qemu_set_nonblock(so->s);
return 1; return 1;
} }

View File

@ -187,7 +187,7 @@ soread(struct socket *so)
*/ */
sopreprbuf(so, iov, &n); sopreprbuf(so, iov, &n);
nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0); nn = slirp_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
if (nn <= 0) { if (nn <= 0) {
if (nn < 0 && (errno == EINTR || errno == EAGAIN)) if (nn < 0 && (errno == EINTR || errno == EAGAIN))
return 0; return 0;
@ -203,7 +203,7 @@ soread(struct socket *so)
if (getpeername(so->s, paddr, &alen) < 0) { if (getpeername(so->s, paddr, &alen) < 0) {
err = errno; err = errno;
} else { } else {
getsockopt(so->s, SOL_SOCKET, SO_ERROR, slirp_getsockopt(so->s, SOL_SOCKET, SO_ERROR,
&err, &elen); &err, &elen);
} }
} }
@ -233,7 +233,7 @@ soread(struct socket *so)
*/ */
if (n == 2 && nn == iov[0].iov_len) { if (n == 2 && nn == iov[0].iov_len) {
int ret; int ret;
ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0); ret = slirp_recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
if (ret > 0) if (ret > 0)
nn += ret; nn += ret;
} }
@ -554,7 +554,7 @@ sorecvfrom(struct socket *so)
*/ */
len = M_FREEROOM(m); len = M_FREEROOM(m);
/* if (so->so_fport != htons(53)) { */ /* if (so->so_fport != htons(53)) { */
ioctlsocket(so->s, FIONREAD, &n); slirp_ioctlsocket(so->s, FIONREAD, &n);
if (n > len) { if (n > len) {
n = (m->m_data - m->m_dat) + m->m_len + n + 1; n = (m->m_data - m->m_dat) + m->m_len + n + 1;
@ -719,14 +719,14 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
addr.sin_addr.s_addr = haddr; addr.sin_addr.s_addr = haddr;
addr.sin_port = hport; addr.sin_port = hport;
if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) || if (((s = slirp_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
(socket_set_fast_reuse(s) < 0) || (slirp_socket_set_fast_reuse(s) < 0) ||
(bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
(listen(s,1) < 0)) { (listen(s,1) < 0)) {
int tmperrno = errno; /* Don't clobber the real reason we failed */ int tmperrno = errno; /* Don't clobber the real reason we failed */
if (s >= 0) { if (s >= 0) {
closesocket(s); slirp_closesocket(s);
} }
sofree(so); sofree(so);
/* Restore the real errno */ /* Restore the real errno */
@ -737,9 +737,9 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
#endif #endif
return NULL; return NULL;
} }
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); slirp_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
opt = 1; opt = 1;
qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int)); slirp_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
getsockname(s,(struct sockaddr *)&addr,&addrlen); getsockname(s,(struct sockaddr *)&addr,&addrlen);
so->so_ffamily = AF_INET; so->so_ffamily = AF_INET;

View File

@ -337,7 +337,7 @@ tcp_close(struct tcpcb *tp)
/* clobber input socket cache if we're closing the cached connection */ /* clobber input socket cache if we're closing the cached connection */
if (so == slirp->tcp_last_so) if (so == slirp->tcp_last_so)
slirp->tcp_last_so = &slirp->tcb; slirp->tcp_last_so = &slirp->tcb;
closesocket(so->s); slirp_closesocket(so->s);
sbfree(&so->so_rcv); sbfree(&so->so_rcv);
sbfree(&so->so_snd); sbfree(&so->so_snd);
sofree(so); sofree(so);
@ -407,17 +407,17 @@ int tcp_fconnect(struct socket *so, unsigned short af)
DEBUG_CALL("tcp_fconnect"); DEBUG_CALL("tcp_fconnect");
DEBUG_ARG("so = %p", so); DEBUG_ARG("so = %p", so);
ret = so->s = qemu_socket(af, SOCK_STREAM, 0); ret = so->s = slirp_socket(af, SOCK_STREAM, 0);
if (ret >= 0) { if (ret >= 0) {
int opt, s=so->s; int opt, s=so->s;
struct sockaddr_storage addr; struct sockaddr_storage addr;
qemu_set_nonblock(s); qemu_set_nonblock(s);
socket_set_fast_reuse(s); slirp_socket_set_fast_reuse(s);
opt = 1; opt = 1;
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); slirp_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
opt = 1; opt = 1;
qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); slirp_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
addr = so->fhost.ss; addr = so->fhost.ss;
DEBUG_CALL(" connect()ing"); DEBUG_CALL(" connect()ing");
@ -485,10 +485,10 @@ void tcp_connect(struct socket *inso)
return; return;
} }
qemu_set_nonblock(s); qemu_set_nonblock(s);
socket_set_fast_reuse(s); slirp_socket_set_fast_reuse(s);
opt = 1; opt = 1;
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); slirp_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
socket_set_nodelay(s); slirp_socket_set_nodelay(s);
so->fhost.ss = addr; so->fhost.ss = addr;
sotranslate_accept(so); sotranslate_accept(so);
@ -496,7 +496,7 @@ void tcp_connect(struct socket *inso)
/* Close the accept() socket, set right state */ /* Close the accept() socket, set right state */
if (inso->so_state & SS_FACCEPTONCE) { if (inso->so_state & SS_FACCEPTONCE) {
/* If we only accept once, close the accept() socket */ /* If we only accept once, close the accept() socket */
closesocket(so->s); slirp_closesocket(so->s);
/* Don't select it yet, even though we have an FD */ /* Don't select it yet, even though we have an FD */
/* if it's not FACCEPTONCE, it's already NOFDREF */ /* if it's not FACCEPTONCE, it's already NOFDREF */

View File

@ -281,7 +281,7 @@ int udp_output(struct socket *so, struct mbuf *m,
int int
udp_attach(struct socket *so, unsigned short af) udp_attach(struct socket *so, unsigned short af)
{ {
so->s = qemu_socket(af, SOCK_DGRAM, 0); so->s = slirp_socket(af, SOCK_DGRAM, 0);
if (so->s != -1) { if (so->s != -1) {
so->so_expire = curtime + SO_EXPIRE; so->so_expire = curtime + SO_EXPIRE;
insque(so, &so->slirp->udb); insque(so, &so->slirp->udb);
@ -292,7 +292,7 @@ udp_attach(struct socket *so, unsigned short af)
void void
udp_detach(struct socket *so) udp_detach(struct socket *so)
{ {
closesocket(so->s); slirp_closesocket(so->s);
sofree(so); sofree(so);
} }
@ -327,7 +327,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
socklen_t addrlen = sizeof(struct sockaddr_in); socklen_t addrlen = sizeof(struct sockaddr_in);
so = socreate(slirp); so = socreate(slirp);
so->s = qemu_socket(AF_INET,SOCK_DGRAM,0); so->s = slirp_socket(AF_INET,SOCK_DGRAM,0);
if (so->s < 0) { if (so->s < 0) {
sofree(so); sofree(so);
return NULL; return NULL;
@ -343,7 +343,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
udp_detach(so); udp_detach(so);
return NULL; return NULL;
} }
socket_set_fast_reuse(so->s); slirp_socket_set_fast_reuse(so->s);
getsockname(so->s,(struct sockaddr *)&addr,&addrlen); getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
so->fhost.sin = addr; so->fhost.sin = addr;

176
slirp/util.c Normal file
View File

@ -0,0 +1,176 @@
/*
* util.c (mostly based on QEMU os-win32.c)
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2010-2016 Red Hat, Inc.
*
* QEMU library functions for win32 which are shared between QEMU and
* the QEMU tools.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "util.h"
#include <glib.h>
#include <fcntl.h>
#include <stdint.h>
#if defined(_WIN32) && !defined(WITH_QEMU)
int inet_aton(const char *cp, struct in_addr *ia)
{
uint32_t addr = inet_addr(cp);
if (addr == 0xffffffff) {
return 0;
}
ia->s_addr = addr;
return 1;
}
#endif
static void slirp_set_cloexec(int fd)
{
#ifndef _WIN32
int f;
f = fcntl(fd, F_GETFD);
assert(f != -1);
f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
assert(f != -1);
#endif
}
/*
* Opens a socket with FD_CLOEXEC set
*/
int slirp_socket(int domain, int type, int protocol)
{
int ret;
#ifdef SOCK_CLOEXEC
ret = socket(domain, type | SOCK_CLOEXEC, protocol);
if (ret != -1 || errno != EINVAL) {
return ret;
}
#endif
ret = socket(domain, type, protocol);
if (ret >= 0) {
slirp_set_cloexec(ret);
}
return ret;
}
#ifdef _WIN32
static int socket_error(void)
{
switch (WSAGetLastError()) {
case 0:
return 0;
case WSAEINTR:
return EINTR;
case WSAEINVAL:
return EINVAL;
case WSA_INVALID_HANDLE:
return EBADF;
case WSA_NOT_ENOUGH_MEMORY:
return ENOMEM;
case WSA_INVALID_PARAMETER:
return EINVAL;
case WSAENAMETOOLONG:
return ENAMETOOLONG;
case WSAENOTEMPTY:
return ENOTEMPTY;
case WSAEWOULDBLOCK:
/* not using EWOULDBLOCK as we don't want code to have
* to check both EWOULDBLOCK and EAGAIN */
return EAGAIN;
case WSAEINPROGRESS:
return EINPROGRESS;
case WSAEALREADY:
return EALREADY;
case WSAENOTSOCK:
return ENOTSOCK;
case WSAEDESTADDRREQ:
return EDESTADDRREQ;
case WSAEMSGSIZE:
return EMSGSIZE;
case WSAEPROTOTYPE:
return EPROTOTYPE;
case WSAENOPROTOOPT:
return ENOPROTOOPT;
case WSAEPROTONOSUPPORT:
return EPROTONOSUPPORT;
case WSAEOPNOTSUPP:
return EOPNOTSUPP;
case WSAEAFNOSUPPORT:
return EAFNOSUPPORT;
case WSAEADDRINUSE:
return EADDRINUSE;
case WSAEADDRNOTAVAIL:
return EADDRNOTAVAIL;
case WSAENETDOWN:
return ENETDOWN;
case WSAENETUNREACH:
return ENETUNREACH;
case WSAENETRESET:
return ENETRESET;
case WSAECONNABORTED:
return ECONNABORTED;
case WSAECONNRESET:
return ECONNRESET;
case WSAENOBUFS:
return ENOBUFS;
case WSAEISCONN:
return EISCONN;
case WSAENOTCONN:
return ENOTCONN;
case WSAETIMEDOUT:
return ETIMEDOUT;
case WSAECONNREFUSED:
return ECONNREFUSED;
case WSAELOOP:
return ELOOP;
case WSAEHOSTUNREACH:
return EHOSTUNREACH;
default:
return EIO;
}
}
#undef ioctlsocket
int slirp_ioctlsocket(int fd, int req, void *val)
{
int ret;
ret = ioctlsocket(fd, req, val);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#undef closesocket
int slirp_closesocket(int fd)
{
int ret;
ret = closesocket(fd);
if (ret < 0) {
errno = socket_error();
}
return ret;
}
#endif /* WIN32 */

View File

@ -23,10 +23,71 @@
#ifndef UTIL_H_ #ifndef UTIL_H_
#define UTIL_H_ #define UTIL_H_
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inttypes.h>
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#endif
#if defined(_WIN32) #if defined(_WIN32)
# define SLIRP_PACKED __attribute__((gcc_struct, packed)) # define SLIRP_PACKED __attribute__((gcc_struct, packed))
#else #else
# define SLIRP_PACKED __attribute__((packed)) # define SLIRP_PACKED __attribute__((packed))
#endif #endif
#ifdef _WIN32
int slirp_closesocket(int fd);
int slirp_ioctlsocket(int fd, int req, void *val);
#ifndef WITH_QEMU
int inet_aton(const char *cp, struct in_addr *ia);
#endif
#define slirp_getsockopt(sockfd, level, optname, optval, optlen) \
getsockopt(sockfd, level, optname, (void *)optval, optlen)
#define slirp_setsockopt(sockfd, level, optname, optval, optlen) \
setsockopt(sockfd, level, optname, (const void *)optval, optlen)
#define slirp_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags)
#else
#define slirp_setsockopt setsockopt
#define slirp_getsockopt getsockopt
#define slirp_recv recv
#define slirp_closesocket close
#define slirp_ioctlsocket ioctl
#endif
int slirp_socket(int domain, int type, int protocol);
static inline int slirp_socket_set_nodelay(int fd)
{
int v = 1;
return slirp_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
}
static inline int slirp_socket_set_fast_reuse(int fd)
{
#ifndef _WIN32
int v = 1;
return slirp_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
#else
/* Enabling the reuse of an endpoint that was used by a socket still in
* TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
* fast reuse is the default and SO_REUSEADDR does strange things. So we
* don't have to do anything here. More info can be found at:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
return 0;
#endif
}
#endif #endif