xemu/include/qemu/sockets.h
Laurent Vivier 894022e616 net: check if the file descriptor is valid before using it
qemu_set_nonblock() checks that the file descriptor can be used and, if
not, crashes QEMU. An assert() is used for that. The use of assert() is
used to detect programming error and the coredump will allow to debug
the problem.

But in the case of the tap device, this assert() can be triggered by
a misconfiguration by the user. At startup, it's not a real problem, but it
can also happen during the hot-plug of a new device, and here it's a
problem because we can crash a perfectly healthy system.

For instance:
 # ip link add link virbr0 name macvtap0 type macvtap mode bridge
 # ip link set macvtap0 up
 # TAP=/dev/tap$(ip -o link show macvtap0 | cut -d: -f1)
 # qemu-system-x86_64 -machine q35 -device pcie-root-port,id=pcie-root-port-0 -monitor stdio 9<> $TAP
 (qemu) netdev_add type=tap,id=hostnet0,vhost=on,fd=9
 (qemu) device_add driver=virtio-net-pci,netdev=hostnet0,id=net0,bus=pcie-root-port-0
 (qemu) device_del net0
 (qemu) netdev_del hostnet0
 (qemu) netdev_add type=tap,id=hostnet1,vhost=on,fd=9
 qemu-system-x86_64: .../util/oslib-posix.c:247: qemu_set_nonblock: Assertion `f != -1' failed.
 Aborted (core dumped)

To avoid that, add a function, qemu_try_set_nonblock(), that allows to report the
problem without crashing.

In the same way, we also update the function for vhostfd in net_init_tap_one() and
for fd in net_init_socket() (both descriptors are provided by the user and can
be wrong).

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
2020-07-15 21:00:13 +08:00

115 lines
3.5 KiB
C

/* headers to use the BSD sockets */
#ifndef QEMU_SOCKETS_H
#define QEMU_SOCKETS_H
#ifdef _WIN32
int inet_aton(const char *cp, struct in_addr *ia);
#endif /* !_WIN32 */
#include "qapi/qapi-types-sockets.h"
/* misc helpers */
bool fd_is_socket(int fd);
int qemu_socket(int domain, int type, int protocol);
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
int socket_set_cork(int fd, int v);
int socket_set_nodelay(int fd);
void qemu_set_block(int fd);
int qemu_try_set_nonblock(int fd);
void qemu_set_nonblock(int fd);
int socket_set_fast_reuse(int fd);
#ifdef WIN32
/* Windows has different names for the same constants with the same values */
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#endif
int inet_ai_family_from_address(InetSocketAddress *addr,
Error **errp);
int inet_parse(InetSocketAddress *addr, const char *str, Error **errp);
int inet_connect(const char *str, Error **errp);
int inet_connect_saddr(InetSocketAddress *saddr, Error **errp);
NetworkAddressFamily inet_netfamily(int family);
int unix_listen(const char *path, Error **errp);
int unix_connect(const char *path, Error **errp);
SocketAddress *socket_parse(const char *str, Error **errp);
int socket_connect(SocketAddress *addr, Error **errp);
int socket_listen(SocketAddress *addr, int num, Error **errp);
void socket_listen_cleanup(int fd, Error **errp);
int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
/* Old, ipv4 only bits. Don't use for new code. */
int parse_host_port(struct sockaddr_in *saddr, const char *str,
Error **errp);
int socket_init(void);
/**
* socket_sockaddr_to_address:
* @sa: socket address struct
* @salen: size of @sa struct
* @errp: pointer to uninitialized error object
*
* Get the string representation of the socket
* address. A pointer to the allocated address information
* struct will be returned, which the caller is required to
* release with a call qapi_free_SocketAddress() when no
* longer required.
*
* Returns: the socket address struct, or NULL on error
*/
SocketAddress *
socket_sockaddr_to_address(struct sockaddr_storage *sa,
socklen_t salen,
Error **errp);
/**
* socket_local_address:
* @fd: the socket file handle
* @errp: pointer to uninitialized error object
*
* Get the string representation of the local socket
* address. A pointer to the allocated address information
* struct will be returned, which the caller is required to
* release with a call qapi_free_SocketAddress() when no
* longer required.
*
* Returns: the socket address struct, or NULL on error
*/
SocketAddress *socket_local_address(int fd, Error **errp);
/**
* socket_remote_address:
* @fd: the socket file handle
* @errp: pointer to uninitialized error object
*
* Get the string representation of the remote socket
* address. A pointer to the allocated address information
* struct will be returned, which the caller is required to
* release with a call qapi_free_SocketAddress() when no
* longer required.
*
* Returns: the socket address struct, or NULL on error
*/
SocketAddress *socket_remote_address(int fd, Error **errp);
/**
* socket_address_flatten:
* @addr: the socket address to flatten
*
* Convert SocketAddressLegacy to SocketAddress. Caller is responsible
* for freeing with qapi_free_SocketAddress().
*
* Returns: the argument converted to SocketAddress.
*/
SocketAddress *socket_address_flatten(SocketAddressLegacy *addr);
#endif /* QEMU_SOCKETS_H */