1 /** @file
2
3 This file contains functions that are shared by local and remote
4 API; in particular it has helper functions used by TSMgmtAPI.cc
5
6 @section license License
7
8 Licensed to the Apache Software Foundation (ASF) under one
9 or more contributor license agreements. See the NOTICE file
10 distributed with this work for additional information
11 regarding copyright ownership. The ASF licenses this file
12 to you under the Apache License, Version 2.0 (the
13 "License"); you may not use this file except in compliance
14 with the License. You may obtain a copy of the License at
15
16 http://www.apache.org/licenses/LICENSE-2.0
17
18 Unless required by applicable law or agreed to in writing, software
19 distributed under the License is distributed on an "AS IS" BASIS,
20 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 See the License for the specific language governing permissions and
22 limitations under the License.
23 */
24 #include "tscore/ink_platform.h"
25 #include "tscore/ink_sock.h"
26 #include "tscore/ink_string.h"
27 #include "tscore/ink_memory.h"
28
29 #include "CoreAPIShared.h"
30 #include "MgmtSocket.h"
31
32 // Forward declarations, used to be in the CoreAPIShared.h include file but
33 // that doesn't make any sense since these are both statically declared. /leif
34 static int poll_write(int fd, int timeout);
35 static int poll_read(int fd, int timeout);
36
37 /* parseHTTPResponse
38 * - parse the response buffer into header and body and calculate
39 * the correct size of the header and body.
40 * INPUT: buffer -- response buffer to be parsed
41 * header -- pointer to the head of the header
42 * hdr_size -- size of the header
43 * body -- pointer to the head of the body
44 * bdy_size -- size of the body
45 * OUTPUT: TSMgmtError -- error status
46 */
47 TSMgmtError
parseHTTPResponse(char * buffer,char ** header,int * hdr_size,char ** body,int * bdy_size)48 parseHTTPResponse(char *buffer, char **header, int *hdr_size, char **body, int *bdy_size)
49 {
50 TSMgmtError err = TS_ERR_OKAY;
51 char *buf;
52
53 // locate HTTP divider
54 if (!(buf = strstr(buffer, HTTP_DIVIDER))) {
55 err = TS_ERR_FAIL;
56 goto END;
57 }
58 // calculate header info
59 if (header) {
60 *header = buffer;
61 }
62 if (hdr_size) {
63 *hdr_size = buf - buffer;
64 }
65
66 // calculate body info
67 buf += strlen(HTTP_DIVIDER);
68 if (body) {
69 *body = buf;
70 }
71 if (bdy_size) {
72 *bdy_size = strlen(buf);
73 }
74
75 END:
76 return err;
77 }
78
79 /* readHTTPResponse
80 * - read from an opened socket to memory-allocated buffer and close the
81 * socket regardless success or failure.
82 * INPUT: sock -- the socket to read the response from
83 * buffer -- the buffer to be filled with the HTTP response
84 * bufsize -- the size allocated for the buffer
85 * OUTPUT: bool -- true if everything went well. false otherwise
86 */
87 TSMgmtError
readHTTPResponse(int sock,char * buffer,int bufsize,uint64_t timeout)88 readHTTPResponse(int sock, char *buffer, int bufsize, uint64_t timeout)
89 {
90 int64_t err, idx;
91
92 idx = 0;
93 for (;;) {
94 // printf("%d\n", idx);
95 if (idx >= bufsize) {
96 // printf("(test) response is too large [%d] %d\n", idx, bufsize);
97 goto error;
98 }
99 // printf("before poll_read\n");
100 err = poll_read(sock, timeout);
101 if (err < 0) {
102 // printf("(test) poll read failed [%d '%s']\n", errno, strerror (errno));
103 goto error;
104 } else if (err == 0) {
105 // printf("(test) read timeout\n");
106 goto error;
107 }
108 // printf("before do\n");
109 do {
110 // printf("in do\n");
111 err = read(sock, &buffer[idx], bufsize - idx);
112 } while ((err < 0) && ((errno == EINTR) || (errno == EAGAIN)));
113 // printf("content: %s\n", buffer);
114
115 if (err < 0) {
116 // printf("(test) read failed [%d '%s']\n", errno, strerror (errno));
117 goto error;
118 } else if (err == 0) {
119 buffer[idx] = '\0';
120 close(sock);
121 return TS_ERR_OKAY;
122 } else {
123 idx += err;
124 }
125 }
126
127 error: /* "Houston, we have a problem!" (Apollo 13) */
128 if (sock >= 0) {
129 close_socket(sock);
130 }
131 return TS_ERR_NET_READ;
132 }
133
134 /* sendHTTPRequest
135 * - Compose a HTTP GET request and sent it via an opened socket.
136 * INPUT: sock -- the socket to send the message to
137 * req -- the request to send
138 * OUTPUT: bool -- true if everything went well. false otherwise (and sock is
139 * closed)
140 */
141 TSMgmtError
sendHTTPRequest(int sock,char * req,uint64_t timeout)142 sendHTTPRequest(int sock, char *req, uint64_t timeout)
143 {
144 char request[BUFSIZ];
145 char *requestPtr;
146 size_t length = 0;
147
148 memset(request, 0, BUFSIZ);
149 snprintf(request, BUFSIZ, "GET %s HTTP/1.0\r\n\r\n", req);
150 length = strlen(request);
151
152 int err = poll_write(sock, timeout);
153 if (err < 0) {
154 // printf("(test) poll write failed [%d '%s']\n", errno, strerror (errno));
155 goto error;
156 } else if (err == 0) {
157 // printf("(test) write timeout\n");
158 goto error;
159 }
160 // Write the request to the server.
161 requestPtr = request;
162 while (length > 0) {
163 do {
164 err = write(sock, request, length);
165 } while ((err < 0) && ((errno == EINTR) || (errno == EAGAIN)));
166
167 if (err < 0) {
168 // printf("(test) write failed [%d '%s']\n", errno, strerror (errno));
169 goto error;
170 }
171 requestPtr += err;
172 length -= err;
173 }
174
175 /* everything went well */
176 return TS_ERR_OKAY;
177
178 error: /* "Houston, we have a problem!" (Apollo 13) */
179 if (sock >= 0) {
180 close_socket(sock);
181 }
182 return TS_ERR_NET_WRITE;
183 }
184
185 int
connectDirect(const char * host,int port,uint64_t)186 connectDirect(const char *host, int port, uint64_t /* timeout ATS_UNUSED */)
187 {
188 int sock;
189
190 // Create a socket
191 do {
192 sock = socket(AF_INET, SOCK_STREAM, 0);
193 } while ((sock < 0) && ((errno == EINTR) || (errno == EAGAIN)));
194
195 if (sock < 0) {
196 // printf("(test) unable to create socket [%d '%s']\n", errno, strerror(errno));
197 goto error;
198 }
199
200 struct sockaddr_in name;
201 memset((void *)&name, 0, sizeof(sockaddr_in));
202
203 int err;
204
205 // Put the socket in non-blocking mode...just to be extra careful
206 // that we never block.
207 do {
208 err = fcntl(sock, F_SETFL, O_NONBLOCK);
209 } while ((err < 0) && ((errno == EINTR) || (errno == EAGAIN)));
210
211 if (err < 0) {
212 // printf("(test) unable to put socket in non-blocking mode [%d '%s']\n", errno, strerror (errno));
213 goto error;
214 }
215 // Connect to the specified port on the machine we're running on.
216 name.sin_family = AF_INET;
217 name.sin_port = htons(port);
218
219 struct hostent *pHostent;
220 pHostent = gethostbyname(host);
221 if (!pHostent) {
222 goto error;
223 }
224 memcpy(reinterpret_cast<caddr_t>(&(name.sin_addr)), pHostent->h_addr, pHostent->h_length);
225
226 do {
227 err = connect(sock, reinterpret_cast<struct sockaddr *>(&name), sizeof(name));
228 } while ((err < 0) && ((errno == EINTR) || (errno == EAGAIN)));
229
230 if ((err < 0) && (errno != EINPROGRESS)) {
231 // printf("(test) unable to connect to server [%d '%s'] at port %d\n", errno, strerror (errno), port);
232 goto error;
233 }
234 return sock;
235
236 error:
237 if (sock >= 0) {
238 close_socket(sock);
239 }
240 return -1;
241 } /* connectDirect */
242
243 static int
poll_read(int fd,int timeout)244 poll_read(int fd, int timeout)
245 {
246 struct pollfd info;
247 int err;
248
249 info.fd = fd;
250 info.events = POLLIN;
251 info.revents = 0;
252
253 do {
254 err = poll(&info, 1, timeout);
255 } while ((err < 0) && ((errno == EINTR) || (errno == EAGAIN)));
256
257 if ((err > 0) && (info.revents & POLLIN)) {
258 return 1;
259 }
260
261 return err;
262 }
263
264 static int
poll_write(int fd,int timeout)265 poll_write(int fd, int timeout)
266 {
267 struct pollfd info;
268 int err;
269
270 info.fd = fd;
271 info.events = POLLOUT;
272 info.revents = 0;
273
274 do {
275 err = poll(&info, 1, timeout);
276 } while ((err < 0) && ((errno == EINTR) || (errno == EAGAIN)));
277
278 if ((err > 0) && (info.revents & POLLOUT)) {
279 return 1;
280 }
281
282 return err;
283 }
284
285 /**********************************************************************
286 * Events
287 **********************************************************************/
288 /**********************************************************************
289 * get_event_id
290 *
291 * Purpose: Given the event_name, returns the event's corresponding
292 * event id
293 * Note: this conversion is based on list defined in Alarms.h and
294 * the identical list defined in CoreAPIShared.cc
295 *********************************************************************/
296 int
get_event_id(const char * event_name)297 get_event_id(const char *event_name)
298 {
299 if (strcmp("MGMT_ALARM_PROXY_PROCESS_DIED", event_name) == 0) {
300 return MGMT_ALARM_PROXY_PROCESS_DIED;
301 } else if (strcmp("MGMT_ALARM_PROXY_PROCESS_BORN", event_name) == 0) {
302 return MGMT_ALARM_PROXY_PROCESS_BORN;
303 } else if (strcmp("MGMT_ALARM_PROXY_CONFIG_ERROR", event_name) == 0) {
304 return MGMT_ALARM_PROXY_CONFIG_ERROR;
305 } else if (strcmp("MGMT_ALARM_PROXY_SYSTEM_ERROR", event_name) == 0) {
306 return MGMT_ALARM_PROXY_SYSTEM_ERROR;
307 } else if (strcmp("MGMT_ALARM_PROXY_CACHE_ERROR", event_name) == 0) {
308 return MGMT_ALARM_PROXY_CACHE_ERROR;
309 } else if (strcmp("MGMT_ALARM_PROXY_CACHE_WARNING", event_name) == 0) {
310 return MGMT_ALARM_PROXY_CACHE_WARNING;
311 } else if (strcmp("MGMT_ALARM_PROXY_LOGGING_ERROR", event_name) == 0) {
312 return MGMT_ALARM_PROXY_LOGGING_ERROR;
313 } else if (strcmp("MGMT_ALARM_PROXY_LOGGING_WARNING", event_name) == 0) {
314 return MGMT_ALARM_PROXY_LOGGING_WARNING;
315 } else if (strcmp("MGMT_ALARM_CONFIG_UPDATE_FAILED", event_name) == 0) {
316 return MGMT_ALARM_CONFIG_UPDATE_FAILED;
317 }
318
319 return -1;
320 }
321
322 /**********************************************************************
323 * get_event_id
324 *
325 * Purpose: based on alarm_id, determine the corresponding alarm name
326 * Note: allocates memory for the name returned
327 *********************************************************************/
328 char *
get_event_name(int id)329 get_event_name(int id)
330 {
331 char name[MAX_EVENT_NAME_SIZE];
332
333 memset(name, 0, MAX_EVENT_NAME_SIZE);
334 switch (id) {
335 case MGMT_ALARM_PROXY_PROCESS_DIED:
336 ink_strlcpy(name, "MGMT_ALARM_PROXY_PROCESS_DIED", sizeof(name));
337 break;
338 case MGMT_ALARM_PROXY_PROCESS_BORN:
339 ink_strlcpy(name, "MGMT_ALARM_PROXY_PROCESS_BORN", sizeof(name));
340 break;
341 case MGMT_ALARM_PROXY_CONFIG_ERROR:
342 ink_strlcpy(name, "MGMT_ALARM_PROXY_CONFIG_ERROR", sizeof(name));
343 break;
344 case MGMT_ALARM_PROXY_SYSTEM_ERROR:
345 ink_strlcpy(name, "MGMT_ALARM_PROXY_SYSTEM_ERROR", sizeof(name));
346 break;
347 case MGMT_ALARM_PROXY_CACHE_ERROR:
348 ink_strlcpy(name, "MGMT_ALARM_PROXY_CACHE_ERROR", sizeof(name));
349 break;
350 case MGMT_ALARM_PROXY_CACHE_WARNING:
351 ink_strlcpy(name, "MGMT_ALARM_PROXY_CACHE_WARNING", sizeof(name));
352 break;
353 case MGMT_ALARM_PROXY_LOGGING_ERROR:
354 ink_strlcpy(name, "MGMT_ALARM_PROXY_LOGGING_ERROR", sizeof(name));
355 break;
356 case MGMT_ALARM_PROXY_LOGGING_WARNING:
357 ink_strlcpy(name, "MGMT_ALARM_PROXY_LOGGING_WARNING", sizeof(name));
358 break;
359 case MGMT_ALARM_CONFIG_UPDATE_FAILED:
360 ink_strlcpy(name, "MGMT_ALARM_CONFIG_UPDATE_FAILED", sizeof(name));
361 break;
362 default:
363 return nullptr;
364 }
365
366 return ats_strdup(name);
367 }
368