source: ogServer-Git/src/core.c @ 0e4857a

Last change on this file since 0e4857a was f3905fe, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#1021 remove LOG_DEBUG syslog

Some distros enable *.* in syslog.conf to add all logging information
to /var/log/syslog. The existing LOG_DEBUG syslog() entries that ogserver
generates fill up the log files very quickly. Remove most of the LOG_DEBUG
syslog() calls.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Copyright (C) 2020 Soleta Networks <info@soleta.eu>
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Affero General Public License as published by the
6 * Free Software Foundation, version 3.
7 */
8
9#include "ogAdmServer.h"
10#include "dbi.h"
11#include "utils.h"
12#include "list.h"
13#include "rest.h"
14#include "client.h"
15#include "json.h"
16#include "schedule.h"
17#include <syslog.h>
18#include <sys/ioctl.h>
19#include <ifaddrs.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <jansson.h>
24#include <time.h>
25
26static void og_client_release(struct ev_loop *loop, struct og_client *cli)
27{
28        list_del(&cli->list);
29        ev_io_stop(loop, &cli->io);
30        close(cli->io.fd);
31        free(cli);
32}
33
34static void og_client_reset_state(struct og_client *cli)
35{
36        cli->state = OG_CLIENT_RECEIVING_HEADER;
37        cli->buf_len = 0;
38}
39
40static int og_client_payload_too_large(struct og_client *cli)
41{
42        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
43                     "Content-Length: 0\r\n\r\n";
44
45        send(og_client_socket(cli), buf, strlen(buf), 0);
46
47        return -1;
48}
49
50static int og_client_state_recv_hdr_rest(struct og_client *cli)
51{
52        char *ptr;
53
54        ptr = strstr(cli->buf, "\r\n\r\n");
55        if (!ptr)
56                return 0;
57
58        cli->msg_len = ptr - cli->buf + 4;
59
60        ptr = strstr(cli->buf, "Content-Length: ");
61        if (ptr) {
62                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
63                if (cli->content_length < 0)
64                        return -1;
65                cli->msg_len += cli->content_length;
66        }
67
68        ptr = strstr(cli->buf, "Authorization: ");
69        if (ptr)
70                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
71
72        return 1;
73}
74
75static int og_client_recv(struct og_client *cli, int events)
76{
77        struct ev_io *io = &cli->io;
78        int ret;
79
80        if (events & EV_ERROR) {
81                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
82                               inet_ntoa(cli->addr.sin_addr),
83                               ntohs(cli->addr.sin_port));
84                return 0;
85        }
86
87        ret = recv(io->fd, cli->buf + cli->buf_len,
88                   sizeof(cli->buf) - cli->buf_len, 0);
89        if (ret <= 0) {
90                if (ret < 0) {
91                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
92                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
93                               strerror(errno));
94                }
95                return ret;
96        }
97
98        return ret;
99}
100
101static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
102{
103        struct og_client *cli;
104        int ret;
105
106        cli = container_of(io, struct og_client, io);
107
108        ret = og_client_recv(cli, events);
109        if (ret <= 0)
110                goto close;
111
112        if (cli->keepalive_idx >= 0)
113                return;
114
115        ev_timer_again(loop, &cli->timer);
116
117        cli->buf_len += ret;
118        if (cli->buf_len >= sizeof(cli->buf)) {
119                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
120                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
121                og_client_payload_too_large(cli);
122                goto close;
123        }
124
125        switch (cli->state) {
126        case OG_CLIENT_RECEIVING_HEADER:
127                ret = og_client_state_recv_hdr_rest(cli);
128                if (ret < 0)
129                        goto close;
130                if (!ret)
131                        return;
132
133                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
134                /* Fall through. */
135        case OG_CLIENT_RECEIVING_PAYLOAD:
136                /* Still not enough data to process request. */
137                if (cli->buf_len < cli->msg_len)
138                        return;
139
140                cli->state = OG_CLIENT_PROCESSING_REQUEST;
141                /* fall through. */
142        case OG_CLIENT_PROCESSING_REQUEST:
143                ret = og_client_state_process_payload_rest(cli);
144                if (ret < 0) {
145                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
146                               inet_ntoa(cli->addr.sin_addr),
147                               ntohs(cli->addr.sin_port));
148                }
149                if (ret < 0)
150                        goto close;
151
152                if (cli->keepalive_idx < 0) {
153                        goto close;
154                } else {
155                        og_client_reset_state(cli);
156                }
157                break;
158        default:
159                syslog(LOG_ERR, "unknown state, critical internal error\n");
160                goto close;
161        }
162        return;
163close:
164        ev_timer_stop(loop, &cli->timer);
165        og_client_release(loop, cli);
166}
167
168enum og_agent_state {
169        OG_AGENT_RECEIVING_HEADER       = 0,
170        OG_AGENT_RECEIVING_PAYLOAD,
171        OG_AGENT_PROCESSING_RESPONSE,
172};
173
174static int og_agent_state_recv_hdr_rest(struct og_client *cli)
175{
176        char *ptr;
177
178        ptr = strstr(cli->buf, "\r\n\r\n");
179        if (!ptr)
180                return 0;
181
182        cli->msg_len = ptr - cli->buf + 4;
183
184        ptr = strstr(cli->buf, "Content-Length: ");
185        if (ptr) {
186                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
187                if (cli->content_length < 0)
188                        return -1;
189                cli->msg_len += cli->content_length;
190        }
191
192        return 1;
193}
194
195static void og_agent_reset_state(struct og_client *cli)
196{
197        cli->state = OG_AGENT_RECEIVING_HEADER;
198        cli->buf_len = 0;
199        cli->content_length = 0;
200        memset(cli->buf, 0, sizeof(cli->buf));
201}
202
203static void og_agent_deliver_pending_cmd(struct og_client *cli)
204{
205        const struct og_cmd *cmd;
206
207        cmd = og_cmd_find(inet_ntoa(cli->addr.sin_addr));
208        if (!cmd)
209                return;
210
211        og_send_request(cmd->method, cmd->type, &cmd->params, cmd->json);
212        cli->last_cmd_id = cmd->id;
213
214        og_cmd_free(cmd);
215}
216
217static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
218{
219        struct og_client *cli;
220        int ret;
221
222        cli = container_of(io, struct og_client, io);
223
224        ret = og_client_recv(cli, events);
225        if (ret <= 0)
226                goto close;
227
228        ev_timer_again(loop, &cli->timer);
229
230        cli->buf_len += ret;
231        if (cli->buf_len >= sizeof(cli->buf)) {
232                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
233                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
234                goto close;
235        }
236
237        switch (cli->state) {
238        case OG_AGENT_RECEIVING_HEADER:
239                ret = og_agent_state_recv_hdr_rest(cli);
240                if (ret < 0)
241                        goto close;
242                if (!ret)
243                        return;
244
245                cli->state = OG_AGENT_RECEIVING_PAYLOAD;
246                /* Fall through. */
247        case OG_AGENT_RECEIVING_PAYLOAD:
248                /* Still not enough data to process request. */
249                if (cli->buf_len < cli->msg_len)
250                        return;
251
252                cli->state = OG_AGENT_PROCESSING_RESPONSE;
253                /* fall through. */
254        case OG_AGENT_PROCESSING_RESPONSE:
255                ret = og_agent_state_process_response(cli);
256                if (ret < 0) {
257                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
258                               inet_ntoa(cli->addr.sin_addr),
259                               ntohs(cli->addr.sin_port));
260                        goto close;
261                } else if (ret == 0) {
262                        og_agent_deliver_pending_cmd(cli);
263                }
264
265                og_agent_reset_state(cli);
266                break;
267        default:
268                syslog(LOG_ERR, "unknown state, critical internal error\n");
269                goto close;
270        }
271        return;
272close:
273        ev_timer_stop(loop, &cli->timer);
274        og_client_release(loop, cli);
275}
276
277static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
278{
279        struct og_client *cli;
280
281        cli = container_of(timer, struct og_client, timer);
282        if (cli->keepalive_idx >= 0) {
283                ev_timer_again(loop, &cli->timer);
284                return;
285        }
286        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
287               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
288
289        og_client_release(loop, cli);
290}
291
292static void og_agent_send_refresh(struct og_client *cli)
293{
294        struct og_msg_params params;
295        int err;
296
297        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
298        params.ips_array_len = 1;
299
300        err = og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, &params, NULL);
301        if (err < 0) {
302                syslog(LOG_ERR, "Can't send refresh to: %s\n",
303                       params.ips_array[0]);
304        } else {
305                syslog(LOG_INFO, "Sent refresh to: %s\n",
306                       params.ips_array[0]);
307        }
308}
309
310/* Shut down connection if there is no complete message after 10 seconds. */
311#define OG_CLIENT_TIMEOUT       10
312
313/* Agent client operation might take longer, shut down after 30 seconds. */
314#define OG_AGENT_CLIENT_TIMEOUT 30
315
316int socket_rest, socket_agent_rest;
317
318void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io, int events)
319{
320        struct sockaddr_in client_addr;
321        socklen_t addrlen = sizeof(client_addr);
322        struct og_client *cli;
323        int client_sd;
324
325        if (events & EV_ERROR)
326                return;
327
328        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
329        if (client_sd < 0) {
330                syslog(LOG_ERR, "cannot accept client connection\n");
331                return;
332        }
333
334        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
335        if (!cli) {
336                close(client_sd);
337                return;
338        }
339        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
340        if (io->fd == socket_agent_rest)
341                cli->keepalive_idx = 0;
342        else
343                cli->keepalive_idx = -1;
344
345        if (io->fd == socket_rest)
346                cli->rest = true;
347        else if (io->fd == socket_agent_rest)
348                cli->agent = true;
349
350        if (io->fd == socket_agent_rest)
351                ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
352        else
353                ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
354
355        ev_io_start(loop, &cli->io);
356        if (io->fd == socket_agent_rest) {
357                ev_timer_init(&cli->timer, og_client_timer_cb,
358                              OG_AGENT_CLIENT_TIMEOUT, 0.);
359        } else {
360                ev_timer_init(&cli->timer, og_client_timer_cb,
361                              OG_CLIENT_TIMEOUT, 0.);
362        }
363        ev_timer_start(loop, &cli->timer);
364        og_client_add(cli);
365
366        if (io->fd == socket_agent_rest) {
367                og_agent_send_refresh(cli);
368        }
369}
370
371int og_socket_server_init(const char *port)
372{
373        struct sockaddr_in local;
374        int sd, on = 1;
375
376        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
377        if (sd < 0) {
378                syslog(LOG_ERR, "cannot create main socket\n");
379                return -1;
380        }
381        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
382
383        local.sin_addr.s_addr = htonl(INADDR_ANY);
384        local.sin_family = AF_INET;
385        local.sin_port = htons(atoi(port));
386
387        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
388                close(sd);
389                syslog(LOG_ERR, "cannot bind socket\n");
390                return -1;
391        }
392
393        listen(sd, 250);
394
395        return sd;
396}
Note: See TracBrowser for help on using the repository browser.