基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3966794.html。

上章节讲解了讲解一个用eXosip2库实现的Demo 程序。Demo讲的是注册的过程,因为篇幅比较长,再分一节写。本节是上一节的继续,主要实现UAC用eXosip2库实现的Demo 程序。本节讲的比较全面,处理实现注册问题还添加了注销和刷新注册的过程。刷新相当于心跳的功能。注意这个函数eXosip_default_action()实现在sip中401和407错误类型的eXosip2库的自动处理。网上有的人问注册报文发送后,只收到401返回码。这是对SIP注册不了解造成的。至于这个过程在前面注册理论部分已经讲解。我也尝试不用eXosip_default_action()这个函数,我自己发送鉴权信息,可惜没成功,不知道什么原因,有时返回200OK,有时不返回,所以还是用了eXosip_default_action()这个函数,让401的响应报文由eXosip2库去发送。

1.eXosip2 API介绍

本章中要用的eXosip2库的API做个简单的介绍和使用方法

1.1 初始化库

在使用eXosip2前你需要初始化eXosip环境和libeXosip2.so库,这一步必须在所有使用之前完成。

 

 1     #include <eXosip2/eXosip.h>

 2     //库处理结果

 3     int result = OSIP_SUCCESS;

 4     //初始化库

 5     if (OSIP_SUCCESS != (result = eXosip_init()))

 6     {

 7         printf("eXosip_init failure.\n");

 8         return 1;

 9     }

10     cout << "eXosip_init success." << endl;

11     //监听

12     if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,

13             AF_INET, 0))

14     {

15         printf("eXosip_listen_addr failure.\n");

16                 eXosip_quit ();

17         return 1;

18     }                        

初始化完成之后,用户就可以发送SIP消息和等待接受SIP事件了。

 

1.2 接受事件

