lib/misc/server.cc
changeset 0 6f7a81934006
equal deleted inserted replaced
-1:000000000000 0:6f7a81934006
       
     1 // Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
       
     2 //
       
     3 // This program is free software; you can redistribute it and/or modify
       
     4 // it under the terms of the GNU General Public License as published by
       
     5 // the Free Software Foundation; either version 2 of the License, or
       
     6 // (at your option) any later version.
       
     7 //
       
     8 // This program is distributed in the hope that it will be useful,
       
     9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    11 // GNU General Public License for more details.
       
    12 //
       
    13 // You should have received a copy of the GNU General Public License
       
    14 // along with this program; if not, write to the Free Software
       
    15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    16 
       
    17 #include <config.h>
       
    18 #include "server.h"
       
    19 #include <stdlib.h>
       
    20 #include <unistd.h>
       
    21 #include "un.h"
       
    22 #include "debug.h"
       
    23 
       
    24 server_call::~server_call()
       
    25 {
       
    26   trace("server_call::~server_call");
       
    27   disconnect();
       
    28   delete[] args;
       
    29 }
       
    30 
       
    31 static unsigned char* encode_string(unsigned char* ptr, mystring str)
       
    32 {
       
    33   unsigned length = str.length();
       
    34   *ptr++ = length >> 8;
       
    35   *ptr++ = length & 0xff;
       
    36   memcpy(ptr, str.c_str(), length);
       
    37   return ptr+length;
       
    38 }
       
    39 
       
    40 mystring server_call::build_msg() const
       
    41 {
       
    42   if(argc >= 1<<8)
       
    43     return "";
       
    44   unsigned msglen = 3 + cmd.length();
       
    45   for(unsigned i = 0; i < argc; i++) {
       
    46     if(args[i].length() >= 1<<16)
       
    47       return "";
       
    48     msglen += 2 + args[i].length();
       
    49   }
       
    50   char buf[msglen+3];
       
    51   unsigned char* ptr = (unsigned char*)buf;
       
    52   *ptr++ = 2;			// protocol ID
       
    53   *ptr++ = msglen >> 8;
       
    54   *ptr++ = msglen & 0xff;
       
    55   *ptr++ = argc;
       
    56   ptr = encode_string(ptr, cmd);
       
    57   for(unsigned i = 0; i < argc; i++)
       
    58     ptr = encode_string(ptr, args[i]);
       
    59   return mystring(buf, msglen+3);
       
    60 }
       
    61 
       
    62 static bool send(int fd, mystring msg)
       
    63 {
       
    64   ssize_t written = 0;
       
    65   while(written < (ssize_t)msg.length()) {
       
    66     ssize_t w = write(fd, msg.c_str()+written, msg.length()-written);
       
    67     if(w == 0 || w == -1)
       
    68       break;
       
    69     written += w;
       
    70   }
       
    71   return written == (ssize_t)msg.length();
       
    72 }
       
    73 
       
    74 int server_call::connect(const mystring& socket_file) const
       
    75 {
       
    76   int s = ::socket(AF_UNIX, SOCK_STREAM, 0);
       
    77   if(s == -1)
       
    78     return -1;
       
    79   size_t size = sizeof(sockaddr_un) + socket_file.length()+1;
       
    80   sockaddr_un* saddr = (sockaddr_un*)malloc(size);
       
    81   saddr->sun_family = AF_UNIX;
       
    82   strcpy(saddr->sun_path, socket_file.c_str());
       
    83   if(::connect(s, (sockaddr*)saddr, SUN_LEN(saddr)) == -1)
       
    84     return -1;
       
    85   free(saddr);
       
    86   return s;
       
    87 }
       
    88 
       
    89 void server_call::disconnect()
       
    90 {
       
    91   if(fd >= 0)
       
    92     close(fd);
       
    93 }
       
    94 
       
    95 response server_call::call(const mystring& socket_file)
       
    96 {
       
    97   trace("server_call::call");
       
    98   mystring msg = build_msg();
       
    99   if(!msg)
       
   100     RETURN(bad, "Invalid command data");
       
   101   fd = connect(socket_file);
       
   102   if(fd == -1)
       
   103     RETURN(econn, "Unable to connect to the server");
       
   104   if(!send(fd, msg))
       
   105     RETURN(econn, "Server aborted the connection");
       
   106   return response::read(fd);
       
   107 }