PJSIP 可靠发送MESSAGE/NOTIFY等消息

基于PJSIP的文章太多太多,但是大多数都是抄来抄去,自己创建的少之又少,最近因为项目的原因需要通过PJSIP来处理基于transaction的可靠消息发送,即发送不给予dialog的消息,但是又不需要自己去管理消息超时和重发,于是折腾来折腾去以后就找到了对应的方法。此程序源自于pjsip自带的stateless/stateful proxy,加以改进的地方是主动发送Message消息,如果要发送其他消息则可以修改msgGwTestSendMessage中的method,以及 MSG_TYPE_TXT MSG_SUBTYPE_TXT 等,makefile如下:

GCC = gcc

CUR_VERSION=$(shell date +%Y%m%d)

CFLAGS = -g -DPJ_HAS_LIMITS_H -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_CURRENT_MAKE_TIME=$(shell date +%s) -Werror -Wall

ROOTPATH=/root/pjproject-2.14.1/

INCLUDES= -I${ROOTPATH}/pjlib-util/include -I${ROOTPATH}/pjlib/include -I${ROOTPATH}/pjsip/include

LIB = -L${ROOTPATH}/pjlib/lib -L${ROOTPATH}/pjlib-util/lib -L${ROOTPATH}/pjnath/lib -L${ROOTPATH}/pjmedia/lib -L${ROOTPATH}/pjsip/lib -L${ROOTPATH}/third_party/lib -lpjsip-x86_64-unknown-linux-gnu -lpjlib-util-x86_64-unknown-linux-gnu -lpj-x86_64-unknown-linux-gnu -luuid -lm -lpthread

OBJ_MSGGW = msgGw.o

.c.o:
    $(GCC) -c $(CFLAGS) $(INCLUDES) $<

all: msggw clean

msggw: ${OBJ_MSGGW}
    $(GCC) -o bin/msgGw ${OBJ_MSGGW} $(CFLAGS) $(LIB)

clean:
    rm *.o

配置文件如下:

LISTENPORT=3456
LOGLEVEL=1
MAXLOGLINE=50000
LOGFILE=/root/msggw/log/msgGw.log

 源代码如下,基本上没有注释,将就看吧,重点是如何建立stateful的transtraction和自定义的消息类型,此处我使用的是application/json格式,当然也可以自己定义,测试环境使用sipp搭建,做了一个并发10000的消息发送/接收脚本,具体如何使用sipp请移步官方网站

//
//作者:陈到底------专注SIP通信24年
//
#include <pjsip.h>
#include <pjlib-util.h>
#include <pjlib.h>
#include <time.h>

#define APP_NAME			"msgGw"
#define	MAX_MSG_BODY_LEN	1500
#define	MSG_TYPE_TXT		"application"
#define	MSG_SUBTYPE_TXT		"json"

static pj_str_t msgContentType = { MSG_TYPE_TXT, strlen(MSG_TYPE_TXT)}, msgContentSubtype = { MSG_SUBTYPE_TXT, strlen(MSG_SUBTYPE_TXT)};

/* Options */
pj_caching_pool	Gcp;
pjsip_endpoint	*PjsipEndpoint;
int				ServerListenPort;
pj_pool_t		*PjsipMemPool;
pj_bool_t		QuitFlag;

#define MAX_LOG_FILES		5
char			DebugFileName[256];
int				LogLevel;
int				MaxLogFileLine;
int				DebugFileLines;
FILE*			DebugFp;

static pj_bool_t msgGwReceiveRxRequest(pjsip_rx_data *rdata );
static pj_bool_t msgGwReceiveRxResponse(pjsip_rx_data *rdata );

void initDebugFile(char* logDir,int logLevel)
{
	DebugFileLines=0;
	LogLevel=logLevel;
	DebugFp=NULL;
	strcpy(DebugFileName,logDir);
}

