0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <errno.h>
0020 #include <netdb.h>
0021 #include <stdio.h>
0022 #include <stdlib.h>
0023 #include <string.h>
0024 #include <unistd.h>
0025 #include <sys/types.h>
0026 #include <sys/socket.h>
0027
0028 #include "timeout.h"
0029 #include "control.h"
0030
0031 static int control_fd = -1;
0032
0033
0034 void control_init(const char *control_host,
0035 const char *control_port,
0036 bool server)
0037 {
0038 struct addrinfo hints = {
0039 .ai_socktype = SOCK_STREAM,
0040 };
0041 struct addrinfo *result = NULL;
0042 struct addrinfo *ai;
0043 int ret;
0044
0045 ret = getaddrinfo(control_host, control_port, &hints, &result);
0046 if (ret != 0) {
0047 fprintf(stderr, "%s\n", gai_strerror(ret));
0048 exit(EXIT_FAILURE);
0049 }
0050
0051 for (ai = result; ai; ai = ai->ai_next) {
0052 int fd;
0053 int val = 1;
0054
0055 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
0056 if (fd < 0)
0057 continue;
0058
0059 if (!server) {
0060 if (connect(fd, ai->ai_addr, ai->ai_addrlen) < 0)
0061 goto next;
0062 control_fd = fd;
0063 printf("Control socket connected to %s:%s.\n",
0064 control_host, control_port);
0065 break;
0066 }
0067
0068 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
0069 &val, sizeof(val)) < 0) {
0070 perror("setsockopt");
0071 exit(EXIT_FAILURE);
0072 }
0073
0074 if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
0075 goto next;
0076 if (listen(fd, 1) < 0)
0077 goto next;
0078
0079 printf("Control socket listening on %s:%s\n",
0080 control_host, control_port);
0081 fflush(stdout);
0082
0083 control_fd = accept(fd, NULL, 0);
0084 close(fd);
0085
0086 if (control_fd < 0) {
0087 perror("accept");
0088 exit(EXIT_FAILURE);
0089 }
0090 printf("Control socket connection accepted...\n");
0091 break;
0092
0093 next:
0094 close(fd);
0095 }
0096
0097 if (control_fd < 0) {
0098 fprintf(stderr, "Control socket initialization failed. Invalid address %s:%s?\n",
0099 control_host, control_port);
0100 exit(EXIT_FAILURE);
0101 }
0102
0103 freeaddrinfo(result);
0104 }
0105
0106
0107 void control_cleanup(void)
0108 {
0109 close(control_fd);
0110 control_fd = -1;
0111 }
0112
0113
0114 void control_writeln(const char *str)
0115 {
0116 ssize_t len = strlen(str);
0117 ssize_t ret;
0118
0119 timeout_begin(TIMEOUT);
0120
0121 do {
0122 ret = send(control_fd, str, len, MSG_MORE);
0123 timeout_check("send");
0124 } while (ret < 0 && errno == EINTR);
0125
0126 if (ret != len) {
0127 perror("send");
0128 exit(EXIT_FAILURE);
0129 }
0130
0131 do {
0132 ret = send(control_fd, "\n", 1, 0);
0133 timeout_check("send");
0134 } while (ret < 0 && errno == EINTR);
0135
0136 if (ret != 1) {
0137 perror("send");
0138 exit(EXIT_FAILURE);
0139 }
0140
0141 timeout_end();
0142 }
0143
0144
0145
0146
0147
0148
0149
0150 char *control_readln(void)
0151 {
0152 char *buf = NULL;
0153 size_t idx = 0;
0154 size_t buflen = 0;
0155
0156 timeout_begin(TIMEOUT);
0157
0158 for (;;) {
0159 ssize_t ret;
0160
0161 if (idx >= buflen) {
0162 char *new_buf;
0163
0164 new_buf = realloc(buf, buflen + 80);
0165 if (!new_buf) {
0166 perror("realloc");
0167 exit(EXIT_FAILURE);
0168 }
0169
0170 buf = new_buf;
0171 buflen += 80;
0172 }
0173
0174 do {
0175 ret = recv(control_fd, &buf[idx], 1, 0);
0176 timeout_check("recv");
0177 } while (ret < 0 && errno == EINTR);
0178
0179 if (ret == 0) {
0180 fprintf(stderr, "unexpected EOF on control socket\n");
0181 exit(EXIT_FAILURE);
0182 }
0183
0184 if (ret != 1) {
0185 perror("recv");
0186 exit(EXIT_FAILURE);
0187 }
0188
0189 if (buf[idx] == '\n') {
0190 buf[idx] = '\0';
0191 break;
0192 }
0193
0194 idx++;
0195 }
0196
0197 timeout_end();
0198
0199 return buf;
0200 }
0201
0202
0203 void control_expectln(const char *str)
0204 {
0205 char *line;
0206
0207 line = control_readln();
0208
0209 control_cmpln(line, str, true);
0210
0211 free(line);
0212 }
0213
0214 bool control_cmpln(char *line, const char *str, bool fail)
0215 {
0216 if (strcmp(str, line) == 0)
0217 return true;
0218
0219 if (fail) {
0220 fprintf(stderr, "expected \"%s\" on control socket, got \"%s\"\n",
0221 str, line);
0222 exit(EXIT_FAILURE);
0223 }
0224
0225 return false;
0226 }