cregit-Linux how code gets into the kernel

Release 4.18 tools/testing/vsock/control.c

/* Control socket for client/server test execution
 *
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Author: Stefan Hajnoczi <stefanha@redhat.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License.
 */

/* 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"


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; int val = 1; 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; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { perror("setsockopt"); exit(EXIT_FAILURE); } 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); }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Hajnoczi330100.00%1100.00%
Total330100.00%1100.00%

/* Free resources */
void control_cleanup(void) { close(control_fd); control_fd = -1; }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Hajnoczi17100.00%1100.00%
Total17100.00%1100.00%

/* 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(); }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Hajnoczi129100.00%1100.00%
Total129100.00%1100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Hajnoczi189100.00%1100.00%
Total189100.00%1100.00%

/* Wait until a given line is received or a timeout occurs */
void control_expectln(const char *str) { char *line; line = control_readln(); if (strcmp(str, line) != 0) { fprintf(stderr, "expected \"%s\" on control socket, got \"%s\"\n", str, line); exit(EXIT_FAILURE); } free(line); }

Contributors

PersonTokensPropCommitsCommitProp
Stefan Hajnoczi53100.00%1100.00%
Total53100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Stefan Hajnoczi762100.00%1100.00%
Total762100.00%1100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.