初始化eXosip2库后,主服务程序就可以接受事件并处理事件了,下面是一些从eXosip2协议栈接受处理事件的实例代码。

 1         //开启循环消息,实际应用中可以开启多线程同时接收信号

 2     eXosip_event_t* osipEventPtr = NULL;

 3 

 4     while (true)

 5     {

 6         // Wait the osip event.

 7         osipEventPtr = ::eXosip_event_wait(0, 200);

 8                 eXosip_lock();

 9         //一般处理401/407采用库默认处理

10         eXosip_default_action(osipEventPtr);

11         eXosip_unlock();

12         // If get nothing osip event,then continue the loop.

13         if (NULL == osipEventPtr)

14         {

15             continue;

16         }

17         // 事件处理

18 

19         switch (osipEventPtr->type)

20         {

21         //需要继续验证REGISTER是什么类型

22         case EXOSIP_REGISTRATION_NEW:

23         {

24             //注册事件处理

25         }

26             break;

27         case EXOSIP_MESSAGE_NEW:

28         {

29                 //消息事件处理

30         }

31             break;

32             case XXXXX:

33         {

34                 //事件处理

35         }

36             break;

37            case XXXXX:

38         {

39                 //事件处理

40         }

41             break;

42         default:

43             cout << "未处理消息 : " << osipEventPtr->type<<endl;

44             break;

45         }

46         eXosip_event_free(osipEventPtr);

47         osipEventPtr = NULL;                    

实际在应用的时候为了提高服务的并发性,一般并不用上面这种服务方式,因为上面这样,如果接受到某个事件,而这个事件的处理事件非常长的话,会影响效率,导致其他事件阻塞等待,得不到即使处理。所以一般采用并发服务器的设计思想,即在接受到一个事件后,分配一个线程来处理。当然如果想效率更高,想节省创建线程的时间,可以在系统一起动后,分配一定大小的线程池,有事件到来的话,直接从线程池中获取线程处理。

 

1.3 消息分析

每个UAC或者UAS发送一个SIP信息后,相对应的UAS或者UAC都会接受到响应的,即事件。每个事件包含两个部分,一个是request和response。request即是这个事件的请求报文, 而response是本次会话建立过程中,最后一次响应请求的报文。用户可以从获取的消息中,分析出message并且获取SIP头部,保存成用户自己的数据形式。下面实例获取expires头部内容。

1     osip_header_t* header = NULL;

2     osip_message_header_get_byname(request, "expires", 0, &header);

3     if (NULL != header && NULL != header->hvalue)

4     {

5            ......

6     }

7     

 

2.UAC代码实例 

  1 /*

  2  ===============================================================

  3  GBT28181 基于eXosip2,osip库实现注册UAC功能

  4  作者:程序人生

  5  博客地址:http://blog.csdn.net/hiwubihe

  6  QQ:1269122125

  7  注:请尊重原作者劳动成果,仅供学习使用,请勿盗用,违者必究!

  8  ================================================================

  9  */

 10 

 11 #include <iostream>

 12 #include <string>

 13 #include <sstream>

 14 #include <osipparser2/osip_message.h>

 15 #include <osipparser2/osip_parser.h>

 16 #include <osipparser2/osip_port.h>

 17 

 18 #include <eXosip2/eXosip.h>

 19 #include <eXosip2/eX_setup.h>

 20 #include <eXosip2/eX_register.h>

 21 #include <eXosip2/eX_options.h>

 22 #include <eXosip2/eX_message.h>

 23 #include <arpa/inet.h>

 24 #include <sys/types.h>

 25 #include <sys/socket.h>

 26 

 27 using namespace std;

 28 

 29 //本地监听IP

 30 #define LISTEN_ADDR ("192.168.50.57")

 31 //本地监听端口

 32 #define UACPORT ("5061")

 33 #define UACPORTINT (5061)

 34 //本UAC地址编码

 35 #define UACCODE ("100110000201000000")

 36 //本地UAC密码

 37 #define UACPWD ("12345")

 38 //远程UAS IP

 39 #define UAS_ADDR ("192.168.50.57")

 40 //远程UAS 端口

 41 #define UAS_PORT ("5060")

 42 //超时

 43 #define EXPIS 300

 44 

 45 //当前服务状态 1 已经注册 0 未注册

 46 static int iCurrentStatus;

 47 //注册成功HANDLE

 48 static int iHandle = -1;

 49 

 50 //SIP From/To 头部

 51 class CSipFromToHeader

 52 {

 53 public:

 54     CSipFromToHeader()

 55     {

 56     }

 57     ~CSipFromToHeader()

 58     {

 59     }

 60     void SetHeader(string addrCod, string addrI, string addrPor)

 61     {

 62         addrCode = addrCod;

 63         addrIp = addrI;

 64         addrPort = addrPor;

 65     }

 66     string GetFormatHeader()

 67     {

 68         std::stringstream stream;

 69         stream << "sip: " << addrCode << "@" << addrIp << ":" << addrPort;

 70         return stream.str();

 71     }

 72     //主机名称

 73     string GetCode()

 74     {

 75         std::stringstream stream;

 76         stream << addrCode;

 77         return stream.str();

 78     }

 79     //主机地址

 80     string GetAddr()

 81     {

 82         std::stringstream stream;

 83         stream << addrIp;

 84         return stream.str();

 85     }

 86     //端口

 87     string GetPort()

 88     {

 89         std::stringstream stream;

 90         stream << addrPort;

 91         return stream.str();

 92     }

 93 

 94 private:

 95     string addrCode;

 96     string addrIp;

 97     string addrPort;

 98 };

 99 

100 //SIP Contract头部

101 class CContractHeader: public CSipFromToHeader

102 {

103 public:

104     CContractHeader()

105     {

106     }

107     ~CContractHeader()

108     {

109     }

110     void SetContractHeader(string addrCod, string addrI, string addrPor)

111     {

112         SetHeader(addrCod, addrI, addrPor);

113     }

114     string GetContractFormatHeader()

115     {

116 

117         std::stringstream stream;

118         stream << "<sip:" << GetCode() << "@" << GetAddr() << ":" << GetPort()

119                 << ">";

120         return stream.str();

121     }

122 };

123 

124 //发送注册信息

125 int SendRegister(int& registerId, CSipFromToHeader &from, CSipFromToHeader &to,

126         CContractHeader &contact, const string& userName, const string& pwd,

127         const int expires, int iType)

128 {

129     cout << "=============================================" << endl;

130     if (iType == 0)

131     {

132         cout << "注册请求信息:" << endl;

133     }

134     else if (iType == 1)

135     {

136         cout << "刷新注册信息:" << endl;

137     }

138     else

139     {

140         cout << "注销信息:" << endl;

141     }

142     cout << "registerId " << registerId << endl;

143     cout << "from " << from.GetFormatHeader() << endl;

144     cout << "to " << to.GetFormatHeader() << endl;

145     cout << "contact" << contact.GetContractFormatHeader() << endl;

146     cout << "userName" << userName << endl;

147     cout << "pwd" << pwd << endl;

148     cout << "expires" << expires << endl;

149     cout << "=============================================" << endl;

150     //服务器注册

151     static osip_message_t *regMsg = 0;

152     int ret;

153 

154     ::eXosip_add_authentication_info(userName.c_str(), userName.c_str(),

155             pwd.c_str(), "MD5", NULL);

156     eXosip_lock();

157     //发送注册信息 401响应由eXosip2库自动发送

158     if (0 == registerId)

159     {

160         // 注册消息的初始化

161         registerId = ::eXosip_register_build_initial_register(

162                 from.GetFormatHeader().c_str(), to.GetFormatHeader().c_str(),

163                 contact.GetContractFormatHeader().c_str(), expires, &regMsg);

164         if (registerId <= 0)

165         {

166             return -1;

167         }

168     }

169     else

170     {

171         // 构建注册消息

172         ret = ::eXosip_register_build_register(registerId, expires, &regMsg);

173         if (ret != OSIP_SUCCESS)

174         {

175             return ret;

176         }

177         //添加注销原因

178         if (expires == 0)

179         {

180             osip_contact_t *contact = NULL;

181             char tmp[128];

182 

183             osip_message_get_contact(regMsg, 0, &contact);

184             {

185                 sprintf(tmp, "<sip:%s@%s:%s>;expires=0",

186                         contact->url->username, contact->url->host,

187                         contact->url->port);

188             }

189             //osip_contact_free(contact);

190             //reset contact header

191             osip_list_remove(&regMsg->contacts, 0);

192             osip_message_set_contact(regMsg, tmp);

193             osip_message_set_header(regMsg, "Logout-Reason", "logout");

194         }

195     }

196     // 发送注册消息

197     ret = ::eXosip_register_send_register(registerId, regMsg);

198     if (ret != OSIP_SUCCESS)

199     {

200         registerId = 0;

201     }eXosip_unlock();

202 

203     return ret;

204 }

205 

206 //注册

207 void Register()

208 {

209     if (iCurrentStatus == 1)

210     {

211         cout << "当前已经注册" << endl;

212         return;

213     }

214     CSipFromToHeader stFrom;

215     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);

216     CSipFromToHeader stTo;

217     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);

