00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #define ULXR_NEED_EXPORTS
00037 #include <ulxmlrpcpp/ulxmlrpcpp.h>
00038
00039 #include <ctype.h>
00040 #include <cstdlib>
00041 #include <cerrno>
00042
00043 #ifdef __WIN32__
00044 #include <winsock2.h>
00045
00046 #endif
00047
00048 #ifdef __unix__
00049 #include <unistd.h>
00050 #include <netdb.h>
00051 #include <sys/time.h>
00052 #include <sys/socket.h>
00053
00054 #if defined(ULXR_USE_EPOLL) && defined(HAVE_SYS_EPOLL_H)
00055 #include <sys/epoll.h>
00056 #endif
00057
00058 #endif
00059
00060 #include <csignal>
00061 #include <cstdio>
00062
00063 #include <ulxmlrpcpp/ulxr_connection.h>
00064 #include <ulxmlrpcpp/ulxr_except.h>
00065 #include <ulxmlrpcpp/ulxr_htmlform_handler.h>
00066
00067
00068 namespace ulxr {
00069
00070
00071 ULXR_API_IMPL(void) Connection::init()
00072 {
00073 setIsConnecting(false);
00074 connector = 0;
00075 ULXR_TRACE(ULXR_PCHAR("init"));
00076 fd_handle = -1;
00077 setTimeout(10);
00078 setConnectionTimeout(0, 0);
00079 #if !defined(__WIN32__) && !defined(_WIN32)
00080 signal (SIGPIPE, SIG_IGN);
00081 #endif
00082 }
00083
00084
00085 ULXR_API_IMPL0 Connection::Connection()
00086 {
00087 ULXR_TRACE(ULXR_PCHAR("Connection"));
00088 init();
00089 }
00090
00091
00092 ULXR_API_IMPL0 Connection::~Connection()
00093 {
00094 ULXR_TRACE(ULXR_PCHAR("~Connection"));
00095 try
00096 {
00097 close();
00098 }
00099 catch(...)
00100 {
00101
00102 }
00103
00104 connector = 0;
00105 }
00106
00107
00108 ULXR_API_IMPL(bool) Connection::isOpen() const
00109 {
00110 ULXR_TRACE( ((fd_handle >= 0) ? ULXR_PCHAR("isOpen: true")
00111 : ULXR_PCHAR("isOpen: false")));
00112 return fd_handle >= 0;
00113 }
00114
00115
00116 ULXR_API_IMPL(ssize_t) Connection::low_level_write(char const *buff, long len)
00117 {
00118 ULXR_TRACE(ULXR_PCHAR("low_level_write ") << len);
00119
00120 #ifndef __unix__
00121 return ::send(fd_handle, buff, len, 0);
00122 #else
00123 return ::write(fd_handle, buff, len);
00124 #endif
00125
00126 }
00127
00128
00129 ULXR_API_IMPL(void) Connection::write(char const *buff, long len)
00130 {
00131 ULXR_TRACE(ULXR_PCHAR("write ") << len);
00132 ULXR_DWRITE_WRITE(buff, len);
00133 ULXR_DOUT_WRITE(ULXR_PCHAR(""));
00134
00135 long written;
00136
00137 if (buff == 0 || !isOpen())
00138 throw RuntimeException(ApplicationError, ulxr_i18n(ULXR_PCHAR("Precondition failed for write() call")));
00139
00140 if (len == 0)
00141 return;
00142
00143 #if defined(ULXR_USE_EPOLL) && defined(HAVE_SYS_EPOLL_H)
00144
00145 #ifdef __GNUC__
00146
00147 #endif
00148
00149 while (buff != 0 && len > 0)
00150 {
00151
00152 int epollfd;
00153
00154
00155 struct epoll_event ev_write;
00156 memset(&ev_write,0,sizeof(struct epoll_event));
00157
00158
00159 if((epollfd = ::epoll_create(1)) != -1)
00160 {
00161
00162 ev_write.events = EPOLLOUT;
00163 ev_write.data.ptr = NULL;
00164
00165
00166 int ctlresult;
00167
00168 if((ctlresult = ::epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_handle, &ev_write)) == 0)
00169 {
00170
00171 struct epoll_event ev[1];
00172 memset(&ev[0],0,sizeof(struct epoll_event));
00173
00174 int toval = -1;
00175 if (getTimeout() != 0)
00176 toval = getTimeout()*1000;
00177
00178 int waitresult;
00179 while ((waitresult = epoll_wait(epollfd, ev, 1, toval)) < 0)
00180 {
00181 if(errno == EINTR || errno == EAGAIN)
00182
00183 continue;
00184 else
00185 {
00186
00187 CppString s = getErrorString(getLastError());
00188 ::close(epollfd);
00189 throw ConnectionException(SystemError,
00190 ulxr_i18n(ULXR_PCHAR("Could not perform epoll_wait() call within write(): ")) + s, 500);
00191 }
00192 }
00193
00194 ::close(epollfd);
00195 if(waitresult == 0)
00196 {
00197 throw ConnectionException(SystemError,
00198 ulxr_i18n(ULXR_PCHAR("Timeout while attempting to write.")), 500);
00199 }
00200 else
00201 {
00202 if(waitresult == 1)
00203 {
00204 if ( (written = low_level_write(buff, len)) < 0)
00205 {
00206 switch(getLastError())
00207 {
00208 case EAGAIN:
00209 case EINTR:
00210 #ifdef __unix__
00211 errno = 0;
00212 #endif
00213 continue;
00214
00215 case EPIPE:
00216 close();
00217 throw ConnectionException(TransportError,
00218 ulxr_i18n(ULXR_PCHAR("Attempt to write to a connection")
00219 ULXR_PCHAR(" already closed by the peer")), 500);
00220
00221 default:
00222 throw ConnectionException(SystemError,
00223 ulxr_i18n(ULXR_PCHAR("Could not perform low_level_write() call: ")
00224 + getErrorString(getLastError())), 500);
00225 }
00226 }
00227 else
00228 {
00229 buff += written;
00230 len -= written;
00231 }
00232 }
00233 else
00234 {
00235 throw ConnectionException(SystemError,
00236 ulxr_i18n(ULXR_PCHAR("Problem while attempting to write by epoll.")), 500);
00237 }
00238 }
00239 }
00240 else
00241 {
00242 ::close(epollfd);
00243 throw ConnectionException(SystemError,
00244 ulxr_i18n(ULXR_PCHAR("Could not perform epoll_ctl() call: ")), 500);
00245 }
00246 }
00247 else
00248 {
00249 throw ConnectionException(SystemError,
00250 ulxr_i18n(ULXR_PCHAR("Could not perform epoll_create() call: ")), 500);
00251 }
00252 }
00253
00254 #else // ULXR_USE_EPOLL
00255
00256 #ifdef __GNUC__
00257
00258 #endif
00259
00260 fd_set wfd;
00261 timeval wait;
00262 timeval *pwait = 0;
00263 if (wait.tv_sec != 0)
00264 pwait = &wait;
00265
00266 while (buff != 0 && len > 0)
00267 {
00268 FD_ZERO(&wfd);
00269 FD_SET((unsigned) fd_handle, &wfd);
00270 int ready;
00271 wait.tv_sec = getTimeout();
00272 wait.tv_usec = 0;
00273 while((ready = select(fd_handle+1, 0, &wfd, 0, pwait)) < 0)
00274 {
00275 if(errno == EINTR || errno == EAGAIN)
00276 {
00277
00278 wait.tv_sec = getTimeout();
00279 wait.tv_usec = 0;
00280 continue;
00281 }
00282 else
00283 throw ConnectionException(SystemError,
00284 ulxr_i18n(ULXR_PCHAR("Could not perform select() call: "))
00285 + getErrorString(getLastError()), 500);
00286 }
00287 if(ready == 0)
00288 throw ConnectionException(SystemError,
00289 ulxr_i18n(ULXR_PCHAR("Timeout while attempting to write.")), 500);
00290
00291 if(FD_ISSET(fd_handle, &wfd))
00292 {
00293 if ( (written = low_level_write(buff, len)) < 0)
00294 {
00295 switch(getLastError())
00296 {
00297 case EAGAIN:
00298 case EINTR:
00299 #ifdef __unix__
00300 errno = 0;
00301 #endif
00302 continue;
00303
00304 case EPIPE:
00305 close();
00306 throw ConnectionException(TransportError,
00307 ulxr_i18n(ULXR_PCHAR("Attempt to write to a connection")
00308 ULXR_PCHAR(" already closed by the peer")), 500);
00309
00310
00311 default:
00312 throw ConnectionException(SystemError,
00313 ulxr_i18n(ULXR_PCHAR("Could not perform low_level_write() call: ")
00314 + getErrorString(getLastError())), 500);
00315
00316 }
00317 }
00318 else
00319 {
00320 buff += written;
00321 len -= written;
00322 }
00323 }
00324 }
00325
00326
00327 #endif // ULXR_USE_EPOLL
00328
00329 }
00330
00331
00332 ULXR_API_IMPL(bool) Connection::hasPendingInput() const
00333 {
00334 return false;
00335 }
00336
00337
00338 ULXR_API_IMPL(ssize_t) Connection::low_level_read(char *buff, long len)
00339 {
00340 #ifndef __unix__
00341 return ::recv(fd_handle, buff, len, 0);
00342 #else
00343 return ::read(fd_handle, buff, len);
00344 #endif
00345 }
00346
00347
00348 ULXR_API_IMPL(ssize_t) Connection::read(char *buff, long len)
00349 {
00350 long readed = 0;
00351
00352 ULXR_TRACE(ULXR_PCHAR("read 1"));
00353
00354 if (buff == 0 || !isOpen())
00355 throw RuntimeException(ApplicationError,
00356 ulxr_i18n(ULXR_PCHAR("Precondition failed for read() call")));
00357
00358 ULXR_TRACE(ULXR_PCHAR("read 2 ") << len);
00359
00360 if (len <= 0)
00361 return 0;
00362
00363 ULXR_TRACE(ULXR_PCHAR("read 3"));
00364
00365 #if !(defined(ULXR_USE_EPOLL) && defined(HAVE_SYS_EPOLL_H))
00366
00367 fd_set rfd;
00368 timeval wait;
00369 timeval *pwait = 0;
00370 wait.tv_sec = 0;
00371 wait.tv_usec = 0;
00372 if (wait.tv_sec != 0)
00373 pwait = &wait;
00374
00375 FD_ZERO(&rfd);
00376 FD_SET((unsigned) fd_handle, &rfd);
00377 int ready;
00378
00379 #endif
00380
00381 if (hasPendingInput())
00382 {
00383 ULXR_TRACE(ULXR_PCHAR("read 3 pending"));
00384 if( (readed = low_level_read(buff, len)) < 0)
00385 {
00386 throw ConnectionException(SystemError,
00387 ulxr_i18n(ULXR_PCHAR("Could not perform read() call on pending input: "))
00388 + getErrorString(getLastError()), 500);
00389 }
00390 ULXR_TRACE(ULXR_PCHAR("read pending readed ") + HtmlFormHandler::makeNumber(readed)
00391 + ULXR_PCHAR(" and wanted ") + HtmlFormHandler::makeNumber(len));
00392 }
00393
00394 #if defined(ULXR_USE_EPOLL) && defined(HAVE_SYS_EPOLL_H)
00395
00396 else
00397 {
00398
00399 int epollfd;
00400
00401
00402 struct epoll_event ev_read;
00403 memset(&ev_read,0,sizeof(struct epoll_event));
00404
00405
00406 if((epollfd = ::epoll_create(1)) != -1)
00407 {
00408
00409 ev_read.events = EPOLLIN;
00410 ev_read.data.ptr = NULL;
00411
00412
00413 int ctlresult;
00414
00415 if((ctlresult = ::epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_handle, &ev_read)) == 0)
00416 {
00417
00418 struct epoll_event ev[1];
00419 memset(&ev[0],0,sizeof(struct epoll_event));
00420
00421 int toval = -1;
00422 if (getTimeout() != 0)
00423 toval = getTimeout()*1000;
00424
00425 ULXR_TRACE(ULXR_PCHAR("read epoll"));
00426 int waitresult;
00427 while ((waitresult = epoll_wait(epollfd, ev, 1, toval)) < 0)
00428 {
00429 ULXR_TRACE(ULXR_PCHAR("read epoll err"));
00430 if(errno == EINTR || errno == EAGAIN)
00431
00432 continue;
00433 else
00434 {
00435
00436 CppString s = getErrorString(getLastError());
00437 ::close(epollfd);
00438 throw ConnectionException(SystemError,
00439 ulxr_i18n(ULXR_PCHAR("Could not perform epoll_wait() call within read(): ")) + s, 500);
00440 }
00441 }
00442
00443 ULXR_TRACE(ULXR_PCHAR("read epoll closing with result ") + HtmlFormHandler::makeNumber(waitresult)
00444 + ULXR_PCHAR(" and errno ") + HtmlFormHandler::makeNumber(errno));
00445 ::close(epollfd);
00446 if(waitresult == 0)
00447 {
00448 throw ConnectionException(SystemError,
00449 ulxr_i18n(ULXR_PCHAR("Timeout after ")) + HtmlFormHandler::makeNumber(toval) + ulxr_i18n(ULXR_PCHAR("ms while attempting to read (using epoll).")), 500);
00450 }
00451 else
00452 {
00453 if(waitresult == 1)
00454 {
00455 if( (readed = low_level_read(buff, len)) < 0)
00456 {
00457 throw ConnectionException(SystemError,
00458 ulxr_i18n(ULXR_PCHAR("Could not perform read() call: "))
00459 + getErrorString(getLastError()), 500);
00460 }
00461 ULXR_TRACE(ULXR_PCHAR("read readed ") + HtmlFormHandler::makeNumber(readed)
00462 + ULXR_PCHAR(" and wanted ") + HtmlFormHandler::makeNumber(len));
00463 }
00464 else
00465 {
00466 throw ConnectionException(SystemError,
00467 ulxr_i18n(ULXR_PCHAR("Problem while attempting to read by epoll.")), 500);
00468 }
00469 }
00470 }
00471 else
00472 {
00473 ::close(epollfd);
00474 throw ConnectionException(SystemError,
00475 ulxr_i18n(ULXR_PCHAR("Could not perform epoll_ctl() call: ")), 500);
00476 }
00477 }
00478 else
00479 {
00480 throw ConnectionException(SystemError,
00481 ulxr_i18n(ULXR_PCHAR("Could not perform epoll_create() call: ")), 500);
00482 }
00483 }
00484
00485 #else // ULXR_USE_EPOLL
00486
00487 else
00488 {
00489 ULXR_TRACE(ULXR_PCHAR("read 3a"));
00490
00491 wait.tv_sec = getTimeout();
00492 wait.tv_usec = 0;
00493 while((ready = ::select(fd_handle+1, &rfd, 0, 0, pwait)) < 0)
00494 {
00495 ULXR_TRACE(ULXR_PCHAR("read ~select"));
00496 if(errno == EINTR || errno == EAGAIN)
00497 {
00498
00499 wait.tv_sec = getTimeout();
00500 wait.tv_usec = 0;
00501 continue;
00502 }
00503
00504 else
00505 {
00506 ULXR_TRACE(ULXR_PCHAR("read ConnEx"));
00507 throw ConnectionException(SystemError,
00508 ulxr_i18n(ULXR_PCHAR("Could not perform select() call: "))
00509 + getErrorString(getLastError()), 500);
00510 }
00511 }
00512
00513 ULXR_TRACE(ULXR_PCHAR("read 4"));
00514 if(ready == 0)
00515 throw ConnectionException(SystemError,
00516 ulxr_i18n(ULXR_PCHAR("Timeout while attempting to read (using select).")), 500);
00517
00518 ULXR_TRACE(ULXR_PCHAR("read 5"));
00519
00520 if(FD_ISSET(fd_handle, &rfd))
00521 {
00522 while ( (readed = low_level_read(buff, len)) < 0)
00523 {
00524 ULXR_TRACE(ULXR_PCHAR("read 6: ") << getErrorString(getLastError()));
00525 switch(getLastError())
00526 {
00527 case EAGAIN:
00528 case EINTR:
00529 #ifdef __unix__
00530 errno = 0;
00531 #endif
00532 continue;
00533
00534 default:
00535 throw ConnectionException(SystemError,
00536 ulxr_i18n(ULXR_PCHAR("Could not perform read() call: "))
00537 + getErrorString(getLastError()), 500);
00538 }
00539 }
00540 }
00541 }
00542
00543
00544 #endif // ULXR_USE_EPOLL
00545
00546 ULXR_TRACE (ULXR_PCHAR("readed ") << readed);
00547 ULXR_DWRITE_READ(buff, readed);
00548
00549
00550
00551 if (readed == 0 )
00552 {
00553 ULXR_TRACE (ULXR_PCHAR("readed == 0"));
00554 close();
00555 throw ConnectionException(TransportError,
00556 ulxr_i18n(ULXR_PCHAR("Attempt to read from a connection")
00557 ULXR_PCHAR(" already closed by the peer")), 500);
00558 }
00559
00560 return readed;
00561 }
00562
00563
00564 ULXR_API_IMPL(void) Connection::cut()
00565 {
00566 ULXR_TRACE(ULXR_PCHAR("cut"));
00567 fd_handle = -1;
00568 }
00569
00570
00571 ULXR_API_IMPL(void) Connection::close()
00572 {
00573 ULXR_TRACE(ULXR_PCHAR("close"));
00574 if (isOpen())
00575 {
00576 #ifndef __unix__
00577 ULXR_TRACE(ULXR_PCHAR("closesocket"));
00578 ::closesocket(fd_handle);
00579 #else
00580
00581 int ret;
00582 ULXR_TRACE(ULXR_PCHAR("close"));
00583 do
00584 ret=::close(fd_handle);
00585 while(ret < 0 && (errno == EINTR || errno == EAGAIN));
00586
00587 if(ret < 0)
00588 throw ConnectionException(TransportError,
00589 ULXR_PCHAR("Close failed: ")+getErrorString(getLastError()), 500);
00590 #endif
00591 }
00592 fd_handle = -1;
00593 ULXR_TRACE(ULXR_PCHAR("/close"));
00594 }
00595
00596
00597 ULXR_API_IMPL(int) Connection::getLastError()
00598 {
00599 #ifdef __WIN32__
00600 return(GetLastError());
00601 #else
00602 return(errno);
00603 #endif
00604 }
00605
00606
00607 ULXR_API_IMPL(CppString) Connection::getErrorString(int err_number)
00608 {
00609 #ifdef __WIN32__
00610 LPSTR lpMsgBuf;
00611 int ok = FormatMessage(
00612 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00613 NULL,
00614 err_number,
00615 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00616 (LPSTR)&lpMsgBuf,
00617 0,
00618 NULL);
00619
00620 if (ok != 0 && lpMsgBuf != 0)
00621 return ULXR_GET_STRING(lpMsgBuf);
00622 else
00623 {
00624 char s[40];
00625 CppString errn = ULXR_GET_STRING(itoa(err_number, s, 10));
00626 return ulxr_i18n(ULXR_PCHAR("Unknown connection problem, Windows error code: #"))+errn;
00627 }
00628 #else
00629 return(getLastErrorString(err_number));
00630 #endif
00631 }
00632
00633
00634 ULXR_API_IMPL(int) Connection::getHandle() const
00635 {
00636 return fd_handle;
00637 }
00638
00639
00640 ULXR_API_IMPL(void) Connection::setHandle(int handle)
00641 {
00642 fd_handle = handle;
00643 }
00644
00645
00646 ULXR_API_IMPL(bool) Connection::isConnecting() const
00647 {
00648 return isconnecting;
00649 }
00650
00651
00652 ULXR_API_IMPL(void) Connection::setIsConnecting(bool connecting)
00653 {
00654 isconnecting = connecting;
00655 }
00656
00657
00658 ULXR_API_IMPL(void) Connection::doConnect()
00659 {
00660 ULXR_TRACE(ULXR_PCHAR("doConnect"));
00661 if(connector != 0)
00662 {
00663 ULXR_TRACE(ULXR_PCHAR("doConnect call"));
00664 setIsConnecting(true);
00665 try
00666 {
00667 connector->call();
00668 }
00669 catch(...)
00670 {
00671 setIsConnecting(false);
00672 throw;
00673 }
00674 setIsConnecting(false);
00675 }
00676 }
00677
00678
00679 ULXR_API_IMPL0 ConnectorWrapperBase::~ConnectorWrapperBase()
00680 {
00681 }
00682
00683
00684 ULXR_API_IMPL(void) Connection::setConnector(ConnectorWrapperBase *in_connector)
00685 {
00686 ULXR_TRACE(ULXR_PCHAR("setConnector ") << (void*) in_connector);
00687 connector = in_connector;
00688 }
00689
00690
00691 ULXR_API_IMPL(void) Connection::setTimeout(unsigned to_sec)
00692 {
00693 ULXR_TRACE(ULXR_PCHAR("current timeout ") << to_sec);
00694 current_to = to_sec;
00695 }
00696
00697
00698 ULXR_API_IMPL(void) Connection::setConnectionTimeout(unsigned def_to_sec, unsigned alive_to_sec)
00699 {
00700 ULXR_TRACE(ULXR_PCHAR("connection timeout ") << def_to_sec << ULXR_PCHAR(" ") << alive_to_sec);
00701 default_to = def_to_sec;
00702 persist_to = alive_to_sec;
00703 }
00704
00705
00706 ULXR_API_IMPL(unsigned) Connection::getTimeout() const
00707 {
00708 return current_to;
00709 }
00710
00711
00712 ULXR_API_IMPL(unsigned) Connection::getDefaultTimeout() const
00713 {
00714 if (default_to == 0)
00715 return current_to;
00716 else
00717 return default_to;
00718 }
00719
00720
00721 ULXR_API_IMPL(unsigned) Connection::getPersistentTimeout() const
00722 {
00723 if (persist_to == 0)
00724 return current_to;
00725 else
00726 return persist_to;
00727 }
00728
00729
00730 }