/*
* 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
*
* Author : Richard GAYRAUD - 04 Nov 2003
* From Hewlett Packard Company.
*/
#ifndef __CALL__
#define __CALL__
#include <map>
#include <list>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include "scenario.hpp"
#ifdef _USE_OPENSSL
#include "sslcommon.h"
#endif
#ifdef PCAPPLAY
#include "send_packets.h"
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#define MAX_HEADER_LEN 2049
#define UDP_MAX_RETRANS_INVITE_TRANSACTION 5
#define UDP_MAX_RETRANS_NON_INVITE_TRANSACTION 9
#define UDP_MAX_RETRANS MAX(UDP_MAX_RETRANS_INVITE_TRANSACTION, UDP_MAX_RETRANS_NON_INVITE_TRANSACTION)
#define MAX_SUB_MESSAGE_LENGTH 2049
#define DEFAULT_T2_TIMER_VALUE 4000
#define SIP_TRANSACTION_TIMEOUT 32000
#ifdef __HPUX
extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result);
#else
extern "C" { extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result); }
#endif
/* Forward declaration of call, so that we can define the call_list iterator
* that is referenced from call. */
class call;
typedef std::list<call *> call_list;
/* This arrangement of wheels lets us support up to 32 bit timers.
*
* If we were to put a minimum bound on timer_resol (or do some kind of dynamic
* allocation), then we could reduce the level one order by a factor of
* timer_resol. */
#define LEVEL_ONE_ORDER 12
#define LEVEL_TWO_ORDER 10
#define LEVEL_THREE_ORDER 10
#define LEVEL_ONE_SLOTS (1 << LEVEL_ONE_ORDER)
#define LEVEL_TWO_SLOTS (1 << LEVEL_TWO_ORDER)
#define LEVEL_THREE_SLOTS (1 << LEVEL_THREE_ORDER)
/* A time wheel structure as defined in Varghese and Lauck's 1996 journal
* article (based on their 1987 SOSP paper). */
class timewheel {
public:
timewheel();
int expire_paused_calls();
/* Add a paused call and increment count. */
void add_paused_call(call *call, bool increment);
void remove_paused_call(call *call);
int size();
private:
/* How many calls are in this wheel. */
int count;
unsigned int wheel_base;
/* The actual wheels. */
call_list wheel_one[LEVEL_ONE_SLOTS];
call_list wheel_two[LEVEL_TWO_SLOTS];
call_list wheel_three[LEVEL_THREE_SLOTS];
/* Calls that are paused indefinitely. */
call_list forever_list;
/* Turn a call into a list (based on wakeup). */
call_list *call2list(call *call);
};
class call {
public:
char * id;
unsigned int number;
unsigned int tdm_map_number;
int msg_index;
/* Last message sent from scenario step (retransmitions do not
* change this index. Only message sent from the scenario
* are kept in this index.) */
int last_send_index;
char * last_send_msg;
/* How long until sending this message times out. */
unsigned int send_timeout;
/* Last received message (expected, not optional, and not
* retransmitted) and the associated hash. Stills setted until a new
* scenario steps sends a message */
unsigned long last_recv_hash;
int last_recv_index;
char * last_recv_msg;
/* Recv message characteristics when we sent a valid message
* (scneario, no retrans) just after a valid reception. This was
* a cause relationship, so the next time this cookie will be recvd,
* we will retransmit the same message we sent this time */
unsigned long recv_retrans_hash;
unsigned int recv_retrans_recv_index;
unsigned int recv_retrans_send_index;
unsigned int recv_timeout;
/* holds the route set */
char * dialog_route_set;
char * next_req_url;
/* cseq value for [cseq] keyword */
unsigned int cseq;
#ifdef PCAPPLAY
int hasMediaInformation;
pthread_t media_thread;
play_args_t play_args_a;
play_args_t play_args_v;
#endif
#ifdef _USE_OPENSSL
/* holds the auth header and if the challenge was 401 or 407 */
char * dialog_authentication;
int dialog_challenge_type;
#endif
unsigned int next_retrans;
int nb_retrans;
unsigned int nb_last_delay;
unsigned int paused_until;
unsigned long start_time;
unsigned long long start_time_rtd[MAX_RTD_INFO_LENGTH];
bool rtd_done[MAX_RTD_INFO_LENGTH];
char *peer_tag;
struct sipp_socket *call_remote_socket;
int call_port;
void * comp_state;
int deleted;
bool call_established; // == true when the call is established
// ie ACK received or sent
// => init to false
bool count_in_stats; // == true if normal call to be counted
// in statistics
bool ack_is_pending; // == true if an ACK is pending
// Needed to avoid abortCall sending a
// CANCEL instead of BYE in some extreme
// cases for 3PCC scenario.
// => init to false
/* Call Variable Table */
CCallVariable ** M_callVariableTable;
/* result of execute action */
enum T_ActionResult
{
E_AR_NO_ERROR = 0,
E_AR_REGEXP_DOESNT_MATCH,
E_AR_STOP_CALL,
E_AR_HDR_NOT_FOUND
};
/* Store the last action result to allow */
/* call to continue and mark it as failed */
T_ActionResult last_action_result;
call(char * id, int userId, bool ipv6);
call (char *id, int userId, bool ipv6 , bool isAutomatic);
~call();
/* rc == true means call not deleted by processing */
bool run();
void formatNextReqUrl (char* next_req_url);
void computeRouteSetAndRemoteTargetUri (char* rrList, char* contact, bool bRequestIncoming);
bool matches_scenario(unsigned int index, int reply_code, char * request, char * responsecseqmethod);
bool process_incoming(char * msg);
T_ActionResult executeAction(char * msg, int scenarioIndex);
void extractSubMessage(char * msg, char * matchingString, char* result, bool case_indep,
int occurrence, bool headers);
bool rejectCall();
double get_rhs(CAction *currentAction);
// P_index use for message index in scenario and ctrl of CRLF
// P_index = -2 No ctrl of CRLF
// P_index = -1 Add crlf to end of message
char* createSendingMessage(SendingMessage *src, int P_index);
char* createSendingMessage(char * src, int P_index, bool skip_sanity = false);
// method for the management of unexpected messages
bool abortCall(); // call aborted with BYE or CANCEL
bool checkInternalCmd(char* cmd); // check of specific internal command
// received from the twin socket
// used for example to cancel the call
// of the third party
bool check_peer_src(char* msg,
int search_index); // 3pcc extended mode:check if
// the twin message received
// comes from the expected sender
void sendBuffer(char *buf); // send a message out of a scenario
// execution
int checkAutomaticResponseMode(char * P_recv);
bool automaticResponseMode(int P_case, char* P_recv);
#ifdef __3PCC__
int sendCmdMessage(int index); // 3PCC
bool process_twinSippCom(char * msg); // 3PCC
int sendCmdBuffer(char* cmd); // for 3PCC, send a command out of a
// scenario execution
#endif
static void readInputFileContents(const char* fileName);
static void dumpFileContents(void);
void getFieldFromInputFile(const char* fileName, int field, char*& dest);
void getFieldFromInputFile(const char* keyword, char*& dest);
/* Associate/Dissociate this call with a socket. */
struct sipp_socket *associate_socket(struct sipp_socket *socket);
struct sipp_socket *dissociate_socket();
/* Associate a user with this call. */
void setUser(int userId);
/* Is this call paused or running? */
bool running;
/* If we are running, the iterator to remove us from the running list. */
call_list::iterator runit;
/* If we are paused, the iterator to remove us from the paused list. */
call_list::iterator pauseit;
private:
/* rc == true means call not deleted by processing */
bool next();
bool process_unexpected(char * msg);
void do_bookkeeping(int index);
void extract_cseq_method (char* responseCseq, char* msg);
int send_raw(char * msg, int index);
char * send_scene(int index, int *send_status);
void connect_socket_if_needed();
char * compute_cseq(char * src);
char * get_header_field_code(char * msg, char * code);
char * get_last_header(char * name);
char * get_header_content(char* message, char * name);
char * get_header(char* message, char * name, bool content);
char * get_first_line(char* message);
char * get_last_request_uri();
typedef std::map <std::string, int> file_line_map;
file_line_map *m_lineNumber;
int userId;
bool use_ipv6;
struct sipp_socket *call_socket;
void get_remote_media_addr(char * message);
#ifdef _USE_OPENSSL
SSL_CTX *m_ctx_ssl ;
BIO *m_bio ;
#endif
};
/* Call contexts interface */
typedef std::pair<std::string, call *> string_call_pair;
typedef std::map<std::string, call *> call_map;
call_map * get_calls();
call_list * get_running_calls();
/* These are wrappers for various circumstances. */
call * add_call(int userId, bool ipv6);
call * add_call(char * call_id , bool ipv6, int userId);
call * add_call(char * call_id , struct sipp_socket *socket);
call * add_call(char * call_id , struct sipp_socket *socket, bool isAutomatic);
/* This is the core function. */
call * add_call(char * call_id , bool ipv6, int userId, bool isAutomatic);
call * get_call(char *);
void delete_call(char *);
void delete_calls(void);
void add_running_call(call *call);
bool remove_running_call(call *call);
int expire_paused_calls();
int paused_calls_count();
void remove_paused_call(call *call);
typedef std::pair<struct sipp_socket *,call_map *> socket_map_pair;
typedef std::map<struct sipp_socket *, void *> socket_call_map_map;
call_list *get_calls_for_socket(struct sipp_socket *socket);
void add_call_to_socket(struct sipp_socket *socket, call *call);
void remove_call_from_socket(struct sipp_socket *socket, call *call);
#endif
syntax highlighted by Code2HTML, v. 0.9.1