218     CContractHeader stContract;

219     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);

220     //发送注册信息

221     int registerId = 0;

222     if (0 > SendRegister(registerId, stFrom, stTo, stContract, UACCODE, UACPWD,

223             3000, 0))

224     {

225         cout << "发送注册失败" << endl;

226         return;

227     }

228     iCurrentStatus = 1;

229     iHandle = registerId;

230 }

231 //刷新注册

232 void RefreshRegister()

233 {

234     if (iCurrentStatus == 0)

235     {

236         cout << "当前未注册,不允许刷新" << endl;

237         return;

238     }

239     CSipFromToHeader stFrom;

240     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);

241     CSipFromToHeader stTo;

242     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);

243     CContractHeader stContract;

244     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);

245     //发送注册信息

246     if (0 > SendRegister(iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,

247             3000, 1))

248     {

249         cout << "发送刷新注册失败" << endl;

250         return;

251     }

252 }

253 //注销

254 void UnRegister()

255 {

256     if (iCurrentStatus == 0)

257     {

258         cout << "当前未注册,不允许注销" << endl;

259         return;

260     }

261     CSipFromToHeader stFrom;

262     stFrom.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);

263     CSipFromToHeader stTo;

264     stTo.SetHeader(UACCODE, UAS_ADDR, UAS_PORT);

265     CContractHeader stContract;

266     stContract.SetContractHeader(UACCODE, LISTEN_ADDR, UACPORT);

267     //发送注册信息

268269     if (0 > SendRegister( iHandle, stFrom, stTo, stContract, UACCODE, UACPWD,

270             0, 2))

271     {

272         cout << "发送注销失败" << endl;

273         return;

274     }

275     iCurrentStatus = 0;

276     iHandle = -1;

277 }

278 static void help()

279 {

280     const char

281             *b =

282     "-------------------------------------------------------------------------------\n"

283     "SIP Library test process - uac v 1.0 (June 13, 2014)\n\n"

284     "SIP UAC端 注册,刷新注册,注销实现\n\n"

285     "Author: 程序人生\n\n"

286     "博客地址:http://blog.csdn.net/hiwubihe QQ:1269122125\n\n"

287     "-------------------------------------------------------------------------------\n"

288     "\n"

289     "              0:Register\n"

290     "              1:RefreshRegister\n"

291     "              2:UnRegister\n"

292     "              3:clear scream\n"

293     "              4:exit\n"

294     "-------------------------------------------------------------------------------\n"

295     "\n";

296     fprintf(stderr, b, strlen(b));

297     cout << "please select method :";

298 }

299 //服务处理线程

