static int vsock_listen_saddr(VsockSocketAddress *vaddr, Error **errp) { struct sockaddr_vm svm; int slisten; if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { return -1; } slisten = qemu_socket(AF_VSOCK, SOCK_STREAM, 0); if (slisten < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) != 0) { error_setg_errno(errp, errno, "Failed to bind socket"); closesocket(slisten); return -1; } if (listen(slisten, 1) != 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); closesocket(slisten); return -1; } return slisten; }
int unix_connect_opts(QemuOpts *opts) { struct sockaddr_un un; const char *path = qemu_opt_get(opts, "path"); int sock; if (NULL == path) { fprintf(stderr, "unix connect: no path specified\n"); return -1; } sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("socket(unix)"); return -1; } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); return -1; } if (sockets_debug) fprintf(stderr, "connect(unix:%s): OK\n", path); return sock; }
static int inet_connect_addr(struct addrinfo *addr, Error **errp) { int sock, rc; sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } socket_set_fast_reuse(sock); /* connect to peer */ do { rc = 0; if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { rc = -errno; } } while (rc == -EINTR); if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect socket"); closesocket(sock); return -1; } return sock; }
static int vsock_connect_addr(const struct sockaddr_vm *svm, Error **errp) { int sock, rc; sock = qemu_socket(AF_VSOCK, SOCK_STREAM, 0); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } /* connect to peer */ do { rc = 0; if (connect(sock, (const struct sockaddr *)svm, sizeof(*svm)) < 0) { rc = -errno; } } while (rc == -EINTR); if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect socket"); closesocket(sock); return -1; } return sock; }
static int vsock_connect_addr(const struct sockaddr_vm *svm, bool *in_progress, ConnectState *connect_state, Error **errp) { int sock, rc; *in_progress = false; sock = qemu_socket(AF_VSOCK, SOCK_STREAM, 0); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } if (connect_state != NULL) { qemu_set_nonblock(sock); } /* connect to peer */ do { rc = 0; if (connect(sock, (const struct sockaddr *)svm, sizeof(*svm)) < 0) { rc = -errno; } } while (rc == -EINTR); if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state); *in_progress = true; } else if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect socket"); closesocket(sock); return -1; } return sock; }
static int icmp_send(struct socket *so, struct mbuf *m, int hlen) { struct ip *ip = mtod(m, struct ip *); struct sockaddr_in addr; so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); if (so->s == -1) { return -1; } so->so_m = m; so->so_faddr = ip->ip_dst; so->so_laddr = ip->ip_src; so->so_iptos = ip->ip_tos; so->so_type = IPPROTO_ICMP; so->so_state = SS_ISFCONNECTED; so->so_expire = curtime + SO_EXPIRE; addr.sin_family = AF_INET; addr.sin_addr = so->so_faddr; insque(so, &so->slirp->icmp); if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0, (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n", errno, strerror(errno))); icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); icmp_detach(so); } return 0; }
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, ConnectState *connect_state, Error **errp) { int sock, rc; *in_progress = false; sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } socket_set_fast_reuse(sock); if (connect_state != NULL) { qemu_set_nonblock(sock); } /* connect to peer */ do { rc = 0; if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { rc = -errno; } } while (rc == -EINTR); if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state); *in_progress = true; } else if (rc < 0) { error_setg_errno(errp, errno, "Failed to connect socket"); closesocket(sock); return -1; } return sock; }
int unix_connect_opts(QemuOpts *opts, Error **errp, NonBlockingConnectHandler *callback, void *opaque) { struct sockaddr_un un; const char *path = qemu_opt_get(opts, "path"); ConnectState *connect_state = NULL; int sock, rc; if (path == NULL) { error_setg(errp, "unix connect: no path specified"); return -1; } sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } if (callback != NULL) { connect_state = g_malloc0(sizeof(*connect_state)); connect_state->callback = callback; connect_state->opaque = opaque; qemu_set_nonblock(sock); } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); /* connect to peer */ do { rc = 0; if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) { rc = -socket_error(); } } while (rc == -EINTR); if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, connect_state); return sock; } else if (rc >= 0) { /* non blocking socket immediate success, call callback */ if (callback != NULL) { callback(sock, NULL, opaque); } } if (rc < 0) { error_setg_errno(errp, -rc, "Failed to connect socket"); close(sock); sock = -1; } g_free(connect_state); return sock; }
static int create_fast_reuse_socket(struct addrinfo *e) { int slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { return -1; } socket_set_fast_reuse(slisten); return slisten; }
int udp_attach(struct socket *so) { if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) { so->so_expire = curtime + SO_EXPIRE; insque(so, &so->slirp->udb); } return(so->s); }
static int net_socket_udp_init(NetClientState *peer, const char *model, const char *name, const char *rhost, const char *lhost) { NetSocketState *s; int fd, val, ret; struct sockaddr_in laddr, raddr; if (parse_host_port(&laddr, lhost) < 0) { return -1; } if (parse_host_port(&raddr, rhost) < 0) { return -1; } fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("socket(PF_INET, SOCK_DGRAM)"); return -1; } val = 1; ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); closesocket(fd); return -1; } ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)); if (ret < 0) { perror("bind"); closesocket(fd); return -1; } s = net_socket_fd_init(peer, model, name, fd, 0); if (!s) { return -1; } s->dgram_dst = raddr; snprintf(s->nc.info_str, sizeof(s->nc.info_str), "socket: udp=%s:%d", inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); return 0; }
static int net_socket_connect_init(NetClientState *peer, const char *model, const char *name, const char *host_str) { NetSocketState *s; int fd, connected, ret, err; struct sockaddr_in saddr; if (parse_host_port(&saddr, host_str) < 0) return -1; fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } socket_set_nonblock(fd); connected = 0; for(;;) { ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { err = socket_error(); if (err == EINTR || err == EWOULDBLOCK) { } else if (err == EINPROGRESS) { break; #ifdef _WIN32 } else if (err == WSAEALREADY || err == WSAEINVAL) { break; #endif } else { perror("connect"); closesocket(fd); return -1; } } else { connected = 1; break; } } s = net_socket_fd_init(peer, model, name, fd, connected); if (!s) return -1; snprintf(s->nc.info_str, sizeof(s->nc.info_str), "socket: connect to %s:%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; }
int unix_listen_opts(QemuOpts *opts) { struct sockaddr_un un; const char *path = qemu_opt_get(opts, "path"); int sock, fd; sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("socket(unix)"); return -1; } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; if (path && strlen(path)) { snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); } else { char *tmpdir = getenv("TMPDIR"); snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", tmpdir ? tmpdir : "/tmp"); /* * This dummy fd usage silences the mktemp() unsecure warning. * Using mkstemp() doesn't make things more secure here * though. bind() complains about existing files, so we have * to unlink first and thus re-open the race window. The * worst case possible is bind() failing, i.e. a DoS attack. */ fd = mkstemp(un.sun_path); close(fd); qemu_opt_set(opts, "path", un.sun_path); } unlink(un.sun_path); if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); goto err; } if (listen(sock, 1) < 0) { fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); goto err; } if (sockets_debug) fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); return sock; err: closesocket(sock); return -1; }
static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) { struct sockaddr_un un; int sock, rc; size_t pathlen; if (saddr->path == NULL) { error_setg(errp, "unix connect: no path specified"); return -1; } sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); return -1; } pathlen = strlen(saddr->path); if (pathlen > sizeof(un.sun_path)) { error_setg(errp, "UNIX socket path '%s' is too long", saddr->path); error_append_hint(errp, "Path must be less than %zu bytes\n", sizeof(un.sun_path)); goto err; } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; memcpy(un.sun_path, saddr->path, pathlen); /* connect to peer */ do { rc = 0; if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) { rc = -errno; } } while (rc == -EINTR); if (rc < 0) { error_setg_errno(errp, -rc, "Failed to connect socket %s", saddr->path); goto err; } return sock; err: close(sock); return -1; }
static int net_socket_listen_init(VLANState *vlan, const char *model, const char *name, const char *host_str) { NetSocketListenState *s; int fd, val, ret; struct sockaddr_in saddr; if (parse_host_port(&saddr, host_str) < 0) return -1; s = g_malloc0(sizeof(NetSocketListenState)); fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); g_free(s); return -1; } socket_set_nonblock(fd); /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { perror("bind"); g_free(s); closesocket(fd); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); g_free(s); closesocket(fd); return -1; } s->vlan = vlan; s->model = g_strdup(model); s->name = name ? g_strdup(name) : NULL; s->fd = fd; qemu_set_fd_handler(fd, net_socket_accept, NULL, s); return 0; }
static int net_socket_listen_init(NetClientState *peer, const char *model, const char *name, const char *host_str) { NetClientState *nc; NetSocketState *s; struct sockaddr_in saddr; int fd, val, ret; if (parse_host_port(&saddr, host_str) < 0) return -1; fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return -1; } socket_set_nonblock(fd); /* allow fast reuse */ val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { perror("bind"); closesocket(fd); return -1; } ret = listen(fd, 0); if (ret < 0) { perror("listen"); closesocket(fd); return -1; } nc = qemu_new_net_client(&net_socket_info, peer, model, name); s = DO_UPCAST(NetSocketState, nc, nc); s->fd = -1; s->listen_fd = fd; s->nc.link_down = true; qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); return 0; }
struct socket * udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, u_int lport, int flags) { struct sockaddr_in addr; struct socket *so; socklen_t addrlen = sizeof(struct sockaddr_in); so = socreate(slirp); if (!so) { return NULL; } so->s = qemu_socket(AF_INET,SOCK_DGRAM,0); so->so_expire = curtime + SO_EXPIRE; insque(so, &slirp->udb); addr.sin_family = AF_INET; addr.sin_addr.s_addr = haddr; addr.sin_port = hport; if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { udp_detach(so); return NULL; } socket_set_fast_reuse(so->s); getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) { so->so_faddr = slirp->vhost_addr; } else { so->so_faddr = addr.sin_addr; } so->so_lport = lport; so->so_laddr.s_addr = laddr; if (flags != SS_FACCEPTONCE) so->so_expire = 0; so->so_state &= SS_PERSISTENT_MASK; so->so_state |= SS_ISFCONNECTED | flags; return so; }
static int connect_to_qemu( const char *host, const char *port ) { struct addrinfo hints; struct addrinfo *server; int ret; sock = qemu_socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { /* Error */ fprintf(stderr, "Error opening socket!\n"); return -1; } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ ret = getaddrinfo(host, port, &hints, &server); if (ret != 0) { /* Error */ fprintf(stderr, "getaddrinfo failed\n"); return -1; } if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) { /* Error */ fprintf(stderr, "Could not connect\n"); return -1; } if (verbose) { printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader)); } return sock; }
int unix_start_incoming_migration(const char *path) { struct sockaddr_un un; int sock; DPRINTF("Attempting to start an incoming migration\n"); sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno)); return -EINVAL; } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); unlink(un.sun_path); if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); goto err; } if (listen(sock, 1) < 0) { fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); goto err; } qemu_set_fd_handler2(sock, NULL, unix_accept_incoming_migration, NULL, (void *)(intptr_t)sock); return 0; err: close(sock); return -EINVAL; }
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, ConnectState *connect_state, Error **errp) { int sock, rc; *in_progress = false; sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) { error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); return -1; } qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (connect_state != NULL) { socket_set_nonblock(sock); } /* connect to peer */ do { rc = 0; if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { rc = -socket_error(); } } while (rc == -EINTR); if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, connect_state); *in_progress = true; } else if (rc < 0) { error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); closesocket(sock); return -1; } return sock; }
int qemu_http_init(void) { QemuHttpState *state = (QemuHttpState *)qemu_mallocz(sizeof(QemuHttpState)); ghttp_state = state; state->listen_fd = 0; memset(state->clients, 0, sizeof(state->clients)); state->connections = 0; state->listen_fd = qemu_socket(AF_INET, SOCK_STREAM, 0); if (state->listen_fd < 0) { return 0; } const int on = 1; setsockopt(state->listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)); struct sockaddr_in laddr; memset(&laddr, 0, sizeof(laddr)); laddr.sin_family = AF_INET; laddr.sin_port = htons(DEFAULT_HTTP_PORT); laddr.sin_addr.s_addr = INADDR_ANY; if (bind(state->listen_fd, (struct sockaddr *)&laddr, sizeof(laddr)) == -1) { return 0; } if (listen(state->listen_fd, QEMU_MAX_HTTP_CONNECTIONS) == -1) { return 0; } fcntl_setfl(state->listen_fd, O_NONBLOCK); qemu_set_fd_handler(state->listen_fd, accept_handler, NULL, (void *)state); return 1; }
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, ConnectState *connect_state) { int sock, rc; *in_progress = false; sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) { fprintf(stderr, "%s: socket(%s): %s\n", __func__, inet_strfamily(addr->ai_family), strerror(errno)); return -1; } qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (connect_state != NULL) { socket_set_nonblock(sock); } /* connect to peer */ do { rc = 0; if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { rc = -socket_error(); } } while (rc == -EINTR); if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { connect_state->fd = sock; qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, connect_state); *in_progress = true; } else if (rc < 0) { closesocket(sock); return -1; } return sock; }
static int unix_listen_saddr(UnixSocketAddress *saddr, Error **errp) { struct sockaddr_un un; int sock, fd; char *pathbuf = NULL; const char *path; sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create Unix socket"); return -1; } if (saddr->path && saddr->path[0]) { path = saddr->path; } else { const char *tmpdir = getenv("TMPDIR"); tmpdir = tmpdir ? tmpdir : "/tmp"; path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir); } if (strlen(path) > sizeof(un.sun_path)) { error_setg(errp, "UNIX socket path '%s' is too long", path); error_append_hint(errp, "Path must be less than %zu bytes\n", sizeof(un.sun_path)); goto err; } if (pathbuf != NULL) { /* * This dummy fd usage silences the mktemp() unsecure warning. * Using mkstemp() doesn't make things more secure here * though. bind() complains about existing files, so we have * to unlink first and thus re-open the race window. The * worst case possible is bind() failing, i.e. a DoS attack. */ fd = mkstemp(pathbuf); if (fd < 0) { error_setg_errno(errp, errno, "Failed to make a temporary socket %s", pathbuf); goto err; } close(fd); } if (unlink(path) < 0 && errno != ENOENT) { error_setg_errno(errp, errno, "Failed to unlink socket %s", path); goto err; } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; strncpy(un.sun_path, path, sizeof(un.sun_path)); if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { error_setg_errno(errp, errno, "Failed to bind socket to %s", path); goto err; } if (listen(sock, 1) < 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); goto err; } g_free(pathbuf); return sock; err: g_free(pathbuf); closesocket(sock); return -1; }
int inet_dgram_opts(QemuOpts *opts) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock = -1, rc; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); if (addr == NULL || strlen(addr) == 0) { addr = "localhost"; } if (port == NULL || strlen(port) == 0) { fprintf(stderr, "inet_dgram: port not specified\n"); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } if (sockets_debug) { fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port); inet_print_addrinfo(__FUNCTION__, peer); } /* lookup local addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; ai.ai_family = peer->ai_family; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "localaddr"); port = qemu_opt_get(opts, "localport"); if (addr == NULL || strlen(addr) == 0) { addr = NULL; } if (!port || strlen(port) == 0) port = "0"; if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } if (sockets_debug) { fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port); inet_print_addrinfo(__FUNCTION__, local); } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), strerror(errno)); goto err; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* bind socket */ if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto err; } if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, inet_strfamily(local->ai_family), uaddr, inet_getport(local)); goto err; } /* connect to peer */ if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen, uaddr, INET6_ADDRSTRLEN, uport, 32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto err; } if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), peer->ai_canonname, uaddr, uport, strerror(errno)); goto err; } freeaddrinfo(local); freeaddrinfo(peer); return sock; err: if (-1 != sock) closesocket(sock); if (local) freeaddrinfo(local); if (peer) freeaddrinfo(peer); return -1; }
int inet_connect_opts(QemuOpts *opts) { struct addrinfo ai,*res,*e; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock,rc; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); if (addr == NULL || port == NULL) { fprintf(stderr, "inet_connect: host and/or port not specified\n"); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; /* lookup */ if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } if (sockets_debug) inet_print_addrinfo(__FUNCTION__, res); for (e = res; e != NULL; e = e->ai_next) { if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); continue; } sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), strerror(errno)); continue; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* connect to peer */ if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { if (sockets_debug || NULL == e->ai_next) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), e->ai_canonname, uaddr, uport, strerror(errno)); closesocket(sock); continue; } if (sockets_debug) fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, inet_strfamily(e->ai_family), e->ai_canonname, uaddr, uport); freeaddrinfo(res); return sock; } freeaddrinfo(res); return -1; }
int inet_listen_opts(QemuOpts *opts, int port_offset) { struct addrinfo ai,*res,*e; const char *addr; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int slisten,rc,to,try_next; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; if ((qemu_opt_get(opts, "host") == NULL) || (qemu_opt_get(opts, "port") == NULL)) { fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__); return -1; } pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); addr = qemu_opt_get(opts, "host"); to = qemu_opt_get_number(opts, "to", 0); if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; /* lookup */ if (port_offset) snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); if (rc != 0) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } if (sockets_debug) inet_print_addrinfo(__FUNCTION__, res); /* create socket + bind */ for (e = res; e != NULL; e = e->ai_next) { getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV); slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), strerror(errno)); continue; } setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); #ifdef IPV6_V6ONLY if (e->ai_family == PF_INET6) { /* listen on both ipv4 and ipv6 */ setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, sizeof(off)); } #endif for (;;) { if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { if (sockets_debug) fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, inet_strfamily(e->ai_family), uaddr, inet_getport(e)); goto listen; } try_next = to && (inet_getport(e) <= to + port_offset); if (!try_next || sockets_debug) fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), uaddr, inet_getport(e), strerror(errno)); if (try_next) { inet_setport(e, inet_getport(e) + 1); continue; } break; } closesocket(slisten); } fprintf(stderr, "%s: FAILED\n", __FUNCTION__); freeaddrinfo(res); return -1; listen: if (listen(slisten,1) != 0) { perror("listen"); closesocket(slisten); freeaddrinfo(res); return -1; } snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset); qemu_opt_set(opts, "host", uaddr); qemu_opt_set(opts, "port", uport); qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off"); qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off"); freeaddrinfo(res); return slisten; }
/* * Listen for incoming TCP connections */ struct socket * tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, u_int lport, int flags) { struct sockaddr_in addr; struct socket *so; int s, opt = 1; socklen_t addrlen = sizeof(addr); memset(&addr, 0, addrlen); DEBUG_CALL("tcp_listen"); DEBUG_ARG("haddr = %x", haddr); DEBUG_ARG("hport = %d", hport); DEBUG_ARG("laddr = %x", laddr); DEBUG_ARG("lport = %d", lport); DEBUG_ARG("flags = %x", flags); so = socreate(slirp); if (!so) { return NULL; } /* Don't tcp_attach... we don't need so_snd nor so_rcv */ if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { free(so); return NULL; } insque(so, &slirp->tcb); /* * SS_FACCEPTONCE sockets must time out. */ if (flags & SS_FACCEPTONCE) so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; so->so_state &= SS_PERSISTENT_MASK; so->so_state |= (SS_FACCEPTCONN | flags); so->so_lport = lport; /* Kept in network format */ so->so_laddr.s_addr = laddr; /* Ditto */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = haddr; addr.sin_port = hport; if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) || (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || (listen(s,1) < 0)) { int tmperrno = errno; /* Don't clobber the real reason we failed */ close(s); sofree(so); /* Restore the real errno */ #ifdef _WIN32 WSASetLastError(tmperrno); #else errno = tmperrno; #endif return NULL; } setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); getsockname(s,(struct sockaddr *)&addr,&addrlen); so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = slirp->vhost_addr; else so->so_faddr = addr.sin_addr; so->s = s; return so; }
int inet_connect_opts(QemuOpts *opts, Error **errp) { struct addrinfo ai,*res,*e; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock,rc; bool block; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); block = qemu_opt_get_bool(opts, "block", 0); if (addr == NULL || port == NULL) { fprintf(stderr, "inet_connect: host and/or port not specified\n"); error_set(errp, QERR_SOCKET_CREATE_FAILED); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; /* lookup */ if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); error_set(errp, QERR_SOCKET_CREATE_FAILED); return -1; } for (e = res; e != NULL; e = e->ai_next) { if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); continue; } sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), strerror(errno)); continue; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); if (!block) { socket_set_nonblock(sock); } /* connect to peer */ do { rc = 0; if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) { rc = -socket_error(); } } while (rc == -EINTR); #ifdef _WIN32 if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK || rc == -WSAEALREADY)) { #else if (!block && (rc == -EINPROGRESS)) { #endif error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS); } else if (rc < 0) { if (NULL == e->ai_next) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), e->ai_canonname, uaddr, uport, strerror(errno)); closesocket(sock); sock = -1; continue; } freeaddrinfo(res); return sock; } error_set(errp, QERR_SOCKET_CONNECT_FAILED); freeaddrinfo(res); return -1; } int inet_dgram_opts(QemuOpts *opts) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock = -1, rc; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); if (addr == NULL || strlen(addr) == 0) { addr = "localhost"; } if (port == NULL || strlen(port) == 0) { fprintf(stderr, "inet_dgram: port not specified\n"); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } /* lookup local addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; ai.ai_family = peer->ai_family; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "localaddr"); port = qemu_opt_get(opts, "localport"); if (addr == NULL || strlen(addr) == 0) { addr = NULL; } if (!port || strlen(port) == 0) port = "0"; if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), strerror(errno)); goto err; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* bind socket */ if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto err; } if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, inet_strfamily(local->ai_family), uaddr, inet_getport(local)); goto err; } /* connect to peer */ if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen, uaddr, INET6_ADDRSTRLEN, uport, 32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto err; } if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), peer->ai_canonname, uaddr, uport, strerror(errno)); goto err; } freeaddrinfo(local); freeaddrinfo(peer); return sock; err: if (-1 != sock) closesocket(sock); if (local) freeaddrinfo(local); if (peer) freeaddrinfo(peer); return -1; } /* compatibility wrapper */ static int inet_parse(QemuOpts *opts, const char *str) { const char *optstr, *h; char addr[64]; char port[33]; int pos; /* parse address */ if (str[0] == ':') { /* no host given */ addr[0] = '\0'; if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { fprintf(stderr, "%s: portonly parse error (%s)\n", __FUNCTION__, str); return -1; } } else if (str[0] == '[') { /* IPv6 addr */ if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv6 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv6", "on"); } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv4 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv4", "on"); } else { /* hostname */ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: hostname parse error (%s)\n", __FUNCTION__, str); return -1; } } qemu_opt_set(opts, "host", addr); qemu_opt_set(opts, "port", port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) qemu_opt_set(opts, "to", h+4); if (strstr(optstr, ",ipv4")) qemu_opt_set(opts, "ipv4", "on"); if (strstr(optstr, ",ipv6")) qemu_opt_set(opts, "ipv6", "on"); return 0; } int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp) { QemuOpts *opts; char *optstr; int sock = -1; opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); if (inet_parse(opts, str) == 0) { sock = inet_listen_opts(opts, port_offset, errp); if (sock != -1 && ostr) { optstr = strchr(str, ','); if (qemu_opt_get_bool(opts, "ipv6", 0)) { snprintf(ostr, olen, "[%s]:%s%s", qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), optstr ? optstr : ""); } else { snprintf(ostr, olen, "%s:%s%s", qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), optstr ? optstr : ""); } } } else { error_set(errp, QERR_SOCKET_CREATE_FAILED); } qemu_opts_del(opts); return sock; }
static void test_io_channel_ipv4(bool async) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); SocketAddress *connect_addr = g_new0(SocketAddress, 1); listen_addr->type = SOCKET_ADDRESS_TYPE_INET; listen_addr->u.inet = (InetSocketAddress) { .host = g_strdup("127.0.0.1"), .port = NULL, /* Auto-select */ }; connect_addr->type = SOCKET_ADDRESS_TYPE_INET; connect_addr->u.inet = (InetSocketAddress) { .host = g_strdup("127.0.0.1"), .port = NULL, /* Filled in later */ }; test_io_channel(async, listen_addr, connect_addr, false); qapi_free_SocketAddress(listen_addr); qapi_free_SocketAddress(connect_addr); } static void test_io_channel_ipv4_sync(void) { return test_io_channel_ipv4(false); } static void test_io_channel_ipv4_async(void) { return test_io_channel_ipv4(true); } static void test_io_channel_ipv6(bool async) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); SocketAddress *connect_addr = g_new0(SocketAddress, 1); listen_addr->type = SOCKET_ADDRESS_TYPE_INET; listen_addr->u.inet = (InetSocketAddress) { .host = g_strdup("::1"), .port = NULL, /* Auto-select */ }; connect_addr->type = SOCKET_ADDRESS_TYPE_INET; connect_addr->u.inet = (InetSocketAddress) { .host = g_strdup("::1"), .port = NULL, /* Filled in later */ }; test_io_channel(async, listen_addr, connect_addr, false); qapi_free_SocketAddress(listen_addr); qapi_free_SocketAddress(connect_addr); } static void test_io_channel_ipv6_sync(void) { return test_io_channel_ipv6(false); } static void test_io_channel_ipv6_async(void) { return test_io_channel_ipv6(true); } #ifndef _WIN32 static void test_io_channel_unix(bool async) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); SocketAddress *connect_addr = g_new0(SocketAddress, 1); #define TEST_SOCKET "test-io-channel-socket.sock" listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX; listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET); connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX; connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET); test_io_channel(async, listen_addr, connect_addr, true); qapi_free_SocketAddress(listen_addr); qapi_free_SocketAddress(connect_addr); g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS) == FALSE); } static void test_io_channel_unix_sync(void) { return test_io_channel_unix(false); } static void test_io_channel_unix_async(void) { return test_io_channel_unix(true); } static void test_io_channel_unix_fd_pass(void) { SocketAddress *listen_addr = g_new0(SocketAddress, 1); SocketAddress *connect_addr = g_new0(SocketAddress, 1); QIOChannel *src, *dst; int testfd; int fdsend[3]; int *fdrecv = NULL; size_t nfdrecv = 0; size_t i; char bufsend[12], bufrecv[12]; struct iovec iosend[1], iorecv[1]; #define TEST_SOCKET "test-io-channel-socket.sock" #define TEST_FILE "test-io-channel-socket.txt" testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700); g_assert(testfd != -1); fdsend[0] = testfd; fdsend[1] = testfd; fdsend[2] = testfd; listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX; listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET); connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX; connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET); test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst); memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend)); iosend[0].iov_base = bufsend; iosend[0].iov_len = G_N_ELEMENTS(bufsend); iorecv[0].iov_base = bufrecv; iorecv[0].iov_len = G_N_ELEMENTS(bufrecv); g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); qio_channel_writev_full(src, iosend, G_N_ELEMENTS(iosend), fdsend, G_N_ELEMENTS(fdsend), &error_abort); qio_channel_readv_full(dst, iorecv, G_N_ELEMENTS(iorecv), &fdrecv, &nfdrecv, &error_abort); g_assert(nfdrecv == G_N_ELEMENTS(fdsend)); /* Each recvd FD should be different from sent FD */ for (i = 0; i < nfdrecv; i++) { g_assert_cmpint(fdrecv[i], !=, testfd); } /* Each recvd FD should be different from each other */ g_assert_cmpint(fdrecv[0], !=, fdrecv[1]); g_assert_cmpint(fdrecv[0], !=, fdrecv[2]); g_assert_cmpint(fdrecv[1], !=, fdrecv[2]); /* Check the I/O buf we sent at the same time matches */ g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); /* Write some data into the FD we received */ g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) == G_N_ELEMENTS(bufsend)); /* Read data from the original FD and make sure it matches */ memset(bufrecv, 0, G_N_ELEMENTS(bufrecv)); g_assert(lseek(testfd, 0, SEEK_SET) == 0); g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) == G_N_ELEMENTS(bufrecv)); g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); object_unref(OBJECT(src)); object_unref(OBJECT(dst)); qapi_free_SocketAddress(listen_addr); qapi_free_SocketAddress(connect_addr); unlink(TEST_SOCKET); unlink(TEST_FILE); close(testfd); for (i = 0; i < nfdrecv; i++) { close(fdrecv[i]); } g_free(fdrecv); } static void test_io_channel_unix_listen_cleanup(void) { QIOChannelSocket *ioc; struct sockaddr_un un; int sock; #define TEST_SOCKET "test-io-channel-socket.sock" ioc = qio_channel_socket_new(); /* Manually bind ioc without calling the qio api to avoid setting * the LISTEN feature */ sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET); unlink(TEST_SOCKET); bind(sock, (struct sockaddr *)&un, sizeof(un)); ioc->fd = sock; ioc->localAddrLen = sizeof(ioc->localAddr); getsockname(sock, (struct sockaddr *)&ioc->localAddr, &ioc->localAddrLen); g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS)); object_unref(OBJECT(ioc)); g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS)); unlink(TEST_SOCKET); }
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr) { struct ip_mreq imr; int fd; int val, ret; #ifdef __OpenBSD__ unsigned char loop; #else int loop; #endif if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) " "does not contain a multicast address\n", inet_ntoa(mcastaddr->sin_addr), (int)ntohl(mcastaddr->sin_addr.s_addr)); return -1; } fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("socket(PF_INET, SOCK_DGRAM)"); return -1; } val = 1; ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val)); if (ret < 0) { perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); goto fail; } ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); if (ret < 0) { perror("bind"); goto fail; } /* Add host to multicast group */ imr.imr_multiaddr = mcastaddr->sin_addr; 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)); if (ret < 0) { perror("setsockopt(IP_ADD_MEMBERSHIP)"); goto fail; } /* Force mcast msgs to loopback (eg. several QEMUs in same host */ loop = 1; ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const char *)&loop, sizeof(loop)); if (ret < 0) { perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); 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: if (fd >= 0) closesocket(fd); return -1; }