torevents.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If 
00004 **  you did not receive the LICENSE file with this file, you may obtain it
00005 **  from the Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to
00008 **  the terms described in the LICENSE file.
00009 */
00010 
00011 /* 
00012 ** \file torevents.cpp
00013 ** \version $Id: torevents.cpp 2780 2008-06-21 21:48:32Z edmanm $
00014 ** \brief Parses and dispatches events from Tor
00015 */
00016 
00017 #include <QApplication>
00018 #include <stringutil.h>
00019 
00020 #include "circuit.h"
00021 #include "stream.h"
00022 #include "torevents.h"
00023 #include "unrecognizedserverstatusevent.h"
00024 #include "unrecognizedclientstatusevent.h"
00025 #include "unrecognizedgeneralstatusevent.h"
00026 #include "circuitestablishedevent.h"
00027 #include "dangerousversionevent.h"
00028 #include "bootstrapstatusevent.h"
00029 
00030 /** Format of expiry times in address map events. */
00031 #define DATE_FMT "\"yyyy-MM-dd HH:mm:ss\""
00032 
00033 
00034 /** Default constructor */
00035 TorEvents::TorEvents()
00036 {
00037 }
00038 
00039 /** Adds an event and interested object to the list */
00040 void
00041 TorEvents::add(TorEvent e, QObject *obj)
00042 {
00043   if (!_eventList.values(e).contains(obj)) {
00044     _eventList.insert(e, obj);
00045   }
00046 }
00047 
00048 /** Removes <b>obj</b> from the list of target objects for event <b>e</b>. */
00049 void
00050 TorEvents::remove(TorEvent e, QObject *obj)
00051 {
00052   QMultiHash<TorEvent,QObject*>::iterator i = _eventList.find(e);
00053   while (i != _eventList.end() && i.key() == e) {
00054     if (i.value() == obj) {
00055       _eventList.erase(i);
00056       break;
00057     }
00058     i++;
00059   }
00060 }
00061 
00062 /** Returns true if an event has any registered handlers */
00063 bool
00064 TorEvents::contains(TorEvent event)
00065 {
00066   if (_eventList.contains(event)) {
00067     return (_eventList.values(event).count() > 0);
00068   }
00069   return false;
00070 }
00071 
00072 /** Returns the list of events in which we're interested */
00073 QList<TorEvents::TorEvent>
00074 TorEvents::eventList()
00075 {
00076   return _eventList.keys();
00077 }
00078 
00079 /** Dispatches a given event to all its handler targets. */
00080 void
00081 TorEvents::dispatch(TorEvent e, QEvent *event)
00082 {
00083   foreach (QObject *obj, _eventList.values(e)) {
00084     QApplication::postEvent(obj, event);
00085   }
00086 }
00087 
00088 /** Converts an event type to a string Tor understands */
00089 QString
00090 TorEvents::toString(TorEvent e)
00091 {
00092   QString event;
00093   switch (e) {
00094     case Bandwidth: event = "BW"; break;
00095     case LogDebug:  event = "DEBUG"; break;
00096     case LogInfo:   event = "INFO"; break;
00097     case LogNotice: event = "NOTICE"; break;
00098     case LogWarn:   event = "WARN"; break;
00099     case LogError:  event = "ERR"; break;
00100     case CircuitStatus:   event = "CIRC"; break;
00101     case StreamStatus:    event = "STREAM"; break;
00102     case OrConnStatus:    event = "ORCONN"; break;
00103     case NewDescriptor:   event = "NEWDESC"; break;
00104     case AddressMap:      event = "ADDRMAP"; break;
00105     case GeneralStatus:   event = "STATUS_GENERAL"; break;
00106     case ClientStatus:    event = "STATUS_CLIENT"; break;
00107     case ServerStatus:    event = "STATUS_SERVER"; break;
00108     default: event = "UNKNOWN"; break;
00109   }
00110   return event;
00111 }
00112 
00113 /** Converts a log severity to its related Tor event */
00114 TorEvents::TorEvent
00115 TorEvents::toTorEvent(LogEvent::Severity severity)
00116 {
00117   TorEvent e;
00118   switch (severity) {
00119     case LogEvent::Debug:  e = LogDebug; break;
00120     case LogEvent::Info:   e = LogInfo; break;
00121     case LogEvent::Notice: e = LogNotice; break;
00122     case LogEvent::Warn:   e = LogWarn; break;
00123     case LogEvent::Error:  e = LogError; break;
00124     default: e = Unknown; break;
00125   }
00126   return e;
00127 }
00128 
00129 /** Converts an event in the string form sent by Tor to its enum value */
00130 TorEvents::TorEvent
00131 TorEvents::toTorEvent(const QString &event)
00132 {
00133   TorEvent e;
00134   if (event == "BW") {
00135     e = Bandwidth;
00136   } else if (event == "CIRC") {
00137     e = CircuitStatus;
00138   } else if (event == "STREAM") {
00139     e = StreamStatus;
00140   } else if (event == "DEBUG") {
00141     e = LogDebug;
00142   } else if (event == "INFO") {
00143     e = LogInfo;
00144   } else if (event == "NOTICE") {
00145     e = LogNotice;
00146   } else if (event == "WARN") {
00147     e = LogWarn;
00148   } else if (event == "ERR") {
00149     e = LogError;
00150   } else if (event == "NEWDESC") {
00151     e = NewDescriptor;
00152   } else if (event == "ADDRMAP") {
00153     e = AddressMap;
00154   } else if (event == "STATUS_GENERAL") {
00155     e = GeneralStatus;
00156   } else if (event == "STATUS_CLIENT") {
00157     e = ClientStatus;
00158   } else if (event == "STATUS_SERVER") {
00159     e = ServerStatus;
00160   } else if (event == "ORCONN") {
00161     e = OrConnStatus;
00162   } else {
00163     e = Unknown;
00164   }
00165   return e;
00166 }
00167 
00168 /** Parse the event type out of a message line and return the corresponding
00169  * Event enum value */
00170 TorEvents::TorEvent
00171 TorEvents::parseEventType(const ReplyLine &line)
00172 {
00173   QString msg = line.getMessage();
00174   int i = msg.indexOf(" ");
00175   return toTorEvent(msg.mid(0, i));
00176 }
00177 
00178 /** Handles an event message from Tor. An event message can potentially have
00179  * more than one line, so we will iterate through them all and dispatch the
00180  * necessary events. */
00181 void
00182 TorEvents::handleEvent(const ControlReply &reply)
00183 {
00184   foreach(ReplyLine line, reply.getLines()) {
00185     switch (parseEventType(line)) {
00186       case Bandwidth:      handleBandwidthUpdate(line); break;
00187       case CircuitStatus:  handleCircuitStatus(line); break;
00188       case StreamStatus:   handleStreamStatus(line); break;
00189       case OrConnStatus:   handleOrConnStatus(line); break;
00190       case NewDescriptor:  handleNewDescriptor(line); break;
00191       case AddressMap:     handleAddressMap(line); break;
00192 
00193       case GeneralStatus:
00194         handleStatusEvent(GeneralStatus, line); break;
00195       case ClientStatus:
00196         handleStatusEvent(ClientStatus, line); break;
00197       case ServerStatus:
00198         handleStatusEvent(ServerStatus, line); break;
00199 
00200       case LogDebug: 
00201       case LogInfo:
00202       case LogNotice:
00203       case LogWarn:
00204       case LogError:
00205         handleLogMessage(line); break;
00206       default: break;
00207     }
00208   }
00209 }
00210 
00211 /** Handle a bandwidth update event, to inform the controller of the bandwidth
00212  * used in the last second. The format of this message is:
00213  *
00214  *     "650" SP "BW" SP BytesRead SP BytesWritten
00215  *     BytesRead = 1*DIGIT
00216  *     BytesWritten = 1*DIGIT
00217  */
00218 void
00219 TorEvents::handleBandwidthUpdate(const ReplyLine &line)
00220 {
00221   QStringList msg = line.getMessage().split(" ");
00222   if (msg.size() >= 3) {
00223     quint64 bytesIn = (quint64)msg.at(1).toULongLong();
00224     quint64 bytesOut = (quint64)msg.at(2).toULongLong();
00225   
00226     /* Post the event to each of the interested targets */
00227     dispatch(Bandwidth, new BandwidthEvent(bytesIn, bytesOut));
00228   }
00229 }
00230 
00231 /** Handle a circuit status event. The format of this message is:
00232  *
00233  *    "650" SP "CIRC" SP CircuitID SP CircStatus SP Path
00234  *    CircStatus =
00235  *             "LAUNCHED" / ; circuit ID assigned to new circuit
00236  *             "BUILT"    / ; all hops finished, can now accept streams
00237  *             "EXTENDED" / ; one more hop has been completed
00238  *             "FAILED"   / ; circuit closed (was not built)
00239  *             "CLOSED"     ; circuit closed (was built)
00240  *    Path = ServerID *("," ServerID)
00241  */
00242 void
00243 TorEvents::handleCircuitStatus(const ReplyLine &line)
00244 {
00245   QString msg = line.getMessage().trimmed();
00246   int i = msg.indexOf(" ") + 1;
00247   if (i > 0) {
00248     /* Post the event to each of the interested targets */
00249     Circuit circ(msg.mid(i));
00250     if (circ.isValid())
00251       dispatch(CircuitStatus, new CircuitEvent(circ));
00252   }
00253 }
00254 
00255 /** Handle a stream status event. The format of this message is:
00256  *     
00257  *    "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target SP 
00258  *     StreamStatus =
00259  *                 "NEW"          / ; New request to connect
00260  *                 "NEWRESOLVE"   / ; New request to resolve an address
00261  *                 "SENTCONNECT"  / ; Sent a connect cell along a circuit
00262  *                 "SENTRESOLVE"  / ; Sent a resolve cell along a circuit
00263  *                 "SUCCEEDED"    / ; Received a reply; stream established
00264  *                 "FAILED"       / ; Stream failed and not retriable.
00265  *                 "CLOSED"       / ; Stream closed
00266  *                 "DETACHED"       ; Detached from circuit; still retriable.
00267  *      Target = Address ":" Port
00268  *
00269  *  If the circuit ID is 0, then the stream is unattached.      
00270  */
00271 void
00272 TorEvents::handleStreamStatus(const ReplyLine &line)
00273 {
00274   QString msg = line.getMessage().trimmed();
00275   int i  = msg.indexOf(" ") + 1;
00276   if (i > 0) {
00277     /* Post the event to each of the interested targets */
00278     dispatch(StreamStatus, new StreamEvent(Stream::fromString(msg.mid(i))));
00279   }
00280 }
00281 
00282 /** Handle a log message event. The format of this message is:
00283  *  The syntax is:
00284  *
00285  *     "650" SP Severity SP ReplyText
00286  *       or
00287  *     "650+" Severity CRLF Data
00288  *     Severity = "DEBUG" / "INFO" / "NOTICE" / "WARN"/ "ERR"
00289  */
00290 void
00291 TorEvents::handleLogMessage(const ReplyLine &line)
00292 {
00293   QString msg = line.getMessage();
00294   int i = msg.indexOf(" ");
00295   LogEvent::Severity severity = LogEvent::toSeverity(msg.mid(0, i));
00296   QString logLine = (line.getData().size() > 0 ? line.getData().join("\n") :
00297                                                  msg.mid(i+1));
00298 
00299   dispatch(toTorEvent(severity), new LogEvent(severity, logLine));
00300 }
00301 
00302 /** Handle an OR Connection Status event. The syntax is:
00303  *     "650" SP "ORCONN" SP (ServerID / Target) SP ORStatus
00304  *
00305  *     ORStatus = "NEW" / "LAUNCHED" / "CONNECTED" / "FAILED" / "CLOSED"
00306  *
00307  *     NEW is for incoming connections, and LAUNCHED is for outgoing
00308  *     connections. CONNECTED means the TLS handshake has finished (in
00309  *     either direction). FAILED means a connection is being closed
00310  *     that hasn't finished its handshake, and CLOSED is for connections
00311  *     that have handshaked.
00312  *
00313  *     A ServerID is specified unless it's a NEW connection, in which
00314  *     case we don't know what server it is yet, so we use Address:Port.
00315  */
00316 void
00317 TorEvents::handleOrConnStatus(const ReplyLine &line)
00318 {
00319   QStringList msg = line.getMessage().split(" ");
00320   if (msg.size() >= 3) {
00321     dispatch(OrConnStatus, 
00322       new OrConnEvent(OrConnEvent::toStatus(msg.at(2)), msg.at(1)));
00323   }
00324 }
00325 
00326 /** Handles a new descriptor event. The format for event messages of this type
00327  * is:
00328  *  
00329  *   "650" SP "NEWDESC" 1*(SP ServerID)
00330  */
00331 void
00332 TorEvents::handleNewDescriptor(const ReplyLine &line)
00333 {
00334   QString descs = line.getMessage();
00335   QStringList descList = descs.mid(descs.indexOf(" ")+1).split(" ");
00336   if (descList.size() > 0) {
00337     dispatch(NewDescriptor, new NewDescriptorEvent(descList));
00338   }
00339 }
00340 
00341 /** Handles a new or updated address mapping event. The format for event
00342  * messages of this type is:
00343  *
00344  *   "650" SP "ADDRMAP" SP Address SP Address SP Expiry
00345  *   Expiry = DQUOTE ISOTime DQUOTE / "NEVER"
00346  *
00347  *   Expiry is expressed as the local time (rather than GMT).
00348  */
00349 void
00350 TorEvents::handleAddressMap(const ReplyLine &line)
00351 {
00352   QStringList msg = line.getMessage().split(" ");
00353   if (msg.size() >= 4) {
00354     QDateTime expires;
00355     if (msg.size() >= 5 && msg.at(3) != "NEVER")
00356       expires = QDateTime::fromString(msg.at(3) + " " + msg.at(4), DATE_FMT);
00357     dispatch(AddressMap, new AddressMapEvent(msg.at(1), msg.at(2), expires));
00358   }
00359 }
00360 
00361 /** Handles a Tor status event. The format for event messages of this type is:
00362  *
00363  *  "650" SP StatusType SP StatusSeverity SP StatusAction
00364  *                                           [SP StatusArguments] CRLF
00365  *
00366  *  StatusType = "STATUS_GENERAL" / "STATUS_CLIENT" / "STATUS_SERVER"
00367  *  StatusSeverity = "NOTICE" / "WARN" / "ERR"
00368  *  StatusAction = 1*ALPHA
00369  *  StatusArguments = StatusArgument *(SP StatusArgument)
00370  *  StatusArgument = StatusKeyword '=' StatusValue
00371  *  StatusKeyword = 1*(ALNUM / "_")
00372  *  StatusValue = 1*(ALNUM / '_')  / QuotedString
00373  */
00374 void
00375 TorEvents::handleStatusEvent(TorEvent type, const ReplyLine &line)
00376 {
00377   QString status;
00378   tc::Severity severity;
00379   QHash<QString,QString> args;
00380   QString msg = line.getMessage();
00381   
00382   severity = tc::toSeverity(msg.section(' ', 1, 1));
00383   status   = msg.section(' ', 2, 2);
00384   args     = string_parse_keyvals(msg.section(' ', 3));
00385   switch (type) {
00386     case ClientStatus:
00387       dispatchClientStatusEvent(severity, status, args); break;
00388     case ServerStatus:
00389       dispatchServerStatusEvent(severity, status, args); break;
00390     default:
00391       dispatchGeneralStatusEvent(severity, status, args);
00392   }
00393 }
00394 
00395 /** Parses and posts a Tor client status event. */
00396 void
00397 TorEvents::dispatchClientStatusEvent(tc::Severity severity,
00398                                      const QString &action,
00399                                      const QHash<QString,QString> &args)
00400 {
00401   ClientStatusEvent *event;
00402   ClientStatusEvent::Status status 
00403     = ClientStatusEvent::statusFromString(action);
00404 
00405   switch (status) {
00406     case ClientStatusEvent::CircuitEstablished:
00407       event = new CircuitEstablishedEvent(severity); break;
00408     
00409     case ClientStatusEvent::Bootstrap:
00410       event = new BootstrapStatusEvent(BootstrapStatus(severity,
00411                     BootstrapStatus::statusFromString(args.value("TAG")),
00412                     args.value("PROGRESS").toInt(),
00413                     args.value("SUMMARY"),
00414                     args.value("WARNING"),
00415                     tc::toConnectionStatusReason(args.value("REASON")),
00416                     BootstrapStatus::actionFromString(
00417                       args.value("RECOMMENDATION"))));
00418 
00419       break;
00420 
00421     default:
00422       event = new UnrecognizedClientStatusEvent(severity, action, args);
00423   }
00424   dispatch(ClientStatus, event);
00425 }
00426 
00427 /** Parses and posts a Tor server status event. */
00428 void
00429 TorEvents::dispatchServerStatusEvent(tc::Severity severity,
00430                                      const QString &action,
00431                                      const QHash<QString,QString> &args)
00432 {
00433   ServerStatusEvent *event;
00434   ServerStatusEvent::Status status
00435     = ServerStatusEvent::statusFromString(action);
00436 
00437   switch (status) {
00438     default:
00439       event = new UnrecognizedServerStatusEvent(severity, action, args);
00440   }
00441   dispatch(ServerStatus, event);
00442 }
00443 
00444 /** Parses and posts a general Tor status event. */
00445 void
00446 TorEvents::dispatchGeneralStatusEvent(tc::Severity severity,
00447                                       const QString &action,
00448                                       const QHash<QString,QString> &args)
00449 {
00450   GeneralStatusEvent *event;
00451   GeneralStatusEvent::Status status
00452     = GeneralStatusEvent::statusFromString(action);
00453 
00454   switch (status) {
00455     case GeneralStatusEvent::DangerousTorVersion:
00456       /* Dangerous Tor version ("DANGEROUS_VERSION") */
00457       event = new DangerousVersionEvent(severity,
00458                 DangerousVersionEvent::reasonFromString(args.value("REASON")),
00459                 args.value("CURRENT"),
00460                 args.value("RECOMMENDED").split(",", QString::SkipEmptyParts));
00461       break;
00462     default:
00463       event = new UnrecognizedGeneralStatusEvent(severity, action, args);
00464   }
00465   dispatch(GeneralStatus, event);
00466 }
00467 

Generated on Wed Nov 26 21:02:42 2008 for Vidalia by  doxygen 1.5.7.1