]> sjero.net Git - linphone/blob - coreapi/callbacks.c
Merge branch 'dev_lsd' into dev_multicall
[linphone] / coreapi / callbacks.c
1 /*
2 linphone
3 Copyright (C) 2010  Simon MORLAT (simon.morlat@free.fr)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20
21 #include "sal.h"
22
23 #include "linphonecore.h"
24 #include "private.h"
25 #include "mediastreamer2/mediastream.h"
26
27
28 static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
29         if (lc->vtable.show)
30                 lc->vtable.show(lc);
31         if (lc->vtable.display_status)
32                 lc->vtable.display_status(lc,_("Connected."));
33         if (lc->vtable.connected_recv)
34                 lc->vtable.connected_recv(lc,call);
35         call->state=LinphoneCallAVRunning;
36         if (lc->ringstream!=NULL){
37                 ring_stop(lc->ringstream);
38                 lc->ringstream=NULL;
39         }
40         if(!linphone_core_in_call(lc))
41         {
42                 linphone_core_set_as_current_call(lc,call);
43         }
44         if(call == linphone_core_get_current_call(lc))
45                 linphone_core_start_media_streams(lc,call);
46 }
47
48 static void call_received(SalOp *h){
49         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
50         char *barmesg;
51         LinphoneCall *call;
52         const char *from,*to;
53         char *tmp;
54         LinphoneAddress *from_parsed;
55
56         /* first check if we can answer successfully to this invite */
57         if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){
58                 ms_message("Not present !! presence mode : %d\n",lc->presence_mode);
59                 if (lc->presence_mode==LINPHONE_STATUS_BUSY)
60                         sal_call_decline(h,SalReasonBusy,NULL);
61                 else if (lc->presence_mode==LINPHONE_STATUS_AWAY
62                          ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK
63                          ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE
64                          ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH
65                          ||lc->presence_mode==LINPHONE_STATUS_OFFLINE)
66                         sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
67                 else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
68                         sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
69                 else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
70                         sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
71                 else
72                         sal_call_decline(h,SalReasonBusy,NULL);
73                 sal_op_release(h);
74                 return;
75         }
76         if (!linphone_core_can_we_add_call(lc)){/*busy*/
77                 sal_call_decline(h,SalReasonBusy,NULL);
78                 sal_op_release(h);
79                 return;
80         }
81         from=sal_op_get_from(h);
82         to=sal_op_get_to(h);
83         
84         call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
85         if(linphone_core_add_call(lc,call)!= 0)
86         {
87                 ms_warning("we cannot have more calls\n");
88                 sal_call_decline(h,SalReasonMedia,NULL);
89                 linphone_call_unref(call);
90                 return;
91         }
92         if(linphone_core_get_current_call(lc)!=NULL) //we are already in call just inform that an incoming call is going on
93         {
94                 char temp[256];
95                 snprintf(temp,sizeof(temp),"A new incoming call from %s during call",from);
96                 lc->vtable.display_status(lc,temp);
97         }
98         sal_call_set_local_media_description(h,call->localdesc);
99         call->resultdesc=sal_call_get_final_media_description(h);
100         if (call->resultdesc)
101                 sal_media_description_ref(call->resultdesc);
102         if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
103                 sal_call_decline(h,SalReasonMedia,NULL);
104                 linphone_call_unref(call);
105                 return;
106         }
107         
108         from_parsed=linphone_address_new(sal_op_get_from(h));
109         linphone_address_clean(from_parsed);
110         tmp=linphone_address_as_string(from_parsed);
111         linphone_address_destroy(from_parsed);
112         gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
113         barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
114             (sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
115         if (lc->vtable.show) lc->vtable.show(lc);
116         if (lc->vtable.display_status) 
117             lc->vtable.display_status(lc,barmesg);
118
119         /* play the ring */
120         if (lc->sound_conf.ring_sndcard!=NULL && !linphone_core_in_call(lc)){
121                 if(lc->ringstream==NULL){
122                         MSSndCard *ringcard=lc->sound_conf.lsd_card ?lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
123                         ms_message("Starting local ring...");
124                         lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard);
125                 }
126                 else
127                 {
128                         ms_message("the local ring is already started");
129                 }
130         }
131         call->state=LinphoneCallRinging;
132         sal_call_notify_ringing(h);
133         linphone_core_init_media_streams(lc,call);
134         if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,call);
135         ms_free(barmesg);
136         ms_free(tmp);
137 }
138
139 static void call_ringing(SalOp *h){
140         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
141         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
142         SalMediaDescription *md;
143         if (call==NULL) return;
144         if (lc->vtable.display_status)
145                 lc->vtable.display_status(lc,_("Remote ringing."));
146         if (lc->vtable.ringing_recv)
147                 lc->vtable.ringing_recv(lc,call);
148         md=sal_call_get_final_media_description(h);
149         if (md==NULL){
150                 if (lc->ringstream!=NULL) return;       /*already ringing !*/
151                 if (lc->sound_conf.play_sndcard!=NULL){
152                         MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
153                         ms_message("Remote ringing...");
154                         lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
155                 }
156         }else{
157                 /*accept early media */
158                 if (lc->audiostream && lc->audiostream->ticker!=NULL){
159                         /*streams already started */
160                         ms_message("Early media already started.");
161                         return;
162                 }
163                 sal_media_description_ref(md);
164                 call->resultdesc=md;
165                 if (lc->vtable.show) lc->vtable.show(lc);
166                 if (lc->vtable.display_status) 
167                         lc->vtable.display_status(lc,_("Early media."));
168                 gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
169                 if (lc->ringstream!=NULL){
170                         ring_stop(lc->ringstream);
171                         lc->ringstream=NULL;
172                 }
173                 ms_message("Doing early media...");
174                 if(call == linphone_core_get_current_call(lc))
175                         linphone_core_start_media_streams(lc,call);
176                 call->media_pending=TRUE;
177         }
178         call->state=LinphoneCallRinging;
179 }
180
181 /*
182  * could be reach :
183  *  - when the call is accepted
184  *  - when a request is accepted (pause, resume)
185  */
186 static void call_accepted(SalOp *op){
187         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
188         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
189         if (call==NULL){
190                 ms_warning("No call to accept.");
191                 return ;
192         }
193         if (call->state==LinphoneCallAVRunning){
194                 ms_message("GET ACK of resume\n");
195                 if(lc->vtable.ack_resumed_recv)
196                         lc->vtable.ack_resumed_recv(lc,call);
197                 return ; //already accepted
198         }
199         if ((lc->audiostream!=NULL) && (lc->audiostream->ticker!=NULL)){
200                 /*case where we accepted early media */
201                 if(call == linphone_core_get_current_call(lc))
202                 {
203                         linphone_core_stop_media_streams(lc,call);
204                         linphone_core_init_media_streams(lc,call);
205                 }
206         }
207         if (call->resultdesc)
208                 sal_media_description_unref(call->resultdesc);
209         call->resultdesc=sal_call_get_final_media_description(op);
210         if (call->resultdesc){
211                 sal_media_description_ref(call->resultdesc);
212                 call->media_pending=FALSE;
213         }
214         if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
215                 //if we initiate a pause
216                 if(call->state == LinphoneCallPaused)
217                 {
218                         ms_message("GET ACK of pause\n");
219                         if(lc->vtable.ack_paused_recv)
220                                 lc->vtable.ack_paused_recv(lc,call);
221                 }//if there is an accepted incoming call
222                 else
223                 {
224                         gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
225                         linphone_connect_incoming(lc,call);
226                 }               
227         }else{
228                 /*send a bye*/
229                 ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
230                 linphone_core_terminate_call(lc,NULL);
231         }
232 }
233
234 static void call_ack(SalOp *op){
235         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
236         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
237         if (call==NULL){
238                 ms_warning("No call to be ACK'd");
239                 return ;
240         }
241         if (call->media_pending){
242                 if (lc->audiostream->ticker!=NULL){
243                         /*case where we accepted early media */
244                         if(call == linphone_core_get_current_call(lc))
245                         {
246                                 linphone_core_stop_media_streams(lc,call);
247                                 linphone_core_init_media_streams(lc,call);
248                         }
249                 }
250                 if (call->resultdesc)
251                         sal_media_description_unref(call->resultdesc);
252                 call->resultdesc=sal_call_get_final_media_description(op);
253                 if (call->resultdesc)
254                         sal_media_description_ref(call->resultdesc);
255                 if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
256                         gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
257                         linphone_connect_incoming(lc,call);
258                 }else{
259                         /*send a bye*/
260                         ms_error("Incompatible SDP response received in ACK, need to abort the call");
261                         linphone_core_terminate_call(lc,NULL);
262                 }
263                 call->media_pending=FALSE;
264         }
265 }
266
267 static void call_updated(SalOp *op){
268         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
269         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
270         if (call->resultdesc)
271                 sal_media_description_unref(call->resultdesc);
272         call->resultdesc=sal_call_get_final_media_description(op);
273         if (call->resultdesc)
274                 sal_media_description_ref(call->resultdesc);
275
276         if (call->resultdesc && !sal_media_description_empty(call->resultdesc))
277         {
278                 if( (call->state == LinphoneCallPaused) && strcmp(call->resultdesc->addr,"0.0.0.0"))
279                 {
280                         if(lc->vtable.display_status)
281                                 lc->vtable.display_status(lc,"we have been resumed...");
282                         call->state = LinphoneCallAVRunning;
283                         lc->vtable.resumed_recv(lc,call);
284                         //we have to keep sending when holded
285                         //linphone_core_start_media_streams(lc,call);
286                 }
287                 else if( (call->state != LinphoneCallPaused) && !strcmp(call->resultdesc->addr,"0.0.0.0"))
288                 {
289                         if(lc->vtable.display_status)
290                                 lc->vtable.display_status(lc,"we have been paused...");
291                         call->state = LinphoneCallPaused;
292                         lc->vtable.paused_recv(lc,call);
293                         //we have to keep sending when holded
294                         /*
295                         if(call == linphone_core_get_current_call(lc))
296                         {
297                                 linphone_core_stop_media_streams(lc,call);
298                                 linphone_core_init_media_streams(lc,call);
299                         }
300                         */
301                 }
302                 else
303                 {
304                         if(call == linphone_core_get_current_call(lc))
305                         {
306                                 linphone_core_stop_media_streams(lc,call);
307                                 linphone_core_init_media_streams(lc,call);
308                         }
309                         linphone_connect_incoming(lc,call);
310                 }
311         }
312 }
313
314 static void call_terminated(SalOp *op, const char *from){
315         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
316         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
317         if (linphone_call_get_state(call)==LinphoneCallTerminated){
318                 ms_warning("call_terminated: ignoring.");
319                 return;
320         }
321         ms_message("Current call terminated...");
322         //we stop the call only if we have this current call or if we are in call
323         if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls)  == 1) || linphone_core_in_call(lc) )) {
324                 ring_stop(lc->ringstream);
325                 lc->ringstream=NULL;
326         }
327         if(call == linphone_core_get_current_call(lc))
328                 linphone_core_stop_media_streams(lc,call);
329         if (lc->vtable.show!=NULL)
330                 lc->vtable.show(lc);
331         if (lc->vtable.display_status!=NULL)
332                 lc->vtable.display_status(lc,_("Call terminated."));
333         linphone_call_set_terminated(call);
334         gstate_new_state(lc, GSTATE_CALL_END, NULL);
335         if (lc->vtable.bye_recv!=NULL){
336                 LinphoneAddress *addr=linphone_address_new(from);
337                 char *tmp;
338                 linphone_address_clean(addr);
339                 tmp=linphone_address_as_string(addr);
340                 lc->vtable.bye_recv(lc,call);
341                 ms_free(tmp);
342                 linphone_address_destroy(addr);
343         }
344         linphone_call_unref(call);
345 }
346
347 static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
348         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
349         char *msg486=_("User is busy.");
350         char *msg480=_("User is temporarily unavailable.");
351         /*char *retrymsg=_("%s. Retry after %i minute(s).");*/
352         char *msg600=_("User does not want to be disturbed.");
353         char *msg603=_("Call declined.");
354         char *msg=NULL;
355         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
356
357         if (lc->vtable.show) lc->vtable.show(lc);
358
359         if (error==SalErrorNoResponse){
360                 if (lc->vtable.display_status)
361                         lc->vtable.display_status(lc,_("No response."));
362         }else if (error==SalErrorProtocol){
363                 if (lc->vtable.display_status)
364                         lc->vtable.display_status(lc, details ? details : _("Protocol error."));
365         }else if (error==SalErrorFailure){
366                 switch(sr){
367                         case SalReasonDeclined:
368                                 msg=msg603;
369                                 if (lc->vtable.display_status)
370                                         lc->vtable.display_status(lc,msg603);
371                         break;
372                         case SalReasonBusy:
373                                 msg=msg486;
374                                 if (lc->vtable.display_status)
375                                         lc->vtable.display_status(lc,msg486);
376                         break;
377                         case SalReasonRedirect:
378                                 msg=_("Redirected");
379                                 if (lc->vtable.display_status)
380                                         lc->vtable.display_status(lc,msg);
381                         break;
382                         case SalReasonTemporarilyUnavailable:
383                                 msg=msg480;
384                                 if (lc->vtable.display_status)
385                                         lc->vtable.display_status(lc,msg480);
386                         break;
387                         case SalReasonNotFound:
388                                 msg=_("Not found");
389                                 if (lc->vtable.display_status)
390                                         lc->vtable.display_status(lc,msg);
391                         break;
392                         case SalReasonDoNotDisturb:
393                                 msg=msg600;
394                                 if (lc->vtable.display_status)
395                                         lc->vtable.display_status(lc,msg600);
396                         break;
397                         case SalReasonMedia:
398                                 msg=_("No common codecs");
399                                 if (lc->vtable.display_status)
400                                         lc->vtable.display_status(lc,msg);
401                         break;
402                         default:
403                                 if (lc->vtable.display_status)
404                                         lc->vtable.display_status(lc,_("Call failed."));
405                 }
406         }
407         if (lc->vtable.failure_recv)
408                 lc->vtable.failure_recv(lc,call,code);
409         if (lc->ringstream!=NULL) {
410                 ring_stop(lc->ringstream);
411                 lc->ringstream=NULL;
412         }
413         if(call == linphone_core_get_current_call(lc))
414                 linphone_core_stop_media_streams(lc,call);
415         if (call!=NULL) {
416                 linphone_call_set_terminated(call);
417                 linphone_call_unref(call);//TODO not an unref here ???//AUREL
418                 if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg);
419                 else gstate_new_state(lc, GSTATE_CALL_END, NULL);
420         }
421 }
422
423 static void auth_requested(SalOp *h, const char *realm, const char *username){
424         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
425         LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
426         ms_message("auth_requested() for realm=%s, username=%s",realm,username);
427         if (ai && (ai->works || ai->usecount<3)){
428                 SalAuthInfo sai;
429                 sai.username=ai->username;
430                 sai.userid=ai->userid;
431                 sai.realm=ai->realm;
432                 sai.password=ai->passwd;
433                 ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username);
434                 sal_op_authenticate(h,&sai);
435                 ai->usecount++;
436         }else{
437                 if (lc->vtable.auth_info_requested)
438                         lc->vtable.auth_info_requested(lc,realm,username);
439         }
440 }
441
442 static void auth_success(SalOp *h, const char *realm, const char *username){
443         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
444         LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username);
445         if (ai){
446                 ms_message("%s/%s authentication works.",realm,username);
447                 ai->works=TRUE;
448         }
449 }
450
451 static void register_success(SalOp *op, bool_t registered){
452         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
453         LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
454         char *msg;
455         cfg->registered=registered;
456         gstate_new_state(lc, GSTATE_REG_OK, NULL);
457         if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
458         else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
459         if (lc->vtable.display_status) 
460                 lc->vtable.display_status(lc,msg);
461         ms_free(msg);
462 }
463
464 static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
465         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
466         char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
467         if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
468         gstate_new_state(lc, GSTATE_REG_FAILED, msg);
469         ms_free(msg);
470 }
471
472 static void vfu_request(SalOp *op){
473 #ifdef VIDEO_ENABLED
474         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
475         if (lc->videostream)
476                 video_stream_send_vfu(lc->videostream);
477 #endif
478 }
479
480 static void dtmf_received(SalOp *op, char dtmf){
481         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
482         if (lc->vtable.dtmf_received != NULL)
483                 lc->vtable.dtmf_received(lc, dtmf);
484 }
485
486 static void refer_received(Sal *sal, SalOp *op, const char *referto){
487         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
488         LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
489         if (lc->vtable.refer_received){
490                 lc->vtable.refer_received(lc,call,referto);
491                 if (op) sal_refer_accept(op);
492         }
493 }
494
495 static void text_received(Sal *sal, const char *from, const char *msg){
496         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
497         linphone_core_text_received(lc,from,msg);
498 }
499
500 static void notify(SalOp *op, const char *from, const char *msg){
501         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
502
503         ms_message("get a %s notify from %s",msg,from);
504         if(lc->vtable.notify_recv)
505                 lc->vtable.notify_recv(lc,from,msg);
506 }
507
508 static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
509         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
510         linphone_notify_recv(lc,op,ss,status);
511 }
512
513 static void subscribe_received(SalOp *op, const char *from){
514         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
515         linphone_subscription_new(lc,op,from);
516 }
517
518 static void subscribe_closed(SalOp *op, const char *from){
519         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
520         linphone_subscription_closed(lc,op);
521 }
522
523 static void internal_message(Sal *sal, const char *msg){
524         LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
525         if (lc->vtable.show)
526                 lc->vtable.show(lc);
527 }
528
529 static void ping_reply(SalOp *op){
530         LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
531         ms_message("ping reply !");
532         if (call){
533                 if (call->state==LinphoneCallPreEstablishing){
534                         linphone_core_start_invite(call->core,call,NULL);
535                 }
536         }
537         else
538         {
539                 ms_warning("ping reply without call attached...");
540         }
541 }
542
543 SalCallbacks linphone_sal_callbacks={
544         call_received,
545         call_ringing,
546         call_accepted,
547         call_ack,
548         call_updated,
549         call_terminated,
550         call_failure,
551         auth_requested,
552         auth_success,
553         register_success,
554         register_failure,
555         vfu_request,
556         dtmf_received,
557         refer_received,
558         text_received,
559         notify,
560         notify_presence,
561         subscribe_received,
562         subscribe_closed,
563         internal_message,
564         ping_reply
565 };
566
567