"Fossies" - the Fresh Open Source Software archive 
Member "evlog-1.6.1/user/cmd/evlogd/evlogrmtd.c" of archive evlog-1.6.1.tar.gz:
/*
* Linux Event Logging for the Enterprise
* Copyright (c) International Business Machines Corp., 2001
*
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Please send e-mail to lkessler@users.sourceforge.net if you have
* questions or comments.
*
* Project Website: http://evlog.sourceforge.net/
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "config.h"
#include "posix_evlog.h"
#include "evlog.h"
#include "evl_list.h"
#include "evl_util.h"
#include "evl_template.h"
#include "evl_common.h"
#include "shared/rmt_common.h"
#define EVLOG_TCP_PORT 12000
#define EVLOG_UDP_PORT 34000
#define MAX_RMT_CONNECTIONS 64
#define MAX_RMT_AUTHDATA 128
//#define DEBUG3
#ifdef DEBUG2
#define TRACE(fmt, args...) fprintf(stdout, fmt, ##args)
#endif
#ifndef DEBUG2
#define TRACE(fmt, args...) /* fprintf(stderr, fmt, ##args) */
#endif
#define max(a,b) (((a)>(b))?(a):(b))
#define CLIENT_SLOT_AVAILABLE -100
#define EVLHOSTS "/etc/evlog.d/evlhosts"
#define EVLOGRMTD_CONF "/etc/evlog.d/evlogrmtd.conf"
#define MAX_BUFREAD_LEN REC_HDR_SIZE + POSIX_LOG_ENTRY_MAXLEN
struct host_entry {
struct in_addr in;
int id;
};
static struct host_entry *host_array = (struct host_entry *) 0;
static int num_hosts = 0;
typedef struct rmt_clientinfo {
int sd;
struct in_addr in;
int node_id;
int authenticated;
int authdata_len;
void *authdata;
} rmt_clientinfo_t;
rmt_clientinfo_t clients[MAX_RMT_CONNECTIONS];
static int maxcl; /* max num of clients */
static int maxci;
static int maxsd;
fd_set all_sds;
static int evlog_sd = -1; /* This socket is for writing events to evlogd */
static char *PidFile = "/var/run/evlogrmtd.pid";
/* Function prototypes */
int authenticate(rmt_clientinfo_t *);
void initClients();
int getMaxClientIndex();
int fwdClientEvent(rmt_clientinfo_t *ci);
static int writeToEvlogd(struct posix_log_entry *rhdr, const char *varbuf);
void closeClientSocket(rmt_clientinfo_t *ci);
/* DEBUG helper functions */
static void printRecord(const struct posix_log_entry *entry, const char *buf);
/*
* Establish a connect to evlogd
*/
static int connectToEvlogd()
{
int fd;
struct sockaddr_un evlsock;
size_t sock_len;
int retry = 0;
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
(void)fprintf(stderr, "Cannot create socket.\n");
exit(1);
}
memset(&evlsock, 0, sizeof(struct sockaddr_un));
evlsock.sun_family = PF_UNIX;
(void)strcpy(evlsock.sun_path, EVLOGD_EVTSERVER_SOCKET);
sock_len = sizeof(evlsock.sun_family) + strlen(evlsock.sun_path);
if (connect(fd, (struct sockaddr *)&evlsock, sock_len) < 0) {
// (void)fprintf(stderr, "Cannot connect to evlogd daemon.\n");
close(fd);
return -1;
}
TRACE("Connected to evlogd, fd=%d.\n", fd);
return fd;
}
/*
* listen to TCP clients
*/
static int listenToStreamClients()
{
int fd, i=1, port;
struct sockaddr_in address;
size_t addrLen = sizeof(struct sockaddr_in);
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "Failed to create server socket.\n");
exit(1);
}
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
address.sin_family = AF_INET;
if (getConfigIntParam(EVLOGRMTD_CONF, "TCPPort", &port) != 0) {
port = EVLOG_TCP_PORT;
}
TRACE("TCP Port=%d\n", port);
address.sin_port = htons(port);
memset(&address.sin_addr, 0, sizeof(address.sin_addr));
if (bind(fd, (struct sockaddr *) &address, sizeof(address))) {
fprintf(stderr, "Failed to bind server address\n");
close(fd);
exit(1);
}
if (listen(fd, MAX_RMT_CONNECTIONS)) {
fprintf(stderr, "Failed to create listening socket.\n");
close(fd);
exit(1);
}
return fd;
}
static int createUDPSocket()
{
int fd, i=1, port;
struct sockaddr_in sin;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
fprintf(stderr, "Failed to create server socket.\n");
exit(1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
if (getConfigIntParam(EVLOGRMTD_CONF, "UDPPort", &port) != 0) {
port = EVLOG_UDP_PORT;
}
TRACE("UDPPort=%d\n", port);
sin.sin_port = htons(port);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
fprintf(stderr, "Failed to bind server address\n");
close(fd);
exit(1);
}
return fd;
}
/*
* evlogrmtd maintains a list of hosts that are allowed to write events
* to evlog in memory (caching).
*
* These are supported routines for loading/unloading hostarray
*/
static int addHost(struct in_addr *in, int id)
{
/* Allocate host table entry */
host_array = (struct host_entry *) realloc(host_array,
(num_hosts+1) * sizeof(struct host_entry));
if (host_array == NULL) {
return 0;
}
memcpy(&host_array[num_hosts].in, in, sizeof(struct in_addr));
host_array[num_hosts].id = id;
++num_hosts;
TRACE("Add host with ip=%s into host array.\n", inet_ntoa(*in));
return 1;
}
int initHostArray()
{
char *p, *name, *id;
char line[256];
FILE * f;
struct hostent *hp;
int nodeID;
struct in_addr inet_addr;
int ret = 0;
num_hosts = 0;
if((f = fopen(EVLHOSTS, "r")) == NULL) {
fprintf(stderr, "can't open evlhosts file.\n");
return -1;
}
while (fgets(line, 256, f) != NULL) {
int len;
if (line[0] == '#' || line[0] == '\n'
|| strcspn(line, "") == 0) {
continue;
}
len = strlen(line);
/* replace newline with null char */
if (line[len -1] == '\n') {
line[len -1] = '\0';
}
/* host id */
id = (char *) strtok(line, " \t");
if (!id) {
/* probably a blank line with a tab or space */
continue;
}
trim(id);
/* host name */
name = (char *) strtok(NULL, " \t");
if (!name) {
ret = -1;
goto error_exit;
}
/* Remove leading space and trailing space */
trim(name);
if ((hp = (struct hostent *)gethostbyname(name)) == NULL) {
fprintf(stderr, "unknown host: %s.\n", name);
continue;
}
if ((p=strchr(id, '.')) != NULL) {
/* id in 255.255 format */
char *endp = 0;
int lowerbyte, upperbyte;
upperbyte = (int) strtoul(id, &endp, 10);
TRACE("ubyte=%d\n", upperbyte);
if (*endp != '.') {
fprintf(stderr, "%s is an invalid node id.\n", id);
continue;
}
lowerbyte = (int) strtoul(p + 1, &endp, 10);
TRACE("lbyte=%d\n", lowerbyte);
if (*endp != '\0') {
fprintf(stderr, "%s is an invalid node id.\n", id);
continue;
}
if (upperbyte > 255 || lowerbyte > 255) {
fprintf(stderr, "%s is an invalid node id.\n", id);
continue;
}
nodeID = (upperbyte << 8) + lowerbyte;
TRACE("NodeID= 0x%x", nodeID);
} else {
nodeID = (int) strtoul(id, (char **) NULL, 0);
}
memcpy(&inet_addr, hp->h_addr_list[0], hp->h_length);
addHost(&inet_addr, nodeID);
}
error_exit:
fclose(f);
return ret;
}
int hostLookUp(struct in_addr *in, int * nodeID)
{
int i;
for (i=0; i < num_hosts; ++i) {
if (host_array[i].in.s_addr == in->s_addr) {
TRACE("hostLoopUp: Found host in cache\n");
*nodeID = host_array[i].id;
return 0;
}
}
return -1;
}
void destroyHostArray()
{
int i;
if (host_array == NULL) {
return;
}
free(host_array);
host_array = (struct host_entry *) 0;
}
int reinitHostArray()
{
destroyHostArray();
return initHostArray();
}
/*
* Forward this event to evlog.
* Check to see if the sending host is allow to send event. Only forward event to
* evlog if it is allowed.
*/
void fwdUDPEvent(char * buff, int recvlen, struct sockaddr_in *sock)
{
int nodeID;
char hostname[80];
int ret;
struct posix_log_entry hdr;
struct net_rechdr * net_hdr;
char *vardata;
/* Lookup host */
if (hostLookUp((struct in_addr *) &sock->sin_addr, &nodeID) != 0) {
TRACE("fwdUDPEvent: hostLookUp failed.\n");
return;
}
net_hdr = (struct net_rechdr *) buff;
ntoh_rechdr(net_hdr, &hdr);
if ((hdr.log_size + NET_REC_HDR_SIZE) != recvlen) {
/* we did not receive the whole record */
return;
}
/* Put nodeID into the upper word of log_processor field */
hdr.log_processor |= (nodeID << 16);
vardata = buff + NET_REC_HDR_SIZE;
writeToEvlogd(&hdr, vardata);
#ifdef DEBUG3
printRecord(&hdr, vardata);
#endif
}
void _daemonize()
{
pid_t pid;
int num_fds, i;
if (_evlValidate_pid(PidFile)) {
fprintf(stderr, "evlogrmtd: Already running.\n");
exit(1);
}
/*
* Fork a child and let the parent exit. This guarentees that
* the first child is not a process group leader.
*/
if ((pid = fork()) < 0) {
fprintf(stderr,
"evlogrmtd: Cannot fork child process. Check system process usage.\n");
exit(1);
} else if (pid > 0) {
exit (0);
}
/*
* First child process.
*
* Disassociate from controlling terminal and process group.
* Ensure the process can't reacquire a new controlling terminal
*/
(void)setpgrp();
/*
* Immunize from process group leader death.
*/
(void)signal(SIGHUP, SIG_IGN);
if ((pid = fork()) < 0) {
fprintf(stderr,
"evlogrmtd: Cannot fork child process. Check system process usage.\n");
exit(1);
} else if (pid > 0) {
exit(0);
}
/*
* Save this pid to to a file, if it is not running yet.
* We allow only one instance of this process at a time.
*
*/
if (!_evlUpdate_pid(PidFile)) {
#if 0
LOGERROR(EVLOG_WRITE_PID, "evlogrmtd: Cannot write 'evlogrmtd' PID to '%s' file\n",
PidFile);
#endif
exit(1);
}
/*
* Redirect fd 0 1 2 to /dev/null .
*/
{
int devnull;
devnull = open("/dev/null", O_WRONLY);
if (devnull != -1) {
num_fds = 2;
for (i=0; i <= num_fds; i++) {
(void)close(i);
dup2(devnull, i);
}
close(devnull);
}
}
/*
* Clear any inherited file mode creation mask.
*/
(void)umask(0);
(void)mkdir(LOG_EVLOG_DIR, 755);
(void)chdir(LOG_EVLOG_DIR);
}
/*
* Handling terminate signal, save request list to file
* and clean up before exit.
*/
static void
SIGTERM_handler()
{
/* Clean up here */
exit(0);
}
static void
validateTCPClients()
{
int i, nodeid;
for (i = 0; i < MAX_RMT_CONNECTIONS; i++) {
if (clients[i].sd == CLIENT_SLOT_AVAILABLE) continue;
if (hostLookUp(&clients[i].in, &nodeid) == -1) {
/* Not in the host list anymore - remove him*/
TRACE("Not in the evlhosts anymore!\n");
closeClientSocket(&clients[i]);
}
}
}
/*
* reinitialize the host array
*/
static int validateHostArray = 0;
static void
SIGHUP_handler(int signum)
{
TRACE("validateHostArray flag set.\n");
validateHostArray = 1;
}
/*
* MAIN()
*/
int main (int argc, char **argv)
{
struct sockaddr_in address;
int tcp_sd, udp_sd, udp_fd, newsd;
socklen_t addrLen = sizeof(struct sockaddr_in);
char buff[MAX_BUFREAD_LEN];
struct sockaddr_in frominet;
char *from;
fd_set read_sds;
int retry = 0;
int daemonize = 1; /* run this app as a daemon */
auto int c; /* Command line option */
struct sigaction act;
static struct sigaction SigTERMAction; /* Signal handler to terminate gracefully */
void SIGTERM_handler();
static struct sigaction SigHUPAction; /* Signal handler to validate hostlist */
//void SIGHUP_handler();
/* Process command line options */
while ((c = getopt(argc, argv, "f")) != EOF) {
switch (c) {
case 'f':
daemonize = 0;
break;
default:
break;
}
}
TRACE("evlrmtd starting ...\n");
/* Daemonize */
if (daemonize) {
_daemonize();
}
initClients();
/* Caching the host list */
if (initHostArray() != 0 || num_hosts == 0) {
//fprintf(stderr, "Failed to initialize the host array.\n");
exit(1);
}
/*
* Create new signal handler for SIGTERM. This will do the cleanup of
* all sockets and terminate gracefully.
*/
(void) memset(&SigTERMAction, 0, sizeof(SigTERMAction));
SigTERMAction.sa_handler = SIGTERM_handler;
SigTERMAction.sa_flags = 0;
if (sigaction(SIGTERM, &SigTERMAction, NULL) < 0){
(void)fprintf(stderr, "%s: sigaction failed for new SIGTERM.\n", argv[0]);
perror("sigaction");
}
if (sigaction(SIGINT, &SigTERMAction, NULL) < 0){
(void)fprintf(stderr, "%s: sigaction failed for new SIGINT.\n", argv[0]);
perror("sigaction");
}
/*
* SIGHUP handler - validate hostlist
*/
(void) memset(&SigHUPAction, 0, sizeof(SigHUPAction));
SigHUPAction.sa_handler = SIGHUP_handler;
SigHUPAction.sa_flags = 0;
if (sigaction(SIGHUP, &SigHUPAction, NULL) < 0){
(void)fprintf(stderr, "%s: sigaction failed for new SIGHUP.\n", argv[0]);
perror("sigaction");
}
/*
* Ignore SIGCHLD
*/
(void) memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
act.sa_flags = 0;
if (sigaction(SIGCHLD, &act, NULL) < 0){
(void)fprintf(stderr, "%s: sigaction failed for new SIGCHLD.\n", argv[0]);
perror("sigaction");
exit(1);
}
/*
* Ignore any SIGPIPE signal. A broken pipe is a normal occurrance as
* clients come and go. We don't want the server to stop because of one.
*/
if (sigaction(SIGPIPE, &act, NULL) < 0){
(void)fprintf(stderr, "%s: sigaction failed for new SIGPIPE.\n", argv[0]);
perror("sigaction");
exit(1);
}
evlog_sd = connectToEvlogd();
/*
* Setup listening socket for accepting connection from TCP clients.
*/
tcp_sd = listenToStreamClients();
udp_fd = createUDPSocket();
udp_sd = udp_fd;
TRACE("udp_sd = %d \n", udp_fd);
FD_ZERO(&all_sds);
FD_SET(tcp_sd, &all_sds);
FD_SET(udp_sd, &all_sds);
maxsd = max(tcp_sd, udp_sd);
if (evlog_sd != -1) {
FD_SET(evlog_sd, &all_sds);
maxsd = max(maxsd, evlog_sd);
}
for (;;) {
int nsel, i, idx;
sigset_t oldset, newset;
int status;
int sigIsBlocked;
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (validateHostArray) {
reinitHostArray();
validateTCPClients();
validateHostArray = 0;
}
if (evlog_sd == -1) {
TRACE( "Try to re-connect\n");
///connection to evlogd is broken - re-establish
if((evlog_sd = connectToEvlogd()) > 0) {
FD_SET(evlog_sd, &all_sds);
maxsd = max(evlog_sd, maxsd);
}
}
bcopy((char *)&all_sds, (char *)&read_sds, sizeof(all_sds));
TRACE("select ............tv_sev=%d\n", tv.tv_sec);
if ((nsel = select(maxsd + 1, &read_sds, 0, 0,
(evlog_sd == -1)? &tv : 0)) >= 0) {
if (errno == EINTR) {
TRACE("got EINTR\n");
continue;
}
if (nsel == 0) {
continue;
}
/*
* Temporary block SIGHUP signal
* during the time I have socket activity.
*/
status = sigaddset(&newset, SIGHUP);
status = sigprocmask(SIG_BLOCK, &newset, &oldset);
if (status != 0) {
perror("sigprocmask");
/*
* Fail to block, but probably the best course is
* just to continue
*/
sigIsBlocked = 0;
} else {
sigIsBlocked = 1;
}
if (FD_ISSET(tcp_sd, &read_sds)) {
/* Client is trying to connect. */
int newsd;
int nodeID;
struct sockaddr_in sockin;
socklen_t socklen = 16;
TRACE("Client's trying to connect...\n");
if ((newsd = accept(tcp_sd,
(struct sockaddr *) &address,
&addrLen)) < 0) {
perror("accept");
goto exit_new_sd;
}
if (maxcl == MAX_RMT_CONNECTIONS -1 ) {
TRACE("Max number of clients reached.\n");
close(newsd);
goto exit_new_sd;
}
TRACE("Server accepted the connection...\n");
if (getpeername(newsd, (struct sockaddr *) &sockin,
&socklen) != 0) {
//fprintf(stderr, "Failed to get peer name.\n");
close(newsd);
goto exit_new_sd;
}
/* Reject connections from hosts not
* listed in our config file */
if (hostLookUp(&sockin.sin_addr, &nodeID) != 0) {
TRACE("Rejecting unknown client %s\n",
inet_ntoa(sockin.sin_addr));
close(newsd);
goto exit_new_sd;
}
maxcl++;
FD_SET(newsd, &all_sds);
if (maxsd < newsd) {
maxsd = newsd;
}
for (idx = 0 ; idx < MAX_RMT_CONNECTIONS; idx++) {
if( clients[idx].sd == CLIENT_SLOT_AVAILABLE) {
TRACE("sd %d in slot %d\n", newsd, idx);
memset(&clients[idx], 0, sizeof(clients[idx]));
clients[idx].sd = newsd;
memcpy(&clients[idx].in, &sockin.sin_addr,
sizeof(struct in_addr));
clients[idx].node_id = nodeID;
TRACE("accept: nodeID=0x%x", nodeID);
break;
}
}
maxci = getMaxClientIndex();
exit_new_sd: /* make gcc happy */ ;
}
/* process UDP clients */
if (FD_ISSET(udp_sd, &read_sds)){
int len = sizeof(frominet);
TRACE("udp packet arrived..\n");
memset(buff, 0, MAX_BUFREAD_LEN);
i = recvfrom(udp_fd, buff, MAX_BUFREAD_LEN, 0,
(struct sockaddr *) &frominet, &len);
if (i > 0) {
/*
* forward udp event. Check if message came from
* an expected host, and it is a complete message
*/
fwdUDPEvent(buff, i, &frominet);
} else if ( i < 0 && errno != EINTR) {
TRACE("UDP socket error: %d\n", errno);
}
}
/* process TCP clients */
for (i= 0; i <= maxci; i++) {
if ( clients[i].sd == CLIENT_SLOT_AVAILABLE
|| !FD_ISSET(clients[i].sd, &read_sds))
continue;
if (!clients[i].authenticated) {
authenticate(&clients[i]);
continue;
}
fwdClientEvent(&clients[i]);
}
if (evlog_sd > 0 && FD_ISSET(evlog_sd, &read_sds)) {
TRACE("evlogd goes away!\n");
close(evlog_sd);
if (evlog_sd == maxsd) {
maxsd--;
}
FD_CLR(evlog_sd, &all_sds);
evlog_sd = -1;
}
/* unblock signal */
if (sigIsBlocked == 1) {
status = sigprocmask(SIG_SETMASK, &oldset, NULL);
if (status != 0) {
perror("sigprocmask (unblock)");
}
}
}
#ifdef DEBUG2
else {
/* select return -1 */
perror("select");
}
#endif
} /* end for */
}
/* Authenticate TCP connection */
int authenticate(rmt_clientinfo_t *ci)
{
int n, total, pwlen, nodeID;
char hostname[80];
char *clnt_password, passwd[80];
/* When we come here, allocate a reasonably sized buffer */
if (ci->authdata_len == 0) {
ci->authdata = malloc(MAX_RMT_AUTHDATA);
if (ci->authdata == NULL)
goto failed;
}
/* Read more data from the socket - either
* the string length, or the string itself
*/
if (ci->authdata_len < sizeof(int)) {
n = sizeof(int) - ci->authdata_len;
total = -1;
} else {
memcpy(&pwlen, ci->authdata, sizeof(int));
pwlen = ntohl(pwlen);
total = sizeof(int) + pwlen;
if (total >= MAX_RMT_AUTHDATA - 1 || total < ci->authdata_len)
goto failed;
n = total - ci->authdata_len;
}
n = read(ci->sd, ci->authdata + ci->authdata_len, n);
if (n <= 0)
goto failed;
ci->authdata_len += n;
if (total < 0 || ci->authdata_len < total)
return 0;
/* We have the password string */
clnt_password = (char *) (ci->authdata + sizeof(int));
clnt_password[pwlen] = '\0';
TRACE("password= %s\n", clnt_password);
if (getConfigStringParam(EVLOGRMTD_CONF, "Password", passwd, sizeof(passwd))) {
// Failed to obtain password from password file
goto failed;
}
if (strcmp(clnt_password, passwd)) {
// Failed password check
goto failed;
}
posix_log_printf(LOG_LOGMGMT, 100,
LOG_NOTICE, 0, "evlogrmtd: This %s host is successfully authenticated.",
inet_ntoa(ci->in));
/* Free authentication data, we don't need it anymore */
free(ci->authdata);
ci->authdata_len = 0;
ci->authdata = NULL;
ci->authenticated = 1;
return 0;
failed: TRACE("Authentication for %s failed\n", inet_ntoa(ci->in));
closeClientSocket(ci);
return -1;
}
/*
* FUNCTION : initClients
*
* PURPOSE : Initializes the clients info array to some known state
*
* ARGS :
*
* RETURN :
*
*/
void
initClients()
{
int i;
maxcl = maxci = 0;
for (i=0; i < MAX_RMT_CONNECTIONS; i++) {
clients[i].sd = CLIENT_SLOT_AVAILABLE;
}
}
/* Compute max client index */
int
getMaxClientIndex()
{
int i;
for (i= MAX_RMT_CONNECTIONS - 1; i >= 0; i--) {
if (clients[i].sd != CLIENT_SLOT_AVAILABLE)
break;
}
return i;
}
/*
* FUNCTION : closeClientSocket
*
* PURPOSE : Closes the client socket
*
* ARGS : client info structure, remove request flag
*
* RETURN :
*
*/
void
closeClientSocket(rmt_clientinfo_t *ci)
{
int i;
int new_maxsd = 0;
int tbclosedsd = ci->sd;
FD_CLR(ci->sd, &all_sds);
(void) close(ci->sd);
ci->sd = CLIENT_SLOT_AVAILABLE;
maxcl--;
TRACE("closeClientSocket:sd = %d maxsd = %d\n", tbclosedsd, maxsd);
if (ci->authdata) {
free(ci->authdata);
ci->authdata_len = 0;
ci->authdata = NULL;
}
/*
* If maxsd = evlogd_sd, we don't need to compute the new
* maxsd
*/
if (maxsd == evlog_sd) {
return;
}
/*
* Compute new maxsd
*/
maxci = getMaxClientIndex();
for (i = maxci; i >= 0 ; i--) {
if (clients[i].sd > new_maxsd)
new_maxsd = clients[i].sd;
}
/*
* If new_maxsd = 0 that means there is no client currently
* connects to evlogd, and the to be closed sd = maxsd then
* maxsd shoulde be maxsd-1
*/
if (new_maxsd == 0 && tbclosedsd == maxsd) {
maxsd--;
} else if (new_maxsd != 0) {
if (new_maxsd < evlog_sd)
maxsd = evlog_sd;
else
maxsd = new_maxsd;
}
TRACE("Done closeClientSocket: maxsd = %d\n", maxsd);
return;
}
int
fwdClientEvent(rmt_clientinfo_t *ci)
{
char buf[MAX_BUFREAD_LEN];
char *varbuf;
struct posix_log_entry *rhdr;
struct net_rechdr net_rhdr;
int n, ret = 0;
TRACE("SIZEOF(long long)=%d\n", sizeof(long long));
TRACE("SIZEOF(net_rechdr)=%d\n", NET_REC_HDR_SIZE);
rhdr = (struct posix_log_entry*) buf;
varbuf = (char *)(buf + REC_HDR_SIZE);
TRACE("fwdClientEvent invoke!\n");
/* Read the header */
if (_evlReadEx(ci->sd, &net_rhdr, NET_REC_HDR_SIZE) != NET_REC_HDR_SIZE) {
TRACE("Failed to read rechdr.\n");
ret = -1;
closeClientSocket(ci);
goto err_exit;
}
ntoh_rechdr(&net_rhdr, rhdr);
if (rhdr->log_size > 0) {
TRACE("fwdClientEvent: reading rec body..\n");
/* Then read the body */
if (_evlReadEx(ci->sd, varbuf, rhdr->log_size) != rhdr->log_size) {
TRACE("Failed to read rec body.\n");
ret -1;
closeClientSocket(ci);
goto err_exit;
}
}
/* Squeeze the node id in log_processor field */
ci->node_id &= 0x0000FFFF;
rhdr->log_processor |= (ci->node_id << 16);
TRACE("fwdClientEvent herei, nodeID=0x%x, log_processor=0x%x.\n",
ci->node_id,rhdr->log_processor );
/* Write the rec to the evlogd */
if((ret= writeToEvlogd(rhdr, varbuf)) == -1) {
TRACE("evlogd probably died\n");
}
#ifdef DEBUG3
printRecord(rhdr, varbuf);
#endif
err_exit:
return ret;
}
/*
* write event to log daemon
*/
static int writeToEvlogd(struct posix_log_entry *rhdr, const char *varbuf)
{
int ret=0;
unsigned char c;
if (evlog_sd == -1)
return -1;
/* First write the header */
if (write(evlog_sd, rhdr, REC_HDR_SIZE) != REC_HDR_SIZE) {
/* socket is broken */
fprintf(stderr, "Failed to write the msg header to evlog daemon.\n");
goto err_exit;
}
/* then write the variable message body */
#ifdef POSIX_LOG_TRUNCATE
if (rhdr->log_format == POSIX_LOG_STRING
&& (rhdr->log_flags & POSIX_LOG_TRUNCATE) != 0) {
char writebuf[POSIX_LOG_ENTRY_MAXLEN];
/*
* buf contains a string that was truncated to
* POSIX_LOG_ENTRY_MAXLEN bytes. Stick a null character at the
* end of our copy of the buffer to make a null-terminated
* string.
*/
bcopy((void *)varbuf, (void *)writebuf, rhdr->log_size);
writebuf[POSIX_LOG_ENTRY_MAXLEN - 1] = '\0';
if (write(evlog_sd, writebuf, rhdr->log_size) != rhdr->log_size) {
/* socket is broken */
fprintf(stderr, "Failed to write the msg body to evlog daemon.\n");
goto err_exit;
}
}
#endif
if (rhdr->log_size > 0) {
if (write(evlog_sd, varbuf, rhdr->log_size) != rhdr->log_size) {
/* socket is broken */
fprintf(stderr, "Failed to write the msg body to evlog daemon.\n");
goto err_exit;
}
}
/* The daemon should tell the client that he finishes reading */
read(evlog_sd, &c, sizeof(char));
if(c != 0xac) {
TRACE("Write problem, c=%u\n", c);
} else {
return 0;
}
err_exit:
close(evlog_sd);
evlog_sd = -1;
return -1;
}
/***************************/
/* DEBUG HELPER */
/***************************/
/*
* This code were yanked from evlview (with a little changes), I use this code
* for testing this plug-in. Event records will be printed to stdout.
* Note: The recid is not aligned with recid in the log (or maybe there is
* no log at all), it will be incremented by 1 starting from 0.
*/
#define FMT_BIN 0x1
#define FMT_TEXT 0x2
#define FMT_DEFAULT FMT_TEXT
#define FMT_SPEC (FMT_TEXT|0x4)
int format = FMT_TEXT;
int outFd = 1; /* Write to here */
//FILE *outFile = NULL;
char *defaultSeparator = ", ";
int newlines = -1;
char *fdbuf; /* Formatted data goes here. */
size_t fdbufLen = 0;
static void
printStringWithNewlines(char *s, int nPrecedingNewlines)
{
if (newlines == -1) {
fprintf(stdout, "%s", s);
if (!_evlEndsWith(s, "\n")) {
fprintf(stdout, "\n");
}
} else {
int i;
int nTrailingNewlines = 0;
int totalNewlines;
int slen = strlen(s);
assert(nPrecedingNewlines == 0 || nPrecedingNewlines == 1);
for (i = slen-1; i >= 0 && s[i] == '\n'; i--) {
nTrailingNewlines++;
}
if (slen > nTrailingNewlines) {
totalNewlines = nTrailingNewlines;
} else {
/* s is nothing but newlines. */
totalNewlines = nPrecedingNewlines + nTrailingNewlines;
}
if (totalNewlines < newlines) {
fprintf(stdout, "%s", s);
while (totalNewlines < newlines) {
fprintf(stdout, "\n");
totalNewlines++;
}
} else if (totalNewlines > newlines) {
int newlinesToShave = totalNewlines - newlines;
char *p = s + (slen - newlinesToShave);
char tmp = *p;
*p = '\0';
fprintf(stdout, "%s", s);
*p = tmp;
} else {
fprintf(stdout, "%s", s);
}
}
}
static void
printRecord(const struct posix_log_entry *entry, const char *buf)
{
int status;
size_t linelen = 80;
int flags = 0x0;
fdbufLen = _evlGetMaxDumpLen();
// assert(fdbufLen > 1000);
fdbuf = (char*) malloc(fdbufLen);
// assert(fdbuf != NULL);
status = evl_format_evrec_fixed(entry, fdbuf, fdbufLen,
NULL, defaultSeparator, linelen, flags);
if (status != 0) {
errno = status;
perror("evl_format_evrec_fixed");
exit(2);
}
(void) fprintf(stdout, "%s\n", fdbuf);
/* Now the variable part... */
switch (entry->log_format) {
case POSIX_LOG_NODATA:
{
static char nada[1] = "";
printStringWithNewlines(nada, 1);
break;
}
case POSIX_LOG_STRING:
printStringWithNewlines((char*)buf, 1);
break;
case POSIX_LOG_BINARY:
status = _evlDumpBytes(buf, entry->log_size,
fdbuf, fdbufLen, NULL);
assert(status == 0);
printStringWithNewlines(fdbuf, 1);
break;
}
free(fdbuf);
}