1 /** @file
2
3 Some utility and support functions for the management module.
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23 #include "tscore/ink_platform.h"
24 #include "tscore/ink_sock.h"
25 #include "MgmtUtils.h"
26 #include "MgmtSocket.h"
27 #include "tscore/Diags.h"
28
29 #include "LocalManager.h"
30
31 static int use_syslog = 0;
32
33 /* mgmt_use_syslog()
34 *
35 * Called to indicate that the syslog should be used and
36 * the log has been opened
37 */
38 void
mgmt_use_syslog()39 mgmt_use_syslog()
40 {
41 use_syslog = 1;
42 }
43
44 /*
45 * mgmt_readline(...)
46 * Simple, inefficient, read line function. Takes a socket to read
47 * from, a char * to write into, and a max len to read. The newline
48 * is stripped.
49 *
50 * Returns: num bytes read
51 * -1 error
52 */
53 int
mgmt_readline(int soc,char * buf,int maxlen)54 mgmt_readline(int soc, char *buf, int maxlen)
55 {
56 int n = 0;
57 char c;
58
59 for (; n < maxlen; n++) {
60 int rc = read_socket(soc, &c, 1);
61 if (rc == 1) {
62 *buf++ = c;
63 if (c == '\n') {
64 --buf;
65 *buf = '\0';
66 if (*(buf - 1) == '\r') {
67 --buf;
68 *buf = '\0';
69 }
70 break;
71 }
72 } else if (rc == 0) {
73 return n;
74 } else { /* Error */
75 if (errno == ECONNRESET || errno == EPIPE) {
76 return n ? n : 0;
77 }
78
79 if (mgmt_transient_error()) {
80 mgmt_sleep_msec(1);
81 continue;
82 }
83
84 return -1;
85 }
86 }
87
88 return n;
89 } /* End mgmt_readline */
90
91 /*
92 * mgmt_writeline(...)
93 * Simple, inefficient, write line function. Takes a soc to write to,
94 * a char * containing the data, and the number of bytes to write.
95 * It sends nbytes + 1 bytes worth of data, the + 1 being the newline
96 * character.
97 *
98 * Returns: num bytes not written
99 * -1 error
100 */
101 int
mgmt_writeline(int soc,const char * data,int nbytes)102 mgmt_writeline(int soc, const char *data, int nbytes)
103 {
104 int nleft, n = 0;
105 const char *tmp = data;
106
107 nleft = nbytes;
108 while (nleft > 0) {
109 int nwritten = write_socket(soc, tmp, nleft);
110 if (nwritten == 0) { // Nothing written
111 mgmt_sleep_msec(1);
112 continue;
113 } else if (nwritten < 0) { // Error
114 if (mgmt_transient_error()) {
115 mgmt_sleep_msec(1);
116 continue;
117 }
118
119 return nwritten;
120 }
121 nleft -= nwritten;
122 tmp += nwritten;
123 }
124
125 while (n != 1) {
126 n = write_socket(soc, "\n", 1); /* Terminating newline */
127 if (n == 0) {
128 mgmt_sleep_msec(1);
129 continue;
130 } else if (n < 0) { // Error
131 if (mgmt_transient_error()) {
132 mgmt_sleep_msec(1);
133 continue;
134 }
135
136 return n;
137 }
138 }
139
140 return (nleft); /* Paranoia */
141 } /* End mgmt_writeline */
142
143 /*
144 * mgmt_read_pipe()
145 * - Reads from a pipe
146 *
147 * Returns: bytes read
148 * 0 on EOF
149 * -errno on error
150 */
151
152 int
mgmt_read_pipe(int fd,char * buf,int bytes_to_read)153 mgmt_read_pipe(int fd, char *buf, int bytes_to_read)
154 {
155 char *p = buf;
156 int bytes_read = 0;
157
158 while (bytes_to_read > 0) {
159 int err = read_socket(fd, p, bytes_to_read);
160 if (err == 0) {
161 // return 0 if partial read.
162 return err;
163 } else if (err < 0) {
164 // Turn ECONNRESET into EOF.
165 if (errno == ECONNRESET || errno == EPIPE) {
166 return bytes_read ? bytes_read : 0;
167 }
168
169 if (mgmt_transient_error()) {
170 mgmt_sleep_msec(1);
171 continue;
172 }
173
174 return -errno;
175 }
176
177 bytes_to_read -= err;
178 bytes_read += err;
179 p += err;
180 }
181
182 return bytes_read;
183 }
184
185 /*
186 * mgmt_write_pipe()
187 * - Writes to a pipe
188 *
189 * Returns: bytes written
190 * 0 on EOF
191 * -errno on error
192 */
193
194 int
mgmt_write_pipe(int fd,char * buf,int bytes_to_write)195 mgmt_write_pipe(int fd, char *buf, int bytes_to_write)
196 {
197 char *p = buf;
198 int bytes_written = 0;
199
200 while (bytes_to_write > 0) {
201 int err = write_socket(fd, p, bytes_to_write);
202 if (err == 0) {
203 // Where this volume of IEEE Std 1003.1-2001 requires -1 to be returned and errno set to [EAGAIN],
204 // most historical implementations return zero for write(2)
205 mgmt_sleep_msec(1);
206 continue;
207 } else if (err < 0) {
208 if (mgmt_transient_error()) {
209 mgmt_sleep_msec(1);
210 continue;
211 }
212
213 return -errno;
214 }
215
216 bytes_to_write -= err;
217 bytes_written += err;
218 p += err;
219 }
220
221 return bytes_written;
222 }
223
224 void
mgmt_log(const char * message_format,...)225 mgmt_log(const char *message_format, ...)
226 {
227 va_list ap;
228 char extended_format[4096], message[4096];
229
230 va_start(ap, message_format);
231 if (diags) {
232 NoteV(message_format, ap);
233 } else {
234 if (use_syslog) {
235 snprintf(extended_format, sizeof(extended_format), "log ==> %s", message_format);
236 vsprintf(message, extended_format, ap);
237 syslog(LOG_WARNING, "%s", message);
238 } else {
239 snprintf(extended_format, sizeof(extended_format), "[E. Mgmt] log ==> %s", message_format);
240 vsprintf(message, extended_format, ap);
241 ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
242 }
243 }
244
245 va_end(ap);
246 return;
247 } /* End mgmt_log */
248
249 void
mgmt_elog(const int lerrno,const char * message_format,...)250 mgmt_elog(const int lerrno, const char *message_format, ...)
251 {
252 va_list ap;
253 char extended_format[4096], message[4096];
254
255 va_start(ap, message_format);
256
257 if (diags) {
258 ErrorV(message_format, ap);
259 if (lerrno != 0) {
260 Error("last system error %d: %s", lerrno, strerror(lerrno));
261 }
262 } else {
263 if (use_syslog) {
264 snprintf(extended_format, sizeof(extended_format), "ERROR ==> %s", message_format);
265 vsprintf(message, extended_format, ap);
266 syslog(LOG_ERR, "%s", message);
267 if (lerrno != 0) {
268 syslog(LOG_ERR, " (last system error %d: %s)", lerrno, strerror(lerrno));
269 }
270 } else {
271 snprintf(extended_format, sizeof(extended_format), "Manager ERROR: %s", message_format);
272 vsprintf(message, extended_format, ap);
273 ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
274 if (lerrno != 0) {
275 snprintf(message, sizeof(message), "(last system error %d: %s)", lerrno, strerror(lerrno));
276 ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
277 }
278 }
279 }
280 va_end(ap);
281 return;
282 } /* End mgmt_elog */
283
284 void
mgmt_fatal(const int lerrno,const char * message_format,...)285 mgmt_fatal(const int lerrno, const char *message_format, ...)
286 {
287 va_list ap;
288
289 va_start(ap, message_format);
290
291 if (diags) {
292 if (lerrno != 0) {
293 Error("last system error %d: %s", lerrno, strerror(lerrno));
294 }
295
296 FatalV(message_format, ap);
297 } else {
298 char extended_format[4096], message[4096];
299 snprintf(extended_format, sizeof(extended_format), "FATAL ==> %s", message_format);
300 vsprintf(message, extended_format, ap);
301
302 ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
303
304 if (use_syslog) {
305 syslog(LOG_ERR, "%s", message);
306 }
307
308 if (lerrno != 0) {
309 fprintf(stderr, "[E. Mgmt] last system error %d: %s", lerrno, strerror(lerrno));
310
311 if (use_syslog) {
312 syslog(LOG_ERR, " (last system error %d: %s)", lerrno, strerror(lerrno));
313 }
314 }
315 }
316
317 va_end(ap);
318
319 mgmt_cleanup();
320 ::exit(1);
321 } /* End mgmt_fatal */
322
323 static inline int
get_interface_mtu(int sock_fd,struct ifreq * ifr)324 get_interface_mtu(int sock_fd, struct ifreq *ifr)
325 {
326 if (ioctl(sock_fd, SIOCGIFMTU, ifr) < 0) {
327 mgmt_log("[getAddrForIntr] Unable to obtain MTU for "
328 "interface '%s'",
329 ifr->ifr_name);
330 return 0;
331 } else {
332 #if defined(solaris) || defined(hpux)
333 return ifr->ifr_metric;
334 #else
335 return ifr->ifr_mtu;
336 #endif
337 }
338 }
339
340 bool
mgmt_getAddrForIntr(char * intrName,sockaddr * addr,int * mtu)341 mgmt_getAddrForIntr(char *intrName, sockaddr *addr, int *mtu)
342 {
343 bool found = false;
344
345 if (intrName == nullptr) {
346 return false;
347 }
348
349 int fakeSocket; // a temporary socket to pass to ioctl
350 struct ifconf ifc; // ifconf information
351 char *ifbuf; // ifconf buffer
352 struct ifreq *ifr, *ifend; // pointer to individual interface info
353 int lastlen;
354 int len;
355
356 // Prevent UMRs
357 memset(addr, 0, sizeof(struct in_addr));
358
359 if ((fakeSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
360 mgmt_fatal(errno, "[getAddrForIntr] Unable to create socket\n");
361 }
362 // INKqa06739
363 // Fetch the list of network interfaces
364 // . from Stevens, Unix Network Prog., pg 434-435
365 ifbuf = nullptr;
366 lastlen = 0;
367 len = 128 * sizeof(struct ifreq); // initial buffer size guess
368 for (;;) {
369 ifbuf = static_cast<char *>(ats_malloc(len));
370 memset(ifbuf, 0, len); // prevent UMRs
371 ifc.ifc_len = len;
372 ifc.ifc_buf = ifbuf;
373 if (ioctl(fakeSocket, SIOCGIFCONF, &ifc) < 0) {
374 if (errno != EINVAL || lastlen != 0) {
375 mgmt_fatal(errno, "[getAddrForIntr] Unable to read network interface configuration\n");
376 }
377 } else {
378 if (ifc.ifc_len == lastlen) {
379 break;
380 }
381 lastlen = ifc.ifc_len;
382 }
383 len *= 2;
384 ats_free(ifbuf);
385 }
386
387 found = false;
388 // Loop through the list of interfaces
389 ifend = reinterpret_cast<struct ifreq *>(ifc.ifc_buf + ifc.ifc_len);
390 for (ifr = ifc.ifc_req; ifr < ifend;) {
391 if (ifr->ifr_addr.sa_family == AF_INET && strcmp(ifr->ifr_name, intrName) == 0) {
392 // Get the address of the interface
393 if (ioctl(fakeSocket, SIOCGIFADDR, reinterpret_cast<char *>(ifr)) < 0) {
394 mgmt_log("[getAddrForIntr] Unable obtain address for network interface %s\n", intrName);
395 } else {
396 // Only look at the address if it an internet address
397 if (ifr->ifr_ifru.ifru_addr.sa_family == AF_INET) {
398 ats_ip_copy(addr, &ifr->ifr_ifru.ifru_addr);
399 found = true;
400
401 if (mtu) {
402 *mtu = get_interface_mtu(fakeSocket, ifr);
403 }
404
405 break;
406 } else {
407 mgmt_log("[getAddrForIntr] Interface %s is not configured for IP.\n", intrName);
408 }
409 }
410 }
411 #if defined(freebsd) || defined(darwin)
412 ifr = (struct ifreq *)((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
413 #else
414 ifr = reinterpret_cast<struct ifreq *>((reinterpret_cast<char *>(ifr)) + sizeof(*ifr));
415 #endif
416 }
417 ats_free(ifbuf);
418 close(fakeSocket);
419
420 return found;
421 } /* End mgmt_getAddrForIntr */
422
423 /*
424 * mgmt_sortipaddrs(...)
425 * Routine to sort and pick smallest ip addr.
426 */
427 struct in_addr *
mgmt_sortipaddrs(int num,struct in_addr ** list)428 mgmt_sortipaddrs(int num, struct in_addr **list)
429 {
430 int i = 0;
431 unsigned long min;
432 struct in_addr *entry, *tmp;
433
434 min = (list[0])->s_addr;
435 entry = list[0];
436 while (i < num && (tmp = list[i]) != nullptr) {
437 i++;
438 if (min > tmp->s_addr) {
439 min = tmp->s_addr;
440 entry = tmp;
441 }
442 }
443 return entry;
444 } /* End mgmt_sortipaddrs */
445
446 void
mgmt_sleep_sec(int seconds)447 mgmt_sleep_sec(int seconds)
448 {
449 sleep(seconds);
450 }
451 void
mgmt_sleep_msec(int msec)452 mgmt_sleep_msec(int msec)
453 {
454 usleep(msec * 1000);
455 }
456