mediarelay.hh 7.51 KB
Newer Older
1
 /*
2 3
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.
Simon Morlat's avatar
Simon Morlat committed
4

5 6 7 8
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.
Simon Morlat's avatar
Simon Morlat committed
9

10 11 12 13
	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 Affero General Public License for more details.
Simon Morlat's avatar
Simon Morlat committed
14

15 16
	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
Simon Morlat's avatar
Simon Morlat committed
18 19 20 21

#ifndef mediarelay_hh
#define mediarelay_hh

22
#include "module.hh"
Simon Morlat's avatar
Simon Morlat committed
23
#include "agent.hh"
24
#include "callstore.hh"
25
#include "sdp-modifier.hh"
Simon Morlat's avatar
Simon Morlat committed
26 27
#include <ortp/rtpsession.h>

28 29 30
class RelayedCall;
class MediaRelayServer;

31
class MediaRelay : public Module, protected ModuleToolbox {
32 33
	friend class MediaRelayServer;
	friend class RelayedCall;
34 35

  public:
36 37
	MediaRelay(Agent *ag);
	~MediaRelay();
38
	virtual void onLoad(const GenericStruct *modconf);
39
	virtual void onUnload();
40 41
	virtual void onRequest(std::shared_ptr<RequestSipEvent> &ev);
	virtual void onResponse(std::shared_ptr<ResponseSipEvent> &ev);
42
	virtual void onIdle();
43 44 45 46 47

  protected:
	virtual void onDeclare(GenericStruct *mc);

  private:
48
	void createServers();
49 50 51 52 53
	bool processNewInvite(const std::shared_ptr<RelayedCall> &c, const std::shared_ptr<OutgoingTransaction> &transaction,
						  const std::shared_ptr<RequestSipEvent> &ev);
	void processResponseWithSDP(const std::shared_ptr<RelayedCall> &c, const std::shared_ptr<OutgoingTransaction> &transaction,
								const std::shared_ptr<MsgSip> &msgSip);
	void configureContext(std::shared_ptr<RelayedCall> &c);
54
	CallStore *mCalls;
jehan's avatar
jehan committed
55
	std::vector<std::shared_ptr<MediaRelayServer>> mServers;
56
	size_t mCurServer;
57
	std::string mSdpMangledParam;
58 59
	int mH264FilteringBandwidth;
	bool mH264DecimOnlyIfLastProxy;
60

61 62 63 64 65
	StatCounter64 *mCountCalls;
	StatCounter64 *mCountCallsFinished;
	int mH264Decim;
	int mMaxCalls;
	int mMinPort, mMaxPort;
66
	int mMaxRelayedEarlyMedia;
67
	time_t mInactivityPeriod;
68 69 70 71
	bool mDropTelephoneEvent;
	bool mByeOrphanDialogs;
	bool mEarlyMediaRelaySingle;
	bool mPreventLoop;
72
	bool mForceRelayForNonIceTargets;
73 74 75
	static ModuleInfo<MediaRelay> sInfo;
};

76
class RelaySession;
77
class MediaRelay;
78

79 80
class PollFd {
  public:
81
	PollFd(int init_size);
82
	~PollFd();
83 84
	void reset();
	int addFd(int fd, unsigned int events);
85 86
	unsigned int getREvents(int index) const;
	struct pollfd *getPfd() {
87 88
		return mPfd;
	}
89
	int getCurIndex() const {
90 91
		return mCurIndex;
	}
92 93

  private:
94 95 96 97 98
	struct pollfd *mPfd;
	int mCurIndex;
	int mCurSize;
};

99
class MediaRelayServer {
100 101 102
	friend class RelayedCall;

  public:
103
	MediaRelayServer(MediaRelay *module);
104
	~MediaRelayServer();
105 106
	std::shared_ptr<RelaySession> createSession(const std::string &frontId,
												const std::pair<std::string, std::string> &frontRelayIps);
107
	void update();
108
	Agent *getAgent();
109
	RtpSession *createRtpSession(const std::string &bindIp);
110
	void enableLoopPrevention(bool val);
111
	bool loopPreventionEnabled() const {
112
		return mModule->mPreventLoop;
113
	}
114 115

  private:
116 117 118 119
	void start();
	void run();
	static void *threadFunc(void *arg);
	Mutex mMutex;
Simon Morlat's avatar
Simon Morlat committed
120
	std::list<std::shared_ptr<RelaySession>> mSessions;
121
	size_t mSessionsCount; /* since std::list::size() is O(n), we use our own counter*/
122
	MediaRelay *mModule;
123 124 125
	pthread_t mThread;
	int mCtlPipe[2];
	bool mRunning;
126
	friend class RelayChannel;
127 128
};

129
class RelayChannel;
130

