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
00029 #include <QDebug>
00030
00031 #include "brisaeventcontroller.h"
00032
00033 using namespace BrisaUpnp;
00034
00035 #ifdef USE_NEW_BRISA_WEBSERVER
00036
00037 BrisaEventController::BrisaEventController(
00038 BrisaCore::BrisaWebserver *sessionManager,
00039 QList<BrisaStateVariable *> *stateVariableList,
00040 QObject *parent) :
00041 BrisaWebService(sessionManager, parent),
00042 variableList(stateVariableList)
00043 {
00044 udpSocket.bind(QHostAddress("239.255.255.246"), 7900);
00045 }
00046
00047 void BrisaEventController::onRequest(const HttpRequest &r,
00048 BrisaWebserverSession *session)
00049 {
00050 if (r.method() == "SUBSCRIBE") {
00051 subscribe(r, session);
00052 } else if (r.method() == "UNSUBSCRIBE") {
00053 unsubscribe(r, session);
00054 }
00055 }
00056
00057 inline void BrisaEventController::subscribe(const HttpRequest &request,
00058 BrisaWebserverSession *session)
00059 {
00060 const QHash<QByteArray, QByteArray> headers = request.headers();
00061 if (headers.contains("SID")) {
00062 if (headers.contains("NT") || headers.contains("CALLBACK")) {
00063 session->respond(HttpResponse(request.httpVersion(),
00064 HttpResponse::BAD_REQUEST,
00065 true));
00066 return;
00067 }
00068
00069 if (headers.value("SID").isEmpty()) {
00070 session->respond(HttpResponse(request.httpVersion(),
00071 HttpResponse::PRECONDITION_FAILED,
00072 true));
00073 return;
00074 }
00075
00076 bool validSubscription = false;
00077 foreach (BrisaEventSubscription *current, subscriptions)
00078 {
00079 if (current->getSid() == headers.value("SID")) {
00080 current->renew(getTimeOut(headers.value("TIMEOUT")));
00081
00082 qDebug()
00083 << "BrisaEventController renewing subscription for "
00084 << headers.value("SID");
00085 validSubscription = true;
00086
00087 session->respond(current->getAcceptSubscriptionResponse());
00088 }
00089 }
00090
00091 if (!validSubscription)
00092 session->respond(HttpResponse(request.httpVersion(),
00093 HttpResponse::PRECONDITION_FAILED));
00094
00095 return;
00096 } else if (headers.contains("NT") && headers.contains("CALLBACK")) {
00097
00098 if (headers.value("NT") != "upnp:event") {
00099 session->respond(HttpResponse(request.httpVersion(),
00100 HttpResponse::PRECONDITION_FAILED));
00101 return;
00102 }
00103
00104 qDebug() << "BrisaEventController received a subscription request:"
00105 " Callback: " << headers.value("CALLBACK") << "- Timeout: "
00106 << headers.value("TIMEOUT");
00107
00108 BrisaEventSubscription *newSubscriber = new BrisaEventSubscription(
00109 getUuid(), getEventUrls(subscriberInfo.value("CALLBACK")),
00110 getTimeOut(subscriberInfo.value("TIMEOUT")));
00111
00112 subscriptions.append(newSubscriber);
00113 session->respond(newSubscriber->getAcceptSubscriptionResponse());
00114
00115 BrisaEventMessage *message = new BrisaEventMessage(*newSubscriber,
00116 this->variableList);
00117 sendEvent(*message, newSubscriber->getUrl());
00118 delete message;
00119
00120 return;
00121 } else {
00122 session->respond(HttpResponse(request.httpVersion()
00123 HttpResponse::PRECONDITION_FAILED));
00124 }
00125 }
00126
00127 inline void BrisaEventController::unsubscribe(const HttpRequest &request,
00128 BrisaWebserverSession *session)
00129 {
00130 const QHash<QByteArray, QByteArray> headers = request.headers();
00131 if (headers.contains("SID")) {
00132 if (headers.contains("NT") || headers.contains("CALLBACK")) {
00133 respond(getErrorHeader(400, ERROR_400_MESSAGE), sessionId,
00134 requestId);
00135 session->respond(HttpResponse(request.httpVersion(),
00136 HttpResponse::BAD_REQUEST));
00137 return;
00138 }
00139
00140 if (headers.value("SID").isEmpty()) {
00141 session->respond(HttpResponse(request.httpVersion(),
00142 HttpResponse::PRECONDITION_FAILED,
00143 true));
00144 return;
00145 }
00146
00147 bool validSubscription = false;
00148 for (int i = 0; i < subscriptions.size(); ++i) {
00149 if (("uuid:" + subscriptions.at(i)->getSid()).toUtf8()
00150 == subscriberInfo.value("SID")) {
00151 session->respond(subscriptions.at(i)
00152 ->getAcceptUnsubscriptionResponse());
00153
00154 delete subscriptions.at(i);
00155 subscriptions.removeAt(i);
00156
00157 qDebug() << "BrisaEventController canceling subscription for "
00158 << headers.value("SID");
00159
00160 validSubscription = true;
00161 }
00162 }
00163
00164 if (!validSubscription)
00165 session->respond(HttpResponse(request.httpVersion(),
00166 HttpResponse::PRECONDITION_FAILED,
00167 true));
00168
00169 } else {
00170 session->respond(HttpResponse(request.httpVersion(),
00171 HttpResponse::PRECONDITION_FAILED));
00172 }
00173 }
00174
00175 void BrisaEventController::sendEvent(const BrisaEventMessage &message, const QUrl &url)
00176 {
00177 QTcpSocket *socket = new QTcpSocket(this);
00178
00179 socket->connectToHost(url.host(), url.port());
00180
00181 connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
00182 connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), socket, SLOT(deleteLater()));
00183 connect(socket, SIGNAL(readyRead()), socket, SLOT(deleteLater()));
00184
00185 socket->write(message.getRequestMessage());
00186
00187 qDebug() << "BrisaEventController sending event to "
00188 << message.getSid() << " at Host: "
00189 << url.host() << ":" << url.port();
00190 }
00191
00192 #else
00193
00194
00195
00196 #define ERROR_400_MESSAGE "Bad Request"
00197 #define ERROR_412_MESSAGE "Precondition Failed"
00198
00199 using namespace BrisaCore;
00200
00201 BrisaEventController::BrisaEventController(
00202 QxtAbstractWebSessionManager *sessionManager,
00203 QList<BrisaStateVariable *> *stateVariableList,
00204 QObject *parent) :
00205 BrisaWebService(sessionManager, parent),
00206 variableList(stateVariableList)
00207 {
00208 QObject::connect(this,
00209 SIGNAL(genericRequestReceived(const QString &,
00210 const QMultiHash<QString, QString> &,
00211 const QByteArray &, int, int)),
00212 this,
00213 SLOT(parseGenericRequest(const QString &,
00214 const QMultiHash<QString, QString> &,
00215 const QByteArray &, int, int))
00216 );
00217 udpSocket.bind(QHostAddress("239.255.255.246"), 7900);
00218 }
00219
00220 void BrisaEventController::parseGenericRequest(const QString &method,
00221 const QMultiHash<QString, QString> &headers,
00222 const QByteArray &requestContent, int sessionId, int requestId)
00223 {
00224 Q_UNUSED(requestContent);
00225
00226 if (method == "SUBSCRIBE") {
00227 subscribe(headers, sessionId, requestId);
00228 } else if (method == "UNSUBSCRIBE") {
00229 unsubscribe(headers, sessionId, requestId);
00230 }
00231 }
00232
00233 void BrisaEventController::subscribe(const QMultiHash<QString, QString> &subscriberInfo,
00234 int sessionId,
00235 int requestId)
00236 {
00237 if (subscriberInfo.contains("SID")) {
00238 if (subscriberInfo.contains("NT")
00239 || subscriberInfo.contains("CALLBACK")) {
00240 respond(getErrorHeader(400, ERROR_400_MESSAGE), sessionId,
00241 requestId);
00242 return;
00243 }
00244
00245 if (subscriberInfo.value("SID") == "") {
00246 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId,
00247 requestId);
00248 return;
00249 }
00250
00251 bool validSubscription = false;
00252 foreach (BrisaEventSubscription *current, this->subscriptions)
00253 {
00254 if (current->getSid() == subscriberInfo.value("SID")) {
00255 current->renew(getTimeOut(subscriberInfo.value("TIMEOUT")));
00256
00257 qDebug()
00258 << "BrisaEventController renewing subscription for "
00259 << subscriberInfo.value("SID");
00260 validSubscription = true;
00261
00262 respond(current->getAcceptSubscriptionResponse(),
00263 sessionId, requestId);
00264 }
00265 }
00266
00267 if (!validSubscription)
00268 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId,
00269 requestId);
00270
00271 return;
00272 } else if (subscriberInfo.contains("NT") && subscriberInfo.contains(
00273 "CALLBACK")) {
00274
00275 if (subscriberInfo.value("NT") != "upnp:event") {
00276 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId,
00277 requestId);
00278 return;
00279 }
00280
00281 qDebug() << "BrisaEventController received a subscription request:"
00282 " Callback: " << subscriberInfo.value("CALLBACK") << "- Timeout: "
00283 << subscriberInfo.value("TIMEOUT");
00284
00285 BrisaEventSubscription *newSubscriber = new BrisaEventSubscription(
00286 getUuid(), getEventUrls(subscriberInfo.value("CALLBACK")),
00287 getTimeOut(subscriberInfo.value("TIMEOUT")));
00288
00289 this->subscriptions.append(newSubscriber);
00290 respond(newSubscriber->getAcceptSubscriptionResponse(), sessionId,
00291 requestId);
00292
00293 BrisaEventMessage *message = new BrisaEventMessage(*newSubscriber,
00294 this->variableList);
00295 sendEvent(*message, newSubscriber->getUrl());
00296 delete message;
00297
00298 return;
00299 } else {
00300 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId, requestId);
00301 }
00302 }
00303
00304 void BrisaEventController::unsubscribe(
00305 const QMultiHash<QString, QString> &subscriberInfo, int sessionId,
00306 int requestId)
00307 {
00308 if (subscriberInfo.contains("SID")) {
00309 if (subscriberInfo.contains("NT")
00310 || subscriberInfo.contains("CALLBACK")) {
00311 respond(getErrorHeader(400, ERROR_400_MESSAGE), sessionId,
00312 requestId);
00313 return;
00314 }
00315
00316 if (subscriberInfo.value("SID") == "") {
00317 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId,
00318 requestId);
00319 return;
00320 }
00321
00322 bool validSubscription = false;
00323 for (int i = 0; i < this->subscriptions.size(); ++i) {
00324 if (("uuid:" + this->subscriptions.at(i)->getSid()) == subscriberInfo.value("SID")) {
00325 respond(this->subscriptions.at(i)->getAcceptUnsubscriptionResponse(),
00326 sessionId, requestId);
00327
00328 delete this->subscriptions.at(i);
00329 this->subscriptions.removeAt(i);
00330
00331 qDebug() << "BrisaEventController canceling subscription for "
00332 << subscriberInfo.value("SID");
00333
00334 validSubscription = true;
00335 }
00336 }
00337
00338 if (!validSubscription)
00339 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId,
00340 requestId);
00341
00342 } else {
00343 respond(getErrorHeader(412, ERROR_412_MESSAGE), sessionId, requestId);
00344 }
00345 }
00346
00347 void BrisaEventController::sendEvent(const BrisaEventMessage &message, const QUrl &url)
00348 {
00349 httpClient.setHost(url.host(), url.port());
00350 httpClient.request(message.getMessageHeader(), message.getMessageBody());
00351
00352 qDebug() << "BrisaEventController sending event to "
00353 << message.getMessageHeader().value("SID") << " at Host: "
00354 << url.host() << ":" << url.port();
00355 }
00356
00357 QHttpResponseHeader BrisaEventController::getErrorHeader(const int &errorCode,
00358 const QString &errorMessage)
00359 {
00360 return QHttpResponseHeader(errorCode, errorMessage);
00361 }
00362
00363 #endif // USE_NEW_BRISA_WEBSERVER
00364
00365 BrisaEventController::~BrisaEventController()
00366 {
00367 while (!this->subscriptions.empty())
00368 delete this->subscriptions.takeFirst();
00369 }
00370
00371 void BrisaEventController::variableChanged(BrisaStateVariable *variable)
00372 {
00373 if (variable->multicastEvents()) {
00374 BrisaMulticastEventMessage message(variable, "upnp:/general");
00375 sendMulticastEvent(message);
00376 }
00377 QList<BrisaStateVariable *> variables;
00378 variables.append(variable);
00379
00380 for (QList<BrisaEventSubscription *>::iterator i = this->subscriptions.begin(); i != this->subscriptions.end(); ++i) {
00381
00382 if ((*i)->hasExpired()) {
00383 qDebug() << "Removing subscription:" << (*i)->getSid();
00384 delete *i;
00385 this->subscriptions.erase(i);
00386 continue;
00387 }
00388 BrisaEventMessage message(*(*i), &variables);
00389 this->sendEvent(message, (*i)->getUrl());
00390 }
00391 }
00392
00393 void BrisaEventController::sendMulticastEvent(const BrisaMulticastEventMessage &message)
00394 {
00395 udpSocket.writeDatagram(message.getMessageHeader().toString().toUtf8() +
00396 message.getMessageBody(),
00397 QHostAddress("239.255.255.246"), 7900);
00398
00399 qDebug() << "BrisaEventController sending multicast event";
00400 }
00401
00402 QStringList BrisaEventController::getEventUrls(const QString &urls)
00403 {
00404 QList<QString> urlList;
00405 QStringList list = urls.split(">", QString::SkipEmptyParts);
00406 list.replaceInStrings("<", "");
00407 return list;
00408 }
00409
00410 int BrisaEventController::getTimeOut(const QString &timeout) {
00411 QString returnTime = timeout;
00412 returnTime.remove("Second-");
00413 bool ok;
00414 return returnTime.toInt(&ok, 10);
00415 }