00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "PortabilityImpl.hh"
00011
00012 #ifdef LOG4CPP_HAVE_UNISTD_H
00013 # include <unistd.h>
00014 #endif
00015 #include <cstdlib>
00016 #include <cstdio>
00017 #include <cstring>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 #include <log4cpp/RemoteSyslogAppender.hh>
00022 #include <log4cpp/FactoryParams.hh>
00023 #include <memory>
00024
00025 #ifdef WIN32
00026 #include <winsock2.h>
00027 #else
00028 #include <netdb.h>
00029 #include <sys/socket.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032 #endif
00033
00034 namespace log4cpp {
00035
00036 int RemoteSyslogAppender::toSyslogPriority(Priority::Value priority) {
00037 static int priorities[8] = { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
00038 LOG_WARNING, LOG_NOTICE, LOG_INFO,
00039 LOG_DEBUG };
00040 int result;
00041
00042 priority++;
00043 priority /= 100;
00044
00045 if (priority < 0) {
00046 result = LOG_EMERG;
00047 } else if (priority > 7) {
00048 result = LOG_DEBUG;
00049 } else {
00050 result = priorities[priority];
00051 }
00052
00053 return result;
00054 }
00055
00056
00057 RemoteSyslogAppender::RemoteSyslogAppender(const std::string& name,
00058 const std::string& syslogName,
00059 const std::string& relayer,
00060 int facility,
00061 int portNumber) :
00062 LayoutAppender(name),
00063 _syslogName(syslogName),
00064 _relayer(relayer),
00065 _facility((facility == -1) ? LOG_USER : facility),
00066 _portNumber((portNumber == -1) ? 514 : portNumber),
00067 _socket (0),
00068 _ipAddr (0),
00069 _cludge (0)
00070 {
00071 open();
00072 }
00073
00074 RemoteSyslogAppender::~RemoteSyslogAppender() {
00075 close();
00076 #ifdef WIN32
00077 if (_cludge) {
00078
00079 WSACleanup ();
00080 }
00081 #endif
00082 }
00083
00084 void RemoteSyslogAppender::open() {
00085 if (!_ipAddr) {
00086 struct hostent *pent = gethostbyname (_relayer.c_str ());
00087 #ifdef WIN32
00088 if (pent == NULL) {
00089 if (WSAGetLastError () == WSANOTINITIALISED) {
00090 WSADATA wsaData;
00091 int err;
00092
00093 err = WSAStartup (0x101, &wsaData );
00094 if (err) {
00095
00096 return;
00097 }
00098 pent = gethostbyname (_relayer.c_str ());
00099 _cludge = 1;
00100 } else {
00101
00102 return;
00103 }
00104 }
00105 #endif
00106 if (pent == NULL) {
00107 in_addr_t ip = inet_addr (_relayer.c_str ());
00108 pent = gethostbyaddr ((const char *) &ip, sizeof(in_addr_t), AF_INET);
00109 if (pent == NULL) {
00110
00111 return;
00112 }
00113 }
00114 _ipAddr = *(in_addr_t*)(pent->h_addr);
00115 }
00116
00117
00118 if ((_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00119
00120 return;
00121 }
00122 }
00123
00124 void RemoteSyslogAppender::close() {
00125 if (_socket) {
00126 #ifdef WIN32
00127 closesocket (_socket);
00128 #else
00129 ::close (_socket);
00130 #endif
00131 _socket = 0;
00132 }
00133 }
00134
00135 void RemoteSyslogAppender::_append(const LoggingEvent& event) {
00136 const std::string message(_getLayout().format(event));
00137 size_t messageLength = message.length();
00138 char *buf = new char [messageLength + 16];
00139 int priority = _facility + toSyslogPriority(event.priority);
00140 int preambleLength = std::sprintf (buf, "<%d>", priority);
00141 memcpy (buf + preambleLength, message.data(), messageLength);
00142
00143 sockaddr_in sain;
00144 sain.sin_family = AF_INET;
00145 sain.sin_port = htons (_portNumber);
00146
00147 sain.sin_addr.s_addr = _ipAddr;
00148
00149 while (messageLength > 0) {
00150
00151
00152 if (preambleLength + messageLength > 900) {
00153 sendto (_socket, buf, 900, 0, (struct sockaddr *) &sain, sizeof (sain));
00154 messageLength -= (900 - preambleLength);
00155 std::memmove (buf + preambleLength, buf + 900, messageLength);
00156
00157 } else {
00158 sendto (_socket, buf, preambleLength + messageLength, 0, (struct sockaddr *) &sain, sizeof (sain));
00159 break;
00160 }
00161 }
00162
00163 delete[] buf;
00164 }
00165
00166 bool RemoteSyslogAppender::reopen() {
00167 close();
00168 open();
00169 return true;
00170 }
00171
00172 std::auto_ptr<Appender> create_remote_syslog_appender(const FactoryParams& params)
00173 {
00174 std::string name, syslog_name, relayer;
00175 int facility = -1, port_number = -1;
00176 params.get_for("remote syslog appender").required("name", name)("syslog_name", syslog_name)("relayer", relayer)
00177 .optional("facility", facility)("port", port_number);
00178 return std::auto_ptr<Appender>(new RemoteSyslogAppender(name, syslog_name, relayer, facility, port_number));
00179 }
00180 }