void myPhoneLogger(int level, const char *data, int len)
{
	if(level>LogLevel)
	{
		return;
	}

	if(0==DebugFileName[0])
	{
		return;
	}

	if(NULL==DebugFp)
	{
		DebugFp=fopen(DebugFileName,"a+");
	}

	if(NULL==DebugFp)
	{
		fprintf(stderr,"Can't open debug file:%s\n",DebugFileName);
		return;
	}

	fprintf(DebugFp,"%s",data);

	if(DebugFileLines++>MaxLogFileLine)
	{
		fclose(DebugFp);

		int	 i;
		char	tmpBuf1[512];
		char	tmpBuf2[512];

		sprintf(tmpBuf1,"%s_5",DebugFileName);
		unlink(tmpBuf1);
		for(i=MAX_LOG_FILES;i>0;i--)
		{
			sprintf(tmpBuf1,"%s_%d",DebugFileName,i);
			sprintf(tmpBuf2,"%s_%d",DebugFileName,i-1);
			rename(tmpBuf2,tmpBuf1);
		}

		rename(DebugFileName,tmpBuf2);
		DebugFileLines=0;

		DebugFp=NULL;
	}

	if(NULL!=DebugFp)
	{
		if(0==level)
		{
			fflush(DebugFp);
		}
		else if(!(DebugFileLines%20))
		{
			fflush(DebugFp);
		}
	}
}

void safeDumpPjstr(pj_str_t* inPut, char* outPut, int maxLen)
{
	int	len;
	outPut[0]=0;

	if(NULL==inPut)
	{
		return;
	}

	if(NULL==inPut->ptr || 0==inPut->slen)
	{
		return;
	}

	len=inPut->slen;

	if(len>maxLen-1)
	{
		len=maxLen-1;
	}

	memcpy(outPut,inPut->ptr,len);
	outPut[len]=0;
}

static pj_bool_t msgGwLogRxSipMessage(pjsip_rx_data *rdata)
{
	PJ_LOG(3,(APP_NAME, "RX %d bytes %s from %s %s:%d:\n"
						 "%.*s\n"
						 "--end msg--\n",
						 rdata->msg_info.len,
						 pjsip_rx_data_get_info(rdata),
						 rdata->tp_info.transport->type_name,
						 rdata->pkt_info.src_name,
						 rdata->pkt_info.src_port,
						 (int)rdata->msg_info.len,
						 rdata->msg_info.msg_buf));

	return PJ_FALSE;
}

static pj_status_t msgGwLogTxSipMessage(pjsip_tx_data *tdata)
{
	PJ_LOG(3,(APP_NAME, "TX %ld bytes %s to %s %s:%d:\n"
						 "%.*s\n"
						 "--end msg--\n",
						 (tdata->buf.cur - tdata->buf.start),
						 pjsip_tx_data_get_info(tdata),
						 tdata->tp_info.transport->type_name,
						 tdata->tp_info.dst_name,
						 tdata->tp_info.dst_port,
						 (int)(tdata->buf.cur - tdata->buf.start),
						 tdata->buf.start));

	return PJ_SUCCESS;
}

/* The module instance. */
static pjsip_module mod_msg_logger =
{
	NULL, NULL,						 /* prev, next.		  */
	{ "mod-msg-logger", 14 },		   /* Name.				*/
	-1,								 /* Id				   */
	PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority			*/
	NULL,							   /* load()			   */
	NULL,							   /* start()			  */
	NULL,							   /* stop()			   */
	NULL,							   /* unload()			 */
	&msgGwLogRxSipMessage,				 /* on_rx_request()	  */
	&msgGwLogRxSipMessage,				 /* on_rx_response()	 */
	&msgGwLogTxSipMessage,				 /* on_tx_request.	   */
	&msgGwLogTxSipMessage,				 /* on_tx_response()	 */
	NULL,							   /* on_tsx_state()	   */

};

static pj_status_t msgGwInitSipStack(void)
{
	pj_status_t 	status;
	pj_sockaddr_in	addr;

	status = pj_init();
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

	status = pjlib_util_init();
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

	pj_caching_pool_init(&Gcp, &pj_pool_factory_default_policy, 0);

	status = pjsip_endpt_create(&Gcp.factory, NULL, &PjsipEndpoint);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

	status = pjsip_tsx_layer_init_module(PjsipEndpoint);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

	/* Create listening transport */
	addr.sin_family = pj_AF_INET();
	addr.sin_addr.s_addr = 0;
	addr.sin_port = pj_htons((pj_uint16_t)ServerListenPort);

	status = pjsip_udp_transport_start( PjsipEndpoint, &addr, NULL, 1, NULL);
	if (status != PJ_SUCCESS)
		return status;

	/* Create pool for the application */
	PjsipMemPool = pj_pool_create(&Gcp.factory, "proxyapp", 1024*1024*1024, 1024*1024, NULL);

	/* Register the logger module */
	pjsip_endpt_register_module(PjsipEndpoint, &mod_msg_logger);

	return PJ_SUCCESS;
}

