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 }