# 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