A tiling window manager

communications: recv_unix: factor out recv() loop from send_command()

Here we make a new function recv_unix() that encapsulates the logic of
receiving a message from a unix domain socket (ie our control socket)
and copying it into a dynamically-sized heap buffer for disposition by
the caller. This will let us use it from other functions, in particular
from receive_command(), which is currently using a single buffer and
reading from the socket one character at a time. Since the logic for
doing this robustly was already implemented in send_command(), we can
just factor it out and use in both places.

authored by

Scott Mcdermott and committed by jcs.org 17489f14 1495c616

+59 -37
+59 -37
communications.c
··· 82 82 rp_glob_screen.control_socket_path)); 83 83 } 84 84 85 + static ssize_t 86 + recv_unix(int fd, char **callerbuf) 87 + { 88 + int firstloop; 89 + char *message; 90 + ssize_t len, count; 91 + 92 + int flags = 0x0; 93 + 94 + #ifdef SENDCMD_DEBUG 95 + pid_t pid = getpid(); 96 + char *dpfx = xsprintf("recv_unix_%d", pid); 97 + #endif 98 + WARNX_DEBUG("%s: enter\n", dpfx); 99 + 100 + message = xmalloc(BUFSZ); 101 + memset(message, 0, BUFSZ); 102 + 103 + len = 0; 104 + firstloop = 1; 105 + 106 + while ((count = recv(fd, message + len, BUFSZ, flags))) { 107 + if (firstloop) { 108 + WARNX_DEBUG("%s: first recv: %zd\n", dpfx, count); 109 + /* 110 + * after blocking for the first buffer, we can 111 + * keep reading until it blocks again, which 112 + * should exhaust the message. 113 + */ 114 + flags += MSG_DONTWAIT; 115 + } 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 + len += count; 130 + message = xrealloc(message, len + BUFSZ); 131 + memset(message + len, 0, BUFSZ); 132 + WARNX_DEBUG("%s: looping after count %zd\n", dpfx, count); 133 + firstloop = 0; 134 + } 135 + #ifdef SENDCMD_DEBUG 136 + free(dpfx); 137 + #endif 138 + *callerbuf = message; 139 + return len; 140 + } 141 + 85 142 int 86 143 send_command(int interactive, char *cmd) 87 144 { ··· 89 146 char *wcmd, *response; 90 147 char success = 0; 91 148 size_t len; 92 - ssize_t count; 93 - int fd, firstloop; 94 - int flags = 0x0; 149 + int fd; 95 150 FILE *outf = NULL; 96 151 97 152 #ifdef SENDCMD_DEBUG ··· 126 181 127 182 free(wcmd); 128 183 129 - response = xmalloc(BUFSZ); 130 - memset(response, 0, BUFSZ); 131 - len = 0; 132 - firstloop = 1; 133 - 134 - while ((count = recv(fd, response + len, BUFSZ, flags))) { 135 - if (firstloop) { 136 - WARNX_DEBUG("%s: first recv: %zu\n", dpfx, count); 137 - /* 138 - * after blocking for the first buffer, we can 139 - * keep reading until it blocks again, which 140 - * should exhaust the message. 141 - */ 142 - flags += MSG_DONTWAIT; 143 - } 144 - if (count == -1) { 145 - WARNX_DEBUG("%s: finish errno: %d\n", dpfx, errno); 146 - /* 147 - * message is complete. sometimes connection is 148 - * closed, other times it would block, depending 149 - * on whether responder finished before us. 150 - * either outcome signals end of the response. 151 - */ 152 - if (errno == EAGAIN || errno == ECONNRESET) 153 - break; 154 - else 155 - err(1, "unanticipated receive error"); 156 - } 157 - len += count; 158 - firstloop = 0; 159 - response = xrealloc(response, len + BUFSZ); 160 - memset(response + len, 0, BUFSZ); 161 - WARNX_DEBUG("%s: looping after count %zu\n", dpfx, count); 162 - } 184 + len = recv_unix(fd, &response) 163 185 164 186 /* first byte is exit status */ 165 187 success = *response;