Improve UDP address selection.
[tinc] / src / logger.c
1 /*
2     logger.c -- logging code
3     Copyright (C) 2004-2012 Guus Sliepen <guus@tinc-vpn.org>
4                   2004-2005 Ivo Timmermans
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "system.h"
22
23 #include "conf.h"
24 #include "meta.h"
25 #include "logger.h"
26 #include "connection.h"
27 #include "control_common.h"
28 #include "sptps.h"
29
30 debug_t debug_level = DEBUG_NOTHING;
31 static logmode_t logmode = LOGMODE_STDERR;
32 static pid_t logpid;
33 extern char *logfilename;
34 static FILE *logfile = NULL;
35 #ifdef HAVE_MINGW
36 static HANDLE loghandle = NULL;
37 #endif
38 static const char *logident = NULL;
39 bool logcontrol = false;
40
41
42 static void real_logger(int level, int priority, const char *message) {
43         char timestr[32] = "";
44         time_t now;
45         static bool suppress = false;
46
47         // Bail out early if there is nothing to do.
48         if(suppress)
49                 return;
50
51         if(!logcontrol && (level > debug_level || logmode == LOGMODE_NULL))
52                 return;
53
54         if(level <= debug_level) {
55                 switch(logmode) {
56                         case LOGMODE_STDERR:
57                                 fprintf(stderr, "%s\n", message);
58                                 fflush(stderr);
59                                 break;
60                         case LOGMODE_FILE:
61                                 now = time(NULL);
62                                 strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
63                                 fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message);
64                                 fflush(logfile);
65                                 break;
66                         case LOGMODE_SYSLOG:
67 #ifdef HAVE_MINGW
68                                 {
69                                         const char *messages[] = {message};
70                                         ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
71                                 }
72 #else
73 #ifdef HAVE_SYSLOG_H
74                                 syslog(priority, "%s", message);
75 #endif
76 #endif
77                                 break;
78                         case LOGMODE_NULL:
79                                 break;
80                 }
81         }
82
83         if(logcontrol) {
84                 suppress = true;
85                 logcontrol = false;
86                 for list_each(connection_t, c, connection_list) {
87                         if(!c->status.log)
88                                 continue;
89                         logcontrol = true;
90                         if(level > (c->outcompression >= 0 ? c->outcompression : debug_level))
91                                 continue;
92                         int len = strlen(message);
93                         if(send_request(c, "%d %d %d", CONTROL, REQ_LOG, len))
94                                 send_meta(c, message, len);
95                 }
96                 suppress = false;
97         }
98 }
99
100 void logger(int level, int priority, const char *format, ...) {
101         va_list ap;
102         char message[1024] = "";
103
104         va_start(ap, format);
105         int len = vsnprintf(message, sizeof message, format, ap);
106         va_end(ap);
107
108         if(len > 0 && len < sizeof message && message[len - 1] == '\n')
109                 message[len - 1] = 0;
110
111         real_logger(level, priority, message);
112 }
113
114 static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap) {
115         char message[1024] = "";
116         int len = vsnprintf(message, sizeof message, format, ap);
117         if(len > 0 && len < sizeof message && message[len - 1] == '\n')
118                 message[len - 1] = 0;
119
120         real_logger(DEBUG_ALWAYS, LOG_ERR, message);
121 }
122
123 void openlogger(const char *ident, logmode_t mode) {
124         logident = ident;
125         logmode = mode;
126
127         switch(mode) {
128                 case LOGMODE_STDERR:
129                         logpid = getpid();
130                         break;
131                 case LOGMODE_FILE:
132                         logpid = getpid();
133                         logfile = fopen(logfilename, "a");
134                         if(!logfile) {
135                                 fprintf(stderr, "Could not open log file %s: %s\n", logfilename, strerror(errno));
136                                 logmode = LOGMODE_NULL;
137                         }
138                         break;
139                 case LOGMODE_SYSLOG:
140 #ifdef HAVE_MINGW
141                         loghandle = RegisterEventSource(NULL, logident);
142                         if(!loghandle) {
143                                 fprintf(stderr, "Could not open log handle!");
144                                 logmode = LOGMODE_NULL;
145                         }
146                         break;
147 #else
148 #ifdef HAVE_SYSLOG_H
149                         openlog(logident, LOG_CONS | LOG_PID, LOG_DAEMON);
150                         break;
151 #endif
152 #endif
153                 case LOGMODE_NULL:
154                         break;
155         }
156
157         if(logmode != LOGMODE_NULL)
158                 sptps_log = sptps_logger;
159         else
160                 sptps_log = sptps_log_quiet;
161 }
162
163 void reopenlogger() {
164         if(logmode != LOGMODE_FILE)
165                 return;
166
167         fflush(logfile);
168         FILE *newfile = fopen(logfilename, "a");
169         if(!newfile) {
170                 logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
171                 return;
172         }
173         fclose(logfile);
174         logfile = newfile;
175 }
176
177
178 void closelogger(void) {
179         switch(logmode) {
180                 case LOGMODE_FILE:
181                         fclose(logfile);
182                         break;
183                 case LOGMODE_SYSLOG:
184 #ifdef HAVE_MINGW
185                         DeregisterEventSource(loghandle);
186                         break;
187 #else
188 #ifdef HAVE_SYSLOG_H
189                         closelog();
190                         break;
191 #endif
192 #endif
193                 case LOGMODE_NULL:
194                 case LOGMODE_STDERR:
195                         break;
196                         break;
197         }
198 }