/* imtcp.c
* This is the implementation of the TCP input module.
*
* NOTE: read comments in module-template.h to understand how this file
* works!
*
* File begun on 2007-12-21 by RGerhards (extracted from syslogd.c)
*
* Copyright 2007 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
* Rsyslog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rsyslog is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rsyslog. If not, see .
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include "rsyslog.h"
#include "syslogd.h"
#include "cfsysline.h"
#include "module-template.h"
#include "tcpsyslog.h"
MODULE_TYPE_INPUT
/* defines */
/* Module static data */
DEF_IMOD_STATIC_DATA
typedef struct _instanceData {
} instanceData;
/* config settings */
/* This function is called to gather input.
*/
BEGINrunInput
int maxfds;
int nfds;
int i;
int iTCPSess;
fd_set readfds;
CODESTARTrunInput
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
* right into the sleep below.
*/
while(1) {
/* Add the Unix Domain Sockets to the list of read
* descriptors.
* rgerhards 2005-08-01: we must now check if there are
* any local sockets to listen to at all. If the -o option
* is given without -a, we do not need to listen at all..
*/
maxfds = 0;
FD_ZERO (&readfds);
/* Add the TCP listen sockets to the list of read descriptors.
*/
if(sockTCPLstn != NULL && *sockTCPLstn) {
for (i = 0; i < *sockTCPLstn; i++) {
/* The if() below is theoretically not needed, but I leave it in
* so that a socket may become unsuable during execution. That
* feature is not yet supported by the current code base.
*/
if (sockTCPLstn[i+1] != -1) {
if(Debug)
debugListenInfo(sockTCPLstn[i+1], "TCP");
FD_SET(sockTCPLstn[i+1], &readfds);
if(sockTCPLstn[i+1]>maxfds) maxfds=sockTCPLstn[i+1];
}
}
/* do the sessions */
iTCPSess = TCPSessGetNxtSess(-1);
while(iTCPSess != -1) {
int fdSess;
fdSess = pTCPSessions[iTCPSess].sock;
dbgprintf("Adding TCP Session %d\n", fdSess);
FD_SET(fdSess, &readfds);
if (fdSess>maxfds) maxfds=fdSess;
/* now get next... */
iTCPSess = TCPSessGetNxtSess(iTCPSess);
}
}
if(Debug) {
dbgprintf("--------imTCP calling select, active file descriptors (max %d): ", maxfds);
for (nfds = 0; nfds <= maxfds; ++nfds)
if ( FD_ISSET(nfds, &readfds) )
dbgprintf("%d ", nfds);
dbgprintf("\n");
}
/* wait for io to become ready */
nfds = select(maxfds+1, (fd_set *) &readfds, NULL, NULL, NULL);
for (i = 0; i < *sockTCPLstn; i++) {
if (FD_ISSET(sockTCPLstn[i+1], &readfds)) {
dbgprintf("New connect on TCP inetd socket: #%d\n", sockTCPLstn[i+1]);
# ifdef USE_GSSAPI
if(bEnableTCP & ALLOWEDMETHOD_GSS)
TCPSessGSSAccept(sockTCPLstn[i+1]);
else
# endif
TCPSessAccept(sockTCPLstn[i+1]);
--nfds; /* indicate we have processed one */
}
}
/* now check the sessions */
iTCPSess = TCPSessGetNxtSess(-1);
while(nfds && iTCPSess != -1) {
int fdSess;
int state;
fdSess = pTCPSessions[iTCPSess].sock;
if(FD_ISSET(fdSess, &readfds)) {
char buf[MAXLINE];
dbgprintf("tcp session socket with new data: #%d\n", fdSess);
/* Receive message */
# ifdef USE_GSSAPI
int allowedMethods = pTCPSessions[iTCPSess].allowedMethods;
if(allowedMethods & ALLOWEDMETHOD_GSS)
state = TCPSessGSSRecv(iTCPSess, buf, sizeof(buf));
else
# endif
state = recv(fdSess, buf, sizeof(buf), 0);
if(state == 0) {
# ifdef USE_GSSAPI
if(allowedMethods & ALLOWEDMETHOD_GSS)
TCPSessGSSClose(iTCPSess);
else {
# endif
/* process any incomplete frames left over */
TCPSessPrepareClose(iTCPSess);
/* Session closed */
TCPSessClose(iTCPSess);
# ifdef USE_GSSAPI
}
# endif
} else if(state == -1) {
logerrorInt("TCP session %d will be closed, error ignored\n",
fdSess);
# ifdef USE_GSSAPI
if(allowedMethods & ALLOWEDMETHOD_GSS)
TCPSessGSSClose(iTCPSess);
else
# endif
TCPSessClose(iTCPSess);
} else {
/* valid data received, process it! */
if(TCPSessDataRcvd(iTCPSess, buf, state) == 0) {
/* in this case, something went awfully wrong.
* We are instructed to terminate the session.
*/
logerrorInt("Tearing down TCP Session %d - see "
"previous messages for reason(s)\n",
iTCPSess);
# ifdef USE_GSSAPI
if(allowedMethods & ALLOWEDMETHOD_GSS)
TCPSessGSSClose(iTCPSess);
else
# endif
TCPSessClose(iTCPSess);
}
}
--nfds; /* indicate we have processed one */
}
iTCPSess = TCPSessGetNxtSess(iTCPSess);
}
}
return iRet;
ENDrunInput
/* initialize and return if will run or not */
BEGINwillRun
CODESTARTwillRun
/* first apply some config settings */
dbgprintf("imtcp: bEnableTCP %d\n", bEnableTCP);
PrintAllowedSenders(2); /* TCP */
#ifdef USE_GSSAPI
PrintAllowedSenders(3); /* GSS */
#endif
if (bEnableTCP) {
if(sockTCPLstn == NULL) {
# ifdef USE_GSSAPI
if(bEnableTCP & ALLOWEDMETHOD_GSS) {
if(TCPSessGSSInit()) {
logerror("GSS-API initialization failed\n");
bEnableTCP &= ~(ALLOWEDMETHOD_GSS);
}
}
if(bEnableTCP)
# endif
if((sockTCPLstn = create_tcp_socket()) != NULL) {
dbgprintf("Opened %d syslog TCP port(s).\n", *sockTCPLstn);
}
}
}
ENDwillRun
BEGINafterRun
CODESTARTafterRun
/* do cleanup here */
if (pAllowedSenders_TCP != NULL) {
clearAllowedSenders (pAllowedSenders_TCP);
pAllowedSenders_TCP = NULL;
}
#ifdef USE_GSSAPI
if (pAllowedSenders_GSS != NULL) {
clearAllowedSenders (pAllowedSenders_GSS);
pAllowedSenders_GSS = NULL;
}
#endif
ENDafterRun
BEGINfreeInstance
CODESTARTfreeInstance
ENDfreeInstance
BEGINdbgPrintInstInfo
CODESTARTdbgPrintInstInfo
ENDdbgPrintInstInfo
BEGINmodExit
CODESTARTmodExit
/* Close the TCP inet socket. */
if(sockTCPLstn != NULL && *sockTCPLstn) {
deinit_tcp_listener();
}
#ifdef USE_GSSAPI
if(bEnableTCP & ALLOWEDMETHOD_GSS)
TCPSessGSSDeinit();
#endif
ENDmodExit
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
#if defined(USE_GSSAPI)
if (gss_listen_service_name != NULL) {
free(gss_listen_service_name);
gss_listen_service_name = NULL;
}
#endif
return RS_RET_OK;
}
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = 1; /* so far, we only support the initial definition */
CODEmodInit_QueryRegCFSLineHdlr
/* register config file handlers */
#if defined(USE_GSSAPI)
CHKiRet(regCfSysLineHdlr((uchar *)"gsslistenservicename", 0, eCmdHdlrGetWord, NULL, &gss_listen_service_name, NULL));
#endif
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
ENDmodInit
/*
* vi:set ai:
*/