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 1255 2006-10-01 23:12:42Z edmanm $
00025  * \brief Parses and dispatches events from Tor
00026  */
00027 
00028 #include <QApplication>
00029 
00030 #include "circuit.h"
00031 #include "stream.h"
00032 #include "torevents.h"
00033 
00034 
00035 /** Default constructor */
00036 TorEvents::TorEvents()
00037 {
00038 }
00039 
00040 /** Adds an event and interested object to the list */
00041 void
00042 TorEvents::add(TorEvent e, QObject *obj)
00043 {
00044   if (!_eventList.values(e).contains(obj)) {
00045     _eventList.insert(e, obj);
00046   }
00047 }
00048 
00049 /** Removes an event and object from the event list */
00050 void
00051 TorEvents::remove(TorEvent e, QObject *obj)
00052 {
00053   int i;
00054   if ((i = _eventList.values(e).indexOf(obj)) >= 0) {
00055     _eventList.values(e).removeAt(i);
00056     if (_eventList.values(e).size() == 0) {
00057       _eventList.remove(e);
00058     }
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     default: event = "UNKNOWN"; break;
00105   }
00106   return event;
00107 }
00108 
00109 /** Converts a log severity to its related Tor event */
00110 TorEvents::TorEvent
00111 TorEvents::toTorEvent(LogEvent::Severity severity)
00112 {
00113   TorEvent e;
00114   switch (severity) {
00115     case LogEvent::Debug:  e = LogDebug; break;
00116     case LogEvent::Info:   e = LogInfo; break;
00117     case LogEvent::Notice: e = LogNotice; break;
00118     case LogEvent::Warn:   e = LogWarn; break;
00119     case LogEvent::Error:  e = LogError; break;
00120     default: e = Unknown; break;
00121   }
00122   return e;
00123 }
00124 
00125 /** Converts an event in the string form sent by Tor to its enum value */
00126 TorEvents::TorEvent
00127 TorEvents::toTorEvent(QString event)
00128 {
00129   TorEvent e;
00130   event = event.toUpper();
00131   if (event == "BW") {
00132     e = Bandwidth;
00133   } else if (event == "CIRC") {
00134     e = CircuitStatus;
00135   } else if (event == "STREAM") {
00136     e = StreamStatus;
00137   } else if (event == "DEBUG") {
00138     e = LogDebug;
00139   } else if (event == "NOTICE") {
00140     e = LogNotice;
00141   } else if (event == "INFO") {
00142     e = LogInfo;
00143   } else if (event == "NOTICE") {
00144     e = LogNotice;
00145   } else if (event == "WARN") {
00146     e = LogWarn;
00147   } else if (event == "ERR") {
00148     e = LogError;
00149   } else if (event == "ORCONN") {
00150     e = OrConnStatus;
00151   } else if (event == "NEWDESC") {
00152     e = NewDescriptor;
00153   } else {
00154     e = Unknown;
00155   }
00156   return e;
00157 }
00158 
00159 /** Parse the event type out of a message line and return the corresponding
00160  * Event enum value */
00161 TorEvents::TorEvent
00162 TorEvents::parseEventType(ReplyLine line)
00163 {
00164   QString msg = line.getMessage();
00165   int i = msg.indexOf(" ");
00166   return toTorEvent(msg.mid(0, i));
00167 }
00168 
00169 /** Handles an event message from Tor. An event message can potentially have
00170  * more than one line, so we will iterate through them all and dispatch the
00171  * necessary events. */
00172 void
00173 TorEvents::handleEvent(ControlReply reply)
00174 {
00175   foreach(ReplyLine line, reply.getLines()) {
00176     switch (parseEventType(line)) {
00177       case Bandwidth:      handleBandwidthUpdate(line); break;
00178       case CircuitStatus:  handleCircuitStatus(line); break;
00179       case StreamStatus:   handleStreamStatus(line); break;
00180       case OrConnStatus:   handleOrConnStatus(line); break;
00181       case NewDescriptor:  handleNewDescriptor(line); break;
00182 
00183       case LogDebug: 
00184       case LogInfo:
00185       case LogNotice:
00186       case LogWarn:
00187       case LogError:
00188         handleLogMessage(line); break;
00189       default: break;
00190     }
00191   }
00192 }
00193 
00194 /** Handle a bandwidth update event, to inform the controller of the bandwidth
00195  * used in the last second. The format of this message is:
00196  *
00197  *     "650" SP "BW" SP BytesRead SP BytesWritten
00198  *     BytesRead = 1*DIGIT
00199  *     BytesWritten = 1*DIGIT
00200  */
00201 void
00202 TorEvents::handleBandwidthUpdate(ReplyLine line)
00203 {
00204   QStringList msg = line.getMessage().split(" ");
00205   if (msg.size() >= 3) {
00206     quint64 bytesIn = (quint64)msg.at(1).toULongLong();
00207     quint64 bytesOut = (quint64)msg.at(2).toULongLong();
00208   
00209     /* Post the event to each of the interested targets */
00210     dispatch(Bandwidth, new BandwidthEvent(bytesIn, bytesOut));
00211   }
00212 }
00213 
00214 /** Handle a circuit status event. The format of this message is:
00215  *
00216  *    "650" SP "CIRC" SP CircuitID SP CircStatus SP Path
00217  *    CircStatus =
00218  *             "LAUNCHED" / ; circuit ID assigned to new circuit
00219  *             "BUILT"    / ; all hops finished, can now accept streams
00220  *             "EXTENDED" / ; one more hop has been completed
00221  *             "FAILED"   / ; circuit closed (was not built)
00222  *             "CLOSED"     ; circuit closed (was built)
00223  *    Path = ServerID *("," ServerID)
00224  */
00225 void
00226 TorEvents::handleCircuitStatus(ReplyLine line)
00227 {
00228   QString msg = line.getMessage().trimmed();
00229   int i = msg.indexOf(" ") + 1;
00230   if (i > 0) {
00231     /* Post the event to each of the interested targets */
00232     dispatch(CircuitStatus, new CircuitEvent(Circuit::fromString(msg.mid(i))));
00233   }
00234 }
00235 
00236 /** Handle a stream status event. The format of this message is:
00237  *     
00238  *    "650" SP "STREAM" SP StreamID SP StreamStatus SP CircID SP Target SP 
00239  *     StreamStatus =
00240  *                 "NEW"          / ; New request to connect
00241  *                 "NEWRESOLVE"   / ; New request to resolve an address
00242  *                 "SENTCONNECT"  / ; Sent a connect cell along a circuit
00243  *                 "SENTRESOLVE"  / ; Sent a resolve cell along a circuit
00244  *                 "SUCCEEDED"    / ; Received a reply; stream established
00245  *                 "FAILED"       / ; Stream failed and not retriable.
00246  *                 "CLOSED"       / ; Stream closed
00247  *                 "DETACHED"       ; Detached from circuit; still retriable.
00248  *      Target = Address ":" Port
00249  *
00250  *  If the circuit ID is 0, then the stream is unattached.      
00251  */
00252 void
00253 TorEvents::handleStreamStatus(ReplyLine line)
00254 {
00255   QString msg = line.getMessage().trimmed();
00256   int i  = msg.indexOf(" ") + 1;
00257   if (i > 0) {
00258     /* Post the event to each of the interested targets */
00259     dispatch(StreamStatus, new StreamEvent(Stream::fromString(msg.mid(i))));
00260   }
00261 }
00262 
00263 /** Handle a log message event. The format of this message is:
00264  *  The syntax is:
00265  *
00266  *     "650" SP Severity SP ReplyText
00267  *       or
00268  *     "650+" Severity CRLF Data
00269  *     Severity = "DEBUG" / "INFO" / "NOTICE" / "WARN"/ "ERR"
00270  */
00271 void
00272 TorEvents::handleLogMessage(ReplyLine line)
00273 {
00274   QString msg = line.getMessage();
00275   int i = msg.indexOf(" ");
00276   LogEvent::Severity severity = LogEvent::toSeverity(msg.mid(0, i));
00277   QString logLine = (line.getData().size() > 0 ? line.getData().join("\n") :
00278                                                  msg.mid(i+1));
00279 
00280   /* Post the event to each of the interested targets */
00281   dispatch(toTorEvent(severity), new LogEvent(severity, logLine.trimmed()));
00282 }
00283 
00284 /** Handle an OR Connection Status event. The syntax is:
00285  *     "650" SP "ORCONN" SP (ServerID / Target) SP ORStatus
00286  *
00287  *     ORStatus = "NEW" / "LAUNCHED" / "CONNECTED" / "FAILED" / "CLOSED"
00288  *
00289  *     NEW is for incoming connections, and LAUNCHED is for outgoing
00290  *     connections. CONNECTED means the TLS handshake has finished (in
00291  *     either direction). FAILED means a connection is being closed
00292  *     that hasn't finished its handshake, and CLOSED is for connections
00293  *     that have handshaked.
00294  *
00295  *     A ServerID is specified unless it's a NEW connection, in which
00296  *     case we don't know what server it is yet, so we use Address:Port.
00297  */
00298 void
00299 TorEvents::handleOrConnStatus(ReplyLine line)
00300 {
00301   QStringList msg = line.getMessage().split(" ");
00302   if (msg.size() >= 3) {
00303     dispatch(OrConnStatus, 
00304       new OrConnEvent(OrConnEvent::toStatus(msg.at(2)), msg.at(1)));
00305   }
00306 }
00307 
00308 /** Handles a new descriptor event. The format for event messages of this type
00309  * is:
00310  *  
00311  *   "650" SP "NEWDESC" 1*(SP ServerID)
00312  */
00313 void
00314 TorEvents::handleNewDescriptor(ReplyLine line)
00315 {
00316   QString descs = line.getMessage();
00317   QStringList descList = descs.mid(descs.indexOf(" ")+1).split(" ");
00318   if (descList.size() > 0) {
00319     dispatch(NewDescriptor, new NewDescriptorEvent(descList));
00320   }
00321 }
00322 

Generated on Mon Oct 23 20:08:16 2006 for Vidalia by  doxygen 1.5.0