cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

control.c (4415B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Control socket for client/server test execution
      3 *
      4 * Copyright (C) 2017 Red Hat, Inc.
      5 *
      6 * Author: Stefan Hajnoczi <stefanha@redhat.com>
      7 */
      8
      9/* The client and server may need to coordinate to avoid race conditions like
     10 * the client attempting to connect to a socket that the server is not
     11 * listening on yet.  The control socket offers a communications channel for
     12 * such coordination tasks.
     13 *
     14 * If the client calls control_expectln("LISTENING"), then it will block until
     15 * the server calls control_writeln("LISTENING").  This provides a simple
     16 * mechanism for coordinating between the client and the server.
     17 */
     18
     19#include <errno.h>
     20#include <netdb.h>
     21#include <stdio.h>
     22#include <stdlib.h>
     23#include <string.h>
     24#include <unistd.h>
     25#include <sys/types.h>
     26#include <sys/socket.h>
     27
     28#include "timeout.h"
     29#include "control.h"
     30
     31static int control_fd = -1;
     32
     33/* Open the control socket, either in server or client mode */
     34void control_init(const char *control_host,
     35		  const char *control_port,
     36		  bool server)
     37{
     38	struct addrinfo hints = {
     39		.ai_socktype = SOCK_STREAM,
     40	};
     41	struct addrinfo *result = NULL;
     42	struct addrinfo *ai;
     43	int ret;
     44
     45	ret = getaddrinfo(control_host, control_port, &hints, &result);
     46	if (ret != 0) {
     47		fprintf(stderr, "%s\n", gai_strerror(ret));
     48		exit(EXIT_FAILURE);
     49	}
     50
     51	for (ai = result; ai; ai = ai->ai_next) {
     52		int fd;
     53		int val = 1;
     54
     55		fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     56		if (fd < 0)
     57			continue;
     58
     59		if (!server) {
     60			if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0)
     61				goto next;
     62			control_fd = fd;
     63			printf("Control socket connected to %s:%s.\n",
     64			       control_host, control_port);
     65			break;
     66		}
     67
     68		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
     69			       &val, sizeof(val)) < 0) {
     70			perror("setsockopt");
     71			exit(EXIT_FAILURE);
     72		}
     73
     74		if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
     75			goto next;
     76		if (listen(fd, 1) < 0)
     77			goto next;
     78
     79		printf("Control socket listening on %s:%s\n",
     80		       control_host, control_port);
     81		fflush(stdout);
     82
     83		control_fd = accept(fd, NULL, 0);
     84		close(fd);
     85
     86		if (control_fd < 0) {
     87			perror("accept");
     88			exit(EXIT_FAILURE);
     89		}
     90		printf("Control socket connection accepted...\n");
     91		break;
     92
     93next:
     94		close(fd);
     95	}
     96
     97	if (control_fd < 0) {
     98		fprintf(stderr, "Control socket initialization failed.  Invalid address %s:%s?\n",
     99			control_host, control_port);
    100		exit(EXIT_FAILURE);
    101	}
    102
    103	freeaddrinfo(result);
    104}
    105
    106/* Free resources */
    107void control_cleanup(void)
    108{
    109	close(control_fd);
    110	control_fd = -1;
    111}
    112
    113/* Write a line to the control socket */
    114void control_writeln(const char *str)
    115{
    116	ssize_t len = strlen(str);
    117	ssize_t ret;
    118
    119	timeout_begin(TIMEOUT);
    120
    121	do {
    122		ret = send(control_fd, str, len, MSG_MORE);
    123		timeout_check("send");
    124	} while (ret < 0 && errno == EINTR);
    125
    126	if (ret != len) {
    127		perror("send");
    128		exit(EXIT_FAILURE);
    129	}
    130
    131	do {
    132		ret = send(control_fd, "\n", 1, 0);
    133		timeout_check("send");
    134	} while (ret < 0 && errno == EINTR);
    135
    136	if (ret != 1) {
    137		perror("send");
    138		exit(EXIT_FAILURE);
    139	}
    140
    141	timeout_end();
    142}
    143
    144/* Return the next line from the control socket (without the trailing newline).
    145 *
    146 * The program terminates if a timeout occurs.
    147 *
    148 * The caller must free() the returned string.
    149 */
    150char *control_readln(void)
    151{
    152	char *buf = NULL;
    153	size_t idx = 0;
    154	size_t buflen = 0;
    155
    156	timeout_begin(TIMEOUT);
    157
    158	for (;;) {
    159		ssize_t ret;
    160
    161		if (idx >= buflen) {
    162			char *new_buf;
    163
    164			new_buf = realloc(buf, buflen + 80);
    165			if (!new_buf) {
    166				perror("realloc");
    167				exit(EXIT_FAILURE);
    168			}
    169
    170			buf = new_buf;
    171			buflen += 80;
    172		}
    173
    174		do {
    175			ret = recv(control_fd, &buf[idx], 1, 0);
    176			timeout_check("recv");
    177		} while (ret < 0 && errno == EINTR);
    178
    179		if (ret == 0) {
    180			fprintf(stderr, "unexpected EOF on control socket\n");
    181			exit(EXIT_FAILURE);
    182		}
    183
    184		if (ret != 1) {
    185			perror("recv");
    186			exit(EXIT_FAILURE);
    187		}
    188
    189		if (buf[idx] == '\n') {
    190			buf[idx] = '\0';
    191			break;
    192		}
    193
    194		idx++;
    195	}
    196
    197	timeout_end();
    198
    199	return buf;
    200}
    201
    202/* Wait until a given line is received or a timeout occurs */
    203void control_expectln(const char *str)
    204{
    205	char *line;
    206
    207	line = control_readln();
    208
    209	control_cmpln(line, str, true);
    210
    211	free(line);
    212}
    213
    214bool control_cmpln(char *line, const char *str, bool fail)
    215{
    216	if (strcmp(str, line) == 0)
    217		return true;
    218
    219	if (fail) {
    220		fprintf(stderr, "expected \"%s\" on control socket, got \"%s\"\n",
    221			str, line);
    222		exit(EXIT_FAILURE);
    223	}
    224
    225	return false;
    226}