一個用eXosip實現的UAC和UAS的例子

/******************************************
編譯方法:
    gcc xxx.c -o xxx -leXosip2
****************************************/
/*******************UAS*****************************************************
本文可以任意轉載,但必須保留出處
作者:rainfish
網址:http://blog.csdn.net/bat603/
測試環境:eXosip3.0.1/redhat AS 4
***************************************************************************/
#include <eXosip2/eXosip.h>
#include <osip2/osip_mt.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

int
main (int argc, char *argv[])
{
  eXosip_event_t *je = NULL;
  osip_message_t *ack = NULL;
  osip_message_t *invite = NULL;
  osip_message_t *answer = NULL;
  sdp_message_t *remote_sdp = NULL;

  int call_id, dialog_id;
  int i,j;
  int id;
  char *sour_call = "sip:[email protected]";
  char *dest_call = "sip:[email protected]:5060";

  char command;
  char tmp[4096];
  char localip[128];

  int pos = 0;

  //初始化sip
  i = eXosip_init ();
  if (i != 0)
    {
      printf ("Can't initialize eXosip!/n");
      return -1;
    }
  else
    {
      printf ("eXosip_init successfully!/n");
    }

  i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5060, AF_INET, 0);
  if (i != 0)
    {
      eXosip_quit ();
      fprintf (stderr, "eXosip_listen_addr error!/nCouldn't initialize transport layer!/n");
    }

  for(;;)
    {
      //偵聽是否有消息到來
      je = eXosip_event_wait (0,50); 

      //協議棧帶有此語句,具體作用未知
      eXosip_lock ();
      eXosip_default_action (je);
      eXosip_automatic_refresh ();
      eXosip_unlock ();

      if (je == NULL)//沒有接收到消息
    continue;
      // printf ("the cid is %s, did is %s/n", je->did, je->cid);
      switch (je->type)
    {
    case EXOSIP_MESSAGE_NEW://新的消息到來
      printf (" EXOSIP_MESSAGE_NEW!/n");
      if (MSG_IS_MESSAGE (je->request))//如果接受到的消息類型是MESSAGE
        {
      {
        osip_body_t *body;
        osip_message_get_body (je->request, 0, &body); 
        printf ("I get the msg is: %s/n", body->body);
        //printf ("the cid is %s, did is %s/n", je->did, je->cid);
      }
      //按照規則,需要回復200 OK信息
      eXosip_message_build_answer (je->tid, 200,&answer);
      eXosip_message_send_answer (je->tid, 200,answer);
        }
      break;
    case EXOSIP_CALL_INVITE:
      //得到接收到消息的具體信息
            printf ("Received a INVITE msg from %s:%s, UserName is %s, password is %s/n",je->request->req_uri->host,
          je->request->req_uri->port, je->request->req_uri->username, je->request->req_uri->password);
      //得到消息體,認爲該消息就是SDP格式.
      remote_sdp = eXosip_get_remote_sdp (je->did);
      call_id = je->cid;
      dialog_id = je->did;
      
      eXosip_lock ();
      eXosip_call_send_answer (je->tid, 180, NULL);
      i = eXosip_call_build_answer (je->tid, 200, &answer);
      if (i != 0)
        {
          printf ("This request msg is invalid!Cann't response!/n");
          eXosip_call_send_answer (je->tid, 400, NULL);
        }
      else
        {
          snprintf (tmp, 4096,
               "v=0/r/n"
               "o=anonymous 0 0 IN IP4 0.0.0.0/r/n"
               "t=1 10/r/n"
               "a=username:rainfish/r/n"
               "a=password:123/r/n");
          
          //設置回覆的SDP消息體,下一步計劃分析消息體
          //沒有分析消息體,直接回復原來的消息,這一塊做的不好。
          osip_message_set_body (answer, tmp, strlen(tmp));
          osip_message_set_content_type (answer, "application/sdp");
          
          eXosip_call_send_answer (je->tid, 200, answer);
          printf ("send 200 over!/n");
        }
      eXosip_unlock ();
      
      //顯示出在sdp消息體中的 attribute 的內容,裏面計劃存放我們的信息
      printf ("the INFO is :/n");
      while (!osip_list_eol (remote_sdp->a_attributes, pos))
        {
          sdp_attribute_t *at;
          
          at = (sdp_attribute_t *) osip_list_get (remote_sdp->a_attributes, pos);
          printf ("%s : %s/n", at->a_att_field, at->a_att_value);//這裏解釋了爲什麼在SDP消息體中屬性a裏面存放必須是兩列 
          
          pos ++;
        }
      break;
    case EXOSIP_CALL_ACK:
      printf ("ACK recieved!/n");
      // printf ("the cid is %s, did is %s/n", je->did, je->cid); 
      break;
    case EXOSIP_CALL_CLOSED:
      printf ("the remote hold the session!/n");
      // eXosip_call_build_ack(dialog_id, &ack);
      //eXosip_call_send_ack(dialog_id, ack); 
      i = eXosip_call_build_answer (je->tid, 200, &answer);
      if (i != 0)
        {
          printf ("This request msg is invalid!Cann't response!/n");
          eXosip_call_send_answer (je->tid, 400, NULL);
        
          }
      else
        {
          eXosip_call_send_answer (je->tid, 200, answer);
          printf ("bye send 200 over!/n");
        }        
      break;

    case EXOSIP_CALL_MESSAGE_NEW://至於該類型和EXOSIP_MESSAGE_NEW的區別,源代碼這麼解釋的
    /*
    /* request related events within calls (except INVITE) */
          EXOSIP_CALL_MESSAGE_NEW,            /**< announce new incoming request. */
    /* response received for request outside calls */
            EXOSIP_MESSAGE_NEW,            /**< announce new incoming request. */
            我也不是很明白,理解是: EXOSIP_CALL_MESSAGE_NEW是一個呼叫中的新的消息到來,比如ring trying都算,所以在接受到後必須判斷
            該消息類型,EXOSIP_MESSAGE_NEW而是表示不是呼叫內的消息到來。
            該解釋有不妥地方,僅供參考。
    */
      printf(" EXOSIP_CALL_MESSAGE_NEW/n");
      if (MSG_IS_INFO(je->request)//如果傳輸的是INFO方法
      {
                   eXosip_lock ();
              i = eXosip_call_build_answer (je->tid, 200, &answer);
              if (i == 0)
                {
                  eXosip_call_send_answer (je->tid, 200, answer);
                }
              eXosip_unlock ();
          {
        osip_body_t *body;
        osip_message_get_body (je->request, 0, &body);
        printf ("the body is %s/n", body->body);
          }
      }
      break; 
    default:
      printf ("Could not parse the msg!/n");
    }
    }
}
/*******************UAC*****************************************************
本文可以任意轉載,但必須保留出處
作者:rainfish
網址:http://blog.csdn.net/bat603/
測試環境:eXosip3.0.1/redhat AS 4
***************************************************************************/

