/* * Copyright (C) 2011 Stefan Sayer * * This file is part of SEMS, a free SIP media server. * * SEMS 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. * * For a license to use the sems software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * SEMS 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 */ #ifndef _DB_REGAgent_h_ #define _DB_REGAgent_h_ #include #include #include using std::map; #include using std::queue; #include "AmApi.h" #include "AmSipRegistration.h" #include "RegistrationTimer.h" #define REG_STATUS_INACTIVE 0 #define REG_STATUS_PENDING 1 #define REG_STATUS_ACTIVE 2 #define REG_STATUS_FAILED 3 #define REG_STATUS_REMOVED 4 #define REG_STATUS_TO_BE_REMOVED 5 #define REG_STATUS_INACTIVE_S "0" #define REG_STATUS_PENDING_S "1" #define REG_STATUS_ACTIVE_S "2" #define REG_STATUS_FAILED_S "3" #define REG_STATUS_REMOVED_S "4" #define REG_STATUS_TO_BE_REMOVED_S "5" #define COLNAME_SUBSCRIBER_ID "subscriber_id" #define COLNAME_USER "user" #define COLNAME_PASS "pass" #define COLNAME_REALM "realm" #define COLNAME_CONTACT "contact" #define COLNAME_STATUS "registration_status" #define COLNAME_EXPIRY "expiry" #define COLNAME_REGISTRATION_TS "last_registration" #define COLNAME_LAST_CODE "last_code" #define COLNAME_LAST_REASON "last_reason" #define RegistrationActionEventID 117 #define ERR_REASON_UNABLE_TO_SEND_REQUEST "unable to send request" struct RegistrationActionEvent : public AmEvent { enum RegAction { Register=0, Deregister }; RegistrationActionEvent(RegAction action, long subscriber_id) : AmEvent(RegistrationActionEventID), action(action), subscriber_id(subscriber_id) { } RegAction action; long subscriber_id; }; class DBRegAgent; // separate thread for REGISTER sending, which can block for rate limiting class DBRegAgentProcessorThread : public AmThread, public AmEventQueue, public AmEventHandler { DBRegAgent* reg_agent; bool stopped; void rateLimitWait(); double allowance; struct timeval last_check; protected: void process(AmEvent* ev); public: DBRegAgentProcessorThread(); ~DBRegAgentProcessorThread(); void run(); void on_stop(); }; class DBRegAgent : public AmDynInvokeFactory, public AmDynInvoke, public AmThread, public AmEventQueue, public AmEventHandler { static string joined_query; static string registrations_table; static double reregister_interval; static double minimum_reregister_interval; static bool enable_ratelimiting; static unsigned int ratelimit_rate; static unsigned int ratelimit_per; static bool ratelimit_slowstart; static bool delete_removed_registrations; static bool delete_failed_deregistrations; static bool save_contacts; static bool db_read_contact; static string contact_hostport; static string outbound_proxy; static bool save_auth_replies; static unsigned int error_retry_interval; map registrations; map registration_ltags; map registration_timers; AmMutex registrations_mut; // connection used in main DBRegAgent thread static mysqlpp::Connection MainDBConnection; // connection used in other thread (processor thread) static mysqlpp::Connection ProcessorDBConnection; int onLoad(); // atomic_ref_cnt interface void on_destroy() { onUnload(); } void onUnload(); RegistrationTimer registration_scheduler; DBRegAgentProcessorThread registration_processor; bool loadRegistrations(); void createDBRegistration(long subscriber_id, mysqlpp::Connection& conn); void deleteDBRegistration(long subscriber_id, mysqlpp::Connection& conn); void updateDBRegistration(mysqlpp::Connection& db_connection, long subscriber_id, int last_code, const string& last_reason, bool update_status = false, int status = 0, bool update_ts=false, unsigned int expiry = 0, bool update_contacts=false, const string& contacts = ""); /** create registration in our list */ void createRegistration(long subscriber_id, const string& user, const string& pass, const string& realm, const string& contact); /** update registration in our list */ void updateRegistration(long subscriber_id, const string& user, const string& pass, const string& realm, const string& contact); /** remove registration */ void removeRegistration(long subscriber_id); /** schedule this subscriber to REGISTER imminently */ void scheduleRegistration(long subscriber_id); /** schedule this subscriber to de-REGISTER imminently*/ void scheduleDeregistration(long subscriber_id); /** create a timer for the registration - fixed expiry + action */ void setRegistrationTimer(long subscriber_id, unsigned int timeout, RegistrationActionEvent::RegAction reg_action); /** create a registration refresh timer for that registration @param subscriber_id - ID of subscription @param expiry - SIP registration expiry time @param reg_start_ts - start TS of the SIP registration @param now_time - current time */ void setRegistrationTimer(long subscriber_id, time_t expiry, time_t reg_start_ts, time_t now_time); /** clear re-registration timer and remove timer object */ void clearRegistrationTimer(long subscriber_id); /** remove timer object */ void removeRegistrationTimer(long subscriber_id); // void run_tests(); // amThread void run(); void on_stop(); // AmEventHandler void process(AmEvent* ev); void onSipReplyEvent(AmSipReplyEvent* ev); void onRegistrationActionEvent(RegistrationActionEvent* reg_action_ev); unsigned int expires; /** processing thread running? */ bool running; /** processing thread shutdown finished? */ bool shutdown_finished; AmDynInvoke* uac_auth_i; void DIcreateRegistration(int subscriber_id, const string& user, const string& pass, const string& realm, const string& contact, AmArg& ret); void DIupdateRegistration(int subscriber_id, const string& user, const string& pass, const string& realm, const string& contact, AmArg& ret); void DIremoveRegistration(int subscriber_id, AmArg& ret); void DIrefreshRegistration(int subscriber_id, AmArg& ret); public: DBRegAgent(const string& _app_name); ~DBRegAgent(); DECLARE_MODULE_INSTANCE(DBRegAgent); // DI // DI factory AmDynInvoke* getInstance() { return instance(); } // DI API void invoke(const string& method, const AmArg& args, AmArg& ret); /** re-registration timer callback */ void timer_cb(RegTimer* timer, long subscriber_id, int data2); friend class DBRegAgentProcessorThread; }; #endif