You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
11 KiB
334 lines
11 KiB
/*
|
|
* 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.
|
|
* Charles P. Wright from IBM Research
|
|
* Andy Aicken
|
|
*/
|
|
|
|
#ifndef __CALL__
|
|
#define __CALL__
|
|
|
|
#include <map>
|
|
#include <list>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <string.h>
|
|
#include "scenario.hpp"
|
|
#include "stat.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
|
|
|
|
/* Retransmission check methods. */
|
|
#define RTCHECK_FULL 1
|
|
#define RTCHECK_LOOSE 2
|
|
|
|
#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); }
|
|
extern "C" { int verifyAuthHeader(char * user, char * password, char * method, char * auth); }
|
|
#endif
|
|
|
|
struct txnInstanceInfo {
|
|
char *txnID;
|
|
unsigned long txnResp;
|
|
int ackIndex;
|
|
};
|
|
|
|
class call : virtual public task, virtual public listener, public virtual socketowner {
|
|
public:
|
|
/* These are wrappers for various circumstances, (private) init does the real work. */
|
|
//call(char * p_id, int userId, bool ipv6, bool isAutomatic);
|
|
call(char *p_id, bool use_ipv6, int userId, struct sockaddr_storage *dest);
|
|
call(char *p_id, struct sipp_socket *socket, struct sockaddr_storage *dest);
|
|
static call *add_call(int userId, bool ipv6, struct sockaddr_storage *dest);
|
|
call(scenario * call_scenario, struct sipp_socket *socket, struct sockaddr_storage *dest, char * p_id, int userId, bool ipv6, bool isAutomatic, bool isInitCall);
|
|
|
|
virtual ~call();
|
|
|
|
virtual bool process_incoming(char * msg, struct sockaddr_storage *src = NULL);
|
|
virtual bool process_twinSippCom(char * msg);
|
|
|
|
virtual bool run();
|
|
/* Terminate this call, depending on action results and timewait. */
|
|
virtual void terminate(CStat::E_Action reason);
|
|
virtual void tcpClose();
|
|
|
|
/* When should this call wake up? */
|
|
virtual unsigned int wake();
|
|
virtual bool abortCall(bool writeLog); // call aborted with BYE or CANCEL
|
|
virtual void abort();
|
|
|
|
/* Dump call info to error log. */
|
|
virtual void dump();
|
|
|
|
/* Automatic */
|
|
enum T_AutoMode
|
|
{
|
|
E_AM_DEFAULT,
|
|
E_AM_UNEXP_BYE,
|
|
E_AM_UNEXP_CANCEL,
|
|
E_AM_PING,
|
|
E_AM_AA,
|
|
E_AM_OOCALL,
|
|
};
|
|
|
|
void setLastMsg(const char *msg);
|
|
bool automaticResponseMode(T_AutoMode P_case, char* P_recv);
|
|
const char *getLastReceived() { return last_recv_msg; };
|
|
|
|
private:
|
|
/* This is the core constructor function. */
|
|
void init(scenario * call_scenario, struct sipp_socket *socket, struct sockaddr_storage *dest, char * p_id, int userId, bool ipv6, bool isAutomatic, bool isInitCall);
|
|
/* This this call for initialization? */
|
|
bool initCall;
|
|
|
|
struct sockaddr_storage call_peer;
|
|
|
|
scenario *call_scenario;
|
|
unsigned int number;
|
|
|
|
public:
|
|
static int maxDynamicId; // max value for dynamicId; this value is reached !
|
|
static int startDynamicId; // offset for first dynamicId FIXME:in CmdLine
|
|
static int stepDynamicId; // step of increment for dynamicId
|
|
static int dynamicId; // a counter for general use, incrementing by stepDynamicId starting at startDynamicId wrapping at maxDynamicId GLOBALY
|
|
private:
|
|
|
|
|
|
unsigned int tdm_map_number;
|
|
|
|
int msg_index;
|
|
int zombie;
|
|
|
|
/* 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;
|
|
int last_send_len;
|
|
|
|
/* 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;
|
|
int recv_retrans_recv_index;
|
|
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
|
|
|
|
|
|
/* holds the auth header and if the challenge was 401 or 407 */
|
|
char * dialog_authentication;
|
|
int dialog_challenge_type;
|
|
|
|
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;
|
|
bool *rtd_done;
|
|
|
|
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 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 */
|
|
VariableTable *M_callVariableTable;
|
|
|
|
/* Our transaction IDs. */
|
|
struct txnInstanceInfo *transactions;
|
|
|
|
/* result of execute action */
|
|
enum T_ActionResult
|
|
{
|
|
E_AR_NO_ERROR = 0,
|
|
E_AR_REGEXP_DOESNT_MATCH,
|
|
E_AR_REGEXP_SHOULDNT_MATCH,
|
|
E_AR_STOP_CALL,
|
|
E_AR_CONNECT_FAILED,
|
|
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;
|
|
|
|
/* rc == true means call not deleted by processing */
|
|
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, char *txn);
|
|
|
|
bool executeMessage(message *curmsg);
|
|
T_ActionResult executeAction(char * msg, message *message);
|
|
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, int *msgLen=NULL);
|
|
char* createSendingMessage(char * src, int P_index, bool skip_sanity = false);
|
|
char* createSendingMessage(SendingMessage *src, int P_index, char *msg_buffer, int buflen, int *msgLen=NULL);
|
|
|
|
// method for the management of unexpected messages
|
|
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, int len = 0); // send a message out of a scenario
|
|
// execution
|
|
|
|
T_AutoMode checkAutomaticResponseMode(char * P_recv);
|
|
|
|
int sendCmdMessage(message *curmsg); // 3PCC
|
|
|
|
int sendCmdBuffer(char* cmd); // for 3PCC, send a command out of a
|
|
// scenario execution
|
|
|
|
static void readInputFileContents(const char* fileName);
|
|
static void dumpFileContents(void);
|
|
|
|
void getFieldFromInputFile(const char* fileName, int field, SendingMessage *line, char*& dest);
|
|
|
|
/* Associate a user with this call. */
|
|
void setUser(int userId);
|
|
|
|
/* Is this call just around for final retransmissions. */
|
|
bool timewait;
|
|
|
|
/* rc == true means call not deleted by processing */
|
|
bool next();
|
|
bool process_unexpected(char * msg);
|
|
void do_bookkeeping(message *curmsg);
|
|
|
|
void extract_cseq_method (char* responseCseq, char* msg);
|
|
void extract_transaction (char* txn, char* msg);
|
|
|
|
int send_raw(char * msg, int index, int len);
|
|
char * send_scene(int index, int *send_status, int *msgLen);
|
|
bool 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();
|
|
unsigned long hash(char * msg);
|
|
|
|
typedef std::map <std::string, int> file_line_map;
|
|
file_line_map *m_lineNumber;
|
|
int userId;
|
|
|
|
bool use_ipv6;
|
|
|
|
void get_remote_media_addr(char * message);
|
|
|
|
bool lost(int index);
|
|
|
|
void computeStat (CStat::E_Action P_action);
|
|
void computeStat (CStat::E_Action P_action, unsigned long P_value);
|
|
void computeStat (CStat::E_Action P_action, unsigned long P_value, int which);
|
|
|
|
|
|
void queue_up(char *msg);
|
|
char *queued_msg;
|
|
|
|
|
|
#ifdef _USE_OPENSSL
|
|
SSL_CTX *m_ctx_ssl ;
|
|
BIO *m_bio ;
|
|
#endif
|
|
|
|
int _callDebug(char *fmt, ...);
|
|
char *debugBuffer;
|
|
int debugLength;
|
|
};
|
|
|
|
|
|
/* Default Message Functions. */
|
|
void init_default_messages();
|
|
void free_default_messages();
|
|
SendingMessage *get_default_message(const char *which);
|
|
void set_default_message(const char *which, char *message);
|
|
|
|
#endif
|