131 132 133 134 135 136
/**
 * The RelaySession holds context for relaying for a single media stream, RTP and RTCP included.
 * It has one front channel (the one to communicate with the party that generated the SDP offer,
 * and one or several back channels, created by each party responding to the other with eventual early-media offers.
 * Each back channel is identified with a unique transaction id.
 * The front channel is identified by its from-tag.
137 138
 * When the call is established, a single back channel remains active, the one corresponding to the party that took the
 *call.
139
**/
Simon Morlat's avatar
Simon Morlat committed
140
class RelaySession : public std::enable_shared_from_this<RelaySession> {
141 142 143
  public:
	RelaySession(MediaRelayServer *server, const std::string &frontId,
				 const std::pair<std::string, std::string> &frontRelayIps);
144
	~RelaySession();
Simon Morlat's avatar
Simon Morlat committed
145

146 147
	void fillPollFd(PollFd *pfd);
	void checkPollFd(const PollFd *pfd, time_t curtime);
148
	void unuse();
149
	int getActiveBranchesCount();
150

151 152 153
	bool isUsed() const {
		return mUsed;
	}
154

155 156 157
	time_t getLastActivityTime() const {
		return mLastActivityTime;
	}
158

159 160 161
	/**
	 * Called each time an INVITE is forked
	 */
162
	std::shared_ptr<RelayChannel> createBranch(const std::string &trId,
163
				 const std::pair<std::string, std::string> &relayIps, bool hasMultipleTargets);
164 165 166 167 168 169
	void removeBranch(const std::string &trId);

	/**
	 * Called when the call is established, to remove unnecessary back channels
	**/
	void setEstablished(const std::string &tr_id);
170

171
	std::shared_ptr<RelayChannel> getChannel(const std::string &partyId, const std::string &trId);
172 173 174 175

	MediaRelayServer *getRelayServer() {
		return mServer;
	}
176
	bool checkChannels();
177

178
  private:
179
	void transfer(time_t current, const std::shared_ptr<RelayChannel> &org, int i);
180
	Mutex mMutex;
181
	MediaRelayServer *mServer;
182
	time_t mLastActivityTime;
183
	std::string mFrontId;
Simon Morlat's avatar
Simon Morlat committed
184
	std::shared_ptr<RelayChannel> mFront;
185
	std::map<std::string, std::shared_ptr<RelayChannel>> mBacks;
186
	std::shared_ptr<RelayChannel> mBack;
Simon Morlat's avatar
Simon Morlat committed
187
	bool_t mUsed;
Simon Morlat's avatar
Simon Morlat committed
188 189
};

190 191
class MediaFilter {
  public:
jehan's avatar
jehan committed
192
	virtual ~MediaFilter() {};
193

194 195 196 197
	/// Should return false if the incoming packet must not be transfered.
	virtual bool onIncomingTransfer(uint8_t *data, size_t size, const sockaddr *addr, socklen_t addrlen) = 0;
	/// Should return false if the packet output must not be sent.
	virtual bool onOutgoingTransfer(uint8_t *data, size_t size, const sockaddr *addr, socklen_t addrlen) = 0;
198 199
};

200
class RelayChannel : public SdpMasqueradeContext{
201 202 203 204
  public:
	enum Dir { SendOnly, SendRecv, Inactive };

	RelayChannel(RelaySession *relaySession, const std::pair<std::string, std::string> &relayIps, bool preventLoops);
205
	~RelayChannel();
206
	bool checkSocketsValid();
Simon Morlat's avatar
Simon Morlat committed
207
	void setRemoteAddr(const std::string &ip, int port, int rtcp_port, Dir dir);
208 209
	const std::string &getRemoteIp() const {
		return mRemoteIp;
210
	}
Simon Morlat's avatar
Simon Morlat committed
211 212 213 214 215
	int getRemoteRtpPort() const {
		return mRemotePort[0];
	}
	int getRemoteRtcpPort() const{
		return mRemotePort[1];
216
	}
217 218
	const std::string &getLocalIp() const {
		return mLocalIp;
219
	}
220 221
	int getLocalPort() const {
		return rtp_session_get_local_port(mSession);
222 223 224
	}
	int recv(int i, uint8_t *buf, size_t size);
	int send(int i, uint8_t *buf, size_t size);
225 226
	void fillPollFd(PollFd *pfd);
	bool checkPollFd(const PollFd *pfd, int i);
227
	void setFilter(std::shared_ptr<MediaFilter> filter);
228
	uint64_t getReceivedPackets() const {
229 230
		return mPacketsReceived;
	}
231
	uint64_t getSentPackets() const {
232 233
		return mPacketsSent;
	}
234 235 236 237 238 239
	void setMultipleTargets(bool val){
		mHasMultipleTargets = val;
	}
	bool hasMultipleTargets()const{
		return mHasMultipleTargets;
	}
240
	static const char *dirToString(Dir dir);
241 242

  private:
Simon Morlat's avatar
Simon Morlat committed
243
	static const int sMaxRecvErrors = 50;
244
	Dir mDir;
245 246
	std::string mLocalIp;
	std::string mRemoteIp;
Simon Morlat's avatar
Simon Morlat committed
247
	int mRemotePort[2];
248
	RtpSession *mSession;
249
	int mSockets[2];
250
	struct sockaddr_storage mSockAddr[2]; /*the destination address in use*/
251
	socklen_t mSockAddrSize[2];
252
	std::shared_ptr<MediaFilter> mFilter;
253
	int mPfdIndex;
Simon Morlat's avatar
Simon Morlat committed
254
	int mRecvErrorCount[2];
255 256
	uint64_t mPacketsSent;
	uint64_t mPacketsReceived;
257
	bool mPreventLoop;
258
	bool mHasMultipleTargets;
259
	bool mDestAddrChanged;
260 261
};

Simon Morlat's avatar
Simon Morlat committed
262
#endif