/** ** File ......... MetainfoSocket.cpp ** Published .... 2005-06-14 ** Author ....... grymse@alhem.net **/ /* Copyright (C) 2005 Anders Hedstrom 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef _WIN32 #pragma warning(disable:4786) #endif #include #include #ifndef _WIN32 #include #endif #include #include "BString.h" #include "Session.h" #include "PeerHandler.h" #include "MetainfoSocket.h" #include "Exception.h" #include "BTDictionary.h" #define DEB(x) x int MetainfoSocket::m_nr = 0; MetainfoSocket::MetainfoSocket(SocketHandler& h) :TcpSocket(h) ,m_filenr(++m_nr) ,m_fil(NULL) ,m_state(STATE_GET_LENGTH) ,m_sz(0) ,m_sz_read(0) { } MetainfoSocket::MetainfoSocket(SocketHandler& h,const std::string& filename) :TcpSocket(h) ,m_filenr(0) ,m_filename(filename) ,m_fil(NULL) ,m_state(STATE_GET_LENGTH) ,m_sz(0) ,m_sz_read(0) { } MetainfoSocket::~MetainfoSocket() { if (m_fil) fclose(m_fil); } void MetainfoSocket::OnConnect() { DEB(printf("MetainfoSocket::OnConnect\n");) struct stat st; if (stat(m_filename.c_str(), &st) == -1) { perror("stat failed"); SetCloseAndDelete(); return; } SendBuf( (char *)&st.st_size, sizeof(off_t)); FILE *fil = fopen(m_filename.c_str(), "rb"); if (fil) { char buf[5000]; int n = fread(buf,1,5000,fil); while (n > 0) { SendBuf(buf,n); n = fread(buf,1,5000,fil); } fclose(fil); } SetCloseAndDelete(); } void MetainfoSocket::OnAccept() { DEB(printf("MetainfoSocket::OnAccept\n");) m_filename = "metafile." + Utility::l2string(m_filenr); m_fil = fopen(m_filename.c_str(), "wb"); m_state = STATE_GET_LENGTH; } /* void MetainfoSocket::OnRawData(const char *p,size_t l) { DEB(printf("MetainfoSocket::OnRawData(,%d)\n",l);) if (m_fil) fwrite(p,1,l,m_fil); } */ void MetainfoSocket::OnRead() { TcpSocket::OnRead(); while (ibuf.GetLength()) { size_t l = ibuf.GetLength(); switch (m_state) { case STATE_GET_LENGTH: if (l < sizeof(off_t)) return; ibuf.Read( (char *)&m_sz, sizeof(off_t)); m_state = STATE_GET_FILE; DEB(printf("File length: %d bytes\n", m_sz);) break; case STATE_GET_FILE: { char slask[TCP_BUFSIZE_READ]; ibuf.Read( slask, l); if (m_fil) fwrite(slask,1,l,m_fil); m_sz_read += l; } break; } } } void MetainfoSocket::OnDelete() { DEB(printf("MetainfoSocket::OnDelete\n");) if (m_fil) { fclose(m_fil); m_fil = NULL; if (m_sz_read == m_sz) { InitSession(); } else { printf("Short metainfo file read - ignoring\n"); } } } void MetainfoSocket::InitSession() { DEB(printf("InitSession\n");) try { FILE *fil = fopen(m_filename.c_str(), "rb"); if (fil) { PeerHandler& ref = static_cast(Handler()); BString meta; meta.read_file(fil); fclose(fil); std::string info_hash = meta.GetHashAsString("info"); // copy metainfo file std::string copy_to = ref.GetTorrentDirectory() + "/" + info_hash + "/.metainfo"; ref.mkpath(copy_to); fil = fopen(m_filename.c_str(), "rb"); if (fil) { FILE *fil2 = fopen(copy_to.c_str(), "wb"); char buf[1000]; size_t n = fread(buf, 1, 1000, fil); while (n > 0) { fwrite(buf, 1, n, fil2); n = fread(buf, 1, 1000, fil); } fclose(fil2); fclose(fil); } if (ref.SessionExists(info_hash)) { DEB(printf("Session for hash %s already exists\n", info_hash.c_str());) } else { DEB(printf("Hash: %s\n", info_hash.c_str());) Session *sess = new Session(Handler(), info_hash); ref.RegSession( sess ); sess -> SetHash(meta.GetHash("info")); BTString *p; if ((p = meta.GetString("announce")) != NULL) { sess -> SetAnnounce(p -> GetValue()); } std::string name; if ((p = meta.GetString("info.name")) != NULL) { sess -> SetName(name = p -> GetValue()); } BTInteger *piecelength = meta.GetInteger("info.piece length"); if (piecelength) { sess -> SetPieceLength(piecelength -> GetVal()); } BTInteger *length = meta.GetInteger("info.length"); if (length) { sess -> AddFile(length -> GetVal()); } else // info.files { BTObject *p = meta.GetBTObject("info.files"); BTList *files = dynamic_cast(p); if (files) { btobject_v& ref = files -> GetList(); for (btobject_v::iterator it = ref.begin(); it != ref.end(); it++) { BTDictionary *p = dynamic_cast(*it); if (p) { BTInteger *length = dynamic_cast(p -> Find("length")); BTList *path = dynamic_cast(p -> Find("path")); if (path && length) { btobject_v& ref = path -> GetList(); std::string pathname = name; for (btobject_v::iterator it = ref.begin(); it != ref.end(); it++) { BTString *p = dynamic_cast(*it); if (p) pathname += "/" + p -> GetValue(); } sess -> AddFile(pathname, length -> GetVal()); } } } } } // pieces checksum BTString *pieces = meta.GetString("info.pieces"); if (pieces) { sess -> SetPieces( pieces -> GetValue() ); } sess -> CreateFileManager(); // restore session sess -> Load(); // /* DEB(printf("Verifying existing files...\n");) sess -> Verify(); DEB(printf("Verify finished\n");) */ } // unlink(m_filename.c_str()); } } catch (const Exception& e) { Handler().LogError(this, "InitSession", 0, e.GetText(), LOG_LEVEL_ERROR); } }