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