SocketUN.cc

Go to the documentation of this file.
00001 // ----------------------------------------------------------------------------
00002 // CERTI - HLA RunTime Infrastructure
00003 // Copyright (C) 2002-2005  ONERA
00004 //
00005 // This program is free software ; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public License
00007 // as published by the Free Software Foundation ; either version 2 of
00008 // the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY ; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this program ; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018 // ----------------------------------------------------------------------------
00019 
00020 
00021 #include "certi.hh"
00022 #include "SocketUN.hh"
00023 
00024 #if defined(RTIA_USE_TCP)
00025     #include "SocketTCP.hh"
00026     #if not defined(_WIN32)
00027         #include <cstring>
00028         #include <cerrno>
00029     #endif
00030 #else
00031 #include <unistd.h>
00032 #include <strings.h>
00033 #include <sstream>
00034 #include <string>
00035 #include <stdio.h>
00036 #include <errno.h>
00037 #include <sys/un.h>
00038 #endif
00039 
00040 #include <iostream>
00041 #include <assert.h>
00042 
00043 using std::ostringstream ;
00044 using std::string ;
00045 using std::cout ;
00046 using std::endl ;
00047 
00048 namespace certi {
00049 static PrettyDebug G("GENDOC",__FILE__);
00050 #define MAX_ATTEMPTS 3
00051 
00052 // ----------------------------------------------------------------------------
00054 void
00055 SocketUN::acceptUN(int RTIA_port)
00056 {
00057 #if defined(RTIA_USE_TCP)
00058     struct sockaddr_in nom_client, nom_serveur;
00059     int lg_nom;
00060     int result;
00061 
00062 #if defined(_WIN32)
00063     assert(SocketTCP::winsockInitialized());
00064     int socklen;
00065 #else
00066     socklen_t socklen;
00067 #endif
00068 
00069     if((sock_connect=socket(AF_INET,SOCK_STREAM,0)) < 0)
00070         error("socket");
00071 
00072     memset(&nom_serveur, 0, sizeof(nom_serveur));
00073 
00074     nom_serveur.sin_family      = AF_INET;
00075     nom_serveur.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00076 
00077     // TEMPO : UNIX socket emulation with TCP/IP sockets
00078     int tcpport;
00079     if (RTIA_port>0) {
00080         tcpport = RTIA_port;
00081     } else {
00082         tcpport = getpid();
00083     }
00084 
00085     // make sure it is contained in a short
00086     if (tcpport > 65535)
00087         throw RTIinternalError("TCP Port too big.");
00088 
00089     nom_serveur.sin_port = htons(tcpport);
00090 
00091     lg_nom = sizeof(nom_serveur);
00092 
00093     result = ::bind(sock_connect,(sockaddr *)&nom_serveur, lg_nom);
00094 
00095     if(result <0)
00096         {// Error on Bind. If the error is "Address already in use", allow
00097         // the user to choose to "reuse address" and then try again.
00098         error("bind");
00099         }
00100     pD->Out(pdInit, "Server: Bind succeeded, now listening.");
00101 #else
00102 
00103     struct sockaddr_un nom_client, nom_serveur ;
00104     socklen_t socklen ;
00105 
00106     pD->Out(pdInit, "Opening Server UNIX Socket.");
00107 
00108     // Socket
00109     if ((sock_connect = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
00110         {
00111         pD->Out(pdError, "Cannot open Server UNIX Socket.");
00112         error("socket");
00113         }
00114 
00115     pD->Out(pdInit, "Server has got UNIX Socket FpD->");
00116 
00117     // Set Server address
00118     memset(&nom_serveur, 0, sizeof(nom_serveur));
00119 
00120     nom_serveur.sun_family = AF_UNIX ;
00121 
00122     if (strlen(NOM_FICHIER_SOCKET) > 90)
00123         throw RTIinternalError("NOM_FICHIER_SOCKET too long.");
00124 
00125     char buffer[256] ;
00126     sprintf( buffer, "%s.%d", NOM_FICHIER_SOCKET, getpid() ) ;
00127     name = buffer ;
00128     strcpy( nom_serveur.sun_path, name.c_str() );
00129 
00130 
00131     // Bind
00132     if (bind(sock_connect, (struct sockaddr*)&nom_serveur,
00133              sizeof(struct sockaddr_un)) < 0)
00134         error("bind");
00135 
00136     pD->Out(pdInit, "Server: Bind succeeded, now listening.");
00137 #endif
00138 
00139 // Listen
00140 if (listen(sock_connect, 10) == -1)
00141   error("listen");
00142 
00143 pD->Out(pdInit, "Server: Listen returned, now accepting.");
00144 
00145 // Accept
00146 socklen = sizeof(struct sockaddr_in);
00147 if ((_socket_un = accept(sock_connect,
00148                        (struct sockaddr*)&nom_client,
00149                        &socklen)) < 0)
00150   // HPUX:(int*) &lg_nom)) < 0)
00151   error("accept");
00152 
00153 pD->Out(pdInit, "Server: Accept OK, server running.");
00154 
00155 _est_init_un = true ;
00156 _est_serveur = true ;
00157 }
00158 
00159 // ----------------------------------------------------------------------------
00161 #ifdef RTIA_USE_TCP
00162     void SocketUN::connectUN(int Server_pid)
00163 #else
00164     int SocketUN::connectUN(pid_t Server_pid)
00165 #endif
00166 {
00167 int Attempt = 0 ;
00168 int Result = 0 ;
00169 
00170 #if defined(RTIA_USE_TCP)
00171     struct sockaddr_in nom_serveur;
00172     int lg_nom;
00173 #ifdef _WIN32
00174     struct hostent *hptr = NULL;
00175     assert(SocketTCP::winsockInitialized());
00176 #endif
00177 #else
00178     struct sockaddr_un nom_serveur;
00179 #endif
00180 
00181 char buffer[256] ;
00182 sprintf( buffer, "%s.%d", NOM_FICHIER_SOCKET, Server_pid ) ;
00183 name = buffer ;
00184 
00185 while (Attempt < MAX_ATTEMPTS)
00186     {
00187     pD->Out(pdInit, "Opening Client UNIX Socket.");
00188 
00189 // TCP Socket case--------------------------------------------------
00190 #if defined(RTIA_USE_TCP)
00191     if((_socket_un = socket(AF_INET, SOCK_STREAM, 0)) == -1)
00192         error("socket");
00193 
00194     pD->Out(pdInit, "Client has got UNIX Socket FpD->");
00195 
00196     // Clear and set Server adress
00197     memset(&nom_serveur, 0, sizeof(nom_serveur));
00198 
00199     nom_serveur.sin_family      = AF_INET;
00200     nom_serveur.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00201 
00202     if (Server_pid > 65535)
00203         throw RTIinternalError("NOM_FICHIER_SOCKET too long.");
00204     nom_serveur.sin_port= htons(Server_pid);
00205 
00206     lg_nom = sizeof(nom_serveur);
00207     Result = ::connect(_socket_un,(sockaddr *)&nom_serveur, lg_nom);
00208 
00209     //pD->Out(pdInit, "Client: Connect returned %d.", Result);
00210 #else
00211     if ((_socket_un = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
00212         error("socket");
00213 
00214     pD->Out(pdInit, "Client has got UNIX Socket FpD->");
00215 
00216     memset(&nom_serveur, 0, sizeof(nom_serveur));   // Clear and set Server adress
00217     nom_serveur.sun_family = AF_UNIX ;
00218 
00219     if (strlen(NOM_FICHIER_SOCKET) > 90)
00220         throw RTIinternalError("NOM_FICHIER_SOCKET too long.");
00221     strcpy( nom_serveur.sun_path, name.c_str() );
00222     Result = connect(_socket_un,
00223                          (struct sockaddr*) &nom_serveur,
00224                          sizeof(struct sockaddr_un));
00225     pD->Out(pdInit, "Client: Connect returned %d.", Result);
00226 #endif
00227 
00228     if (Result == 0)        // Success ? Yes->break
00229         break ;
00230 
00231     // Failure
00232     pD->Out(pdError, "SocketUN: Connect, attempt #%d out of %d failed",
00233             Attempt + 1, MAX_ATTEMPTS);
00234     sleep(1);
00235     Attempt ++ ;
00236     }
00237 
00238 pD->Out(pdInit, "Client: Done.");
00239 
00240 if( Result == 0 )
00241     _est_init_un = true ;
00242 
00243 #ifdef _WIN32
00244 return ; //Result ;
00245 #else
00246 return Result ;
00247 #endif
00248 }
00249 
00250 // ----------------------------------------------------------------------------
00252 SocketUN::SocketUN(SignalHandlerType theType)
00253     : _socket_un(0), _est_serveur(false), _est_init_un(false),
00254       HandlerType(theType), SentBytesCount(0), RcvdBytesCount(0)
00255 {
00256 #ifdef _WIN32
00257     SocketTCP::winsockStartup();
00258 #endif
00259 
00260 #ifdef SOCKUN_BUFFER_LENGTH
00261     RBLength = 0 ;
00262 #endif
00263 
00264  pD = new pdCDebug("SOCKUN", "SocketUN");
00265  pD->Out(pdInit, "UNIX Socket created.");
00266 }
00267 
00268 // ----------------------------------------------------------------------------
00270 SocketUN::~SocketUN()
00271 {
00272 if (_est_init_un)
00273     {
00274     #ifdef _WIN32
00275         closesocket(_socket_un);
00276         if (_est_serveur)
00277             closesocket(sock_connect);
00278     #else
00279         close(_socket_un);
00280         if (_est_serveur)
00281             close(sock_connect);
00282         unlink(name.c_str());
00283     #endif
00284 
00285     if (_est_serveur)
00286         pD->Out(pdTerm, "Server: Closed all sockets.");
00287     else
00288         pD->Out(pdTerm, "Client: Closed all sockets.");
00289     }
00290 
00291 #ifdef _WIN32
00292   SocketTCP::winsockShutdown();
00293 #endif
00294 
00295 pD->Out(pdCom, "Unix Socket %2d : total = %9db sent", _socket_un, SentBytesCount ) ;
00296 pD->Out(pdCom, "Unix Socket %2d : total = %9db received", _socket_un, RcvdBytesCount ) ;
00297 
00298 delete pD ;
00299 }
00300 
00301 // ----------------------------------------------------------------------------
00303 
00306 void
00307 SocketUN::send(const unsigned char *buffer, size_t size)
00308     throw (NetworkError, NetworkSignal)
00309 {
00310 long sent = 0 ;
00311 unsigned long total_sent = 0 ;
00312 
00313 // G.Out(pdGendoc,"enter SocketUN::send");
00314 assert(_est_init_un);
00315 
00316 pD->Out(pdTrace, "Beginning to send UN message...");
00317 
00318 while (total_sent < size)
00319     {
00320     #ifdef _WIN32
00321         sent = ::send(_socket_un, (char *) buffer + total_sent, size - total_sent, 0);
00322     #else
00323         sent = write(_socket_un, (char *) buffer + total_sent, size - total_sent);
00324     #endif
00325 
00326     if (sent > 0)
00327         {
00328         total_sent += sent ;
00329         pD->Out(pdTrace, "Sent %ld bytes out of %ld.", total_sent, size);
00330         }
00331     else
00332         {
00333         if (sent < 0)
00334             {
00335             pD->Out(pdExcept, "Error while sending on UN socket.");
00336 
00337             #ifdef _WIN32
00338                 if(WSAGetLastError() == WSAEINTR)
00339             #else
00340                 if(errno == EINTR)
00341             #endif
00342                 {// Incoming Signal
00343                 if (HandlerType == stSignalInterrupt) throw NetworkSignal("");
00344                 else pD->Out(pdExcept, "EmettreUN ignoring signal interruption.");
00345                 }
00346             else // Other errors
00347                 {
00348                 perror("UN Socket(EmettreUN) : ");
00349                     throw NetworkError("Error while sending UN message.");
00350             }   }
00351 
00352         if (sent == 0)
00353             {
00354             pD->Out(pdExcept, "No data could be sent, connection closed?.");
00355             throw NetworkError("Could not send any data on UN socket.");
00356             }
00357         }
00358     }
00359 SentBytesCount += total_sent ;
00360 // G.Out(pdGendoc,"exit  SocketUN::send");
00361 }
00362 
00363 // ----------------------------------------------------------------------------
00365 void SocketUN::error(const char *msg) throw (NetworkError)
00366 {
00367  std::stringstream smsg;
00368 
00369  smsg << "SocketUN::error <"
00370       << strerror(errno)
00371       << "> msg = <"
00372       << msg <<">";
00373  throw NetworkError(smsg.str().c_str());
00374 }
00375 
00376 // ----------------------------------------------------------------------------
00380 bool
00381 SocketUN::isDataReady()
00382 {
00383 #ifdef SOCKUN_BUFFER_LENGTH
00384     return RBLength > 0 ;
00385 #else
00386     return false ;
00387 #endif
00388 }
00389 
00390 // ----------------------------------------------------------------------------
00391 #ifdef _WIN32
00392 SOCKET
00393 #else
00394 int
00395 #endif
00396 SocketUN::returnSocket()
00397 {
00398     return _socket_un;
00399 }
00400 
00401 // ----------------------------------------------------------------------------
00402 void
00403 SocketUN::receive(const unsigned char *buffer, size_t Size)
00404     throw (NetworkError, NetworkSignal)
00405 {
00406 // G.Out(pdGendoc,"enter SocketUN::receive");
00407 
00408 assert(_est_init_un);
00409 
00410 long nReceived = 0 ;
00411 
00412 #ifndef SOCKUN_BUFFER_LENGTH
00413     unsigned long RBLength = 0 ;
00414 #endif
00415 
00416 pD->Out(pdTrace, "Beginning to receive U/W message...(Size  %ld)",Size);
00417 
00418 while (RBLength < Size)
00419     {
00420     #ifdef _WIN32
00421         #ifdef SOCKUN_BUFFER_LENGTH
00422                 nReceived = recv(_socket_un,
00423                          ReadBuffer + RBLength,
00424                          SOCKUN_BUFFER_LENGTH - RBLength,
00425                          0);
00426         #else
00427                 nReceived = recv(_socket_un,
00428                          (char *) buffer + RBLength,
00429                          Size - RBLength,
00430                          0);
00431         #endif
00432     #else
00433         #ifdef SOCKUN_BUFFER_LENGTH
00434         nReceived = read(_socket_un, ReadBuffer + RBLength, SOCKUN_BUFFER_LENGTH - RBLength);
00435         #else
00436         nReceived = read(_socket_un, (char *) buffer + RBLength, Size - RBLength);
00437         #endif
00438     #endif
00439 
00440     if (nReceived < 0)
00441         {
00442         pD->Out(pdExcept, "Error while receiving on UN socket.");
00443 
00444         #ifdef _WIN32
00445             if(WSAGetLastError() == WSAEINTR)
00446         #else
00447             if(errno == EINTR)
00448         #endif
00449             {// Incoming Signal
00450             if (HandlerType == stSignalInterrupt)
00451                 throw NetworkSignal("");
00452             else
00453                 pD->Out(pdExcept, "RecevoirUN ignoring signal interruption.");
00454             }
00455         else
00456             {// Other errors
00457             perror("UN Socket(RecevoirUN) : ");
00458             throw NetworkError("Error while receiving UN message.");
00459             }
00460         }
00461 
00462     if (nReceived == 0)
00463         {
00464         pD->Out(pdExcept, "UN connection has been closed by peer.");
00465         throw NetworkError("Connection closed by client.");
00466         }
00467     else if (nReceived > 0)
00468         {
00469         RBLength += nReceived ;
00470         RcvdBytesCount += nReceived ;
00471         }
00472     }
00473 pD->Out(pdTrace, "Received %ld bytes out of %ld.", RBLength, Size);
00474 
00475 #ifdef SOCKUN_BUFFER_LENGTH
00476 memcpy(const_cast<unsigned char *>(buffer), ReadBuffer, Size);
00477 memmove((void *) ReadBuffer,
00478 (void *)(ReadBuffer + Size),
00479 RBLength - Size);
00480 RBLength -= Size ;
00481 #endif
00482 // G.Out(pdGendoc,"exit  SocketUN::receive");
00483 }
00484 
00485 } // namespace certi

Generated on Thu Apr 30 15:53:50 2009 for CERTIDeveloperDocumentation by doxygen 1.5.5