1 /*
2 * LOG functions
3 * Copyright (C) 2006-2008 Unix Solutions Ltd.
4 *
5 * Released under MIT license.
6 * See LICENSE-MIT.txt for license terms.
7 */
8 /* Needed for POLLRDHUP */
9 #define _GNU_SOURCE 1
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <netdb.h>
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
20 #include <sys/socket.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <poll.h>
25 #include <errno.h>
26 #include <time.h>
27 #include <pthread.h>
28
29 #include "libfuncs.h"
30 #include "io.h"
31 #include "queue.h"
32 #include "asyncdns.h"
33 #include "log.h"
34
35 static FILE *OUT_FD = NULL;
36
37 struct logger {
38 int use_stderr;
39 int use_syslog;
40
41 char *host_ident;
42
43 char *log_host;
44 int log_port;
45 int log_sock;
46
47 int dienow : 1,
48 dying : 1;
49
50 QUEUE *queue;
51 pthread_t thread;
52 };
53
log_connect(struct logger * l)54 static void log_connect(struct logger *l) {
55 struct sockaddr_in sockname;
56
57 if (!l->use_syslog)
58 return;
59
60 while (1) {
61 if (l->dying || l->dienow)
62 break;
63 int active = 1;
64 int dret = async_resolve_host(l->log_host, l->log_port, &sockname, 500, &active);
65 if (dret != 0) {
66 log_perror("Could not resolve log host.", errno);
67 sleep(2);
68 continue;
69 }
70 l->log_sock = socket(PF_INET, SOCK_STREAM, 0);
71 if (l->log_sock < 0) {
72 log_perror("Could not create syslog socket", errno);
73 sleep(2);
74 continue;
75 }
76 if (connect(l->log_sock, (struct sockaddr *) &sockname, sizeof (sockname)) < 0) {
77 log_perror("Could not connect to log host.", errno);
78 shutdown_fd(&l->log_sock);
79 sleep(2);
80 continue;
81 }
82 int on = 1;
83 setsockopt(l->log_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof(int));
84 break;
85 }
86 }
87
log_thread(void * param)88 static void * log_thread(void *param) {
89 char date[64], logline[1024], *msg=NULL;
90 struct logger *l = (struct logger *)param;
91
92 if (l->log_sock < 0)
93 log_connect(l);
94
95 while (l && !l->dienow) {
96 msg = queue_get(l->queue); // Waits...
97 if (!msg)
98 break;
99
100 time_t now = time(NULL);
101 memset(date, 0, sizeof(date));
102 struct tm ltime;
103 localtime_r(&now, <ime);
104 strftime(date, sizeof(date)-1, "%b %d %H:%M:%S", <ime);
105
106 memset(logline, 0, sizeof(logline));
107 snprintf(logline, sizeof(logline)-1, "<30>%s host %s: %s", date, l->host_ident, msg);
108 logline[sizeof(logline)-2] = '\n';
109 logline[sizeof(logline)-1] = '\0';
110
111 if (l->use_stderr)
112 fprintf(OUT_FD, "%s", logline+4);
113
114 while (l->use_syslog) {
115 struct pollfd fdset[1];
116 int fdready;
117 do {
118 fdset[0].fd = l->log_sock;
119 fdset[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDHUP;
120 fdready = poll(fdset, 1, 5 * 1000);
121 } while (fdready == -1 && errno == EINTR);
122 if (fdready < 1 || (fdready == 1 && fdset[0].revents != POLLOUT)) { /* Timeout || error */
123 do { /* Try to reconnect to log host */
124 if (l->dienow)
125 goto OUT;
126 LOGf("ERROR: Lost connection to log server (%s), fd: %i\n", fdready == 1 ? "poll error" : "timeout", l->log_sock);
127 shutdown_fd(&l->log_sock);
128 log_connect(l);
129 sleep(2);
130 } while (l->log_sock < 0);
131 } else {
132 if (fdwrite(l->log_sock, logline, strlen(logline)) > 0)
133 break;
134 else
135 if (l->dienow)
136 goto OUT;
137 }
138 }
139
140 FREE(msg);
141 }
142 OUT:
143 FREE(msg);
144 pthread_exit(0);
145 }
146
147 static struct logger *logger = NULL;
148
log_init(char * host_ident,int use_syslog,int use_stderr,char * log_host,int log_port)149 void log_init(char *host_ident, int use_syslog, int use_stderr, char *log_host, int log_port) {
150 logger = calloc(1, sizeof(struct logger));
151
152 logger->queue = queue_new();
153 logger->host_ident = strdup(host_ident);
154
155 if (log_host)
156 logger->log_host = strdup(log_host);
157 logger->log_port = log_port;
158 logger->log_sock = -1;
159
160 logger->use_syslog = use_syslog;
161 logger->use_stderr = use_stderr;
162
163 pthread_create(&logger->thread, NULL , &log_thread, logger);
164 }
165
log_set_out_fd(FILE * new_out_fd)166 void log_set_out_fd(FILE *new_out_fd) {
167 OUT_FD = new_out_fd;
168 }
169
log_close(void)170 void log_close(void) {
171 logger->dying = 1;
172 int count = 0;
173 while (logger->queue->items && count++ < 250)
174 usleep(1000);
175 logger->dienow = 1;
176 queue_wakeup(logger->queue);
177 pthread_join(logger->thread, NULL);
178 shutdown_fd(&logger->log_sock);
179 queue_free(&logger->queue);
180 FREE(logger->host_ident);
181 FREE(logger->log_host);
182 FREE(logger);
183 }
184
LOG(const char * msg)185 void LOG(const char *msg) {
186 if (OUT_FD == NULL)
187 OUT_FD = stderr;
188 if (!logger || logger->dying) {
189 fprintf(OUT_FD, "%s", msg);
190 } else {
191 queue_add(logger->queue, strdup(msg));
192 }
193 }
194
LOGf(const char * fmt,...)195 void LOGf(const char *fmt, ...) {
196 char msg[1024];
197 va_list args;
198 va_start(args, fmt);
199 vsnprintf(msg, sizeof(msg)-1, fmt, args);
200 va_end(args);
201 msg[sizeof(msg)-2] = '\n';
202 msg[sizeof(msg)-1] = '\0';
203 LOG(msg);
204 }
205
log_perror(const char * message,int _errno)206 void log_perror(const char *message, int _errno) {
207 char msg[1024];
208 snprintf(msg, sizeof(msg)-1, "PERROR: %s | %s\n", message, strerror(_errno));
209 msg[sizeof(msg)-2] = '\n';
210 msg[sizeof(msg)-1] = '\0';
211 LOG(msg);
212 }
213