#include "net.h"
#include "qemu-char.h"
#include "qemu-common.h"
+#include "qemu-error.h"
#include "qemu-option.h"
#include "qemu_socket.h"
-#include "sysemu.h"
typedef struct NetSocketState {
VLANClientState nc;
qemu_send_packet(&s->nc, s->buf, size);
}
-static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
+static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
{
struct ip_mreq imr;
int fd;
/* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr;
- imr.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (localaddr) {
+ imr.imr_interface = *localaddr;
+ } else {
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq));
goto fail;
}
+ /* If a bind address is given, only send packets from that address */
+ if (localaddr != NULL) {
+ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+ (const char *)localaddr, sizeof(*localaddr));
+ if (ret < 0) {
+ perror("setsockopt(IP_MULTICAST_IF)");
+ goto fail;
+ }
+ }
+
socket_set_nonblock(fd);
return fd;
fail:
return NULL;
}
/* clone dgram socket */
- newfd = net_socket_mcast_create(&saddr);
+ newfd = net_socket_mcast_create(&saddr, NULL);
if (newfd < 0) {
/* error already reported by net_socket_mcast_create() */
close(fd);
} else if (err == EINPROGRESS) {
break;
#ifdef _WIN32
- } else if (err == WSAEALREADY) {
+ } else if (err == WSAEALREADY || err == WSAEINVAL) {
break;
#endif
} else {
static int net_socket_mcast_init(VLANState *vlan,
const char *model,
const char *name,
- const char *host_str)
+ const char *host_str,
+ const char *localaddr_str)
{
NetSocketState *s;
int fd;
struct sockaddr_in saddr;
+ struct in_addr localaddr, *param_localaddr;
if (parse_host_port(&saddr, host_str) < 0)
return -1;
+ if (localaddr_str != NULL) {
+ if (inet_aton(localaddr_str, &localaddr) == 0)
+ return -1;
+ param_localaddr = &localaddr;
+ } else {
+ param_localaddr = NULL;
+ }
- fd = net_socket_mcast_create(&saddr);
+ fd = net_socket_mcast_create(&saddr, param_localaddr);
if (fd < 0)
return -1;
if (qemu_opt_get(opts, "listen") ||
qemu_opt_get(opts, "connect") ||
- qemu_opt_get(opts, "mcast")) {
- qemu_error("listen=, connect= and mcast= is invalid with fd=\n");
+ qemu_opt_get(opts, "mcast") ||
+ qemu_opt_get(opts, "localaddr")) {
+ error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=");
return -1;
}
if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "connect") ||
- qemu_opt_get(opts, "mcast")) {
- qemu_error("fd=, connect= and mcast= is invalid with listen=\n");
+ qemu_opt_get(opts, "mcast") ||
+ qemu_opt_get(opts, "localaddr")) {
+ error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=");
return -1;
}
if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "listen") ||
- qemu_opt_get(opts, "mcast")) {
- qemu_error("fd=, listen= and mcast= is invalid with connect=\n");
+ qemu_opt_get(opts, "mcast") ||
+ qemu_opt_get(opts, "localaddr")) {
+ error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=");
return -1;
}
return -1;
}
} else if (qemu_opt_get(opts, "mcast")) {
- const char *mcast;
+ const char *mcast, *localaddr;
if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "connect") ||
qemu_opt_get(opts, "listen")) {
- qemu_error("fd=, connect= and listen= is invalid with mcast=\n");
+ error_report("fd=, connect= and listen= is invalid with mcast=");
return -1;
}
mcast = qemu_opt_get(opts, "mcast");
+ localaddr = qemu_opt_get(opts, "localaddr");
- if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
+ if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
return -1;
}
} else {
- qemu_error("-socket requires fd=, listen=, connect= or mcast=\n");
+ error_report("-socket requires fd=, listen=, connect= or mcast=");
return -1;
}