/** * Create a non-blocking socket and connect it to an address. * Calls the callback function with fd in case of success or -1 in case of * error. * * @str: address string * @callback: callback function that is called when connect completes, * cannot be NULL. * @opaque: opaque for callback function * @errp: set in case of an error * * Returns: -1 on immediate error, file descriptor on success. **/ int inet_nonblocking_connect(const char *str, NonBlockingConnectHandler *callback, void *opaque, Error **errp) { QemuOpts *opts; int sock = -1; InetSocketAddress *addr; g_assert(callback != NULL); addr = inet_parse(str, errp); if (addr != NULL) { opts = qemu_opts_create_nofail(&dummy_opts); inet_addr_to_opts(opts, addr); qapi_free_InetSocketAddress(addr); sock = inet_connect_opts(opts, errp, callback, opaque); qemu_opts_del(opts); } return sock; }
/* compatibility wrapper */ InetSocketAddress *inet_parse(const char *str, Error **errp) { InetSocketAddress *addr; const char *optstr, *h; char host[65]; char port[33]; int to; int pos; addr = g_new0(InetSocketAddress, 1); /* parse address */ if (str[0] == ':') { /* no host given */ host[0] = '\0'; if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) { error_setg(errp, "error parsing port in address '%s'", str); goto fail; } } else if (str[0] == '[') { /* IPv6 addr */ if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) { error_setg(errp, "error parsing IPv6 address '%s'", str); goto fail; } addr->ipv6 = addr->has_ipv6 = true; } else { /* hostname or IPv4 addr */ if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) { error_setg(errp, "error parsing address '%s'", str); goto fail; } if (host[strspn(host, "0123456789.")] == '\0') { addr->ipv4 = addr->has_ipv4 = true; } } addr->host = g_strdup(host); addr->port = g_strdup(port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) { h += 4; if (sscanf(h, "%d%n", &to, &pos) != 1 || (h[pos] != '\0' && h[pos] != ',')) { error_setg(errp, "error parsing to= argument"); goto fail; } addr->has_to = true; addr->to = to; } if (strstr(optstr, ",ipv4")) { addr->ipv4 = addr->has_ipv4 = true; } if (strstr(optstr, ",ipv6")) { addr->ipv6 = addr->has_ipv6 = true; } return addr; fail: qapi_free_InetSocketAddress(addr); return NULL; }
static void nbd_parse_filename(const char *filename, QDict *options, Error **errp) { char *file; char *export_name; const char *host_spec; const char *unixpath; if (qdict_haskey(options, "host") || qdict_haskey(options, "port") || qdict_haskey(options, "path")) { error_setg(errp, "host/port/path and a file name may not be specified " "at the same time"); return; } if (strstr(filename, "://")) { int ret = nbd_parse_uri(filename, options); if (ret < 0) { error_setg(errp, "No valid URL specified"); } return; } file = g_strdup(filename); export_name = strstr(file, EN_OPTSTR); if (export_name) { if (export_name[strlen(EN_OPTSTR)] == 0) { goto out; } export_name[0] = 0; /* truncate 'file' */ export_name += strlen(EN_OPTSTR); qdict_put(options, "export", qstring_from_str(export_name)); } /* extract the host_spec - fail if it's not nbd:... */ if (!strstart(file, "nbd:", &host_spec)) { error_setg(errp, "File name string for NBD must start with 'nbd:'"); goto out; } if (!*host_spec) { goto out; } /* are we a UNIX or TCP socket? */ if (strstart(host_spec, "unix:", &unixpath)) { qdict_put(options, "path", qstring_from_str(unixpath)); } else { InetSocketAddress *addr = NULL; addr = inet_parse(host_spec, errp); if (!addr) { goto out; } qdict_put(options, "host", qstring_from_str(addr->host)); qdict_put(options, "port", qstring_from_str(addr->port)); qapi_free_InetSocketAddress(addr); } out: g_free(file); }