controlsocket.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /** 
00023  * \file controlsocket.cpp
00024  * \version $Id: controlsocket.cpp 1863 2007-08-23 18:50:23Z edmanm $
00025  * \brief Socket used to connect to Tor's control interface
00026  */
00027 
00028 #include <QHostAddress>
00029 #include <util/string.h>
00030 #include <vidalia.h>
00031 
00032 #include "controlsocket.h"
00033 
00034 /** Give up after waiting five seconds for the control socket to connect to
00035 * Tor. This timeout used to be shorter (three seconds), but some Agnitum
00036 * OutPost users yelled at us wanting a longer timeout, for some reason. */
00037 #define CONN_TIMEOUT  5000
00038 
00039 /** Timeout reads in 250ms. We can set this to a short value because if there
00040 * isn't any data to read, we want to return anyway. */
00041 #define READ_TIMEOUT  250
00042 
00043 
00044 /** Default constructor. */
00045 ControlSocket::ControlSocket()
00046 {
00047 }
00048 
00049 /** Connects to Tor's control socket on the specified host and port. If the
00050  * connection is successful, true is returned. If the connection fails, then
00051  * this function returns false and sets <b>errmsg</b> appropriately, if not
00052  * null. */
00053 bool
00054 ControlSocket::connect(QHostAddress addr, quint16 port, QString *errmsg)
00055 {
00056   /* Connect the control socket. */
00057   vNotice("Connecting to Tor's control port on %1:%2").arg(addr.toString())
00058                                                       .arg(port);
00059   connectToHost(addr, port);
00060   if (!waitForConnected(CONN_TIMEOUT)) {
00061     vWarn("Failed to connect to Tor's control port: %1").arg(errorString());
00062     return err(errmsg, tr("Error connecting to %1:%2 [%3]")
00063                                             .arg(addr.toString())
00064                                             .arg(port)
00065                                             .arg(errorString()));
00066   }
00067   return true;
00068 }
00069 
00070 /** Disconnects from Tor's control socket */
00071 bool
00072 ControlSocket::disconnect(QString *errmsg)
00073 {
00074   disconnectFromHost();
00075   if (isConnected()) {
00076     if (!waitForDisconnected(CONN_TIMEOUT)) {
00077       vWarn("Failed to disconnect from Tor: %1").arg(errorString());
00078       return err(errmsg, tr("Error disconnecting socket. [%1]")
00079                                             .arg(errorString()));
00080     }
00081   }
00082   return true;
00083 }
00084 
00085 /** Returns true if the control socket is connected and ready to send or
00086  * receive. */
00087 bool
00088 ControlSocket::isConnected()
00089 {
00090   return (isValid() && state() == QAbstractSocket::ConnectedState);
00091 }
00092 
00093 /** Send a control command to Tor on the control socket, conforming to Tor's
00094  * Control Protocol V1:
00095  *
00096  *   Command = Keyword Arguments CRLF / "+" Keyword Arguments CRLF Data
00097  *   Keyword = 1*ALPHA
00098  *   Arguments = *(SP / VCHAR)
00099  */
00100 bool
00101 ControlSocket::sendCommand(ControlCommand cmd, QString *errmsg)
00102 {
00103   if (!isConnected()) {
00104     return err(errmsg, tr("Control socket is not connected."));
00105   }
00106   
00107   /* Format the control command */
00108   QString strCmd = cmd.toString();
00109   vInfo("Control Command: %1").arg(strCmd.trimmed());
00110 
00111   /* Attempt to send the command to Tor */
00112   if (write(strCmd.toAscii()) != strCmd.length()) {
00113     return err(errmsg, tr("Error sending control command. [%1]")
00114                                             .arg(errorString()));
00115   }
00116   flush();
00117   return true;
00118 }
00119 
00120 /** Reads line data, one chunk at a time, until a newline character is
00121  * encountered. */
00122 bool
00123 ControlSocket::readLineData(QString &line, QString *errmsg)
00124 {
00125   char buffer[1024];  /* Read in 1024 byte chunks at a time */
00126   int bytesRecv = QAbstractSocket::readLine(buffer, 1024);
00127   while (bytesRecv != -1) {
00128     line.append(buffer);
00129     if (buffer[bytesRecv-1] == '\n') {
00130       break;
00131     }
00132     bytesRecv = QAbstractSocket::readLine(buffer, 1024);
00133   }
00134   if (bytesRecv == -1) {
00135     return err(errmsg, errorString());
00136   }
00137   return true;
00138 }
00139 
00140 /** Reads a line of data from the socket and returns true if successful or
00141  * false if an error occurred while waiting for a line of data to become
00142  * available. */
00143 bool
00144 ControlSocket::readLine(QString &line, QString *errmsg)
00145 {
00146   /* Make sure we have data to read before attempting anything. Note that this
00147    * essentially makes our socket a blocking socket */
00148   while (!canReadLine()) {
00149     if (!isConnected()) {
00150       return err(errmsg, tr("Socket disconnected while attempting "
00151                             "to read a line of data."));
00152     }
00153     waitForReadyRead(READ_TIMEOUT);
00154   }
00155   line.clear();
00156   return readLineData(line, errmsg);
00157 }
00158 
00159 /** Read a complete reply from the control socket. Replies take the following
00160  * form, based on Tor's Control Protocol v1:
00161  *
00162  *    Reply = *(MidReplyLine / DataReplyLine) EndReplyLine
00163  *
00164  *    MidReplyLine = "-" ReplyLine
00165  *    DataReplyLine = "+" ReplyLine Data
00166  *    EndReplyLine = SP ReplyLine
00167  *    ReplyLine = StatusCode [ SP ReplyText ]  CRLF
00168  *    ReplyText = XXXX
00169  *    StatusCode = XXiX
00170  */
00171 bool
00172 ControlSocket::readReply(ControlReply &reply, QString *errmsg)
00173 {
00174   QChar c;
00175   QString line;
00176 
00177   if (!isConnected()) {
00178     return false;
00179   }
00180 
00181   /* The implementation below is (loosely) based on the Java control library from Tor */
00182   do {
00183     /* Read a line of the response */
00184     if (!readLine(line, errmsg)) {
00185       return false;
00186     }
00187     
00188     if (line.length() < 4) {
00189       return err(errmsg, tr("Invalid control reply. [%1]").arg(line));
00190     }
00191 
00192     /* Parse the status and message */
00193     ReplyLine replyLine(line.mid(0, 3), line.mid(4));
00194     c = line.at(3);
00195 
00196     /* If the reply line contains data, then parse out the data up until the
00197      * trailing CRLF "." CRLF */
00198     if (c == QChar('+') &&
00199         !line.startsWith("250+PROTOCOLINFO")) {
00200         /* XXX The second condition above is a hack to deal with Tor
00201          * 0.2.0.5-alpha that gives a malformed PROTOCOLINFO reply. This
00202          * should be removed once that version of Tor is sufficiently dead. */
00203       while (true) {
00204         if (!readLine(line, errmsg)) {
00205           return false;
00206         }
00207         if (line.trimmed() == ".") {
00208           break;
00209         }
00210         replyLine.appendData(line);
00211       }
00212     }
00213     reply.appendLine(replyLine);
00214   } while (c != QChar(' '));
00215   return true;
00216 }
00217 

Generated on Wed Sep 5 15:49:27 2007 for Vidalia by  doxygen 1.5.3