3
* This is an RFC 3195 listener. All data received is forwarded to
4
* local UNIX domain socket, where it can be picked up by a
5
* syslog daemon (like rsyslogd ;)).
7
* \author Rainer Gerhards <rgerhards@adiscon.com>
9
* Copyright 2003-2005 Rainer Gerhards and Adiscon GmbH.
11
* This program is free software; you can redistribute it and/or
12
* modify it under the terms of the GNU General Public License
13
* as published by the Free Software Foundation; either version 2
14
* of the License, or (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this program; if not, write to the Free Software
23
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
* A copy of the GPL can be found in the file "COPYING" in this distribution.
30
#ifndef FEATURE_RFC3195
31
/* this is a trick: if RFC3195 is not to be supported, we just do an
36
fprintf(stderr, "error: not compiled with FEATURE_RFC3195 - terminating.\n");
42
#include <sys/socket.h>
43
#include <sys/errno.h>
45
#include "liblogging.h"
47
#include "syslogmessage.h"
49
/* configurable params! */
50
static char* pPathLogname = "/dev/log3195";
52
static int NoFork = 0;
54
static int listenPort = 601;
56
/* we use a global API object below, because this listener is
57
* not very complex. As such, this hack should not harm anything.
58
* rgerhards, 2005-10-12
60
static srAPIObj* pAPI;
62
static int LogFile = -1; /* fd for log */
63
static int connected; /* have done connect */
64
static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */
66
/* small usage info */
69
/* The following usage line is what we intend to have - it
70
* is commented out as a reminder. The one below is what we
71
* currently actually do...
72
fprintf(stderr, "usage: rfc3195d [-dv] [-i pidfile] [-n] [-p path]\n");
74
fprintf(stderr, "usage: rfc3195d [-dv] [-r port] [-p path]\n");
78
/* CLOSELOG -- close the system log
80
static void closelog(void)
87
/* OPENLOG -- open system log
92
SyslogAddr.sa_family = AF_UNIX;
93
strncpy(SyslogAddr.sa_data, pPathLogname,
94
sizeof(SyslogAddr.sa_data));
95
LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
98
printf("error opening '%s': %s\n",
99
pPathLogname, strerror_r(errno, errStr, sizeof(errStr)));
102
if (LogFile != -1 && !connected &&
103
connect(LogFile, &SyslogAddr, sizeof(SyslogAddr.sa_family)+
104
strlen(SyslogAddr.sa_data)) != -1)
108
printf("error connecting '%s': %s\n",
109
pPathLogname, strerror_r(errno, errStr, sizeof(errStr)));
114
/* This method is called when a message has been fully received.
115
* It passes the received message to the specified unix domain
116
* socket. Please note that this callback is synchronous, thus
117
* liblogging will be on hold until it returns. This is important
118
* to note because in an error case we might stay in this code
119
* for an extended amount of time. So far, we think this is the
120
* best solution, but real-world experience might tell us a
122
* rgerhards 2005-10-12
124
void OnReceive(srAPIObj* pAPI, srSLMGObj* pSLMG)
126
unsigned char *pszRawMsg;
127
int iRetries; /* number of retries connecting to log socket */
133
srSLMGGetRawMSG(pSLMG, &pszRawMsg);
135
/* we need to loop writing the message. At least in
136
* theory, a single write might not send all data to the
137
* syslogd. So we need to continue until everything is written.
138
* Also, we need to check if there are any socket erros, in
139
* which case we reconect. We will re-try indefinitely, if this
140
* is not acceptable, you need to change the code.
141
* rgerhards 2005-10-12
144
nToWrite = strlen(pszRawMsg);
146
while(nToWrite != 0) {
147
if(LogFile < 0 || !connected)
149
if(LogFile < 0 || !connected) {
150
/* still not connected, retry */
152
iSleep = (iRetries < 30) ? iRetries : 30;
153
/* we sleep a little to prevent a thight loop */
155
printf("multiple retries connecting to log socket"
156
" - doing sleep(%d)\n", iSleep);
161
nWritten = write(LogFile, pszRawMsg, strlen(pszRawMsg));
163
/* error, recover! */
165
printf("error writing to domain socket: %s\r\n", strerror_r(errno, errStr, sizeof(errStr)));
168
/* prepare for (potential) next write */
169
nToWrite -= nWritten;
170
iWriteOffset += nWritten;
176
static int largest = 0;
177
int sz = strlen(pszRawMsg);
180
printf("Msg(%d/%d):%s\n\n", largest, sz, pszRawMsg);
185
/* As we are single-threaded in this example, we need
186
* one way to shut down the listener running on this
187
* single thread. We use SIG_INT to do so - it effectively
188
* provides a short-lived second thread ;-)
190
void doShutdown(int i)
192
printf("Shutting down rfc3195d. Be patient, this can take up to 30 seconds...\n");
193
srAPIShutdownListener(pAPI);
197
/* on the the real program ;) */
198
int main(int argc, char* argv[])
202
struct sigaction sigAct;
204
while ((ch = getopt(argc, argv, "di:np:r:v")) != EOF)
206
case 'd': /* debug */
209
case 'i': /* pid file name */
212
case 'n': /* don't fork */
215
case 'p': /* path to regular log socket */
216
pPathLogname = optarg;
218
case 'r': /* listen port */
219
listenPort = atoi(optarg);
220
if(listenPort < 1 || listenPort > 65535) {
221
printf("Error: invalid listen port '%s', using 601 instead\n",
227
printf("rfc3195d %s.%s (using liblogging version %d.%d.%d).\n",
229
LIBLOGGING_VERSION_MAJOR, LIBLOGGING_VERSION_MINOR,
230
LIBLOGGING_VERSION_SUBMINOR);
231
printf("See http://www.rsyslog.com for more information.\n");
237
if ((argc -= optind))
240
memset(&sigAct, 0, sizeof(sigAct));
241
sigemptyset(&sigAct.sa_mask);
242
sigAct.sa_handler = doShutdown;
243
sigaction(SIGUSR1, &sigAct, NULL);
244
sigaction(SIGTERM, &sigAct, NULL);
248
sigAct.sa_handler = SIG_IGN;
249
sigaction(SIGINT, &sigAct, NULL);
252
if((pAPI = srAPIInitLib()) == NULL)
254
printf("Error initializing liblogging - aborting!\n");
258
if((iRet = srAPISetOption(pAPI, srOPTION_BEEP_LISTENPORT, listenPort)) != SR_RET_OK)
260
printf("Error %d setting listen port - aborting\n", iRet);
264
if((iRet = srAPISetupListener(pAPI, OnReceive)) != SR_RET_OK)
266
printf("Error %d setting up listener - aborting\n", iRet);
270
/* now move the listener to running state. Control will only
271
* return after SIGUSR1.
273
if((iRet = srAPIRunListener(pAPI)) != SR_RET_OK)
275
printf("Error %d running the listener - aborting\n", iRet);
279
/** control will reach this point after shutdown */
284
#endif /* #ifndef FEATURE_RFC3195 - main wrapper */