libsocket 1.5
localsocket.cc
Go to the documentation of this file.
00001 /*
00002 ** localsocket.cc
00003 ** Login : Julien Lemoine <speedblue@happycoders.org>
00004 ** Started on  Sun May 11 22:19:51 2003 Julien Lemoine
00005 ** $Id: localsocket.cc,v 1.9 2004/11/14 19:37:46 speedblue Exp $
00006 **
00007 ** Copyright (C) 2003,2004 Julien Lemoine
00008 ** This program is free software; you can redistribute it and/or modify
00009 ** it under the terms of the GNU Lesser General Public License as published by
00010 ** the Free Software Foundation; either version 2 of the License, or
00011 ** (at your option) any later version.
00012 **
00013 ** This program is distributed in the hope that it will be useful,
00014 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 ** GNU Lesser General Public License for more details.
00017 **
00018 ** You should have received a copy of the GNU Lesser General Public License
00019 ** along with this program; if not, write to the Free Software
00020 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00021 */
00022 
00023 #include "localsocket.hh"
00024 
00025 #ifndef LIBSOCKET_WIN
00026 
00027 #include <sys/types.h>
00028 #include <sys/un.h>
00029 #include <cstddef>
00030 #include "socket.hxx"
00031 
00032 namespace Network
00033 {
00034   void  LocalSocket::init(const std::string& filename)
00035   {
00036     _socket = _bind(filename);
00037     _filename = filename;
00038   }
00039 
00040   void  LocalSocket::close()
00041   {
00042     if (_socket > 0)
00043       _close(_socket);
00044     _socket = 0;
00045     unlink(_filename.c_str());
00046     _filename = "";
00047   }
00048 
00049   int           LocalSocket::_bind(const std::string& filename)
00050   {
00051     int                         s;
00052     struct sockaddr_un          name;
00053     size_t                      size;
00054 
00055     s = socket(PF_UNIX, SOCK_DGRAM, 0);
00056     if (s < 0)
00057       throw NoConnection("Socket error", HERE);
00058     name.sun_family = AF_UNIX;
00059     strncpy(name.sun_path, filename.c_str(), sizeof (name.sun_path));
00060     name.sun_path[sizeof (name.sun_path) - 1] = '\0';
00061     size = (offsetof (struct sockaddr_un, sun_path)
00062             + strlen (name.sun_path) + 1);
00063     if (bind (s, (struct sockaddr *) &name, size) < 0)
00064       throw BindError("Bind error", HERE);
00065     return s;
00066   }
00067 
00068   void  LocalSocket::_write_str(int socket, const std::string& str,
00069                                 const std::string& filename) const
00070   {
00071     int                         res = 1;
00072     const char                  *buf = str.c_str();
00073     unsigned int                count = 0;
00074     struct sockaddr_un          name;
00075 
00076     name.sun_family = AF_UNIX;
00077     strncpy(name.sun_path, filename.c_str(), sizeof (name.sun_path));
00078     name.sun_path[sizeof (name.sun_path) - 1] = '\0';
00079 
00080     if (socket < 0)
00081       throw NoConnection("No Socket", HERE);
00082     while (res && count < str.size())
00083       {
00084         res = sendto(socket, buf + count,
00085                      str.size() - count, SENDTO_FLAGS,
00086                      (const struct sockaddr*)&name, sizeof(name));
00087         if (res <= 0)
00088           throw ConnectionClosed("Connection Closed", HERE);
00089         count += res;
00090       }
00091   }
00092 
00093   void  LocalSocket::_write_str_bin(int socket, const std::string& str,
00094                                     const std::string& filename) const
00095   {
00096     int                         res = 1;
00097     unsigned int                count = 0;
00098     struct sockaddr_un          name;
00099     char                        buf[str.size() + 2];
00100 
00101     buf[0] = str.size() / 256;
00102     buf[1] = str.size() % 256;
00103     memcpy(buf + 2, str.c_str(), str.size());
00104     name.sun_family = AF_UNIX;
00105     strncpy(name.sun_path, filename.c_str(), sizeof (name.sun_path));
00106     name.sun_path[sizeof (name.sun_path) - 1] = DEFAULT_DELIM;
00107 
00108     if (socket < 0)
00109       throw NoConnection("No Socket", HERE);
00110     while (res && count < str.size() + 2)
00111       {
00112         res = sendto(socket, buf + count, str.size() + 2 - count, SENDTO_FLAGS,
00113                      (const struct sockaddr*)&name, sizeof(name));
00114         if (res <= 0)
00115           throw ConnectionClosed("Connection Closed", HERE);
00116         count += res;
00117       }
00118   }
00119 
00120   std::string   LocalSocket::_read_line(int socket,
00121                                         std::string& filename)
00122   {
00123     char                chr[MAXPKTSIZE];
00124     std::string         str = "";
00125     int                 res = 1, i;
00126     std::pair<int, int> delim;
00127     struct sockaddr_un  addr;
00128     size_t              size;
00129     bool                end = false;
00130 
00131     size = sizeof(addr);
00132     if (socket < 0)
00133       throw NoConnection("No Socket", HERE);
00134     if (!_update_buffer(delim, i, str))
00135       while (!end)
00136         {
00137 #ifdef __CYGWIN__
00138           res = recvfrom(socket, chr, MAXPKTSIZE, 0,
00139                          (struct sockaddr*)&addr,
00140                          (socklen_t*)&size);
00141 #else
00142           res = recvfrom(socket, chr, MAXPKTSIZE, MSG_TRUNC,
00143                          (struct sockaddr*)&addr,
00144                          (socklen_t*)&size);
00145 #endif
00146           if (res <= 0)
00147             throw ConnectionClosed("Connection Closed", HERE);
00148           _buffer += std::string(chr, res);
00149           if (_update_buffer(delim, i, str))
00150             end = true;
00151         }
00152     filename = std::string(addr.sun_path);
00153     _state_timeout = 0;
00154     return str;
00155   }
00156 
00157   std::string   LocalSocket::_read_line_bin(int socket, unsigned int size)
00158   {
00159     char                chr[MAXPKTSIZE];
00160     std::string         str = "";
00161     int                 res = 1;
00162     bool                end = false;
00163 
00164     if (socket < 0)
00165       throw NoConnection("No Socket", HERE);
00166     if (_buffer.size() >= 2 && !size)
00167       {
00168         size = (unsigned char)_buffer[0] * 256 + (unsigned char)_buffer[1];
00169         _buffer = _buffer.substr(2, _buffer.size() - 2);
00170       }
00171     if (size && _buffer.size() >= size)
00172       {
00173         str = _buffer.substr(0, size);
00174         _buffer = _buffer.substr(size, _buffer.size() - size);
00175       }
00176     else
00177       while (!end)
00178         {
00179           memset(chr, 0, MAXPKTSIZE);
00180 #ifdef __CYGWIN__
00181           res = recv(socket, chr, MAXPKTSIZE, 0);
00182 #else
00183           res = recv(socket, chr, MAXPKTSIZE, MSG_TRUNC);
00184 #endif
00185           if (res <= 0)
00186             throw ConnectionClosed("Connection Closed", HERE);
00187           // _buffer += all octets received
00188           _buffer += std::string(chr, res);
00189           if (!size)
00190             {
00191               // extract size from _buffer and reduce it
00192               size = (unsigned char)_buffer[0] * 256 + (unsigned char)_buffer[1];
00193               _buffer = _buffer.substr(2, _buffer.size() - 2);
00194             }
00195           if (_buffer.size() > size - str.size())
00196             {
00197               str += _buffer.substr(0, size - str.size());
00198               _buffer = _buffer.substr(size - str.size(), 
00199                                        _buffer.size() - size - str.size());
00200             }
00201           else
00202             {
00203               str += _buffer;
00204               _buffer = "";
00205             }
00206           if (str.size() >= size)
00207             end = true;
00208         }
00209     return str;
00210   }
00211 
00212   std::string   LocalSocket::_read_line(int socket)
00213   {
00214     char                chr[MAXPKTSIZE];
00215     std::string         str = "";
00216     int                 res = 1, i;
00217     std::pair<int, int> delim;
00218     bool                end = false;
00219 
00220     if (socket < 0)
00221       throw NoConnection("No Socket", HERE);
00222     if (!_update_buffer(delim, i, str))
00223       while (!end)
00224         {
00225           memset(chr, 0, MAXPKTSIZE);
00226 #ifdef __CYGWIN__
00227           res = recv(socket, chr, MAXPKTSIZE, 0);
00228 #else
00229           res = recv(socket, chr, MAXPKTSIZE, MSG_TRUNC);
00230 #endif
00231           if (res <= 0)
00232             throw ConnectionClosed("Connection Closed", HERE);
00233           _buffer += std::string(chr, res);
00234           if (_update_buffer(delim, i, str))
00235             end = true;
00236         }
00237     _state_timeout = 0;
00238     return str;
00239   }
00240 
00241   std::string   LocalSocket::_read_line_bin(int socket,
00242                                             std::string& filename,
00243                                             unsigned int pkg_size)
00244   {
00245     char                chr[MAXPKTSIZE];
00246     std::string         str = "";
00247     int                 res = 1;
00248     struct sockaddr_un  addr;
00249     size_t              size;
00250     bool                end = false;
00251 
00252     size = sizeof(addr);
00253     if (socket < 0)
00254       throw NoConnection("No Socket", HERE);
00255     if (_buffer.size() >= 2 && !pkg_size)
00256       {
00257         pkg_size = (unsigned char)_buffer[0] * 256 + (unsigned char)_buffer[1];
00258         _buffer = _buffer.substr(2, _buffer.size() - 2);
00259       }
00260     if (pkg_size && _buffer.size() >= pkg_size)
00261       {
00262         str = _buffer.substr(0, pkg_size);
00263         _buffer = _buffer.substr(pkg_size, _buffer.size() - pkg_size);
00264       }
00265     else
00266       while (!end)
00267         {
00268 #ifdef __CYGWIN__
00269           res = recvfrom(socket, chr, MAXPKTSIZE, 0,
00270                          (struct sockaddr*)&addr,
00271                          (socklen_t*)&size);
00272 #else
00273           res = recvfrom(socket, chr, MAXPKTSIZE, MSG_TRUNC,
00274                          (struct sockaddr*)&addr,
00275                          (socklen_t*)&size);
00276 #endif
00277           if (res <= 0)
00278             throw ConnectionClosed("Connection Closed", HERE);
00279           // _buffer += all octets received
00280           _buffer += std::string(chr, res).substr(0, res);
00281           if (!pkg_size)
00282             {
00283               // extract size from _buffer and reduce it
00284               pkg_size = (unsigned char)_buffer[0] * 256 + 
00285                 (unsigned char)_buffer[1];
00286               _buffer = _buffer.substr(2, _buffer.size() - 2);
00287             }
00288           if (_buffer.size() > pkg_size - str.size())
00289             {
00290               str += _buffer.substr(0, pkg_size - str.size());
00291               _buffer = _buffer.substr(pkg_size - str.size(), 
00292                                        _buffer.size() - pkg_size - str.size());
00293             }
00294           else
00295             {
00296               str += _buffer;
00297               _buffer = "";
00298             }
00299           if (str.size() >= pkg_size)
00300             end = true;
00301         }
00302     filename = std::string(addr.sun_path);
00303     return str;
00304   }
00305 
00306   void LocalSocket::writeto(const std::string& str,
00307                             const std::string& filename)
00308   {
00309     if (_proto_kind == binary)
00310       _write_str_bin(_socket, str, filename);
00311     else
00312       _write_str(_socket, str, filename);
00313   }
00314 
00315   std::string   LocalSocket::readn(unsigned int size)
00316   {
00317     // _read_line_bin is bufferised with the same buffer as textual
00318     // protocols, so this function can be used for binary and text
00319     // protocols.
00320     return _read_line_bin(_socket, size);
00321   }
00322 
00323   std::string   LocalSocket::readn(int timeout, unsigned int size)
00324   {
00325     if (!size || size > _buffer.size())
00326       _set_timeout(true, _socket, timeout);
00327     // _read_line_bin is bufferised with the same buffer as textual
00328     // protocols, so this function can be used for binary and text
00329     // protocols.
00330     return _read_line_bin(_socket, size);
00331   }
00332 
00333   std::string   LocalSocket::readn(std::string& filename, unsigned int size)
00334   {
00335     // _read_line_bin is bufferised with the same buffer as textual
00336     // protocols, so this function can be used for binary and text
00337     // protocols.
00338     return _read_line_bin(_socket, filename, size);
00339   }
00340 
00341   std::string   LocalSocket::readn(std::string& filename,
00342                                    int timeout, unsigned int size)
00343   {
00344     if (!size || size > _buffer.size())
00345       _set_timeout(true, _socket, timeout);
00346     // _read_line_bin is bufferised with the same buffer as textual
00347     // protocols, so this function can be used for binary and text
00348     // protocols.
00349     return _read_line_bin(_socket, filename, size);
00350   }
00351 
00352   std::string   LocalSocket::read()
00353   {
00354     if (_proto_kind == binary)
00355       return _read_line_bin(_socket, 0);
00356     else
00357       return _read_line(_socket);
00358   }
00359 
00360   std::string   LocalSocket::read(int timeout)
00361   {
00362     if (_proto_kind == binary)
00363       {
00364         _set_timeout(true, _socket, timeout);
00365         return _read_line_bin(_socket, 0);
00366       }
00367     else
00368       {
00369         _state_timeout = timeout;
00370         return _read_line(_socket);
00371       }
00372   }
00373 
00374   std::string   LocalSocket::read(std::string& filename)
00375   {
00376     if (_proto_kind)
00377       return _read_line_bin(_socket, filename, 0);
00378     else
00379       return _read_line(_socket, filename);
00380   }
00381 
00382   std::string   LocalSocket::read(std::string& filename, int timeout)
00383   {
00384     if (_proto_kind == binary)
00385       {
00386         _set_timeout(true, _socket, timeout);
00387         return _read_line_bin(_socket, filename, 0);
00388       }
00389     else
00390       {
00391         _state_timeout = timeout;
00392         return _read_line(_socket, filename);
00393       }
00394   }
00395 }
00396 
00397 #endif