diff options
Diffstat (limited to 'plugins/upnp/upnpmcastsocket.cpp')
-rw-r--r-- | plugins/upnp/upnpmcastsocket.cpp | 313 |
1 files changed, 0 insertions, 313 deletions
diff --git a/plugins/upnp/upnpmcastsocket.cpp b/plugins/upnp/upnpmcastsocket.cpp deleted file mode 100644 index 0172ed2..0000000 --- a/plugins/upnp/upnpmcastsocket.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005 by Joris Guisson * - * joris.guisson@gmail.com * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#include <kurl.h> -extern "C" { - #include <unistd.h> - inline ssize_t mycread (int __fd, void *__buf, size_t __nbytes) { return read(__fd, __buf, __nbytes); } -}; -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <arpa/inet.h> -#include <netinet/ip.h> -#include <tqstringlist.h> -#include <tdesocketdevice.h> -#include <tdesocketaddress.h> -#include <util/log.h> -#include <torrent/globals.h> -#include <tqfile.h> -#include <tqtextstream.h> -#include "upnpmcastsocket.h" - -using namespace KNetwork; -using namespace bt; - -namespace kt -{ - - UPnPMCastSocket::UPnPMCastSocket(bool verbose) : verbose(verbose) - { - routers.setAutoDelete(true); - TQObject::connect(this,TQT_SIGNAL(readyRead()),this,TQT_SLOT(onReadyRead())); - TQObject::connect(this,TQT_SIGNAL(gotError(int)),this,TQT_SLOT(onError(int))); - setAddressReuseable(true); - setFamily(KNetwork::KResolver::IPv4Family); - setBlocking(true); - for (Uint32 i = 0;i < 10;i++) - { - if (!bind(TQString(),TQString::number(1900 + i))) - Out(SYS_PNP|LOG_IMPORTANT) << "Cannot bind to UDP port 1900" << endl; - else - break; - } - setBlocking(false); - joinUPnPMCastGroup(); - } - - - UPnPMCastSocket::~UPnPMCastSocket() - { - leaveUPnPMCastGroup(); - TQObject::disconnect(this,TQT_SIGNAL(readyRead()),this,TQT_SLOT(onReadyRead())); - TQObject::disconnect(this,TQT_SIGNAL(gotError(int)),this,TQT_SLOT(onError(int))); - } - - void UPnPMCastSocket::discover() - { - Out(SYS_PNP|LOG_NOTICE) << "Trying to find UPnP devices on the local network" << endl; - - // send a HTTP M-SEARCH message to 239.255.255.250:1900 - const char* data = "M-SEARCH * HTTP/1.1\r\n" - "HOST: 239.255.255.250:1900\r\n" - "ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n" - "MAN:\"ssdp:discover\"\r\n" - "MX:3\r\n" - "\r\n\0"; - - if (verbose) - { - Out(SYS_PNP|LOG_NOTICE) << "Sending : " << endl; - Out(SYS_PNP|LOG_NOTICE) << data << endl; - } - - KDatagramSocket::send(KNetwork::KDatagramPacket(data,strlen(data),KInetSocketAddress("239.255.255.250",1900))); - } - - void UPnPMCastSocket::onXmlFileDownloaded(UPnPRouter* r,bool success) - { - if (!success) - { - // we couldn't download and parse the XML file so - // get rid of it - r->deleteLater(); - } - else - { - // add it to the list and emit the signal - if (!routers.contains(r->getServer())) - { - routers.insert(r->getServer(),r); - discovered(r); - } - else - { - r->deleteLater(); - } - } - } - - void UPnPMCastSocket::onReadyRead() - { - if (bytesAvailable() == 0) - { - Out(SYS_PNP|LOG_NOTICE) << "0 byte UDP packet " << endl; - // KDatagramSocket wrongly handles UDP packets with no payload - // so we need to deal with it oursleves - int fd = socketDevice()->socket(); - char tmp; - mycread(fd,&tmp,1); - return; - } - - KNetwork::KDatagramPacket p = KDatagramSocket::receive(); - if (p.isNull()) - return; - - if (verbose) - { - Out(SYS_PNP|LOG_NOTICE) << "Received : " << endl; - Out(SYS_PNP|LOG_NOTICE) << TQString(p.data()) << endl; - } - - // try to make a router of it - UPnPRouter* r = parseResponse(p.data()); - if (r) - { - TQObject::connect(r,TQT_SIGNAL(xmlFileDownloaded( UPnPRouter*, bool )), - this,TQT_SLOT(onXmlFileDownloaded( UPnPRouter*, bool ))); - - // download it's xml file - r->downloadXMLFile(); - } - } - - UPnPRouter* UPnPMCastSocket::parseResponse(const TQByteArray & arr) - { - TQStringList lines = TQStringList::split("\r\n",TQString(arr),false); - TQString server; - KURL location; - - /* - Out(SYS_PNP|LOG_DEBUG) << "Received : " << endl; - for (Uint32 idx = 0;idx < lines.count(); idx++) - Out(SYS_PNP|LOG_DEBUG) << lines[idx] << endl; - */ - - // first read first line and see if contains a HTTP 200 OK message - TQString line = lines.first(); - if (!line.contains("HTTP")) - { - // it is either a 200 OK or a NOTIFY - if (!line.contains("NOTIFY") && !line.contains("200")) - return 0; - } - else if (line.contains("M-SEARCH")) // ignore M-SEARCH - return 0; - - // quick check that the response being parsed is valid - bool validDevice = false; - for (Uint32 idx = 0;idx < lines.count() && !validDevice; idx++) - { - line = lines[idx]; - if ((line.contains("ST:") || line.contains("NT:")) && line.contains("InternetGatewayDevice")) - { - validDevice = true; - } - } - if (!validDevice) - { - // Out(SYS_PNP|LOG_IMPORTANT) << "Not a valid Internet Gateway Device" << endl; - return 0; - } - - // read all lines and try to find the server and location fields - for (Uint32 i = 1;i < lines.count();i++) - { - line = lines[i]; - if (line.startsWith("Location") || line.startsWith("LOCATION") || line.startsWith("location")) - { - location = line.mid(line.find(':') + 1).stripWhiteSpace(); - if (!location.isValid()) - return 0; - } - else if (line.startsWith("Server") || line.startsWith("server") || line.startsWith("SERVER")) - { - server = line.mid(line.find(':') + 1).stripWhiteSpace(); - if (server.length() == 0) - return 0; - - } - } - - if (routers.contains(server)) - { - return 0; - } - else - { - Out(SYS_PNP|LOG_NOTICE) << "Detected IGD " << server << endl; - // everything OK, make a new UPnPRouter - return new UPnPRouter(server,location,verbose); - } - } - - void UPnPMCastSocket::onError(int) - { - Out(SYS_PNP|LOG_IMPORTANT) << "UPnPMCastSocket Error : " << TDESocketBase::errorString() << endl; - } - - void UPnPMCastSocket::saveRouters(const TQString & file) - { - TQFile fptr(file); - if (!fptr.open(IO_WriteOnly)) - { - Out(SYS_PNP|LOG_IMPORTANT) << "Cannot open file " << file << " : " << TQString(fptr.errorString()) << endl; - return; - } - - // file format is simple : 2 lines per router, - // one containing the server, the other the location - TQTextStream fout(&fptr); - bt::PtrMap<TQString,UPnPRouter>::iterator i = routers.begin(); - while (i != routers.end()) - { - UPnPRouter* r = i->second; - fout << r->getServer() << endl; - fout << r->getLocation().prettyURL() << endl; - i++; - } - } - - void UPnPMCastSocket::loadRouters(const TQString & file) - { - TQFile fptr(file); - if (!fptr.open(IO_ReadOnly)) - { - Out(SYS_PNP|LOG_IMPORTANT) << "Cannot open file " << file << " : " << TQString(fptr.errorString()) << endl; - return; - } - - // file format is simple : 2 lines per router, - // one containing the server, the other the location - TQTextStream fin(&fptr); - - while (!fin.atEnd()) - { - TQString server, location; - server = fin.readLine(); - location = fin.readLine(); - if (!routers.contains(server)) - { - UPnPRouter* r = new UPnPRouter(server,location); - // download it's xml file - TQObject::connect(r,TQT_SIGNAL(xmlFileDownloaded( UPnPRouter*, bool )),this,TQT_SLOT(onXmlFileDownloaded( UPnPRouter*, bool ))); - r->downloadXMLFile(); - } - } - } - - void UPnPMCastSocket::joinUPnPMCastGroup() - { - int fd = socketDevice()->socket(); - struct ip_mreq mreq; - - memset(&mreq,0,sizeof(struct ip_mreq)); - - inet_aton("239.255.255.250",&mreq.imr_multiaddr); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - - if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(struct ip_mreq)) < 0) - { - Out(SYS_PNP|LOG_NOTICE) << "Failed to join multicast group 239.255.255.250" << endl; - } - } - - void UPnPMCastSocket::leaveUPnPMCastGroup() - { - int fd = socketDevice()->socket(); - struct ip_mreq mreq; - - memset(&mreq,0,sizeof(struct ip_mreq)); - - inet_aton("239.255.255.250",&mreq.imr_multiaddr); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - - if (setsockopt(fd,IPPROTO_IP,IP_DROP_MEMBERSHIP,&mreq,sizeof(struct ip_mreq)) < 0) - { - Out(SYS_PNP|LOG_NOTICE) << "Failed to leave multicast group 239.255.255.250" << endl; - } - } -} - - - -#include "upnpmcastsocket.moc" |