00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031 #define LOG4SENDPP_NEED_EXPORTS
00032 #include <log4sendpp/log4sendpp.h>
00033
00034 #if defined(__WIN32__) || defined(_MSC_VER)
00035 #include <winsock2.h>
00036
00037 typedef int socklen_t;
00038 #endif
00039
00040 #ifdef __unix__
00041 #include <unistd.h>
00042 #include <netdb.h>
00043 #include <arpa/inet.h>
00044 #include <netinet/in.h>
00045 #include <sys/socket.h>
00046 #endif
00047
00048 #include <csignal>
00049 #include <cerrno>
00050
00051 #include <log4sendpp/tcpip_appender.h>
00052 #include <log4sendpp/exception.h>
00053 #include <log4sendpp/formatter.h>
00054
00055
00056 LOG4SENDPP_NS_START
00057
00058
00061 struct TcpIpAppender::Impl
00062 {
00063 unsigned timeout;
00064 struct sockaddr_in hostdata;
00065 int fd_handle;
00066 unsigned port;
00067 bool net_error;
00068 };
00069
00070
00071 #if defined(__WIN32__) && !defined (LOG4SENDPP_NO_WSA_STARTUP)
00072
00073 bool TcpIpAppender::WSA_is_initialized = false;
00074
00075 #endif
00076
00078
00079
00080 LOG4SENDPP_API_IMPL(int) TcpIpAppender::getLastError()
00081 {
00082 #ifdef __WIN32__
00083 return(::WSAGetLastError());
00084 #else
00085 return(errno);
00086 #endif
00087 }
00088
00089
00090 LOG4SENDPP_API_IMPL(LOG4SENDPP_STD_NS::string)
00091 TcpIpAppender::getErrorString(int err_number)
00092 {
00093 #ifdef __WIN32__
00094 LPSTR lpMsgBuf;
00095 int ok = FormatMessage(
00096 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00097 NULL,
00098 err_number,
00099 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00100 (LPSTR)&lpMsgBuf,
00101 0,
00102 NULL);
00103
00104 if (ok != 0 && lpMsgBuf != 0)
00105 return lpMsgBuf;
00106
00107 else
00108 {
00109 char s[40];
00110 LOG4SENDPP_STD_NS::string errn = itoa(err_number, s, 10);
00111 return LOG4SENDPP_STD_NS::string("Unknown connection problem, Windows error code: #")+errn;
00112 }
00113 #else
00114 return LOG4SENDPP_STD_NS::strerror(err_number);
00115 #endif
00116 }
00117
00118
00119 LOG4SENDPP_API_IMPL(void)
00120 TcpIpAppender::asciiToInAddr(const char *address, struct in_addr &saddr)
00121 {
00122 memset (&saddr, 0, sizeof(in_addr));
00123 struct hostent *host;
00124
00125
00126 saddr.s_addr = inet_addr(address);
00127 if ((int)saddr.s_addr == -1)
00128 {
00129 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("inet_addr() failed: ")
00130 + getErrorString(getLastError())));
00131 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00132 pimpl->net_error = true;
00133 return;
00134 #endif
00135 }
00136
00137 host = ::gethostbyname(address);
00138 if (host == 0)
00139 {
00140 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("gethostbyname() failed: ")
00141 + getErrorString(getLastError())));
00142 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00143 pimpl->net_error = true;
00144 return;
00145 #endif
00146 }
00147
00148 memmove((void*)&saddr, host->h_addr_list, sizeof(in_addr));
00149 }
00150
00151
00152 LOG4SENDPP_API_IMPL(struct hostent *)
00153 TcpIpAppender::getHostAdress(const LOG4SENDPP_STD_NS::string &dom)
00154 {
00155 return ::gethostbyname(dom.c_str() );
00156 }
00157
00158
00159 #if defined(__WIN32__) && !defined (LOG4SENDPP_NO_WSA_STARTUP)
00160
00161
00162 LOG4SENDPP_API_IMPL(void) TcpIpAppender::WSA_init()
00163 {
00164 if (!WSA_is_initialized)
00165 {
00166 WSA_is_initialized = true;
00167 WORD wVersionRequested;
00168 WSADATA wsaData;
00169 wVersionRequested = MAKEWORD( 2, 0 );
00170
00171 if (::WSAStartup( wVersionRequested, &wsaData) != 0)
00172 {
00173 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("Initializing Windows sockets failed: ")
00174 + getErrorString(getLastError())));
00175 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00176 pimpl->net_error = true;
00177 return;
00178 #endif
00179 }
00180 }
00181 }
00182
00183 #endif
00184
00185
00186 LOG4SENDPP_API_IMPL0 TcpIpAppender::TcpIpAppender(Formatter *formatter, long adr, unsigned prt)
00187 : Appender(formatter)
00188 {
00189 init(prt);
00190 pimpl->hostdata.sin_addr.s_addr = htonl(adr);
00191
00192 LOG4SENDPP_TRY
00193 {
00194 open();
00195 }
00196 LOG4SENDPP_CATCH_ALL
00197 {
00198 pimpl->net_error = true;
00199 }
00200 }
00201
00202
00203 LOG4SENDPP_API_IMPL(LOG4SENDPP_STD_NS::string) TcpIpAppender::gethostname()
00204 {
00205 #if defined(__WIN32__) && !defined (LOG4SENDPP_NO_WSA_STARTUP)
00206 WSA_init();
00207 #endif
00208
00209 char buffer[1000];
00210 memset(buffer, 0, sizeof(buffer));
00211
00212 int ret = ::gethostname ( buffer, sizeof(buffer)-1);
00213 if (ret != 0)
00214 {
00215 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("gethostname() failed: ")
00216 + getErrorString(getLastError())));
00217 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00218 return "";
00219 #endif
00220 }
00221 return LOG4SENDPP_STD_NS::string(buffer);
00222 }
00223
00224
00225 LOG4SENDPP_API_IMPL0 TcpIpAppender::TcpIpAppender(Formatter *formatter, const LOG4SENDPP_STD_NS::string &host, unsigned prt)
00226 : Appender(formatter)
00227 {
00228 init(prt);
00229
00230 struct hostent *hp = getHostAdress(host);
00231 if (hp == 0)
00232 {
00233
00234 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00235 pimpl->net_error = true;
00236 return;
00237 #endif
00238 }
00239
00240 memcpy(&(pimpl->hostdata.sin_addr), hp->h_addr_list[0], hp->h_length);
00241
00242 LOG4SENDPP_TRY
00243 {
00244 open();
00245 }
00246
00247 LOG4SENDPP_CATCH_ALL
00248 {
00249 pimpl->net_error = true;
00250 }
00251 }
00252
00253 LOG4SENDPP_API_IMPL(void) TcpIpAppender::init(unsigned prt)
00254 {
00255 #if !defined(__WIN32__) && !defined(_WIN32)
00256 signal (SIGPIPE, SIG_IGN);
00257 #endif
00258
00259 #if defined(__WIN32__) && !defined (LOG4SENDPP_NO_WSA_STARTUP)
00260 WSA_init();
00261 #endif
00262
00263 pimpl = new Impl;
00264 pimpl->timeout = 10;
00265 pimpl->port = prt;
00266 memset(&pimpl->hostdata, 0, sizeof(pimpl->hostdata));
00267 pimpl->hostdata.sin_port = htons(prt);
00268 pimpl->hostdata.sin_family = AF_INET;
00269 pimpl->net_error = false;
00270 pimpl->fd_handle = -1;
00271 }
00272
00273
00274 LOG4SENDPP_API_IMPL0 TcpIpAppender::~TcpIpAppender()
00275 {
00276 LOG4SENDPP_TRY
00277 {
00278 close();
00279 }
00280
00281 LOG4SENDPP_CATCH_ALL
00282 {
00283
00284 }
00285
00286 delete pimpl;
00287 pimpl = 0;
00288 }
00289
00290
00291 LOG4SENDPP_API_IMPL(bool) TcpIpAppender::isWorking() const
00292 {
00293 return pimpl->fd_handle > 0 && !pimpl->net_error;
00294 }
00295
00296
00297 LOG4SENDPP_API_IMPL(void) TcpIpAppender::open()
00298 {
00299 if (pimpl->fd_handle >= 0)
00300 return;
00301
00302 pimpl->fd_handle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00303 if (pimpl->fd_handle < 0)
00304 {
00305 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("socket() failed: ")
00306 + getErrorString(getLastError())));
00307 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00308 pimpl->net_error = true;
00309 return;
00310 #endif
00311 }
00312
00313 int iOptVal = pimpl->timeout * 1000;
00314 int iOptLen = sizeof(int);
00315 int ret;
00316 ret = ::setsockopt(pimpl->fd_handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&iOptVal, iOptLen);
00317 ret = ::setsockopt(pimpl->fd_handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&iOptVal, iOptLen);
00318
00319 if(::connect(pimpl->fd_handle, (struct sockaddr *)&pimpl->hostdata, sizeof(pimpl->hostdata)) < 0)
00320 {
00321 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("connect() failed: ")
00322 + getErrorString(getLastError())));
00323 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00324 pimpl->net_error = true;
00325 return;
00326 #endif
00327 }
00328
00329 pimpl->net_error = false;
00330
00331 LOG4SENDPP_UNUSED(ret);
00332 }
00333
00334
00335 LOG4SENDPP_API_IMPL(signed long) TcpIpAppender::low_level_write(char const *buff, long len)
00336 {
00337 #ifndef __unix__
00338 return ::send(pimpl->fd_handle, buff, len, 0);
00339 #else
00340 return ::write(pimpl->fd_handle, buff, len);
00341 #endif
00342
00343 }
00344
00345
00346 LOG4SENDPP_API_IMPL(void) TcpIpAppender::append (Logger::Level level,
00347 LOG4SENDPP_STD_NS::string msg,
00348 LOG4SENDPP_STD_NS::string category,
00349 LOG4SENDPP_INT64 stamp,
00350 const LocationInformation *info,
00351 const Logger::DiagnosticInformation *diaginfo )
00352 {
00353 if (!isWorking())
00354 return;
00355
00356 LOG4SENDPP_TRY
00357 {
00358 Formatter *formatter = getFormatter();
00359 if (formatter)
00360 {
00361 LOG4SENDPP_STD_NS::vector<LOG4SENDPP_STD_NS::string> msgs = formatter->format(level, msg, category, stamp, info, diaginfo);
00362
00363 LOG4SENDPP_STD_NS::string s;
00364 for (unsigned i = 0; i < msgs.size(); ++i)
00365 s += msgs[i] + "\n";
00366
00367 writeString(s);
00368 }
00369 }
00370
00371 LOG4SENDPP_CATCH_ALL
00372 {
00373 pimpl->net_error = true;
00374 LOG4SENDPP_RETHROW;
00375 }
00376 }
00377
00378
00379 LOG4SENDPP_API_IMPL(void) TcpIpAppender::writeString(const LOG4SENDPP_STD_NS::string &data)
00380 {
00381 long written;
00382
00383 if (!isWorking() || data.length() == 0)
00384 return;
00385
00386 fd_set wfd;
00387
00388 timeval wait;
00389 wait.tv_sec = pimpl->timeout;
00390 wait.tv_usec = 0;
00391
00392 unsigned len = data.length();
00393 char *buff = (char*) data.data();
00394
00395 while (len > 0)
00396 {
00397 FD_ZERO(&wfd);
00398 FD_SET((unsigned) pimpl->fd_handle, &wfd);
00399 int ready;
00400 wait.tv_sec = pimpl->timeout;
00401 wait.tv_usec = 0;
00402 while((ready = select(pimpl->fd_handle+1, 0, &wfd, 0, &wait)) < 0)
00403 {
00404 if(errno == EINTR || errno == EAGAIN)
00405 {
00406 wait.tv_sec = pimpl->timeout;
00407 wait.tv_usec = 0;
00408 continue;
00409 }
00410
00411 else
00412 {
00413 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("select() failed: ")
00414 + getErrorString(getLastError())));
00415 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00416 pimpl->net_error = true;
00417 return;
00418 #endif
00419 }
00420 }
00421
00422 if(ready == 0)
00423 {
00424 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, "timeout while attempting to write."));
00425 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00426 pimpl->net_error = true;
00427 return;
00428 #endif
00429 }
00430
00431 if(FD_ISSET(pimpl->fd_handle, &wfd))
00432 {
00433 if ( (written = low_level_write(buff, len)) < 0)
00434 {
00435 switch(getLastError())
00436 {
00437 case EAGAIN:
00438 case EINTR:
00439 #ifdef __unix__
00440 errno = 0;
00441 #endif
00442 continue;
00443
00444 case EPIPE:
00445 close();
00446 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("attempt to write to a connection"
00447 " already closed by the peer")));
00448 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00449 pimpl->net_error = true;
00450 return;
00451 #endif
00452
00453
00454 default:
00455 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("low_level_write() failed: ")
00456 + getErrorString(getLastError())));
00457 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00458 pimpl->net_error = true;
00459 return;
00460 #endif
00461
00462 }
00463 }
00464
00465 else
00466 {
00467 buff += written;
00468 len -= written;
00469 }
00470 }
00471 }
00472 }
00473
00474
00475 LOG4SENDPP_API_IMPL(void) TcpIpAppender::close()
00476 {
00477 pimpl->net_error = false;
00478
00479 if (pimpl->fd_handle < 0)
00480 return;
00481
00482 int ret;
00483
00484 #ifndef __unix__
00485
00486 ret = closesocket(pimpl->fd_handle);
00487
00488 #else
00489
00490 do
00491 ret = ::close(pimpl->fd_handle);
00492 while(ret < 0 && (errno == EINTR || errno == EAGAIN));
00493
00494 #endif
00495
00496 pimpl->fd_handle = -1;
00497
00498 if(ret < 0)
00499 {
00500 LOG4SENDPP_THROW(Exception(__LINE__, __FILE__, LOG4SENDPP_STD_NS::string("close() failed: ")
00501 + getErrorString(getLastError())));
00502 #ifdef LOG4SENDPP_NO_EXCEPTIONS
00503 pimpl->net_error = true;
00504 return;
00505 #endif
00506 }
00507 }
00508
00509
00510 LOG4SENDPP_NS_END
00511