Commit d247d25f18764402899b37c381bb696a79000b4e
1 parent
065e2813
sockets: helper functions for qemu (Gerd Hoffman)
This patch creates a new source file qemu-sockets.c with a bunch of helper functions to create listening and connected sockets. New features of this code are (a) support for searching for a free port in a given range and (b) support for IPv6. The following patches put that code into use. Compile fixes for Windows added by Anthony Liguori Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5695 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
417 additions
and
6 deletions
Makefile.target
| ... | ... | @@ -589,7 +589,7 @@ ifndef CONFIG_USER_ONLY |
| 589 | 589 | |
| 590 | 590 | OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o net-checksum.o |
| 591 | 591 | OBJS+=fw_cfg.o aio.o buffered_file.o migration.o migration-tcp.o qemu-char.o |
| 592 | -OBJS+=net.o | |
| 592 | +OBJS+=net.o qemu-sockets.o | |
| 593 | 593 | ifdef CONFIG_KVM |
| 594 | 594 | OBJS+=kvm.o kvm-all.o |
| 595 | 595 | endif | ... | ... |
qemu-char.c
| ... | ... | @@ -442,7 +442,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) |
| 442 | 442 | |
| 443 | 443 | |
| 444 | 444 | #ifdef _WIN32 |
| 445 | -int send_all(int fd, const uint8_t *buf, int len1) | |
| 445 | +int send_all(int fd, const void *buf, int len1) | |
| 446 | 446 | { |
| 447 | 447 | int ret, len; |
| 448 | 448 | |
| ... | ... | @@ -487,7 +487,7 @@ static int unix_write(int fd, const uint8_t *buf, int len1) |
| 487 | 487 | return len1 - len; |
| 488 | 488 | } |
| 489 | 489 | |
| 490 | -int send_all(int fd, const uint8_t *buf, int len1) | |
| 490 | +int send_all(int fd, const void *buf, int len1) | |
| 491 | 491 | { |
| 492 | 492 | return unix_write(fd, buf, len1); |
| 493 | 493 | } | ... | ... |
qemu-common.h
qemu-sockets.c
0 → 100644
| 1 | +#include <stdio.h> | |
| 2 | +#include <stdlib.h> | |
| 3 | +#include <string.h> | |
| 4 | +#include <ctype.h> | |
| 5 | +#include <errno.h> | |
| 6 | +#include <unistd.h> | |
| 7 | + | |
| 8 | +#include "qemu_socket.h" | |
| 9 | + | |
| 10 | +#ifndef AI_ADDRCONFIG | |
| 11 | +# define AI_ADDRCONFIG 0 | |
| 12 | +#endif | |
| 13 | + | |
| 14 | +static int sockets_debug = 0; | |
| 15 | +static const int on=1, off=0; | |
| 16 | + | |
| 17 | +static int inet_getport(struct addrinfo *e) | |
| 18 | +{ | |
| 19 | + struct sockaddr_in *i4; | |
| 20 | + struct sockaddr_in6 *i6; | |
| 21 | + | |
| 22 | + switch (e->ai_family) { | |
| 23 | + case PF_INET6: | |
| 24 | + i6 = (void*)e->ai_addr; | |
| 25 | + return ntohs(i6->sin6_port); | |
| 26 | + case PF_INET: | |
| 27 | + i4 = (void*)e->ai_addr; | |
| 28 | + return ntohs(i4->sin_port); | |
| 29 | + default: | |
| 30 | + return 0; | |
| 31 | + } | |
| 32 | +} | |
| 33 | + | |
| 34 | +static void inet_setport(struct addrinfo *e, int port) | |
| 35 | +{ | |
| 36 | + struct sockaddr_in *i4; | |
| 37 | + struct sockaddr_in6 *i6; | |
| 38 | + | |
| 39 | + switch (e->ai_family) { | |
| 40 | + case PF_INET6: | |
| 41 | + i6 = (void*)e->ai_addr; | |
| 42 | + i6->sin6_port = htons(port); | |
| 43 | + break; | |
| 44 | + case PF_INET: | |
| 45 | + i4 = (void*)e->ai_addr; | |
| 46 | + i4->sin_port = htons(port); | |
| 47 | + break; | |
| 48 | + } | |
| 49 | +} | |
| 50 | + | |
| 51 | +static const char *inet_strfamily(int family) | |
| 52 | +{ | |
| 53 | + switch (family) { | |
| 54 | + case PF_INET6: return "ipv6"; | |
| 55 | + case PF_INET: return "ipv4"; | |
| 56 | + case PF_UNIX: return "unix"; | |
| 57 | + } | |
| 58 | + return "????"; | |
| 59 | +} | |
| 60 | + | |
| 61 | +static void inet_print_addrinfo(const char *tag, struct addrinfo *res) | |
| 62 | +{ | |
| 63 | + struct addrinfo *e; | |
| 64 | + char uaddr[INET6_ADDRSTRLEN+1]; | |
| 65 | + char uport[33]; | |
| 66 | + | |
| 67 | + for (e = res; e != NULL; e = e->ai_next) { | |
| 68 | + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, | |
| 69 | + uaddr,INET6_ADDRSTRLEN,uport,32, | |
| 70 | + NI_NUMERICHOST | NI_NUMERICSERV); | |
| 71 | + fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", | |
| 72 | + tag, inet_strfamily(e->ai_family), uaddr, uport); | |
| 73 | + } | |
| 74 | +} | |
| 75 | + | |
| 76 | +int inet_listen(const char *str, char *ostr, int olen, | |
| 77 | + int socktype, int port_offset) | |
| 78 | +{ | |
| 79 | + struct addrinfo ai,*res,*e; | |
| 80 | + char addr[64]; | |
| 81 | + char port[33]; | |
| 82 | + char uaddr[INET6_ADDRSTRLEN+1]; | |
| 83 | + char uport[33]; | |
| 84 | + const char *opts, *h; | |
| 85 | + int slisten,rc,pos,to,try_next; | |
| 86 | + | |
| 87 | + memset(&ai,0, sizeof(ai)); | |
| 88 | + ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; | |
| 89 | + ai.ai_family = PF_UNSPEC; | |
| 90 | + ai.ai_socktype = socktype; | |
| 91 | + | |
| 92 | + /* parse address */ | |
| 93 | + if (str[0] == ':') { | |
| 94 | + /* no host given */ | |
| 95 | + strcpy(addr,""); | |
| 96 | + if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { | |
| 97 | + fprintf(stderr, "%s: portonly parse error (%s)\n", | |
| 98 | + __FUNCTION__, str); | |
| 99 | + return -1; | |
| 100 | + } | |
| 101 | + } else if (str[0] == '[') { | |
| 102 | + /* IPv6 addr */ | |
| 103 | + if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { | |
| 104 | + fprintf(stderr, "%s: ipv6 parse error (%s)\n", | |
| 105 | + __FUNCTION__, str); | |
| 106 | + return -1; | |
| 107 | + } | |
| 108 | + ai.ai_family = PF_INET6; | |
| 109 | + } else if (isdigit(str[0])) { | |
| 110 | + /* IPv4 addr */ | |
| 111 | + if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { | |
| 112 | + fprintf(stderr, "%s: ipv4 parse error (%s)\n", | |
| 113 | + __FUNCTION__, str); | |
| 114 | + return -1; | |
| 115 | + } | |
| 116 | + ai.ai_family = PF_INET; | |
| 117 | + } else { | |
| 118 | + /* hostname */ | |
| 119 | + if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { | |
| 120 | + fprintf(stderr, "%s: hostname parse error (%s)\n", | |
| 121 | + __FUNCTION__, str); | |
| 122 | + return -1; | |
| 123 | + } | |
| 124 | + } | |
| 125 | + | |
| 126 | + /* parse options */ | |
| 127 | + opts = str + pos; | |
| 128 | + h = strstr(opts, ",to="); | |
| 129 | + to = h ? atoi(h+4) : 0; | |
| 130 | + if (strstr(opts, ",ipv4")) | |
| 131 | + ai.ai_family = PF_INET; | |
| 132 | + if (strstr(opts, ",ipv6")) | |
| 133 | + ai.ai_family = PF_INET6; | |
| 134 | + | |
| 135 | + /* lookup */ | |
| 136 | + if (port_offset) | |
| 137 | + snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); | |
| 138 | + rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); | |
| 139 | + if (rc != 0) { | |
| 140 | + fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, | |
| 141 | + addr, port, gai_strerror(rc)); | |
| 142 | + return -1; | |
| 143 | + } | |
| 144 | + if (sockets_debug) | |
| 145 | + inet_print_addrinfo(__FUNCTION__, res); | |
| 146 | + | |
| 147 | + /* create socket + bind */ | |
| 148 | + for (e = res; e != NULL; e = e->ai_next) { | |
| 149 | + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, | |
| 150 | + uaddr,INET6_ADDRSTRLEN,uport,32, | |
| 151 | + NI_NUMERICHOST | NI_NUMERICSERV); | |
| 152 | + slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); | |
| 153 | + if (slisten < 0) { | |
| 154 | + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, | |
| 155 | + inet_strfamily(e->ai_family), strerror(errno)); | |
| 156 | + continue; | |
| 157 | + } | |
| 158 | + | |
| 159 | + setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); | |
| 160 | +#ifdef IPV6_V6ONLY | |
| 161 | + if (e->ai_family == PF_INET6) { | |
| 162 | + /* listen on both ipv4 and ipv6 */ | |
| 163 | + setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off)); | |
| 164 | + } | |
| 165 | +#endif | |
| 166 | + | |
| 167 | + for (;;) { | |
| 168 | + if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { | |
| 169 | + if (sockets_debug) | |
| 170 | + fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, | |
| 171 | + inet_strfamily(e->ai_family), uaddr, inet_getport(e)); | |
| 172 | + goto listen; | |
| 173 | + } | |
| 174 | + try_next = to && (inet_getport(e) <= to + port_offset); | |
| 175 | + if (!try_next || sockets_debug) | |
| 176 | + fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, | |
| 177 | + inet_strfamily(e->ai_family), uaddr, inet_getport(e), | |
| 178 | + strerror(errno)); | |
| 179 | + if (try_next) { | |
| 180 | + inet_setport(e, inet_getport(e) + 1); | |
| 181 | + continue; | |
| 182 | + } | |
| 183 | + break; | |
| 184 | + } | |
| 185 | + closesocket(slisten); | |
| 186 | + } | |
| 187 | + fprintf(stderr, "%s: FAILED\n", __FUNCTION__); | |
| 188 | + freeaddrinfo(res); | |
| 189 | + return -1; | |
| 190 | + | |
| 191 | +listen: | |
| 192 | + if (listen(slisten,1) != 0) { | |
| 193 | + perror("listen"); | |
| 194 | + closesocket(slisten); | |
| 195 | + return -1; | |
| 196 | + } | |
| 197 | + if (ostr) { | |
| 198 | + if (e->ai_family == PF_INET6) { | |
| 199 | + snprintf(ostr, olen, "[%s]:%d%s", uaddr, | |
| 200 | + inet_getport(e) - port_offset, opts); | |
| 201 | + } else { | |
| 202 | + snprintf(ostr, olen, "%s:%d%s", uaddr, | |
| 203 | + inet_getport(e) - port_offset, opts); | |
| 204 | + } | |
| 205 | + } | |
| 206 | + freeaddrinfo(res); | |
| 207 | + return slisten; | |
| 208 | +} | |
| 209 | + | |
| 210 | +int inet_connect(const char *str, int socktype) | |
| 211 | +{ | |
| 212 | + struct addrinfo ai,*res,*e; | |
| 213 | + char addr[64]; | |
| 214 | + char port[33]; | |
| 215 | + char uaddr[INET6_ADDRSTRLEN+1]; | |
| 216 | + char uport[33]; | |
| 217 | + int sock,rc; | |
| 218 | + | |
| 219 | + memset(&ai,0, sizeof(ai)); | |
| 220 | + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; | |
| 221 | + ai.ai_family = PF_UNSPEC; | |
| 222 | + ai.ai_socktype = socktype; | |
| 223 | + | |
| 224 | + /* parse address */ | |
| 225 | + if (str[0] == '[') { | |
| 226 | + /* IPv6 addr */ | |
| 227 | + if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { | |
| 228 | + fprintf(stderr, "%s: ipv6 parse error (%s)\n", | |
| 229 | + __FUNCTION__, str); | |
| 230 | + return -1; | |
| 231 | + } | |
| 232 | + ai.ai_family = PF_INET6; | |
| 233 | + } else if (isdigit(str[0])) { | |
| 234 | + /* IPv4 addr */ | |
| 235 | + if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { | |
| 236 | + fprintf(stderr, "%s: ipv4 parse error (%s)\n", | |
| 237 | + __FUNCTION__, str); | |
| 238 | + return -1; | |
| 239 | + } | |
| 240 | + ai.ai_family = PF_INET; | |
| 241 | + } else { | |
| 242 | + /* hostname */ | |
| 243 | + if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { | |
| 244 | + fprintf(stderr, "%s: hostname parse error (%s)\n", | |
| 245 | + __FUNCTION__, str); | |
| 246 | + return -1; | |
| 247 | + } | |
| 248 | + } | |
| 249 | + | |
| 250 | + /* parse options */ | |
| 251 | + if (strstr(str, ",ipv4")) | |
| 252 | + ai.ai_family = PF_INET; | |
| 253 | + if (strstr(str, ",ipv6")) | |
| 254 | + ai.ai_family = PF_INET6; | |
| 255 | + | |
| 256 | + /* lookup */ | |
| 257 | + if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { | |
| 258 | + fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc), | |
| 259 | + addr, port); | |
| 260 | + return -1; | |
| 261 | + } | |
| 262 | + if (sockets_debug) | |
| 263 | + inet_print_addrinfo(__FUNCTION__, res); | |
| 264 | + | |
| 265 | + for (e = res; e != NULL; e = e->ai_next) { | |
| 266 | + if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, | |
| 267 | + uaddr,INET6_ADDRSTRLEN,uport,32, | |
| 268 | + NI_NUMERICHOST | NI_NUMERICSERV) != 0) { | |
| 269 | + fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); | |
| 270 | + continue; | |
| 271 | + } | |
| 272 | + sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); | |
| 273 | + if (sock < 0) { | |
| 274 | + fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, | |
| 275 | + inet_strfamily(e->ai_family), strerror(errno)); | |
| 276 | + continue; | |
| 277 | + } | |
| 278 | + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); | |
| 279 | + | |
| 280 | + /* connect to peer */ | |
| 281 | + if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { | |
| 282 | + if (sockets_debug || NULL == e->ai_next) | |
| 283 | + fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, | |
| 284 | + inet_strfamily(e->ai_family), | |
| 285 | + e->ai_canonname, uaddr, uport, strerror(errno)); | |
| 286 | + closesocket(sock); | |
| 287 | + continue; | |
| 288 | + } | |
| 289 | + if (sockets_debug) | |
| 290 | + fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, | |
| 291 | + inet_strfamily(e->ai_family), | |
| 292 | + e->ai_canonname, uaddr, uport); | |
| 293 | + freeaddrinfo(res); | |
| 294 | + return sock; | |
| 295 | + } | |
| 296 | + freeaddrinfo(res); | |
| 297 | + return -1; | |
| 298 | +} | |
| 299 | + | |
| 300 | +#ifndef _WIN32 | |
| 301 | + | |
| 302 | +int unix_listen(const char *str, char *ostr, int olen) | |
| 303 | +{ | |
| 304 | + struct sockaddr_un un; | |
| 305 | + char *path, *opts; | |
| 306 | + int sock, fd, len; | |
| 307 | + | |
| 308 | + sock = socket(PF_UNIX, SOCK_STREAM, 0); | |
| 309 | + if (sock < 0) { | |
| 310 | + perror("socket(unix)"); | |
| 311 | + return -1; | |
| 312 | + } | |
| 313 | + | |
| 314 | + opts = strchr(str, ','); | |
| 315 | + if (opts) { | |
| 316 | + len = opts - str; | |
| 317 | + path = malloc(len+1); | |
| 318 | + snprintf(path, len+1, "%.*s", len, str); | |
| 319 | + } else | |
| 320 | + path = strdup(str); | |
| 321 | + | |
| 322 | + memset(&un, 0, sizeof(un)); | |
| 323 | + un.sun_family = AF_UNIX; | |
| 324 | + if (path && strlen(path)) { | |
| 325 | + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); | |
| 326 | + } else { | |
| 327 | + char *tmpdir = getenv("TMPDIR"); | |
| 328 | + snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", | |
| 329 | + tmpdir ? tmpdir : "/tmp"); | |
| 330 | + /* | |
| 331 | + * This dummy fd usage silences the mktemp() unsecure warning. | |
| 332 | + * Using mkstemp() doesn't make things more secure here | |
| 333 | + * though. bind() complains about existing files, so we have | |
| 334 | + * to unlink first and thus re-open the race window. The | |
| 335 | + * worst case possible is bind() failing, i.e. a DoS attack. | |
| 336 | + */ | |
| 337 | + fd = mkstemp(un.sun_path); close(fd); | |
| 338 | + } | |
| 339 | + snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : ""); | |
| 340 | + | |
| 341 | + unlink(un.sun_path); | |
| 342 | + if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { | |
| 343 | + fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); | |
| 344 | + goto err; | |
| 345 | + } | |
| 346 | + if (listen(sock, 1) < 0) { | |
| 347 | + fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); | |
| 348 | + goto err; | |
| 349 | + } | |
| 350 | + | |
| 351 | + if (sockets_debug) | |
| 352 | + fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); | |
| 353 | + free(path); | |
| 354 | + return sock; | |
| 355 | + | |
| 356 | +err: | |
| 357 | + free(path); | |
| 358 | + closesocket(sock); | |
| 359 | + return -1; | |
| 360 | +} | |
| 361 | + | |
| 362 | +int unix_connect(const char *path) | |
| 363 | +{ | |
| 364 | + struct sockaddr_un un; | |
| 365 | + int sock; | |
| 366 | + | |
| 367 | + sock = socket(PF_UNIX, SOCK_STREAM, 0); | |
| 368 | + if (sock < 0) { | |
| 369 | + perror("socket(unix)"); | |
| 370 | + return -1; | |
| 371 | + } | |
| 372 | + | |
| 373 | + memset(&un, 0, sizeof(un)); | |
| 374 | + un.sun_family = AF_UNIX; | |
| 375 | + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); | |
| 376 | + if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { | |
| 377 | + fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); | |
| 378 | + return -1; | |
| 379 | + } | |
| 380 | + | |
| 381 | + if (sockets_debug) | |
| 382 | + fprintf(stderr, "connect(unix:%s): OK\n", path); | |
| 383 | + return sock; | |
| 384 | +} | |
| 385 | + | |
| 386 | +#else | |
| 387 | + | |
| 388 | +int unix_listen(const char *path, char *ostr, int olen) | |
| 389 | +{ | |
| 390 | + fprintf(stderr, "unix sockets are not available on windows\n"); | |
| 391 | + return -1; | |
| 392 | +} | |
| 393 | + | |
| 394 | +int unix_connect(const char *path) | |
| 395 | +{ | |
| 396 | + fprintf(stderr, "unix sockets are not available on windows\n"); | |
| 397 | + return -1; | |
| 398 | +} | |
| 399 | + | |
| 400 | +#endif | ... | ... |
qemu_socket.h
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | |
| 5 | 5 | #ifdef _WIN32 |
| 6 | 6 | #define WIN32_LEAN_AND_MEAN |
| 7 | +#define WINVER 0x0501 /* needed for ipv6 bits */ | |
| 7 | 8 | #include <windows.h> |
| 8 | 9 | #include <winsock2.h> |
| 9 | 10 | #include <ws2tcpip.h> |
| ... | ... | @@ -28,15 +29,24 @@ int inet_aton(const char *cp, struct in_addr *ia); |
| 28 | 29 | #define socket_error() errno |
| 29 | 30 | #define closesocket(s) close(s) |
| 30 | 31 | |
| 31 | -int parse_unix_path(struct sockaddr_un *uaddr, const char *str); | |
| 32 | - | |
| 33 | 32 | #endif /* !_WIN32 */ |
| 34 | 33 | |
| 34 | +/* misc helpers */ | |
| 35 | 35 | void socket_set_nonblock(int fd); |
| 36 | +int send_all(int fd, const void *buf, int len1); | |
| 37 | + | |
| 38 | +/* New, ipv6-ready socket helper functions, see qemu-sockets.c */ | |
| 39 | +int inet_listen(const char *str, char *ostr, int olen, | |
| 40 | + int socktype, int port_offset); | |
| 41 | +int inet_connect(const char *str, int socktype); | |
| 42 | + | |
| 43 | +int unix_listen(const char *path, char *ostr, int olen); | |
| 44 | +int unix_connect(const char *path); | |
| 45 | + | |
| 46 | +/* Old, ipv4 only bits. Don't use for new code. */ | |
| 36 | 47 | int parse_host_port(struct sockaddr_in *saddr, const char *str); |
| 37 | 48 | int parse_host_src_port(struct sockaddr_in *haddr, |
| 38 | 49 | struct sockaddr_in *saddr, |
| 39 | 50 | const char *str); |
| 40 | -int send_all(int fd, const uint8_t *buf, int len1); | |
| 41 | 51 | |
| 42 | 52 | #endif /* QEMU_SOCKET_H */ | ... | ... |