torevents.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 torevents.cpp
00024  * \version $Id: torevents.cpp 1797 2007-07-03 01:30:35Z edmanm $
00025  * \brief Parses and dispatches events from Tor
00026  */
00027 
00028 #include <QApplication>
00029 
00030 #include <vidalia.h>
00031 
00032 #include "circuit.h"
00033 #include "stream.h"
00034 #include "torevents.h"
00035 
00036 /** Format of expiry times in address map events. */
00037 #define DATE_FMT "\"yyyy-MM-dd HH:mm:ss\""
00038 
00039 
00040 /** Default constructor */
00041 TorEvents::TorEvents()
00042 {
00043 }
00044 
00045 /** Adds an event and interested object to the list */
00046 void
00047 TorEvents::add(TorEvent e, QObject *obj)
00048 {
00049   if (!_eventList.values(e).contains(obj)) {
00050     _eventList.insert(e, obj);
00051   }
00052 }
00053 
00054 /** Removes <b>obj</b> from the list of target objects for event <b>e</b>. */
00055 void
00056 TorEvents::remove(TorEvent e, QObject *obj)
00057 {
00058   QMultiHash<TorEvent,QObject*>::iterator i = _eventList.find(e);
00059   while (i != _eventList.end() && i.key() == e) {
00060     if (i.value() == obj) {
00061       _eventList.erase(i);
00062       break;
00063     }
00064     i++;
00065   }
00066 }
00067 
00068 /** Returns true if an event has any registered handlers */
00069 bool
00070 TorEvents::contains(TorEvent event)
00071 {
00072   if (_eventList.contains(event)) {
00073     return (_eventList.values(event).count() > 0);
00074   }
00075   return false;
00076 }
00077 
00078 /** Returns the list of events in which we're interested */
00079 QList<TorEvents::TorEvent>
00080 TorEvents::eventList()
00081 {
00082   return _eventList.keys();
00083 }
00084 
00085 /** Dispatches a given event to all its handler targets. */
00086 void
00087 TorEvents::dispatch(TorEvent e, QEvent *event)
00088 {
00089   foreach (QObject *obj, _eventList.values(e)) {
00090     QApplication::postEvent(obj, event);
00091   }
00092 }
00093 
00094 /** Converts an event type to a string Tor understands */
00095 QString
00096 TorEvents::toString(TorEvent e)
00097 {
00098   QString event;
00099   switch (e) {
00100     case Bandwidth: event = "BW"; break;
00101     case LogDebug:  event = "DEBUG"; break;
00102     case LogInfo:   event = "INFO"; break;
00103     case LogNotice: event = "NOTICE"; break;
00104     case LogWarn:   event = "WARN"; break;
00105     case LogError:  event = "ERR"; break;
00106     case CircuitStatus:   event = "CIRC"; break;
00107     case StreamStatus:    event = "STREAM"; break;
00108     case OrConnStatus:    event = "ORCONN"; break;
00109     case NewDescriptor:   event = "NEWDESC"; break;
00110     case AddressMap:      event = "ADDRMAP"; break;
00111     default: event = "UNKNOWN"; break;
00112   }
00113   return event;
00114 }
00115 
00116 /** Converts a log severity to its related Tor event */
00117 TorEvents::TorEvent
00118 TorEvents::toTorEvent(LogEvent::Severity severity)
00119 {
00120   TorEvent e;
00121   switch (severity) {
00122     case LogEvent::Debug:  e = LogDebug; break;
00123     case LogEvent::Info:   e = LogInfo; break;
00124     case LogEvent::Notice: e = LogNotice; break;
00125     case LogEvent::Warn:   e = LogWarn; break;
00126     case LogEvent::Error:  e = LogError; break;
00127     default: e = Unknown; break;
00128   }
00129   return e;
00130 }
00131 
00132 /** Converts an event in the string form sent by Tor to its enum value */
00133 TorEvents::TorEvent
00134 TorEvents::toTorEvent(QString event)
00135 {
00136   TorEvent e;
00137   event = event.toUpper();
00138   if (event == "BW") {
00139     e = Bandwidth;
00140   } else if (event == "CIRC") {
00141     e = CircuitStatus;
00142   } else if (event == "STREAM") {
00143     e = StreamStatus;
00144   } else if (event == "DEBUG") {
00145     e = LogDebug;
00146   } else if (event == "INFO") {
00147     e = LogInfo;
00148   } else if (event == "NOTICE") {
00149     e = LogNotice;
00150   } else if (event == "WARN") {
00151     e = LogWarn;
00152   } else if (event == "ERR") {
00153     e = LogError;
00154   } else if (event == "ORCONN") {
00155     e = OrConnStatus;
00156   } else if (event == "NEWDESC") {
00157     e = NewDescriptor;
00158   } else if (event == "ADDRMAP") {
00159     e = AddressMap;
00160   } else {
00161     e = Unknown;
00162   }
00163   return e;
00164 }
00165 
00166 /** Parse the event type out of a message line and return the corresponding
00167  * Event enum value */
00168 TorEvents::TorEvent
00169 TorEvents::parseEventType(ReplyLine line)
00170 {
00171   QString msg = line.getMessage();
00172   int i = msg.indexOf(" ");
00173   return toTorEvent(msg.mid(0, i));
00174 }
00175 
00176 /** Handles an event message from Tor. An event message can potentially have
00177  * more than one line, so we will iterate through them all and dispatch the
00178  * necessary events. */
00179 void
00180 TorEvents::handleEvent(ControlReply reply)
00181 {
00182   foreach(ReplyLine line, reply.getLines()) {
00183     switch (parseEventType(line)) {
00184       case Bandwidth:      handleBandwidthUpdate(line); break;
00185       case CircuitStatus:  handleCircuitStatus(line); break;
00186       case StreamStatus:   handleStreamStatus(line); break;
00187       case OrConnStatus:   handleOrConnStatus(line); break;
00188       case NewDescriptor:  handleNewDescriptor(line); break;
00189       case AddressMap:     handleAddressMap(line); break;
00190 
00191       case LogDebug: 
00192       case LogInfo:
00193       case LogNotice:
00194       case LogWarn:
00195       case LogError:
00196         handleLogMessage(line); break;
00197       default: break;
00198     }
00199   }
00200 }
00201 
00202 /** Handle a bandwidth update event, to inform the controller of the bandwidth
00203  * used in the last second. The format of this message is:
00204  *
00205  *     "650" SP "BW" SP BytesRead SP BytesWritten
00206  *     BytesRead = 1*DIGIT
00207  *     BytesWritten = 1*DIGIT
00208  */
00209 void
00210 TorEvents::handleBandwidthUpdate(ReplyLine line)
00211 {
00212   QStringList msg = line.getMessage().split(" ");
00213   if (msg.size() >= 3) {
00214     quint64 bytesIn = (quint64)msg.at(1).toULongLong();
00215     quint64 bytesOut = (quint64)msg.at(2).toULongLong();
00216   
00217     /* Post the event to each of the interested targets */
00218     dispatch(Bandwidth, new BandwidthEvent(bytesIn, bytesOut));
00219   }
00220 }
00221 
00222 /** Handle a circuit status event. The format of this message is:
00223  *
00224  *    "650" SP "CIRC" SP CircuitID SP CircStatus SP Path
00225  *    CircStatus =
00226  *             "LAUNCHED" / ; circuit ID assigned to new circuit
00227  *             "BUILT"    / ; all hops finished, can now accept streams
00228  *             "EXTENDED" / ; one more hop has been completed
00229  *             "FAILED"   / ; circuit closed (was not built)
00230  *             "CLOSED"     ; circuit closed (was built)
00231  *    Path = ServerID *("," ServerID)
00232  */
00233 void
00234 TorEvents::handleCircuitStatus(ReplyLine line)
00235 {
00236   QString msg = line.getMessage().trimmed();
00237   int i = msg.indexOf(" ") + 1;
00238   if (i > 0) {
00239     /* Post the event to each of the interested targets */
00240     dispatch(CircuitStatus, new CircuitEvent(Circuit::fromString(msg.mid(i))));
00241   }
00242 }
00243 
00244 /** Handle a stream status event. The format of this message is:
00245  *     
00246  *    "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target SP 
00247  *     StreamStatus =
00248  *                 "NEW"          / ; New request to connect
00249  *                 "NEWRESOLVE"   / ; New request to resolve an address
00250  *                 "SENTCONNECT"  / ; Sent a connect cell along a circuit
00251  *                 "SENTRESOLVE"  / ; Sent a resolve cell along a circuit
00252  *                 "SUCCEEDED"    / ; Received a reply; stream established
00253  *                 "FAILED"       / ; Stream failed and not retriable.
00254  *                 "CLOSED"       / ; Stream closed
00255  *                 "DETACHED"       ; Detached from circuit; still retriable.
00256  *      Target = Address ":" Port
00257  *
00258  *  If the circuit ID is 0, then the stream is unattached.      
00259  */
00260 void
00261 TorEvents::handleStreamStatus(ReplyLine line)
00262 {
00263   QString msg = line.getMessage().trimmed();
00264   int i  = msg.indexOf(" ") + 1;
00265   if (i > 0) {
00266     /* Post the event to each of the interested targets */
00267     dispatch(StreamStatus, new StreamEvent(Stream::fromString(msg.mid(i))));
00268   }
00269 }
00270 
00271 /** Handle a log message event. The format of this message is:
00272  *  The syntax is:
00273  *
00274  *     "650" SP Severity SP ReplyText
00275  *       or
00276  *     "650+" Severity CRLF Data
00277  *     Severity = "DEBUG" / "INFO" / "NOTICE" / "WARN"/ "ERR"
00278  */
00279 void
00280 TorEvents::handleLogMessage(ReplyLine line)
00281 {
00282   QString msg = line.getMessage();
00283   int i = msg.indexOf(" ");
00284   LogEvent::Severity severity = LogEvent::toSeverity(msg.mid(0, i));
00285   QString logLine = (line.getData().size() > 0 ? line.getData().join("\n") :
00286                                                  msg.mid(i+1));
00287 
00288   dispatch(toTorEvent(severity), new LogEvent(severity, logLine));
00289 }
00290 
00291 /** Handle an OR Connection Status event. The syntax is:
00292  *     "650" SP "ORCONN" SP (ServerID / Target) SP ORStatus
00293  *
00294  *     ORStatus = "NEW" / "LAUNCHED" / "CONNECTED" / "FAILED" / "CLOSED"
00295  *
00296  *     NEW is for incoming connections, and LAUNCHED is for outgoing
00297  *     connections. CONNECTED means the TLS handshake has finished (in
00298  *     either direction). FAILED means a connection is being closed
00299  *     that hasn't finished its handshake, and CLOSED is for connections
00300  *     that have handshaked.
00301  *
00302  *     A ServerID is specified unless it's a NEW connection, in which
00303  *     case we don't know what server it is yet, so we use Address:Port.
00304  */
00305 void
00306 TorEvents::handleOrConnStatus(ReplyLine line)
00307 {
00308   QStringList msg = line.getMessage().split(" ");
00309   if (msg.size() >= 3) {
00310     dispatch(OrConnStatus, 
00311       new OrConnEvent(OrConnEvent::toStatus(msg.at(2)), msg.at(1)));
00312   }
00313 }
00314 
00315 /** Handles a new descriptor event. The format for event messages of this type
00316  * is:
00317  *  
00318  *   "650" SP "NEWDESC" 1*(SP ServerID)
00319  */
00320 void
00321 TorEvents::handleNewDescriptor(ReplyLine line)
00322 {
00323   QString descs = line.getMessage();
00324   QStringList descList = descs.mid(descs.indexOf(" ")+1).split(" ");
00325   if (descList.size() > 0) {
00326     dispatch(NewDescriptor, new NewDescriptorEvent(descList));
00327   }
00328 }
00329 
00330 /** Handles a new or updated address mapping event. The format for event
00331  * messages of this type is:
00332  *
00333  *   "650" SP "ADDRMAP" SP Address SP Address SP Expiry
00334  *   Expiry = DQUOTE ISOTime DQUOTE / "NEVER"
00335  *
00336  *   Expiry is expressed as the local time (rather than GMT).
00337  */
00338 void
00339 TorEvents::handleAddressMap(ReplyLine line)
00340 {
00341   QStringList msg = line.getMessage().split(" ");
00342   if (msg.size() >= 4) {
00343     QDateTime expires;
00344     if (msg.size() >= 5 && msg.at(3) != "NEVER")
00345       expires = QDateTime::fromString(msg.at(3) + " " + msg.at(4), DATE_FMT);
00346     dispatch(AddressMap, new AddressMapEvent(msg.at(1), msg.at(2), expires));
00347   }
00348 }
00349 

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