#include <eXosip2/eXosip.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

int 
main (int argc, char *argv[])
{
  eXosip_event_t *je;
  osip_message_t *reg = NULL;
  osip_message_t *invite = NULL;
  osip_message_t *ack = NULL;
  osip_message_t *info = NULL;
  osip_message_t *message = NULL;

  int call_id, dialog_id;
  int i,flag;
  int flag1 = 1;
  int id;
  
  char *identity = "sip:[email protected]";
  char *registerer = "sip:192.168.0.133:5060";
  char *source_call = "sip:[email protected]";
  char *dest_call = "sip:[email protected]:5060";
  
  char command;
  char tmp[4096];
  char localip[128];

  printf("r     向服務器註冊/n/n");
  printf("c     取消註冊/n/n");
  printf("i     發起呼叫請求/n/n");
  printf("h     掛斷/n/n");
  printf("q     退出程序/n/n");
  printf("s     執行方法INFO/n/n");
  printf("m     執行方法MESSAGE/n/n");
  //初始化
  i = eXosip_init ();
  if (i != 0)
    {
      printf ("Couldn't initialize eXosip!/n");
      return -1;
    }
  else
    {
      printf ("eXosip_init successfully!/n");
    }

  i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5060, AF_INET, 0);
  if (i != 0)
    {
      eXosip_quit ();
      fprintf (stderr, "Couldn't initialize transport layer!/n");
      return -1;
    }
  flag = 1;
  while (flag)
    {
      printf ("please input the comand:/n");
      
      scanf ("%c", &command);
      getchar ();
      
      switch (command)
    {
    case 'r':
      printf ("This modal isn't commpleted!/n");
      break;
    case 'i':/* INVITE */
      i = eXosip_call_build_initial_invite (&invite, dest_call, source_call, NULL, "This si a call for a conversation");
      if (i != 0)
        {
          printf ("Intial INVITE failed!/n");
          break;
        }
        //符合SDP格式,其中屬性a是自定義格式,也就是說可以存放自己的信息,但是隻能是兩列,比如帳戶信息
        //但是經測試,格式:v o t必不可少,原因未知,估計是協議棧在傳輸時需要檢查的
      snprintf (tmp, 4096,
            "v=0/r/n"
            "o=anonymous 0 0 IN IP4 0.0.0.0/r/n"
            "t=1 10/r/n"
            "a=username:rainfish/r/n"
            "a=password:123/r/n");
      osip_message_set_body (invite, tmp, strlen(tmp));
      osip_message_set_content_type (invite, "application/sdp");
      
      eXosip_lock ();
      i = eXosip_call_send_initial_invite (invite);
      eXosip_unlock ();
      flag1 = 1;
      while (flag1)
        {
          je = eXosip_event_wait (0, 200);
          
          if (je == NULL)
        {
          printf ("No response or the time is over!/n");
          break;
        }
          
          switch (je->type)
        {
        case EXOSIP_CALL_INVITE:
          printf ("a new invite reveived!/n");
          break;
        case EXOSIP_CALL_PROCEEDING:
          printf ("proceeding!/n");
          break;
        case EXOSIP_CALL_RINGING:
          printf ("ringing!/n");
          // call_id = je->cid;
          // dialog_id = je->did;
          printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did);
          break;
        case EXOSIP_CALL_ANSWERED:
          printf ("ok! connected!/n");
          call_id = je->cid;
          dialog_id = je->did;
          printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did);

          eXosip_call_build_ack (je->did, &ack);
          eXosip_call_send_ack (je->did, ack);
          flag1 = 0;
          break;
        case EXOSIP_CALL_CLOSED:
          printf ("the other sid closed!/n");
          break;
        case EXOSIP_CALL_ACK:
          printf ("ACK received!/n");
          break;
        default:
          printf ("other response!/n");
          break;
        }
          eXosip_event_free (je);
         
        }
      break;
    case 'h':
      printf ("Holded !/n");
      
      eXosip_lock ();
      eXosip_call_terminate (call_id, dialog_id);
      eXosip_unlock ();
      break;
    case 'c':
      printf ("This modal isn't commpleted!/n");
      break;
    case 's':
    //傳輸INFO方法
      eXosip_call_build_info (dialog_id, &info);
      snprintf (tmp , 4096,
            "hello,rainfish");
      osip_message_set_body (info, tmp, strlen(tmp));
      //格式可以任意設定,text/plain代表文本信息
      osip_message_set_content_type (info, "text/plain");
      eXosip_call_send_request (dialog_id, info);
      break;
    case 'm':
    //傳輸MESSAGE方法,也就是即時消息,和INFO方法相比,我認爲主要區別,是MESSAGE不用建立連接,直接傳輸信息,而INFO必須
    //在建立INVITE的基礎上傳輸。
      printf ("the mothed :MESSAGE/n");
      eXosip_message_build_request (&message, "MESSAGE", dest_call, source_call, NULL);
      snprintf (tmp, 4096,
            "hellor rainfish");
      osip_message_set_body (message, tmp, strlen(tmp));
      //假設格式是xml
      osip_message_set_content_type (message, "text/xml");
      eXosip_message_send_request (message);
      break;
    case 'q':
      eXosip_quit ();
      printf ("Exit the setup!/n");
      flag = 0;
      break;
    }
    }
  return (0);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章