A tiling window manager
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

communications: handle transient and unanticipated errors in recv_unix()

There are some transient conditions which are normal, such as an
interrupted system call, which can happen if sdorfehs received a signal
during processing, such as SIGCHLD when a forked process exited (a
completely normal situation). Of course, we should retry the syscall in
that case

. We can retry these after a small sleep of
200ms

both send_message() and receive_message()

authored by

Scott Mcdermott and committed by
joshua stein
272c450a 153f4ce5

+45 -17
+45 -17
communications.c
··· 90 90 ssize_t len, count; 91 91 92 92 int flags = 0x0; 93 + int retries = 0; 93 94 94 95 #ifdef SENDCMD_DEBUG 95 96 pid_t pid = getpid(); ··· 104 105 firstloop = 1; 105 106 106 107 while ((count = recv(fd, message + len, BUFSZ, flags))) { 108 + if (count == -1) { 109 + switch (errno) { 110 + /* 111 + * message is complete 112 + */ 113 + case ECONNRESET: /* sender finished and closed */ 114 + case EAGAIN: /* no more left to read */ 115 + WARNX_DEBUG("%s: done: e%d\n", dpfx, errno); 116 + break; 117 + /* 118 + * transient conditions for retrying 119 + */ 120 + case ECONNREFUSED: 121 + case ENOMEM: 122 + if (retries++ >= 5) { 123 + warn("recv_unix: retries exhausted"); 124 + len = -1; 125 + break; 126 + } 127 + usleep(200); 128 + /* fallthrough */ 129 + case EINTR: 130 + warn("recv_unix: trying again"); 131 + continue; 132 + /* 133 + * usage error or untenable situation: 134 + * EBADF, EFAULT, EINVAL, ENOTCONN, ENOTSOCK 135 + */ 136 + default: 137 + warn("unanticipated receive error"); 138 + len = -1; 139 + } 140 + break; 141 + } 107 142 if (firstloop) { 108 143 WARNX_DEBUG("%s: first recv: %zd\n", dpfx, count); 109 144 /* ··· 113 148 */ 114 149 flags += MSG_DONTWAIT; 115 150 } 116 - if (count == -1) { 117 - WARNX_DEBUG("%s: finish errno: %d\n", dpfx, errno); 118 - /* 119 - * receive is complete. sometimes connection is 120 - * closed, other times it would block, depending 121 - * on whether sender finished before us. either 122 - * outcome signals end of the message. 123 - */ 124 - if (errno == EAGAIN || errno == ECONNRESET) 125 - break; 126 - else 127 - err("unanticipated receive error"); 128 - } 129 151 len += count; 130 152 message = xrealloc(message, len + BUFSZ); 131 153 memset(message + len, 0, BUFSZ); ··· 145 167 struct sockaddr_un sun; 146 168 char *wcmd, *response; 147 169 char success = 0; 148 - size_t len; 170 + ssize_t len; 149 171 int fd; 150 172 FILE *outf = NULL; 151 173 ··· 181 203 182 204 free(wcmd); 183 205 184 - len = recv_unix(fd, &response) 206 + if ((len = recv_unix(fd, &response)) == -1) 207 + warnx("send_message: aborted reply from receiver"); 185 208 186 209 /* first byte is exit status */ 187 210 success = *response; ··· 221 244 return; 222 245 } 223 246 224 - len = recv_unix(cl, &cmd) 247 + if ((len = recv_unix(cl, &cmd)) <= 1) { 248 + warnx("receive_command: %s\n", 249 + (len == -1 ? "encountered error during receive" 250 + : "received command was malformed")); 251 + goto done; 252 + } 225 253 if (cmd[len] != '\0') { 226 254 /* should not be possible, TODO remove */ 227 255 warnx("%s\n", "last byte of sent command not null"); ··· 253 281 warn("%s: short write", __func__); 254 282 255 283 PRINT_DEBUG(("receive_command: write finished, closing\n")); 256 - 284 + done: 257 285 free(cmd); 258 286 close(cl); 259 287 }