static pj_status_t msgGwInitProcess(void)
{
	pj_sockaddr		pri_addr;
	pj_sockaddr		addr_list[16];
	unsigned		addrCnt = PJ_ARRAY_SIZE(addr_list);
	unsigned		i;
	unsigned		nameCnt=0;
	pjsip_host_port	hostPort[64];

	/* List all names matching local endpoint.
	 * Note that PJLIB version 0.6 and newer has a function to
	 * enumerate local IP interface (pj_enum_ip_interface()), so
	 * by using it would be possible to list all IP interfaces in
	 * this host.
	 */

	/* The first address is important since this would be the one
	 * to be added in Record-Route.
	 */
	if (pj_gethostip(pj_AF_INET(), &pri_addr)==PJ_SUCCESS)
	{
		char addr[PJ_INET_ADDRSTRLEN];
		pj_inet_ntop(pj_AF_INET(), &pri_addr.ipv4.sin_addr, addr, sizeof(addr));
		pj_strdup2(PjsipMemPool, &hostPort[nameCnt].host, addr);
		hostPort[nameCnt].port = ServerListenPort;
		nameCnt++;
	}

	/* Get the rest of IP interfaces */
	if (pj_enum_ip_interface(pj_AF_INET(), &addrCnt, addr_list) == PJ_SUCCESS)
	{
		for (i=0; i<addrCnt; ++i)
		{
			char addr[PJ_INET_ADDRSTRLEN];

			if (addr_list[i].ipv4.sin_addr.s_addr == pri_addr.ipv4.sin_addr.s_addr)
				continue;

			pj_inet_ntop(pj_AF_INET(), &addr_list[i].ipv4.sin_addr, addr, sizeof(addr));
			pj_strdup2(PjsipMemPool, &hostPort[nameCnt].host, addr);
			hostPort[nameCnt].port = ServerListenPort;
			nameCnt++;
		}
	}

	/* Add loopback address. */
#if PJ_IP_HELPER_IGNORE_LOOPBACK_IF
	hostPort[nameCnt].host = pj_str("127.0.0.1");
	hostPort[nameCnt].port = ServerListenPort;
	nameCnt++;
#endif

	hostPort[nameCnt].host = *pj_gethostname();
	hostPort[nameCnt].port = ServerListenPort;
	nameCnt++;

	hostPort[nameCnt].host = pj_str("localhost");
	hostPort[nameCnt].port = ServerListenPort;
	nameCnt++;

	PJ_LOG(1,(APP_NAME, "Proxy started, listening on port %d", ServerListenPort));
	PJ_LOG(1,(APP_NAME, "Local host aliases:"));
	for (i=0; i<nameCnt; ++i)
	{
		PJ_LOG(1,(APP_NAME, " %.*s:%d", (int)hostPort[i].host.slen, hostPort[i].host.ptr, hostPort[i].port));
	}

	return PJ_SUCCESS;
}

static int msgGwWorkerThread(void *p)
{
	pj_time_val delay = {0, 10};

	PJ_UNUSED_ARG(p);

	while (!QuitFlag)
	{
		pjsip_endpt_handle_events(PjsipEndpoint, &delay);
	}

	return 0;
}

void msgGwUriProcessing(const pjsip_uri* inUri, char* outPut,int len)
{
	pjsip_sip_uri	*uri;

	outPut[0]=0;
	if(!PJSIP_URI_SCHEME_IS_SIP(inUri) && !PJSIP_URI_SCHEME_IS_SIPS(inUri))
	{
		PJ_LOG(1,(APP_NAME,"%s Not sip or sips uri",__func__));
		return;
	}

	uri=(pjsip_sip_uri*)inUri;
	safeDumpPjstr(&(uri->host), outPut, len-1);

	//pjsip_uri_print(PJSIP_URI_IN_OTHER, uri, tmpString, sizeof(tmpString)-1);
	//printf("URI String:\n%s\n",tmpString);
}

