Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252// SPDX-License-Identifier: GPL-2.0-only/* Control socket for client/server test execution * * Copyright (C) 2017 Red Hat, Inc. * * Author: Stefan Hajnoczi <stefanha@redhat.com> */
/* The client and server may need to coordinate to avoid race conditions like * the client attempting to connect to a socket that the server is not * listening on yet. The control socket offers a communications channel for * such coordination tasks. * * If the client calls control_expectln("LISTENING"), then it will block until * the server calls control_writeln("LISTENING"). This provides a simple * mechanism for coordinating between the client and the server. */
#include <errno.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>
#include "timeout.h"#include "control.h"#include "util.h"
static int control_fd = -1;
/* Open the control socket, either in server or client mode */void control_init(const char *control_host, const char *control_port, bool server){ struct addrinfo hints = { .ai_socktype = SOCK_STREAM, }; struct addrinfo *result = NULL; struct addrinfo *ai; int ret;
ret = getaddrinfo(control_host, control_port, &hints, &result); if (ret != 0) { fprintf(stderr, "%s\n", gai_strerror(ret)); exit(EXIT_FAILURE); }
for (ai = result; ai; ai = ai->ai_next) { int fd;
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (fd < 0) continue;
if (!server) { if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0) goto next; control_fd = fd; printf("Control socket connected to %s:%s.\n", control_host, control_port); break; }
setsockopt_int_check(fd, SOL_SOCKET, SO_REUSEADDR, 1, "setsockopt SO_REUSEADDR");
if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) goto next; if (listen(fd, 1) < 0) goto next;
printf("Control socket listening on %s:%s\n", control_host, control_port); fflush(stdout);
control_fd = accept(fd, NULL, 0); close(fd);
if (control_fd < 0) { perror("accept"); exit(EXIT_FAILURE); } printf("Control socket connection accepted...\n"); break;
next: close(fd); }
if (control_fd < 0) { fprintf(stderr, "Control socket initialization failed. Invalid address %s:%s?\n", control_host, control_port); exit(EXIT_FAILURE); }
freeaddrinfo(result);}
/* Free resources */void control_cleanup(void){ close(control_fd); control_fd = -1;}
/* Write a line to the control socket */void control_writeln(const char *str){ ssize_t len = strlen(str); ssize_t ret;
timeout_begin(TIMEOUT);
do { ret = send(control_fd, str, len, MSG_MORE); timeout_check("send"); } while (ret < 0 && errno == EINTR);
if (ret != len) { perror("send"); exit(EXIT_FAILURE); }
do { ret = send(control_fd, "\n", 1, 0); timeout_check("send"); } while (ret < 0 && errno == EINTR);
if (ret != 1) { perror("send"); exit(EXIT_FAILURE); }
timeout_end();}
void control_writeulong(unsigned long value){ char str[32];
if (snprintf(str, sizeof(str), "%lu", value) >= sizeof(str)) { perror("snprintf"); exit(EXIT_FAILURE); }
control_writeln(str);}
unsigned long control_readulong(void){ unsigned long value; char *str;
str = control_readln();
if (!str) exit(EXIT_FAILURE);
value = strtoul(str, NULL, 10); free(str);
return value;}
/* Return the next line from the control socket (without the trailing newline). * * The program terminates if a timeout occurs. * * The caller must free() the returned string. */char *control_readln(void){ char *buf = NULL; size_t idx = 0; size_t buflen = 0;
timeout_begin(TIMEOUT);
for (;;) { ssize_t ret;
if (idx >= buflen) { char *new_buf;
new_buf = realloc(buf, buflen + 80); if (!new_buf) { perror("realloc"); exit(EXIT_FAILURE); }
buf = new_buf; buflen += 80; }
do { ret = recv(control_fd, &buf[idx], 1, 0); timeout_check("recv"); } while (ret < 0 && errno == EINTR);
if (ret == 0) { fprintf(stderr, "unexpected EOF on control socket\n"); exit(EXIT_FAILURE); }
if (ret != 1) { perror("recv"); exit(EXIT_FAILURE); }
if (buf[idx] == '\n') { buf[idx] = '\0'; break; }
idx++; }
timeout_end();
return buf;}
/* Wait until a given line is received or a timeout occurs */void control_expectln(const char *str){ char *line;
line = control_readln();
control_cmpln(line, str, true);
free(line);}
bool control_cmpln(char *line, const char *str, bool fail){ if (strcmp(str, line) == 0) return true;
if (fail) { fprintf(stderr, "expected \"%s\" on control socket, got \"%s\"\n", str, line); exit(EXIT_FAILURE); }
return false;}