300 void *serverHandle(void *pUser)

301 {

302     sleep(3);

303     help();

304     char ch = getchar();

305     getchar();

306     while (1)

307     {

308         switch (ch)

309         {

310         case '0':

311             //注册

312             Register();

313             break;

314         case '1':

315             //刷新注册

316             RefreshRegister();

317             break;

318         case '2':

319             //注销

320             UnRegister();

321             break;

322         case '3':

323             if (system("clear") < 0)

324             {

325                 cout << "clear scream error" << endl;

326                 exit(1);

327             }

328             break;

329         case '4':

330             cout << "exit sipserver......" << endl;

331             getchar();

332             exit(0);

333         default:

334             cout << "select error" << endl;

335             break;

336         }

337         cout << "press any key to continue......" << endl;

338         getchar();

339         help();

340         ch = getchar();

341         getchar();

342     }

343     return NULL;

344 }

345 

346 //事件处理线程

347 void *eventHandle(void *pUser)

348 {

349     eXosip_event_t* osipEventPtr = (eXosip_event_t*) pUser;

350     switch (osipEventPtr->type)

351     {

352     //需要继续验证REGISTER是什么类型

353     case EXOSIP_REGISTRATION_SUCCESS:

354     case EXOSIP_REGISTRATION_FAILURE:

355     {

356         cout<<"收到状态码:"<<osipEventPtr->response->status_code<<"报文"<<endl;

357         if(osipEventPtr->response->status_code == 401)

358         {

359             cout<<"发送鉴权报文"<<endl;

360         }

361         else if(osipEventPtr->response->status_code == 200)

362         {

363             cout<<"接收成功"<<endl;

364         }

365         else

366         {}

367     }

368         break;

369     default:

370         cout << "The sip event type that not be precessed.the event "

371             "type is : " << osipEventPtr->type << endl;

372         break;

373     }

374     eXosip_event_free(osipEventPtr);

375     return NULL;

376 }

377 

378 int main()

379 {

380     iCurrentStatus = 0;

381     //库处理结果

382     int result = OSIP_SUCCESS;

383     //初始化库

384     if (OSIP_SUCCESS != (result = eXosip_init()))

385     {

386         printf("eXosip_init failure.\n");

387         return 1;

388     }

389     cout << "eXosip_init success." << endl;

390     eXosip_set_user_agent(NULL);

391     //监听

392     if (OSIP_SUCCESS != eXosip_listen_addr(IPPROTO_UDP, NULL, UACPORTINT,

393             AF_INET, 0))

394     {

395         printf("eXosip_listen_addr failure.\n");

396         return 1;

397     }

398     //设置监听网卡

399     if (OSIP_SUCCESS != eXosip_set_option(

400     EXOSIP_OPT_SET_IPV4_FOR_GATEWAY,

401             LISTEN_ADDR))

402     {

403         return -1;

404     }

405     //开启服务线程

406     pthread_t pthser;

407     if (0 != pthread_create(&pthser, NULL, serverHandle, NULL))

408     {

409         printf("创建主服务失败\n");

410         return -1;

411     }

412     //事件用于等待

413     eXosip_event_t* osipEventPtr = NULL;

414     //开启事件循环

415     while (true)

416     {

417         //等待事件 0的单位是秒,500是毫秒

418         osipEventPtr = ::eXosip_event_wait(0, 200);

419         //处理eXosip库默认处理

420         {

421             usleep(500 * 1000);

422             eXosip_lock();

423             //一般处理401/407采用库默认处理

424             eXosip_default_action(osipEventPtr);

425             eXosip_unlock();

426         }

427         //事件空继续等待

428         if (NULL == osipEventPtr)

429         {

430             continue;

431         }

432         //开启线程处理事件并在事件处理完毕将事件指针释放

433         pthread_t pth;

434         if (0 != pthread_create(&pth, NULL, eventHandle, (void*) osipEventPtr))

435         {

436             printf("创建线程处理事件失败\n");

437             continue;

438         }

439         osipEventPtr = NULL;

440     }

441 }

 

3.测试效果

 3.1 启动后

基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

3.2 输入0 注册

可以看到第一次收到了401报文,库自动发送鉴权信息,然后收到了200OK报文。

基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

3.3 然后输入1刷新

可以看到收到200OK报文

基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

3.4 输入2注销后

收到200OK报文。并且可以看到expires为0了。

基于GBT28181:SIP协议组件开发-----------第五篇SIP注册流程eXosip2实现(二)

至此eXosip2库实现注册,全部功能完成。

 

你可能感兴趣的:(OS)