pj_bool_t msgGwProcessReceivedMessage(pjsip_rx_data *rdata)
{
	pjsip_msg_body	*body;
	char			msgBodyStr[MAX_MSG_BODY_LEN];
	char			fromUser[256];
	char			toUser[256];
	int				len;

	if(NULL==rdata)
	{
		PJ_LOG(1,(APP_NAME,"%s rdata is null",__func__));
		return PJ_FALSE;
	}

	//TODO:获取到发送人和接收人的名称,需要做检查处理
	msgGwUriProcessing(rdata->msg_info.from->uri,fromUser,sizeof(fromUser)-1);
	msgGwUriProcessing(rdata->msg_info.to->uri,toUser,sizeof(toUser)-1);

	body=rdata->msg_info.msg->body;
	if(NULL==body || NULL==body->data)
	{
		return PJ_FALSE;
	}

	safeDumpPjstr(&(body->content_type.type), msgBodyStr, sizeof(msgBodyStr)-1);
	if(strcasecmp(MSG_TYPE_TXT,msgBodyStr))
	{
		PJ_LOG(1,(APP_NAME,"%s Get message but content type<%s>not supported",__func__,msgBodyStr));
		return PJ_FALSE;
	}

	safeDumpPjstr(&(body->content_type.subtype), msgBodyStr, sizeof(msgBodyStr)-1);
	if(strcasecmp(MSG_SUBTYPE_TXT,msgBodyStr))
	{
		PJ_LOG(1,(APP_NAME,"%s Get message but content subtype<%s>not supported",__func__,msgBodyStr));
		return PJ_FALSE;
	}

	len=body->print_body(body, msgBodyStr, sizeof(msgBodyStr));
	if(len<=0)
	{
		return PJ_FALSE;
	}

	//TODO:对接收到的消息体进行处理

	return PJ_TRUE;
}

static pj_status_t msgGwVerifyRequest(pjsip_rx_data *rdata)
{
	/* URI scheme */
	if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.msg->line.req.uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.msg->line.req.uri))
	{
		pjsip_endpt_respond_stateless(PjsipEndpoint, rdata, PJSIP_SC_UNSUPPORTED_URI_SCHEME, NULL, NULL, NULL);
		return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_UNSUPPORTED_URI_SCHEME);
	}

	/* Max-Forwards */
	if (rdata->msg_info.max_fwd && rdata->msg_info.max_fwd->ivalue <= 1)
	{
		pjsip_endpt_respond_stateless(PjsipEndpoint, rdata, PJSIP_SC_TOO_MANY_HOPS, NULL, NULL, NULL);
		return PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_TOO_MANY_HOPS);
	}

	//TODO:如果要限制消息来自某个特定的IP,则在此处做检查
	//printf("Src Address:%s\n",rdata->pkt_info.src_name);

	return PJ_SUCCESS;
}

static void msgGwSafeQuitStack(void)
{
	pjsip_endpt_destroy(PjsipEndpoint);
	pj_pool_release(PjsipMemPool);
	pj_caching_pool_destroy(&Gcp);

	pj_shutdown();
}

static pjsip_module msgGwModStruct =
{
	NULL, NULL,						 /* prev, next.		  */
	{ "mod-stateful-proxy", 18 },	   /* Name.				*/
	-1,								 /* Id				   */
	PJSIP_MOD_PRIORITY_UA_PROXY_LAYER,  /* Priority			 */
	NULL,							   /* load()			   */
	NULL,							   /* start()			  */
	NULL,							   /* stop()			   */
	NULL,							   /* unload()			 */
	&msgGwReceiveRxRequest,			   /* on_rx_request()	  */
	&msgGwReceiveRxResponse,		  /* on_rx_response()	 */
	NULL,							   /* on_tx_request.	   */
	NULL,							   /* on_tx_response()	 */
	NULL,							   /* on_tsx_state()	   */
};

static pj_status_t msgGwInitStateful(void)
{
	pj_status_t status;

	status = pjsip_endpt_register_module( PjsipEndpoint, &msgGwModStruct);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

	return PJ_SUCCESS;
}

/* Callback to be called to handle new incoming requests. */
static pj_bool_t msgGwReceiveRxRequest( pjsip_rx_data *rdata )
{
	pj_status_t		status;
	pjsip_method	*method;
	char			tmpString[128];

	//PJSIP_OTHER_METHOD
	method=&(rdata->msg_info.msg->line.req.method);
	safeDumpPjstr(&(method->name), tmpString, sizeof(tmpString)-1);
	if(PJSIP_CANCEL_METHOD!=method->id && !strcasecmp(tmpString,"MESSAGE"))
	{
		status = msgGwVerifyRequest(rdata);
		if (PJ_SUCCESS!=status)
		{
			PJ_LOG(1,(APP_NAME,"RX invalid request"));
			return PJ_TRUE;
		}

		if(PJ_TRUE==msgGwProcessReceivedMessage(rdata))
		{
			pjsip_endpt_respond_stateless(PjsipEndpoint, rdata, 200, NULL, NULL, NULL);
		}
		else
		{
			pjsip_endpt_respond_stateless(PjsipEndpoint, rdata, PJSIP_SC_BAD_REQUEST, NULL, NULL, NULL);
		}
	}
	else
	{
		pjsip_endpt_respond_stateless(PjsipEndpoint, rdata, PJSIP_SC_BAD_REQUEST, NULL, NULL, NULL);
	}

	return PJ_TRUE;
}

