summaryrefslogtreecommitdiffstats
blob: b4db9a627173074ace5ea41e3c48d23ecfb67f2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Copyright (c) 2010 Isode Limited.
 * All rights reserved.
 * See the COPYING file for more information.
 */

#include <Swiften/FileTransfer/IBBReceiveSession.h>

#include <boost/bind.hpp>

#include <Swiften/Base/Log.h>
#include <Swiften/Queries/IQRouter.h>
#include <Swiften/FileTransfer/IBBRequest.h>
#include <Swiften/FileTransfer/BytestreamException.h>
#include <Swiften/Queries/SetResponder.h>

#include <cassert>

namespace Swift {

class IBBReceiveSession::IBBResponder : public SetResponder<IBB> {
	public:
		IBBResponder(IBBReceiveSession* session, IQRouter* router) : SetResponder<IBB>(router), session(session), sequenceNumber(0), receivedSize(0) {
		}

		virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) {
			if (from == session->from && ibb->getStreamID() == session->id) {
				if (ibb->getAction() == IBB::Data) {
					if (sequenceNumber == ibb->getSequenceNumber()) {
						session->bytestream->write(ibb->getData());
						receivedSize += ibb->getData().size();
						sequenceNumber++;
						sendResponse(from, id, IBB::ref());
						if (receivedSize >= session->size) {
							if (receivedSize > session->size) {
								SWIFT_LOG(warning) << "Received more data than expected";
							}
							session->finish(boost::optional<FileTransferError>());
						}
					}
					else {
						SWIFT_LOG(warning) << "Received data out of order";
						sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel);
						session->finish(FileTransferError(FileTransferError::ClosedError));
					}
				}
				else if (ibb->getAction() == IBB::Open) {
					SWIFT_LOG(debug) << "IBB open received";
					sendResponse(from, id, IBB::ref());
				}
				else if (ibb->getAction() == IBB::Close) {
					SWIFT_LOG(debug) << "IBB close received";
					sendResponse(from, id, IBB::ref());
					session->finish(FileTransferError(FileTransferError::ClosedError));
				}
				return true;
			}
			SWIFT_LOG(debug) << "wrong from/sessionID: " << from << " == " << session->from << " / " <<ibb->getStreamID() << " == " << session->id;
			return false;
		}

	private:
		IBBReceiveSession* session;
		int sequenceNumber;
		unsigned long long receivedSize;
};


IBBReceiveSession::IBBReceiveSession(
		const std::string& id, 
		const JID& from, 
		const JID& to, 
		unsigned long long size, 
		boost::shared_ptr<WriteBytestream> bytestream,
		IQRouter* router) : 
			id(id), 
			from(from), 
			to(to), 
			size(size), 
			bytestream(bytestream),
			router(router), 
			active(false) {
	assert(!id.empty());
	assert(from.isValid());
	responder = new IBBResponder(this, router);
}

IBBReceiveSession::~IBBReceiveSession() {
	if (active) {
		SWIFT_LOG(warning) << "Session still active";
	}
	delete responder;
}

void IBBReceiveSession::start() {
	SWIFT_LOG(debug) << "receive session started";
	active = true;
	responder->start();
}

void IBBReceiveSession::stop() {
	SWIFT_LOG(debug) << "receive session stopped";
	responder->stop();
	if (active) {
		if (router->isAvailable()) {
			IBBRequest::create(to, from, IBB::createIBBClose(id), router)->send();
		}
		finish(boost::optional<FileTransferError>());
	}
}

void IBBReceiveSession::finish(boost::optional<FileTransferError> error) {
	active = false;
	onFinished(error);
}

}