/*
* RemoteSyslogAppender.cpp
*
* Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
* Copyright 2001, Walter Stroebel. All rights reserved.
*
* See the COPYING file for the terms of usage and distribution.
*/
#include "PortabilityImpl.hh"
#ifdef LOG4CPP_HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <cstdlib>
#include <stdio.h>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <log4cpp/RemoteSyslogAppender.hh>
#include <log4cpp/FactoryParams.hh>
#include <memory>
#ifdef WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
namespace log4cpp {
int RemoteSyslogAppender::toSyslogPriority(Priority::Value priority) {
static int priorities[8] = { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
LOG_WARNING, LOG_NOTICE, LOG_INFO,
LOG_DEBUG };
int result;
priority++;
priority /= 100;
if (priority < 0) {
result = LOG_EMERG;
} else if (priority > 7) {
result = LOG_DEBUG;
} else {
result = priorities[priority];
}
return result;
}
RemoteSyslogAppender::RemoteSyslogAppender(const std::string& name,
const std::string& syslogName,
const std::string& relayer,
int facility,
int portNumber) :
LayoutAppender(name),
_syslogName(syslogName),
_relayer(relayer),
_facility((facility == -1) ? LOG_USER : facility),
_portNumber((portNumber == -1) ? 514 : portNumber),
_socket (0),
_ipAddr (0),
_cludge (0)
{
open();
}
RemoteSyslogAppender::~RemoteSyslogAppender() {
close();
#ifdef WIN32
if (_cludge) {
// we started it, we end it.
WSACleanup ();
}
#endif
}
void RemoteSyslogAppender::open() {
if (!_ipAddr) {
struct hostent *pent = gethostbyname (_relayer.c_str ());
#ifdef WIN32
if (pent == NULL) {
if (WSAGetLastError () == WSANOTINITIALISED) {
WSADATA wsaData;
int err;
err = WSAStartup (0x101, &wsaData );
if (err) {
// loglog("RemoteSyslogAppender: WSAStartup returned %d", err);
return; // fail silently
}
pent = gethostbyname (_relayer.c_str ());
_cludge = 1;
} else {
// loglog("RemoteSyslogAppender: gethostbyname returned error");
return; // fail silently
}
}
#endif
if (pent == NULL) {
in_addr_t ip = inet_addr (_relayer.c_str ());
pent = gethostbyaddr ((const char *) &ip, sizeof(in_addr_t), AF_INET);
if (pent == NULL) {
// loglog("RemoteSyslogAppender: failed to resolve host %s", _relayer.c_str());
return; // fail silently
}
}
_ipAddr = *(in_addr_t*)(pent->h_addr); // fixed bug #1579890
}
// Get a datagram socket.
_socket = socket(AF_INET, SOCK_DGRAM, 0);
if
#ifdef WIN32
(_socket == INVALID_SOCKET)
#else
(_socket < 0)
#endif
{
// loglog("RemoteSyslogAppender: failed to open socket");
return; // fail silently
}
}
void RemoteSyslogAppender::close() {
if (_socket) {
#ifdef WIN32
closesocket (_socket);
#else
::close (_socket);
#endif
_socket = 0;
}
}
void RemoteSyslogAppender::_append(const LoggingEvent& event) {
const std::string message(_getLayout().format(event));
size_t messageLength = message.length();
char *buf = new char [messageLength + 16];
int priority = _facility + toSyslogPriority(event.priority);
int preambleLength = sprintf (buf, "<%d>", priority);
memcpy (buf + preambleLength, message.data(), messageLength);
sockaddr_in sain;
sain.sin_family = AF_INET;
sain.sin_port = htons (_portNumber);
// NO, do NOT use htonl on _ipAddr. Is already in network order.
sain.sin_addr.s_addr = _ipAddr;
while (messageLength > 0) {
/* if packet larger than maximum (900 bytes), split
into two or more syslog packets. */
if (preambleLength + messageLength > 900) {
sendto (_socket, buf, 900, 0, (struct sockaddr *) &sain, sizeof (sain));
messageLength -= (900 - preambleLength);
std::memmove (buf + preambleLength, buf + 900, messageLength);
// note: we might need to sleep a bit here
} else {
sendto (_socket, buf, preambleLength + messageLength, 0, (struct sockaddr *) &sain, sizeof (sain));
break;
}
}
delete[] buf;
}
bool RemoteSyslogAppender::reopen() {
close();
open();
return true;
}
std::LOG4CPP_UNIQUE_PTR<Appender> create_remote_syslog_appender(const FactoryParams& params)
{
std::string name, syslog_name, relayer;
int facility = -1, port_number = -1;
params.get_for("remote syslog appender").required("name", name)("syslog_name", syslog_name)("relayer", relayer)
.optional("facility", facility)("port", port_number);
return std::LOG4CPP_UNIQUE_PTR<Appender>(new RemoteSyslogAppender(name, syslog_name, relayer, facility, port_number));
}
}