static pj_bool_t msgGwReceiveRxResponse( pjsip_rx_data *rdata )
{
	PJ_LOG(1,(APP_NAME,"%s get response here",__func__));
	return PJ_TRUE;
}

static void msgGwMessageTransactionCallBack(void *token, pjsip_event *event)
{
	pjsip_transaction	*tsx;

	if (event->type != PJSIP_EVENT_TSX_STATE)
	{
		return;
	}

	tsx = event->body.tsx_state.tsx;

	if (PJSIP_TSX_STATE_COMPLETED==tsx->state)
	{
		//TODO: 处理传输完成或者失败,需要对你自己的数据库做标记
		PJ_LOG(1,(APP_NAME,"tsx->state:%d token:%p completed",tsx->state,token));
	}
	else if (PJSIP_TSX_STATE_TERMINATED==tsx->state)
	{
		PJ_LOG(1,(APP_NAME,"tsx->state:%d token:%p terminated",tsx->state,token));
	}
	else if (PJSIP_TSX_STATE_DESTROYED==tsx->state)
	{
		PJ_LOG(1,(APP_NAME,"tsx->state:%d token:%p destroyed",tsx->state,token));
	}
}

//此处将生成你自己的 contentType 和 msg Body
void msgGwAppendMessageBody(pjsip_tx_data* tdata, char* msgBody)
{
	pjsip_msg		*msg;
	pjsip_msg_body	*body;
	int				len;

	len=strlen(msgBody);

	if(0==len)
	{
		return;
	}

	msg=tdata->msg;
	body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
	body->content_type.type = msgContentType;
	body->content_type.subtype = msgContentSubtype;
	body->data = pj_pool_alloc(tdata->pool, len+1);
	pj_memcpy(body->data, msgBody, len);
	body->len = (unsigned)len;
	body->print_body = &pjsip_print_text_body;
	msg->body = body;
}

static pj_status_t msgGwTestSendMessage(void)
{
	pjsip_tx_data	*tdata;
	pj_status_t		status;
	pjsip_method	method={PJSIP_OTHER_METHOD, {"MESSAGE", 7}};
	char			dstString[256];
	pj_str_t		dst_uri;
	char			localString[256];
	pj_str_t		local_uri;
	char			contactString[256];
	pj_str_t		local_contact;
	char			textString[1024];
	long			tmpToken;

	sprintf(dstString,"<sip:chenjian@192.168.1.101:2345>");
	sprintf(localString,"<sip:sender@192.168.1.101:3456>");
	sprintf(contactString,"<sip:sender@192.168.1.101:3456>");
	sprintf(textString,"{\"msgtype\": \"1\", \"subtype\":\"3\", \"body\": \"This is a test msg\"}");

	dst_uri=pj_str(dstString);
	local_uri=pj_str(localString);
	local_contact=pj_str(contactString);

	//pj_str_t		pText;
	//pText=pj_str(textString);
	//status = pjsip_endpt_create_request(PjsipEndpoint, &method, &dst_uri, &local_uri, &dst_uri, &local_contact, NULL, -1, &pText, &tdata);
	status = pjsip_endpt_create_request(PjsipEndpoint, &method, &dst_uri, &local_uri, &dst_uri, &local_contact, NULL, -1, NULL, &tdata);
	if(PJ_SUCCESS!=status)
	{
		printf("%s can't create request\n",__func__);
		return status;
	}

	msgGwAppendMessageBody(tdata, textString);

	tmpToken=rand();
	status=pjsip_endpt_send_request(PjsipEndpoint, tdata, -1, (void*)tmpToken, &msgGwMessageTransactionCallBack);

	if (status != PJ_SUCCESS)
	{
		printf("Error sending stateful request\n");
	}

	return status;
}

