int inet_listen_opts(QemuOpts *opts, int port_offset) { SockAddress** list; SockAddress* e; unsigned flags = SOCKET_LIST_PASSIVE; const char *addr; char port[33]; char uaddr[256+1]; char uport[33]; int slisten,to,try_next,nn; #ifdef CONFIG_ANDROID const char* socket_fd = qemu_opt_get(opts, "socket"); if (socket_fd) { return atoi(socket_fd); } #endif 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)) flags |= SOCKET_LIST_FORCE_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) flags |= SOCKET_LIST_FORCE_IN6; /* lookup */ if (port_offset) snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); list = sock_address_list_create( strlen(addr) ? addr : NULL, port, flags ); if (list == NULL) { fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, addr, port, errno_str); return -1; } /* create socket + bind */ for (nn = 0; list[nn] != NULL; nn++) { SocketFamily family; e = list[nn]; family = sock_address_get_family(e); sock_address_get_numeric_info(e, uaddr, sizeof uaddr, uport, sizeof uport); slisten = socket_create(family, SOCKET_STREAM); if (slisten < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, sock_address_strfamily(e), errno_str); continue; } socket_set_xreuseaddr(slisten); #ifdef IPV6_V6ONLY /* listen on both ipv4 and ipv6 */ if (family == SOCKET_IN6) { socket_set_ipv6only(slisten); } #endif for (;;) { if (socket_bind(slisten, e) == 0) { if (sockets_debug) fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, sock_address_strfamily(e), uaddr, sock_address_get_port(e)); goto listen; } socket_close(slisten); try_next = to && (sock_address_get_port(e) <= to + port_offset); if (!try_next || sockets_debug) fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, sock_address_strfamily(e), uaddr, sock_address_get_port(e), strerror(errno)); if (try_next) { sock_address_set_port(e, sock_address_get_port(e) + 1); continue; } break; } } sock_address_list_free(list); fprintf(stderr, "%s: FAILED\n", __FUNCTION__); return -1; listen: if (socket_listen(slisten,1) != 0) { perror("listen"); socket_close(slisten); return -1; } snprintf(uport, sizeof(uport), "%d", sock_address_get_port(e) - port_offset); qemu_opt_set(opts, "host", uaddr); qemu_opt_set(opts, "port", uport); qemu_opt_set(opts, "ipv6", (e->family == SOCKET_IN6) ? "on" : "off"); qemu_opt_set(opts, "ipv4", (e->family != SOCKET_IN6) ? "on" : "off"); sock_address_list_free(list); return slisten; }
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) { struct addrinfo ai,*res,*e; const char *addr; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int slisten, rc, to, port_min, port_max, p; 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)) { error_setg(errp, "host and/or port not specified"); 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) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); return -1; } /* 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) { if (!e->ai_next) { error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); } continue; } qemu_setsockopt(slisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); #ifdef IPV6_V6ONLY if (e->ai_family == PF_INET6) { /* listen on both ipv4 and ipv6 */ qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); } #endif port_min = inet_getport(e); port_max = to ? to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { inet_setport(e, p); if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { goto listen; } if (p == port_max) { if (!e->ai_next) { error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); } } } closesocket(slisten); } freeaddrinfo(res); return -1; listen: if (listen(slisten,1) != 0) { error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED); 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; }
int inet_connect_opts(QemuOpts *opts) { SockAddress** list; SockAddress* e; unsigned flags = 0; const char *addr; const char *port; int sock, nn; #ifdef CONFIG_ANDROID const char* socket_fd = qemu_opt_get(opts, "socket"); if (socket_fd) { return atoi(socket_fd); } #endif 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)) { flags &= SOCKET_LIST_FORCE_IN6; flags |= SOCKET_LIST_FORCE_INET; } if (qemu_opt_get_bool(opts, "ipv6", 0)) { flags &= SOCKET_LIST_FORCE_INET; flags |= SOCKET_LIST_FORCE_IN6; } /* lookup */ list = sock_address_list_create(addr, port, flags); if (list == NULL) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, errno_str); return -1; } for (nn = 0; list[nn] != NULL; nn++) { e = list[nn]; sock = socket_create(sock_address_get_family(e), SOCKET_STREAM); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, sock_address_strfamily(e), errno_str); continue; } socket_set_xreuseaddr(sock); /* connect to peer */ if (socket_connect(sock,e) < 0) { if (sockets_debug) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, sock_address_strfamily(e), sock_address_to_string(e), addr, port, strerror(errno)); socket_close(sock); continue; } if (sockets_debug) fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, sock_address_strfamily(e), sock_address_to_string(e), addr, port); goto EXIT; } sock = -1; EXIT: sock_address_list_free(list); return sock; }
int inet_dgram_opts(QemuOpts *opts) { SockAddress** peer_list = NULL; SockAddress** local_list = NULL; SockAddress* e; unsigned flags = 0; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock = -1; int nn; /* lookup peer addr */ 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; } flags = SOCKET_LIST_DGRAM; if (qemu_opt_get_bool(opts, "ipv4", 0)) { flags &= SOCKET_LIST_FORCE_IN6; flags |= SOCKET_LIST_FORCE_INET; } if (qemu_opt_get_bool(opts, "ipv6", 0)) { flags &= SOCKET_LIST_FORCE_INET; flags |= SOCKET_LIST_FORCE_IN6; } peer_list = sock_address_list_create(addr, port, flags); if (peer_list == NULL) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, errno_str); return -1; } /* lookup local addr */ 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"; flags = SOCKET_LIST_DGRAM | SOCKET_LIST_PASSIVE; local_list = sock_address_list_create(addr, port, flags); if (local_list == NULL) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, errno_str); goto EXIT; } if (sock_address_get_numeric_info(local_list[0], uaddr, INET6_ADDRSTRLEN, uport, 32)) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto EXIT; } for (nn = 0; peer_list[nn] != NULL; nn++) { SockAddress *local = local_list[0]; e = peer_list[nn]; sock = socket_create(sock_address_get_family(e), SOCKET_DGRAM); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, sock_address_strfamily(e), errno_str); continue; } socket_set_xreuseaddr(sock); /* bind socket */ if (socket_bind(sock, local) < 0) { fprintf(stderr,"%s: bind(%s,%s,%s): OK\n", __FUNCTION__, sock_address_strfamily(local), addr, port); socket_close(sock); continue; } /* connect to peer */ if (socket_connect(sock,e) < 0) { if (sockets_debug) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, sock_address_strfamily(e), sock_address_to_string(e), addr, port, strerror(errno)); socket_close(sock); continue; } if (sockets_debug) fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, sock_address_strfamily(e), sock_address_to_string(e), addr, port); goto EXIT; } sock = -1; EXIT: if (local_list) sock_address_list_free(local_list); if (peer_list) sock_address_list_free(peer_list); return sock; }
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) { struct addrinfo ai,*res,*e; const char *addr; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int slisten, rc, to, port_min, port_max, p; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; if ((qemu_opt_get(opts, "host") == NULL) || (qemu_opt_get(opts, "port") == NULL)) { error_setg(errp, "host and/or port not specified"); 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) { unsigned long long baseport; if (parse_uint_full(port, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", port); return -1; } if (baseport > 65535 || baseport + port_offset > 65535) { error_setg(errp, "port %s out of range", port); return -1; } snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); } rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); return -1; } /* 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) { if (!e->ai_next) { error_setg_errno(errp, errno, "Failed to create socket"); } continue; } socket_set_fast_reuse(slisten); #ifdef IPV6_V6ONLY if (e->ai_family == PF_INET6) { /* listen on both ipv4 and ipv6 */ const int off = 0; qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); } #endif port_min = inet_getport(e); port_max = to ? to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { inet_setport(e, p); if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { goto listen; } if (p == port_max) { if (!e->ai_next) { error_setg_errno(errp, errno, "Failed to bind socket"); } } } closesocket(slisten); } freeaddrinfo(res); return -1; listen: if (listen(slisten,1) != 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); closesocket(slisten); freeaddrinfo(res); return -1; } qemu_opt_set(opts, "host", uaddr, &error_abort); qemu_opt_set_number(opts, "port", inet_getport(e) - port_offset, &error_abort); qemu_opt_set_bool(opts, "ipv6", e->ai_family == PF_INET6, &error_abort); qemu_opt_set_bool(opts, "ipv4", e->ai_family != PF_INET6, &error_abort); freeaddrinfo(res); return slisten; }
int inet_dgram_opts(QemuOpts *opts, Error **errp) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; 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) { error_setg(errp, "remote port not specified"); 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))) { error_setg(errp, "address resolution failed for %s:%s: %s", 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))) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); goto err; } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); goto err; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* bind socket */ if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); goto err; } /* connect to peer */ if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); goto err; } freeaddrinfo(local); freeaddrinfo(peer); return sock; err: if (-1 != sock) closesocket(sock); if (local) freeaddrinfo(local); if (peer) freeaddrinfo(peer); return -1; }
static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *host = qemu_opt_get(opts, "host"); const char *port = qemu_opt_get(opts, "port"); const char *localaddr = qemu_opt_get(opts, "localaddr"); const char *localport = qemu_opt_get(opts, "localport"); bool has_local = false; SocketAddressLegacy *addr; ChardevUdp *udp; backend->type = CHARDEV_BACKEND_KIND_UDP; if (host == NULL || strlen(host) == 0) { host = "localhost"; } if (port == NULL || strlen(port) == 0) { error_setg(errp, "chardev: udp: remote port not specified"); return; } if (localport == NULL || strlen(localport) == 0) { localport = "0"; } else { has_local = true; } if (localaddr == NULL || strlen(localaddr) == 0) { localaddr = ""; } else { has_local = true; } udp = backend->u.udp.data = g_new0(ChardevUdp, 1); qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); addr = g_new0(SocketAddressLegacy, 1); addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(host), .port = g_strdup(port), .has_ipv4 = qemu_opt_get(opts, "ipv4"), .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), .has_ipv6 = qemu_opt_get(opts, "ipv6"), .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), }; udp->remote = addr; if (has_local) { udp->has_local = true; addr = g_new0(SocketAddressLegacy, 1); addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(localaddr), .port = g_strdup(localport), }; udp->local = addr; } } static void qmp_chardev_open_udp(Chardev *chr, ChardevBackend *backend, bool *be_opened, Error **errp) { ChardevUdp *udp = backend->u.udp.data; SocketAddress *local_addr = socket_address_flatten(udp->local); SocketAddress *remote_addr = socket_address_flatten(udp->remote); QIOChannelSocket *sioc = qio_channel_socket_new(); char *name; UdpChardev *s = UDP_CHARDEV(chr); int ret; ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp); qapi_free_SocketAddress(local_addr); qapi_free_SocketAddress(remote_addr); if (ret < 0) { object_unref(OBJECT(sioc)); return; } name = g_strdup_printf("chardev-udp-%s", chr->label); qio_channel_set_name(QIO_CHANNEL(sioc), name); g_free(name); s->ioc = QIO_CHANNEL(sioc); /* be isn't opened until we get a connection */ *be_opened = false; }
static int curl_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVCURLState *s = bs->opaque; CURLState *state = NULL; QemuOpts *opts; Error *local_err = NULL; const char *file; const char *cookie; double d; static int inited = 0; if (flags & BDRV_O_RDWR) { error_setg(errp, "curl block device does not support writes"); return -EROFS; } opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { error_propagate(errp, local_err); goto out_noclean; } s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD, READ_AHEAD_DEFAULT); if ((s->readahead_size & 0x1ff) != 0) { error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", s->readahead_size); goto out_noclean; } s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT, CURL_TIMEOUT_DEFAULT); if (s->timeout > CURL_TIMEOUT_MAX) { error_setg(errp, "timeout parameter is too large or negative"); goto out_noclean; } s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true); cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE); s->cookie = g_strdup(cookie); file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL); if (file == NULL) { error_setg(errp, "curl block driver requires an 'url' option"); goto out_noclean; } if (!inited) { curl_global_init(CURL_GLOBAL_ALL); inited = 1; } DPRINTF("CURL: Opening %s\n", file); s->aio_context = bdrv_get_aio_context(bs); s->url = g_strdup(file); state = curl_init_state(bs, s); if (!state) goto out_noclean; // Get file size s->accept_range = false; curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1); curl_easy_setopt(state->curl, CURLOPT_HEADERFUNCTION, curl_header_cb); curl_easy_setopt(state->curl, CURLOPT_HEADERDATA, s); if (curl_easy_perform(state->curl)) goto out; curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d); if (d) s->len = (size_t)d; else if(!s->len) goto out; if ((!strncasecmp(s->url, "http://", strlen("http://")) || !strncasecmp(s->url, "https://", strlen("https://"))) && !s->accept_range) { pstrcpy(state->errmsg, CURL_ERROR_SIZE, "Server does not support 'range' (byte ranges)."); goto out; } DPRINTF("CURL: Size = %zd\n", s->len); curl_clean_state(state); curl_easy_cleanup(state->curl); state->curl = NULL; curl_attach_aio_context(bs, bdrv_get_aio_context(bs)); qemu_opts_del(opts); return 0; out: error_setg(errp, "CURL: Error opening file: %s", state->errmsg); curl_easy_cleanup(state->curl); state->curl = NULL; out_noclean: g_free(s->cookie); g_free(s->url); qemu_opts_del(opts); return -EINVAL; }
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; }
static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, Error **errp) { bool is_listen = qemu_opt_get_bool(opts, "server", false); bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true); bool is_telnet = qemu_opt_get_bool(opts, "telnet", false); bool is_tn3270 = qemu_opt_get_bool(opts, "tn3270", false); bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true); int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0); const char *path = qemu_opt_get(opts, "path"); const char *host = qemu_opt_get(opts, "host"); const char *port = qemu_opt_get(opts, "port"); const char *tls_creds = qemu_opt_get(opts, "tls-creds"); SocketAddressLegacy *addr; ChardevSocket *sock; backend->type = CHARDEV_BACKEND_KIND_SOCKET; if (!path) { if (!host) { error_setg(errp, "chardev: socket: no host given"); return; } if (!port) { error_setg(errp, "chardev: socket: no port given"); return; } } else { if (tls_creds) { error_setg(errp, "TLS can only be used over TCP socket"); return; } } sock = backend->u.socket.data = g_new0(ChardevSocket, 1); qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock)); sock->has_nodelay = true; sock->nodelay = do_nodelay; sock->has_server = true; sock->server = is_listen; sock->has_telnet = true; sock->telnet = is_telnet; sock->has_tn3270 = true; sock->tn3270 = is_tn3270; sock->has_wait = true; sock->wait = is_waitconnect; sock->has_reconnect = true; sock->reconnect = reconnect; sock->tls_creds = g_strdup(tls_creds); addr = g_new0(SocketAddressLegacy, 1); if (path) { UnixSocketAddress *q_unix; addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX; q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); q_unix->path = g_strdup(path); } else { addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(host), .port = g_strdup(port), .has_to = qemu_opt_get(opts, "to"), .to = qemu_opt_get_number(opts, "to", 0), .has_ipv4 = qemu_opt_get(opts, "ipv4"), .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), .has_ipv6 = qemu_opt_get(opts, "ipv6"), .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), }; } sock->addr = addr; } static void char_socket_get_addr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { SocketChardev *s = SOCKET_CHARDEV(obj); visit_type_SocketAddress(v, name, &s->addr, errp); }
int net_init_tap(QemuOpts *opts, const char *name, VLANState *vlan) { TAPState *s; int fd, vnet_hdr = 0; const char *model; if (qemu_opt_get(opts, "fd")) { if (qemu_opt_get(opts, "ifname") || qemu_opt_get(opts, "script") || qemu_opt_get(opts, "downscript") || qemu_opt_get(opts, "vnet_hdr") || qemu_opt_get(opts, "helper")) { error_report("ifname=, script=, downscript=, vnet_hdr=, " "and helper= are invalid with fd="); return -1; } fd = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "fd")); if (fd == -1) { return -1; } fcntl(fd, F_SETFL, O_NONBLOCK); vnet_hdr = tap_probe_vnet_hdr(fd); model = "tap"; } else if (qemu_opt_get(opts, "helper")) { if (qemu_opt_get(opts, "ifname") || qemu_opt_get(opts, "script") || qemu_opt_get(opts, "downscript") || qemu_opt_get(opts, "vnet_hdr")) { error_report("ifname=, script=, downscript=, and vnet_hdr= " "are invalid with helper="); return -1; } fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"), DEFAULT_BRIDGE_INTERFACE); if (fd == -1) { return -1; } fcntl(fd, F_SETFL, O_NONBLOCK); vnet_hdr = tap_probe_vnet_hdr(fd); model = "bridge"; } else { if (!qemu_opt_get(opts, "script")) { qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT); } if (!qemu_opt_get(opts, "downscript")) { qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT); } fd = net_tap_init(opts, &vnet_hdr); if (fd == -1) { return -1; } model = "tap"; } s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr); if (!s) { close(fd); return -1; } if (tap_set_sndbuf(s->fd, opts) < 0) { return -1; } if (qemu_opt_get(opts, "fd")) { snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); } else if (qemu_opt_get(opts, "helper")) { snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", qemu_opt_get(opts, "helper")); } else { const char *ifname, *script, *downscript; ifname = qemu_opt_get(opts, "ifname"); script = qemu_opt_get(opts, "script"); downscript = qemu_opt_get(opts, "downscript"); snprintf(s->nc.info_str, sizeof(s->nc.info_str), "ifname=%s,script=%s,downscript=%s", ifname, script, downscript); if (strcmp(downscript, "no") != 0) { snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname); } } if (qemu_opt_get_bool(opts, "vhost", !!qemu_opt_get(opts, "vhostfd") || qemu_opt_get_bool(opts, "vhostforce", false))) { int vhostfd, r; bool force = qemu_opt_get_bool(opts, "vhostforce", false); if (qemu_opt_get(opts, "vhostfd")) { r = net_handle_fd_param(cur_mon, qemu_opt_get(opts, "vhostfd")); if (r == -1) { return -1; } vhostfd = r; } else { vhostfd = -1; } s->vhost_net = vhost_net_init(&s->nc, vhostfd, force); if (!s->vhost_net) { error_report("vhost-net requested but could not be initialized"); return -1; } } else if (qemu_opt_get(opts, "vhostfd")) { error_report("vhostfd= is not valid without vhost"); return -1; } return 0; }