reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
RequestFilter.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
7#include "rutil/Logger.hxx"
8
12#include "repro/FilterStore.hxx"
13#include "repro/Proxy.hxx"
14#ifdef USE_MYSQL
15#include "repro/MySqlDb.hxx"
16#endif
17#ifdef USE_POSTGRESQL
18#include "repro/SqlDb.hxx"
19#endif
22
23#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
24
25using namespace resip;
26using namespace repro;
27using namespace std;
28
30{
31public:
33 const resip::Data& tid,
34 TransactionUser* passedtu,
35 Data& query) :
36 AsyncProcessorMessage(proc,tid,passedtu),
38 {
39 }
40
41 virtual EncodeStream& encode(EncodeStream& strm) const { strm << "RequestFilterAsyncMessage(tid=" << mTid << ")"; return strm; }
42
45 std::vector<Data> mQueryResultData;
46};
47
49 Dispatcher* asyncDispatcher) :
50 AsyncProcessor("RequestFilter", asyncDispatcher),
51 mFilterStore(config.getDataStore()->mFilterStore),
52 mSqlDb(0),
53 mDefaultNoMatchBehavior(config.getConfigData("RequestFilterDefaultNoMatchBehavior", "")), // Default: empty string = Continue Processing
54 mDefaultDBErrorBehavior(config.getConfigData("RequestFilterDefaultDBErrorBehavior", "500, Server Internal DB Error"))
55{
56#if defined(USE_MYSQL) || defined(USE_POSTGRESQL)
57 const char* databaseParams[] = { "RequestFilterDatabase", "RuntimeDatabase", "DefaultDatabase", 0 };
58 for(const char** databaseParam = databaseParams; *databaseParam != 0; databaseParam++)
59 {
60 int databaseIndex = config.getConfigInt(*databaseParam, -1);
61 if(databaseIndex >= 0)
62 {
63 mSqlDb = dynamic_cast<SqlDb*>(config.getDatabase(databaseIndex));
64 // FIXME - should we check it is an SQL database and not BerkeleyDB?
65 }
66 }
67#endif
68#ifdef USE_MYSQL
69 if(!mSqlDb) // Try legacy configuration parameter names
70 {
71 Data mySQLSettingPrefix("RequestFilter");
72 Data mySQLServer = config.getConfigData("RequestFilterMySQLServer", "");
73 if(mySQLServer.empty())
74 {
75 // If RequestFilterMySQLServer setting is blank, then fallback to
76 // RuntimeMySql settings
77 mySQLSettingPrefix = "Runtime";
78 mySQLServer = config.getConfigData("RuntimeMySQLServer", "");
79 if(mySQLServer.empty())
80 {
81 // If RuntimeMySQLServer setting is blank, then fallback to
82 // global MySql settings
83 mySQLSettingPrefix.clear();
84 mySQLServer = config.getConfigData("MySQLServer", "");
85 }
86 }
87
88 if(!mySQLServer.empty())
89 {
90 // Initialize My SQL using Global settings
91 WarningLog(<<"Using deprecated parameter " << mySQLSettingPrefix << "MySQLServer, please update to indexed Database definitions.");
92 mSqlDb = new MySqlDb(config, mySQLServer,
93 config.getConfigData(mySQLSettingPrefix + "MySQLUser", ""),
94 config.getConfigData(mySQLSettingPrefix + "MySQLPassword", ""),
95 config.getConfigData(mySQLSettingPrefix + "MySQLDatabaseName", ""),
96 config.getConfigUnsignedLong(mySQLSettingPrefix + "MySQLPort", 0),
98 }
99 }
100#endif
101}
102
106
107short
108RequestFilter::parseActionResult(const Data& result, Data& rejectReason)
109{
110 Data rejectionStatusCode;
111 ParseBuffer pb(result);
112 const char* anchor = pb.position();
113 pb.skipToChar(',');
114 pb.data(rejectionStatusCode, anchor);
115 if(pb.position()[0] == ',')
116 {
117 pb.skipChar();
118 pb.skipWhitespace();
119 anchor = pb.position();
120 pb.skipToEnd();
121 pb.data(rejectReason, anchor);
122 }
123 return (short)rejectionStatusCode.convertInt();
124}
125
126
128RequestFilter::applyActionResult(RequestContext &rc, const Data& actionResult)
129{
130 if(!actionResult.empty())
131 {
132 Data rejectionReason;
133 short rejectionStatusCode = parseActionResult(actionResult, rejectionReason);
134
135 if(rejectionStatusCode >= 400 && rejectionStatusCode < 600)
136 {
137 // Blocked - reject request
138 SipMessage response;
139 InfoLog(<<"Request is blocked - responding with a " << rejectionStatusCode << ", customReason=" << rejectionReason);
140 Helper::makeResponse(response, rc.getOriginalRequest(), rejectionStatusCode, rejectionReason);
141 rc.sendResponse(response);
142 return SkipThisChain;
143 }
144 }
145
146 // Not blocked - continue processing
147 DebugLog(<< "Request is accepted");
148 return Continue;
149}
150
153{
154 DebugLog(<< "Monkey handling request: " << *this << "; reqcontext = " << rc);
155
156 Message *message = rc.getCurrentEvent();
157
158 RequestFilterAsyncMessage *async = dynamic_cast<RequestFilterAsyncMessage*>(message);
159
160 if (async)
161 {
162 if(async->mQueryResult == 0 && async->mQueryResultData.size() > 0) // If query was successful, then get query result
163 {
164 InfoLog(<< "RequestFilter query completed successfully: queryResult=" << async->mQueryResult << ", resultData=" << async->mQueryResultData.front());
165
166 return applyActionResult(rc, async->mQueryResultData.front());
167 }
168 else
169 {
170 InfoLog(<< "RequestFilter query failed: queryResult=" << async->mQueryResult);
171
172 return applyActionResult(rc, mDefaultDBErrorBehavior);
173 }
174 }
175 else
176 {
177 short action;
178 Data actionData;
179 if(mFilterStore.process(rc.getOriginalRequest(), action, actionData))
180 {
181 // Match found
182 switch(action)
183 {
185 return applyActionResult(rc, actionData);
187 if(mSqlDb)
188 {
189 // Dispatch async
190 std::unique_ptr<ApplicationMessage> async(new RequestFilterAsyncMessage(*this, rc.getTransactionId(), &rc.getProxy(), actionData));
191 mAsyncDispatcher->post(async);
192 return WaitingForEvent;
193 }
194 else
195 {
196 // No DB - use default DB Error behavior
197 WarningLog(<< "Request filter with action type SQL Query exists, however there is no MySQL support compiled in, using DefaultDBErrorBehavior");
198 return applyActionResult(rc, mDefaultDBErrorBehavior);
199 }
201 default:
202 DebugLog(<< "Request is accepted");
203 return Continue;
204 }
205 }
206 else
207 {
208 // No Match found - apply default behavior
209 return applyActionResult(rc, mDefaultNoMatchBehavior);
210 }
211 }
212}
213
214bool
216{
217 RequestFilterAsyncMessage* async = dynamic_cast<RequestFilterAsyncMessage*>(msg);
218 resip_assert(async);
219
220#ifdef USE_MYSQL
221 if(mSqlDb)
222 {
223 async->mQueryResult = mSqlDb->singleResultQuery(async->mQuery, async->mQueryResultData);
224 return true;
225 }
226#else
227 resip_assert(false);
228 async->mQueryResult = -1;
229#endif
230 return false;
231}
232
233/* ====================================================================
234 * The Vovida Software License, Version 1.0
235 *
236 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
237 *
238 * Redistribution and use in source and binary forms, with or without
239 * modification, are permitted provided that the following conditions
240 * are met:
241 *
242 * 1. Redistributions of source code must retain the above copyright
243 * notice, this list of conditions and the following disclaimer.
244 *
245 * 2. Redistributions in binary form must reproduce the above copyright
246 * notice, this list of conditions and the following disclaimer in
247 * the documentation and/or other materials provided with the
248 * distribution.
249 *
250 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
251 * and "Vovida Open Communication Application Library (VOCAL)" must
252 * not be used to endorse or promote products derived from this
253 * software without prior written permission. For written
254 * permission, please contact vocal@vovida.org.
255 *
256 * 4. Products derived from this software may not be called "VOCAL", nor
257 * may "VOCAL" appear in their name, without prior written
258 * permission of Vovida Networks, Inc.
259 *
260 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
261 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
262 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
263 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
264 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
265 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
266 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
267 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
268 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
269 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
270 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
271 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
272 * DAMAGE.
273 *
274 * ====================================================================
275 *
276 * This software consists of voluntary contributions made by Vovida
277 * Networks, Inc. and many individuals on behalf of Vovida Networks,
278 * Inc. For more information on Vovida Networks, Inc., please see
279 * <http://www.vovida.org/>.
280 *
281 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define resip_assert(x)
This file needs to work for both C and C++ code.
RequestFilterAsyncMessage(AsyncProcessor &proc, const resip::Data &tid, TransactionUser *passedtu, Data &query)
std::vector< Data > mQueryResultData
virtual EncodeStream & encode(EncodeStream &strm) const
output the entire message to stream
resip::Dispatcher * mAsyncDispatcher
bool process(const resip::SipMessage &request, short &action, resip::Data &actionData)
virtual AbstractDb * getDatabase(int configIndex)
resip::SipMessage & getOriginalRequest()
Returns the SipMessage associated with the server transaction.
resip::Message * getCurrentEvent()
Returns the event that we are currently working on.
void sendResponse(resip::SipMessage &response)
resip::Data getTransactionId() const
virtual bool asyncProcess(AsyncProcessorMessage *msg)
virtual processor_action_t process(RequestContext &)
RequestFilter(ProxyConfig &config, resip::Dispatcher *asyncDispatcher)
virtual int singleResultQuery(const resip::Data &queryCommand, std::vector< resip::Data > &fields) const =0
int getConfigInt(const resip::Data &name, int defaultValue) const
resip::Data getConfigData(const resip::Data &name, const resip::Data &defaultValue, bool useDefaultIfEmpty=false) const
unsigned long getConfigUnsignedLong(const resip::Data &name, unsigned long defaultValue) const
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
int convertInt() const
Takes the contents of the Data and converts them to an integer.
Definition Data.cxx:1684
Data & clear()
Clears the contents of this Data.
Definition Data.hxx:800
A generic thread-bank class.
virtual bool post(std::unique_ptr< resip::ApplicationMessage > &work)
Posts a message to this thread bank.
static void makeResponse(SipMessage &response, const SipMessage &request, int responseCode, const Data &reason=Data::Empty, const Data &hostname=Data::Empty, const Data &warning=Data::Empty)
Make a response to a provided request.
Definition Helper.cxx:412
The base-class used for message-passing.
Definition Message.hxx:21
Provides string-parsing functionality with protection from buffer overflow.
Represents a SIP message.
The base-class for an RFC 3261 Transaction User.
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
#define EncodeStream