00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <QHostAddress>
00029 #include <util/string.h>
00030
00031 #include "controlsocket.h"
00032
00033
00034
00035
00036 #define CONN_TIMEOUT 5000
00037
00038
00039
00040 #define READ_TIMEOUT 250
00041
00042
00043
00044 ControlSocket::ControlSocket()
00045 {
00046 }
00047
00048
00049
00050
00051
00052 bool
00053 ControlSocket::connect(QHostAddress addr, quint16 port, QString *errmsg)
00054 {
00055 ProtocolVersion version;
00056
00057
00058 connectToHost(addr, port);
00059 if (!waitForConnected(CONN_TIMEOUT)) {
00060 return err(errmsg, tr("Error connecting to %1:%2 [%3]")
00061 .arg(addr.toString())
00062 .arg(port)
00063 .arg(errorString()));
00064 }
00065
00066
00067 blockSignals(true);
00068 version = protocolVersion();
00069 blockSignals(false);
00070 if (version != Version1) {
00071 disconnect();
00072 return err(errmsg, tr("Vidalia only supports Version 1 of Tor's Control Protocol "
00073 "(Version %1 detected).\n"
00074 "Upgrade to a newer version of Tor.").arg(version));
00075 }
00076
00077
00078 return true;
00079 }
00080
00081
00082 bool
00083 ControlSocket::disconnect(QString *errmsg)
00084 {
00085 disconnectFromHost();
00086 if (isConnected()) {
00087 if (!waitForDisconnected(CONN_TIMEOUT)) {
00088 return err(errmsg, tr("Error disconnecting socket. [%1]")
00089 .arg(errorString()));
00090 }
00091 }
00092 return true;
00093 }
00094
00095
00096
00097 bool
00098 ControlSocket::isConnected()
00099 {
00100 return (isValid() && state() == QAbstractSocket::ConnectedState);
00101 }
00102
00103
00104 ControlSocket::ProtocolVersion
00105 ControlSocket::protocolVersion()
00106 {
00107 QByteArray versionData;
00108
00109
00110 if (!write("\0\0\r\n", 4)) {
00111 return VersionUnknown;
00112 }
00113 while (bytesAvailable() < 4) {
00114 if (!waitForReadyRead(-1)) {
00115 return VersionUnknown;
00116 }
00117 }
00118
00119
00120
00121 versionData = readAll();
00122 return (!qstrlen(versionData.data()) ? Version0 : Version1);
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132 bool
00133 ControlSocket::sendCommand(ControlCommand cmd, QString *errmsg)
00134 {
00135 if (!isConnected()) {
00136 return err(errmsg, tr("Control socket is not connected."));
00137 }
00138
00139
00140 QString strCmd = cmd.toString();
00141
00142
00143 if (write(strCmd.toAscii()) != strCmd.length()) {
00144 return err(errmsg, tr("Error sending control command. [%1]")
00145 .arg(errorString()));
00146 }
00147 flush();
00148 return true;
00149 }
00150
00151
00152
00153 bool
00154 ControlSocket::readLineData(QString &line, QString *errmsg)
00155 {
00156 char buffer[1024];
00157 int bytesRecv = QAbstractSocket::readLine(buffer, 1024);
00158 while (bytesRecv != -1) {
00159 line.append(buffer);
00160 if (buffer[bytesRecv-1] == '\n') {
00161 break;
00162 }
00163 bytesRecv = QAbstractSocket::readLine(buffer, 1024);
00164 }
00165 if (bytesRecv == -1) {
00166 return err(errmsg, errorString());
00167 }
00168 return true;
00169 }
00170
00171
00172
00173
00174 bool
00175 ControlSocket::readLine(QString &line, QString *errmsg)
00176 {
00177
00178
00179 while (!canReadLine()) {
00180 if (!isConnected()) {
00181 return err(errmsg, tr("Socket disconnected while attempting "
00182 "to read a line of data."));
00183 }
00184 waitForReadyRead(READ_TIMEOUT);
00185 }
00186 line.clear();
00187 return readLineData(line, errmsg);
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 bool
00203 ControlSocket::readReply(ControlReply &reply, QString *errmsg)
00204 {
00205 QChar c;
00206 QString line;
00207
00208 if (!isConnected()) {
00209 return false;
00210 }
00211
00212
00213 do {
00214
00215 if (!readLine(line, errmsg)) {
00216 return false;
00217 }
00218
00219 if (line.length() < 4) {
00220 return err(errmsg, tr("Invalid control reply. [%1]").arg(line));
00221 }
00222
00223
00224 ReplyLine replyLine(line.mid(0, 3), line.mid(4));
00225 c = line.at(3);
00226
00227
00228
00229 if (c == QChar('+')) {
00230 while (true) {
00231 if (!readLine(line, errmsg)) {
00232 return false;
00233 }
00234 if (line.trimmed() == ".") {
00235 break;
00236 }
00237 replyLine.appendData(line);
00238 }
00239 }
00240 reply.appendLine(replyLine);
00241 } while (c != QChar(' '));
00242 return true;
00243 }
00244