int getConfigFromFile( FILE* fp, char *itemTitle, char *outvalue)
{
	int	 i;
	char	fileBuffer[1024];
	char	itemFormat[256];
	int	 ret=0;

	fseek(fp,0,SEEK_SET);

	sprintf(itemFormat,"%s=%%s",itemTitle);
	outvalue[0]=0;

	while (1)
	{
		memset(fileBuffer,0,sizeof(fileBuffer));
		fgets( fileBuffer, sizeof(fileBuffer)-10, fp );
		if( feof( fp ) )
		{
			break;
		}

		for(i=0;i<sizeof(fileBuffer)-10;i++)
		{
			if(fileBuffer[i]==' '||fileBuffer[i]=='\n')
			{
				fileBuffer[i]=0;
				break;
			}
		}

		if( (fileBuffer[0] == '#')||(fileBuffer[0] == ';')) //comment line
			continue;

		if(0==strncmp(fileBuffer,itemTitle,strlen(itemTitle)) && fileBuffer[strlen(itemTitle)]=='=')
		{
			if(sscanf(fileBuffer,itemFormat,outvalue)==1)
			{
				ret=1;
			}
			break;
		}
	}
	return(ret);
}

void msgGwGetConfigFromFile(char* fileName)
{
	FILE*	fp;
	char	tmpString[1024];
	int		i;
	char	logFile[256];

	ServerListenPort = 3456;
	MaxLogFileLine=50000;
	pj_log_set_level(1);

	if((fp=fopen(fileName,"r"))==NULL)
	{
		printf("Can't open config file:%s\n",fileName);
		exit(0);
	}

	if(getConfigFromFile(fp,"LISTENPORT", tmpString))
	{
		ServerListenPort=atoi(tmpString);
	}

	if(getConfigFromFile(fp,"MAXLOGLINE", tmpString))
	{
		MaxLogFileLine=atoi(tmpString);
	}

	if(getConfigFromFile(fp,"LOGLEVEL", tmpString))
	{
		i=atoi(tmpString);
		if(i>=0)
		{
			pj_log_set_level(i);
		}
	}

	logFile[0]=0;
	if(getConfigFromFile(fp,"LOGFILE", tmpString))
	{
		strcpy(logFile,tmpString);
	}

	initDebugFile(logFile,i);

	fclose(fp);
}

int main(int argc, char *argv[])
{
	pj_status_t	status;
	pj_thread_t	*threadPid;
	int			i;

	srand(time(NULL));
	msgGwGetConfigFromFile("msgGw.cfg");

	pj_log_set_log_func(myPhoneLogger);

	status = msgGwInitSipStack();
	if (status != PJ_SUCCESS)
	{
		PJ_LOG(1,(APP_NAME,"Error initializing stack"));
		return 1;
	}

	status = msgGwInitProcess();
	if (status != PJ_SUCCESS)
	{
		PJ_LOG(1,(APP_NAME,"Error initializing proxy"));
		return 1;
	}

	status = msgGwInitStateful();
	if (status != PJ_SUCCESS)
	{
		PJ_LOG(1,(APP_NAME,"Error initializing stateful proxy"));
		return 1;
	}

	status = pj_thread_create(PjsipMemPool, "sproxy", &msgGwWorkerThread, NULL, 0, 0, &threadPid);
	if (status != PJ_SUCCESS)
	{
		PJ_LOG(1,(APP_NAME,"Error creating thread"));
		return 1;
	}

	while (!QuitFlag)
	{
		char line[10];

		if (fgets(line, sizeof(line), stdin) == NULL)
		{
			puts("EOF while reading stdin, will quit now..");
			QuitFlag = PJ_TRUE;
			break;
		}

		if(line[0]=='s')
		{
			while(1)
			{
				for(i=0;i<10000;i++)
				{
					msgGwTestSendMessage();
				}
				sleep(1);
			}
		}
		else if (line[0] == 'q')
		{
			QuitFlag = PJ_TRUE;
		}
		else if (line[0] == 'd')
		{
			pj_bool_t detail = (line[1] == 'd');
			pjsip_endpt_dump(PjsipEndpoint, detail);
			pjsip_tsx_layer_dump(detail);
		}
	}

	pj_thread_join(threadPid);
	msgGwSafeQuitStack();
	return 0;
}

main中通过s来开始发送消息,每发送10000条消息sleep 1 秒,经测试如果没有sleep的话会有内存连续增长的问题,加上sleep以后没有出现内存连续增长,此程序也能

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值