2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Implementation of the Skinny protocol
23 * \author Jeremy McNamara & Florian Overkamp
24 * \ingroup channel_drivers
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <sys/ioctl.h>
40 #include <arpa/inet.h>
41 #include <sys/signal.h>
47 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
49 #include "asterisk/lock.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/config.h"
52 #include "asterisk/logger.h"
53 #include "asterisk/module.h"
54 #include "asterisk/pbx.h"
55 #include "asterisk/options.h"
56 #include "asterisk/lock.h"
57 #include "asterisk/sched.h"
58 #include "asterisk/io.h"
59 #include "asterisk/rtp.h"
60 #include "asterisk/acl.h"
61 #include "asterisk/callerid.h"
62 #include "asterisk/cli.h"
63 #include "asterisk/say.h"
64 #include "asterisk/cdr.h"
65 #include "asterisk/astdb.h"
66 #include "asterisk/features.h"
67 #include "asterisk/app.h"
68 #include "asterisk/musiconhold.h"
69 #include "asterisk/utils.h"
70 #include "asterisk/dsp.h"
71 #include "asterisk/stringfields.h"
73 /************************************************************************************/
74 /* Skinny/Asterisk Protocol Settings */
75 /************************************************************************************/
76 static const char desc[] = "Skinny Client Control Protocol (Skinny)";
77 static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
78 static const char config[] = "skinny.conf";
80 /* Just about everybody seems to support ulaw, so make it a nice default */
81 static int capability = AST_FORMAT_ULAW;
83 #define DEFAULT_SKINNY_PORT 2000
84 #define DEFAULT_SKINNY_BACKLOG 2
85 #define SKINNY_MAX_PACKET 1000
87 static int keep_alive = 120;
88 static char date_format[6] = "D-M-Y";
89 static char version_id[16] = "P002F202";
91 /* these should be in an include file, but dunno what to include */
92 typedef unsigned char UINT8;
93 typedef unsigned short UINT16;
94 typedef unsigned int UINT32;
96 #if __BYTE_ORDER == __LITTLE_ENDIAN
100 #define htoles(x) (x)
102 #if defined(SOLARIS) || defined(__Darwin__) || defined(__NetBSD__)
103 #define __bswap_16(x) \
104 ((((x) & 0xff00) >> 8) | \
105 (((x) & 0x00ff) << 8))
106 #define __bswap_32(x) \
107 ((((x) & 0xff000000) >> 24) | \
108 (((x) & 0x00ff0000) >> 8) | \
109 (((x) & 0x0000ff00) << 8) | \
110 (((x) & 0x000000ff) << 24))
112 #include <bits/byteswap.h>
114 #define letohl(x) __bswap_32(x)
115 #define letohs(x) __bswap_16(x)
116 #define htolel(x) __bswap_32(x)
117 #define htoles(x) __bswap_16(x)
121 /************************************************************************************/
122 /* Protocol Messages */
123 /************************************************************************************/
125 #define KEEP_ALIVE_MESSAGE 0x0000
126 /* no additional struct */
128 #define REGISTER_MESSAGE 0x0001
129 typedef struct register_message {
138 #define IP_PORT_MESSAGE 0x0002
140 #define KEYPAD_BUTTON_MESSAGE 0x0003
141 typedef struct keypad_button_message {
143 } keypad_button_message;
145 #define STIMULUS_MESSAGE 0x0005
146 typedef struct stimulus_message {
148 int stimulusInstance;
151 #define OFFHOOK_MESSAGE 0x0006
152 #define ONHOOK_MESSAGE 0x0007
154 #define CAPABILITIES_RES_MESSAGE 0x0010
155 typedef struct station_capabilities {
162 } station_capabilities;
164 typedef struct capabilities_res_message {
166 struct station_capabilities caps[18];
167 } capabilities_res_message;
169 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
170 typedef struct speed_dial_stat_req_message {
172 } speed_dial_stat_req_message;
174 #define LINE_STATE_REQ_MESSAGE 0x000B
175 typedef struct line_state_req_message {
177 } line_state_req_message;
179 #define TIME_DATE_REQ_MESSAGE 0x000D
180 #define VERSION_REQ_MESSAGE 0x000F
181 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
182 #define SERVER_REQUEST_MESSAGE 0x0012
183 #define ALARM_MESSAGE 0x0020
185 #define OPEN_RECIEVE_CHANNEL_ACK_MESSAGE 0x0022
186 typedef struct open_recieve_channel_ack_message {
191 } open_recieve_channel_ack_message;
193 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
194 #define UNREGISTER_MESSAGE 0x0027
195 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
197 #define REGISTER_ACK_MESSAGE 0x0081
198 typedef struct register_ack_message {
200 char dateTemplate[6];
202 int secondaryKeepAlive;
204 } register_ack_message;
206 #define START_TONE_MESSAGE 0x0082
207 typedef struct start_tone_message {
209 } start_tone_message;
211 #define STOP_TONE_MESSAGE 0x0083
213 #define SET_RINGER_MESSAGE 0x0085
214 typedef struct set_ringer_message {
216 } set_ringer_message;
218 #define SET_LAMP_MESSAGE 0x0086
219 typedef struct set_lamp_message {
221 int stimulusInstance;
225 #define SET_SPEAKER_MESSAGE 0x0088
226 typedef struct set_speaker_message {
228 } set_speaker_message;
230 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
231 typedef struct media_qualifier {
238 typedef struct start_media_transmission_message {
245 media_qualifier qualifier;
246 } start_media_transmission_message;
248 #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
249 typedef struct stop_media_transmission_message {
252 } stop_media_transmission_message;
254 #define CALL_INFO_MESSAGE 0x008F
255 typedef struct call_info_message {
256 char callingPartyName[40];
257 char callingParty[24];
258 char calledPartyName[40];
259 char calledParty[24];
263 char originalCalledPartyName[40];
264 char originalCalledParty[24];
267 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
268 typedef struct speed_dial_stat_res_message {
270 char speedDialDirNumber[24];
271 char speedDialDisplayName[40];
272 } speed_dial_stat_res_message;
274 #define LINE_STAT_RES_MESSAGE 0x0092
275 typedef struct line_stat_res_message {
277 char lineDirNumber[24];
278 char lineDisplayName[42];
280 } line_stat_res_message;
282 #define DEFINETIMEDATE_MESSAGE 0x0094
283 typedef struct definetimedate_message {
284 int year; /* since 1900 */
286 int dayofweek; /* monday = 1 */
293 } definetimedate_message;
295 #define DISPLAYTEXT_MESSAGE 0x0099
296 typedef struct displaytext_message {
298 } displaytext_message;
300 #define CLEAR_DISPLAY_MESSAGE 0x009A
302 #define REGISTER_REJ_MESSAGE 0x009D
303 typedef struct register_rej_message {
305 } register_rej_message;
307 #define CAPABILITIES_REQ_MESSAGE 0x009B
309 #define SERVER_RES_MESSAGE 0x009E
310 typedef struct server_identifier {
314 typedef struct server_res_message {
315 server_identifier server[5];
316 int serverListenPort[5];
318 } server_res_message;
320 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
322 typedef struct buttondefinition {
323 UINT8 instanceNumber;
324 UINT8 buttonDefinition;
327 #define STIMULUS_REDIAL 0x01
328 #define STIMULUS_SPEEDDIAL 0x02
329 #define STIMULUS_HOLD 0x03
330 #define STIMULUS_TRANSFER 0x04
331 #define STIMULUS_FORWARDALL 0x05
332 #define STIMULUS_FORWARDBUSY 0x06
333 #define STIMULUS_FORWARDNOANSWER 0x07
334 #define STIMULUS_DISPLAY 0x08
335 #define STIMULUS_LINE 0x09
336 #define STIMULUS_VOICEMAIL 0x0F
337 #define STIMULUS_AUTOANSWER 0x11
338 #define STIMULUS_CONFERENCE 0x7D
339 #define STIMULUS_CALLPARK 0x7E
340 #define STIMULUS_CALLPICKUP 0x7F
341 #define STIMULUS_NONE 0xFF
343 button_definition button_def_30vip[] = {
344 { 1, STIMULUS_LINE }, /* Line 1 */
345 { 2, STIMULUS_LINE }, /* Line 2 */
346 { 3, STIMULUS_LINE }, /* Line 3 */
347 { 4, STIMULUS_LINE }, /* Line 4 */
348 { 1, STIMULUS_CALLPARK }, /* Call Park */
349 { 0, STIMULUS_NONE },
350 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
351 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
352 { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */
353 { 4, STIMULUS_SPEEDDIAL }, /* Speeddial 4 */
354 { 5, STIMULUS_SPEEDDIAL }, /* Speeddial 5 */
355 { 6, STIMULUS_SPEEDDIAL }, /* Speeddial 6 */
356 { 1, STIMULUS_VOICEMAIL }, /* Voicemail */
357 { 1, STIMULUS_FORWARDALL }, /* Forward All */
358 { 1, STIMULUS_CONFERENCE }, /* Conference */
359 { 0, STIMULUS_NONE },
360 { 0, STIMULUS_NONE },
361 { 0, STIMULUS_NONE },
362 { 0, STIMULUS_NONE },
363 { 0, STIMULUS_NONE },
364 { 7, STIMULUS_SPEEDDIAL }, /* Speeddial 7 */
365 { 8, STIMULUS_SPEEDDIAL }, /* Speeddial 8 */
366 { 9, STIMULUS_SPEEDDIAL }, /* Speeddial 9 */
367 { 10, STIMULUS_SPEEDDIAL } /* Speeddial 10 */
370 button_definition button_def_12sp[] = {
371 { 1, STIMULUS_LINE }, /* Line 1 */
372 { 1, STIMULUS_LINE }, /* Line 1 */
373 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
374 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
375 { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */
376 { 4, STIMULUS_SPEEDDIAL }, /* Speeddial 4 */
377 { 1, STIMULUS_VOICEMAIL }, /* Voicemail */
378 { 5, STIMULUS_SPEEDDIAL }, /* Speeddial 5 */
379 { 6, STIMULUS_SPEEDDIAL }, /* Speeddial 6 */
380 { 7, STIMULUS_SPEEDDIAL }, /* Speeddial 7 */
381 { 8, STIMULUS_SPEEDDIAL }, /* Speeddial 8 */
382 { 9, STIMULUS_SPEEDDIAL } /* Speeddial 9 */
385 button_definition button_def_7902[] = {
386 { 1, STIMULUS_LINE }, /* Line 1 */
387 { 1, STIMULUS_HOLD }, /* Hold */
388 { 1, STIMULUS_TRANSFER },
389 { 1, STIMULUS_DISPLAY },
390 { 1, STIMULUS_VOICEMAIL },
391 { 1, STIMULUS_CONFERENCE },
392 { 1, STIMULUS_FORWARDALL },
393 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
394 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
395 { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */
396 { 4, STIMULUS_SPEEDDIAL }, /* Speeddial 4 */
397 { 1, STIMULUS_REDIAL }
400 button_definition button_def_7910[] = {
401 { 1, STIMULUS_LINE }, /* Line 1 */
402 { 1, STIMULUS_HOLD }, /* Hold */
403 { 1, STIMULUS_TRANSFER },
404 { 1, STIMULUS_DISPLAY },
405 { 1, STIMULUS_VOICEMAIL },
406 { 1, STIMULUS_CONFERENCE },
407 { 1, STIMULUS_FORWARDALL },
408 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
409 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
410 { 1, STIMULUS_REDIAL }
413 button_definition button_def_7920[] = {
414 { 1, STIMULUS_LINE }, /* Line 1 */
415 { 2, STIMULUS_LINE }, /* Line 2 */
416 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
417 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
418 { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */
419 { 4, STIMULUS_SPEEDDIAL } /* Speeddial 4 */
422 button_definition button_def_7935[] = {
423 { 1, STIMULUS_LINE }, /* Line 1 */
424 { 2, STIMULUS_LINE } /* Line 2 */
427 button_definition button_def_7940[] = {
428 { 1, STIMULUS_LINE }, /* Line 1 */
429 { 2, STIMULUS_LINE } /* Line 2 */
432 button_definition button_def_7960[] = {
433 { 1, STIMULUS_LINE }, /* Line 1 */
434 { 2, STIMULUS_LINE }, /* Line 2 */
435 { 3, STIMULUS_LINE }, /* Line 3 */
436 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
437 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
438 { 3, STIMULUS_SPEEDDIAL } /* Speeddial 3 */
441 button_definition button_def_7970[] = {
442 { 1, STIMULUS_LINE }, /* Line 1 */
443 { 2, STIMULUS_LINE }, /* Line 2 */
444 { 3, STIMULUS_LINE }, /* Line 3 */
445 { 1, STIMULUS_SPEEDDIAL }, /* Speeddial 1 */
446 { 2, STIMULUS_SPEEDDIAL }, /* Speeddial 2 */
447 { 3, STIMULUS_SPEEDDIAL }, /* Speeddial 3 */
448 { 4, STIMULUS_SPEEDDIAL }, /* Speeddial 4 */
449 { 5, STIMULUS_SPEEDDIAL } /* Speeddial 5 */
452 button_definition button_def_none = { 0, STIMULUS_NONE };
454 typedef struct button_defs {
457 button_definition *button_def;
460 button_defs_t button_defs[] = {
461 { "12SP", 12, button_def_12sp }, /* First one is used if
463 { "30VIP", 26, button_def_30vip },
464 { "7902", 12, button_def_7902 },
465 { "7910", 10, button_def_7910 },
466 { "7920", 6, button_def_7920 },
467 { "7935", 2, button_def_7935 },
468 { "7940", 2, button_def_7940 },
469 { "7960", 6, button_def_7960 },
470 { "7970", 8, button_def_7970 },
474 typedef struct button_template_res_message {
477 UINT32 totalButtonCount;
478 button_definition definition[42];
479 } button_template_res_message;
481 #define VERSION_RES_MESSAGE 0x0098
482 typedef struct version_res_message {
484 } version_res_message;
486 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
488 #define OPEN_RECIEVE_CHANNEL_MESSAGE 0x0105
489 typedef struct open_recieve_channel_message {
496 } open_recieve_channel_message;
498 #define CLOSE_RECIEVE_CHANNEL_MESSAGE 0x0106
499 typedef struct close_recieve_channel_message {
502 } close_recieve_channel_message;
504 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
506 typedef struct soft_key_template_definition {
507 char softKeyLabel[16];
509 } soft_key_template_definition;
511 soft_key_template_definition soft_key_template_default[] = {
518 { "CFwdNoAnswer", 7 },
532 typedef struct soft_key_template {
535 int totalSoftKeyCount;
536 soft_key_template_definition softKeyTemplateDefinition[32];
539 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
540 static const char *soft_key_set_hack = {
541 "\x01\x02\x05\x03\x09\x0a\x0b\x10\x11\x12\x04\x0e\x0d\x00\x00\x00"
542 "\x2d\x01\x2e\x01\x31\x01\x2f\x01\x35\x01\x36\x01\x37\x01\x3c\x01"
543 "\x3d\x01\x3e\x01\x30\x01\x3a\x01\x39\x01\x00\x00\x00\x00\x00\x00"
544 "\x03\x09\x04\x0e\x0d\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
545 "\x2f\x01\x35\x01\x30\x01\x3a\x01\x39\x01\x3f\x01\x00\x00\x00\x00"
546 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
547 "\x0a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
548 "\x36\x01\x2e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
549 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
550 "\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
551 "\x37\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
552 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
553 "\x01\x09\x05\x10\x11\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
554 "\x2d\x01\x35\x01\x31\x01\x3c\x01\x3d\x01\x3e\x01\x00\x00\x00\x00"
555 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
556 "\x00\x09\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
557 "\x00\x00\x35\x01\x30\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
558 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
559 "\x08\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
560 "\x34\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
561 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
562 "\x00\x09\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
563 "\x00\x00\x35\x01\x39\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
564 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
565 "\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
566 "\x00\x00\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
567 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
568 "\x01\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
569 "\x2d\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
570 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
571 "\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
572 "\x41\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
573 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
576 typedef struct soft_key_set_definition {
577 UINT8 softKeyTemplateIndex[16];
578 UINT16 softKeyInfoIndex[16];
579 } soft_key_set_definition;
581 typedef struct soft_key_sets {
582 UINT32 softKeySetOffset;
583 UINT32 softKeySetCount;
584 UINT32 totalSoftKeySetCount;
585 soft_key_set_definition softKeySetDefinition[16];
589 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
590 typedef struct select_soft_keys_message {
595 } select_soft_keys_message;
597 #define CALL_STATE_MESSAGE 0x0111
598 typedef struct call_state_message {
602 } call_state_message;
604 #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
605 typedef struct display_prompt_status_message {
607 char promptMessage[32];
610 } display_prompt_status_message;
612 #define DISPLAY_NOTIFY_MESSAGE 0x0114
613 typedef struct display_notify_message {
615 char displayMessage[100];
616 } display_notify_message;
618 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
619 typedef struct activate_call_plane_message {
621 } activate_call_plane_message;
623 #define DIALLED_NUMBER_MESSAGE 0x011D
624 typedef struct dialled_number_message {
625 char dialledNumber[24];
628 } dialled_number_message;
630 /* packet composition */
636 speed_dial_stat_req_message speeddialreq;
637 register_message reg;
638 register_ack_message regack;
639 register_rej_message regrej;
640 capabilities_res_message caps;
641 version_res_message version;
642 button_template_res_message buttontemplate;
643 displaytext_message displaytext;
644 display_prompt_status_message displaypromptstatus;
645 definetimedate_message definetimedate;
646 start_tone_message starttone;
647 speed_dial_stat_res_message speeddial;
648 line_state_req_message line;
649 line_stat_res_message linestat;
650 soft_key_sets softkeysets;
651 soft_key_template softkeytemplate;
652 server_res_message serverres;
653 set_lamp_message setlamp;
654 set_ringer_message setringer;
655 call_state_message callstate;
656 keypad_button_message keypad;
657 select_soft_keys_message selectsoftkey;
658 activate_call_plane_message activatecallplane;
659 stimulus_message stimulus;
660 set_speaker_message setspeaker;
661 call_info_message callinfo;
662 start_media_transmission_message startmedia;
663 stop_media_transmission_message stopmedia;
664 open_recieve_channel_message openrecievechannel;
665 open_recieve_channel_ack_message openrecievechannelack;
666 close_recieve_channel_message closerecievechannel;
667 display_notify_message displaynotify;
668 dialled_number_message diallednumber;
672 /************************************************************************************/
673 /* Asterisk specific globals */
674 /************************************************************************************/
676 static int skinnydebug = 1; /* XXX for now, enable debugging default */
678 /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
679 static struct sockaddr_in bindaddr;
680 static char ourhost[256];
682 static struct in_addr __ourip;
683 struct ast_hostent ahp; struct hostent *hp;
684 static int skinnysock = -1;
685 static pthread_t tcp_thread;
686 static pthread_t accept_t;
687 static char context[AST_MAX_CONTEXT] = "default";
688 static char language[MAX_LANGUAGE] = "";
689 static char musicclass[MAX_MUSICCLASS] = "";
690 static char cid_num[AST_MAX_EXTENSION] = "";
691 static char cid_name[AST_MAX_EXTENSION] = "";
692 static char linelabel[AST_MAX_EXTENSION] ="";
694 static ast_group_t cur_callergroup = 0;
695 static ast_group_t cur_pickupgroup = 0;
696 static int immediate = 0;
697 static int callwaiting = 0;
698 static int callreturn = 0;
699 static int threewaycalling = 0;
700 static int mwiblink = 0;
701 /* This is for flashhook transfers */
702 static int transfer = 0;
703 static int cancallforward = 0;
704 /* static int busycount = 3;*/
705 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
706 static char mailbox[AST_MAX_EXTENSION];
707 static int amaflags = 0;
708 static int callnums = 1;
714 #define SKINNY_SPEAKERON 1
715 #define SKINNY_SPEAKEROFF 2
717 #define SKINNY_OFFHOOK 1
718 #define SKINNY_ONHOOK 2
719 #define SKINNY_RINGOUT 3
720 #define SKINNY_RINGIN 4
721 #define SKINNY_CONNECTED 5
722 #define SKINNY_BUSY 6
723 #define SKINNY_CONGESTION 7
724 #define SKINNY_HOLD 8
725 #define SKINNY_CALLWAIT 9
726 #define SKINNY_TRANSFER 10
727 #define SKINNY_PARK 11
728 #define SKINNY_PROGRESS 12
729 #define SKINNY_INVALID 14
731 #define SKINNY_SILENCE 0x00
732 #define SKINNY_DIALTONE 0x21
733 #define SKINNY_BUSYTONE 0x23
734 #define SKINNY_ALERT 0x24
735 #define SKINNY_REORDER 0x25
736 #define SKINNY_CALLWAITTONE 0x2D
737 #define SKINNY_NOTONE 0x7F
739 #define SKINNY_LAMP_OFF 1
740 #define SKINNY_LAMP_ON 2
741 #define SKINNY_LAMP_WINK 3
742 #define SKINNY_LAMP_FLASH 4
743 #define SKINNY_LAMP_BLINK 5
745 #define SKINNY_RING_OFF 1
746 #define SKINNY_RING_INSIDE 2
747 #define SKINNY_RING_OUTSIDE 3
748 #define SKINNY_RING_FEATURE 4
753 /* Skinny rtp stream modes. Do we really need this? */
754 #define SKINNY_CX_SENDONLY 0
755 #define SKINNY_CX_RECVONLY 1
756 #define SKINNY_CX_SENDRECV 2
757 #define SKINNY_CX_CONF 3
758 #define SKINNY_CX_CONFERENCE 3
759 #define SKINNY_CX_MUTE 4
760 #define SKINNY_CX_INACTIVE 4
763 static char *skinny_cxmodes[] = {
772 /* driver scheduler */
773 static struct sched_context *sched;
774 static struct io_context *io;
776 /* usage count and locking */
777 static int usecnt = 0;
778 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
780 /* Protect the monitoring thread, so only one process can kill or start it, and not
781 when it's doing something critical. */
782 AST_MUTEX_DEFINE_STATIC(monlock);
783 /* Protect the network socket */
784 AST_MUTEX_DEFINE_STATIC(netlock);
785 /* Protect the session list */
786 AST_MUTEX_DEFINE_STATIC(sessionlock);
787 /* Protect the device list */
788 AST_MUTEX_DEFINE_STATIC(devicelock);
790 /* Protect the paging device list */
791 AST_MUTEX_DEFINE_STATIC(pagingdevicelock);
794 /* This is the thread for the monitor which checks for input on the channels
795 which are not currently in use. */
796 static pthread_t monitor_thread = AST_PTHREADT_NULL;
798 /* Wait up to 16 seconds for first digit */
799 static int firstdigittimeout = 16000;
801 /* How long to wait for following digits */
802 static int gendigittimeout = 8000;
804 /* How long to wait for an extra digit, if there is an ambiguous match */
805 static int matchdigittimeout = 3000;
807 struct skinny_subchannel {
810 struct ast_channel *owner;
811 struct skinny_line *parent;
821 struct skinny_subchannel *next;
827 char label[42]; /* Label that shows next to the line buttons */
828 struct skinny_subchannel *sub; /* pointer to our current connection, channel and stuff */
829 char accountcode[AST_MAX_ACCOUNT_CODE];
830 char exten[AST_MAX_EXTENSION]; /* Extention where to start */
831 char context[AST_MAX_CONTEXT];
832 char language[MAX_LANGUAGE];
833 char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */
834 char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */
835 char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */
836 char call_forward[AST_MAX_EXTENSION];
837 char mailbox[AST_MAX_EXTENSION];
838 char musicclass[MAX_MUSICCLASS];
839 int curtone; /* Current tone being played */
840 ast_group_t callgroup;
841 ast_group_t pickupgroup;
848 int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
857 int nonCodecCapability;
859 int msgstate; /* voicemail message state */
863 struct skinny_line *next;
864 struct skinny_device *parent;
867 static struct skinny_device {
868 /* A device containing one or more lines */
875 struct sockaddr_in addr;
876 struct in_addr ourip;
877 struct skinny_line *lines;
879 struct skinnysession *session;
880 struct skinny_device *next;
883 struct skinny_paging_device {
886 struct skinny_device ** devices;
887 struct skinny_paging_device *next;
890 static struct skinnysession {
893 struct sockaddr_in sin;
895 char inbuf[SKINNY_MAX_PACKET];
896 struct skinny_device *device;
897 struct skinnysession *next;
900 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);
901 static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
902 static int skinny_hangup(struct ast_channel *ast);
903 static int skinny_answer(struct ast_channel *ast);
904 static struct ast_frame *skinny_read(struct ast_channel *ast);
905 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
906 static int skinny_indicate(struct ast_channel *ast, int ind);
907 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
908 static int skinny_senddigit(struct ast_channel *ast, char digit);
910 static const struct ast_channel_tech skinny_tech = {
912 .description = tdesc,
913 .capabilities = AST_FORMAT_ULAW,
914 .properties = AST_CHAN_TP_WANTSJITTER,
915 .requester = skinny_request,
917 .hangup = skinny_hangup,
918 .answer = skinny_answer,
920 .write = skinny_write,
921 .indicate = skinny_indicate,
922 .fixup = skinny_fixup,
923 .send_digit = skinny_senddigit,
924 /* .bridge = ast_rtp_bridge, */
927 static skinny_req *req_alloc(size_t size)
930 req = malloc(size+12);
934 memset(req, 0, size+12);
938 static struct skinny_subchannel *find_subchannel_by_line(struct skinny_line *l)
940 /* XXX Need to figure out how to determine which sub we want */
941 struct skinny_subchannel *sub = l->sub;
945 static struct skinny_subchannel *find_subchannel_by_name(char *dest)
947 struct skinny_line *l;
948 struct skinny_device *d;
953 strncpy(line, dest, sizeof(line) - 1);
954 at = strchr(line, '@');
956 ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest);
962 ast_mutex_lock(&devicelock);
965 if (!strcasecmp(d->name, device)) {
967 ast_verbose("Found device: %s\n", d->name);
969 /* Found the device */
972 /* Search for the right line */
973 if (!strcasecmp(l->name, line)) {
974 ast_mutex_unlock(&devicelock);
982 /* Device not found*/
983 ast_mutex_unlock(&devicelock);
987 static int transmit_response(struct skinnysession *s, skinny_req *req)
990 ast_mutex_lock(&s->lock);
994 ast_verbose("writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd);
998 res = write(s->fd, req, letohl(req->len)+8);
999 if (res != letohl(req->len)+8) {
1000 ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
1002 ast_mutex_unlock(&s->lock);
1006 /* XXX Do this right */
1007 static int convert_cap(int capability)
1009 return 4; /* ulaw (this is not the same as asterisk's '4' */
1013 static void transmit_speaker_mode(struct skinnysession *s, int mode)
1017 req = req_alloc(sizeof(struct set_speaker_message));
1019 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1022 req->len = htolel(sizeof(set_speaker_message)+4);
1023 req->e = htolel(SET_SPEAKER_MESSAGE);
1024 req->data.setspeaker.mode = htolel(mode);
1025 transmit_response(s, req);
1028 static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid)
1031 int memsize = sizeof(struct call_state_message);
1033 req = req_alloc(memsize);
1035 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1038 if (state == SKINNY_ONHOOK) {
1039 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
1041 req->len = htolel(sizeof(call_state_message)+4);
1042 req->e = htolel(CALL_STATE_MESSAGE);
1043 req->data.callstate.callState = htolel(state);
1044 req->data.callstate.lineInstance = htolel(instance);
1045 req->data.callstate.callReference = htolel(callid);
1046 transmit_response(s, req);
1047 if (state == SKINNY_OFFHOOK) {
1048 memset(req, 0, memsize);
1049 req->len = htolel(sizeof(activate_call_plane_message)+4);
1050 req->e = htolel(ACTIVATE_CALL_PLANE_MESSAGE);
1051 req->data.activatecallplane.lineInstance = htolel(instance);
1052 transmit_response(s, req);
1053 } else if (state == SKINNY_ONHOOK) {
1054 memset(req, 0, memsize);
1055 req->len = htolel(sizeof(activate_call_plane_message)+4);
1056 req->e = htolel(ACTIVATE_CALL_PLANE_MESSAGE);
1057 req->data.activatecallplane.lineInstance = 0;
1058 transmit_response(s, req);
1059 memset(req, 0, memsize);
1060 req->len = htolel(sizeof(close_recieve_channel_message)+4);
1061 req->e = htolel(CLOSE_RECIEVE_CHANNEL_MESSAGE);
1062 req->data.closerecievechannel.conferenceId = 0;
1063 req->data.closerecievechannel.partyId = 0;
1064 transmit_response(s, req);
1065 memset(req, 0, memsize);
1066 req->len = htolel(sizeof(stop_media_transmission_message)+4);
1067 req->e = htolel(STOP_MEDIA_TRANSMISSION_MESSAGE);
1068 req->data.stopmedia.conferenceId = 0;
1069 req->data.stopmedia.passThruPartyId = 0;
1070 transmit_response(s, req);
1074 static void transmit_callinfo(struct skinnysession *s, char *fromname, char *fromnum, char *toname, char *tonum, int instance, int callid, int calltype)
1078 req = req_alloc(sizeof(struct call_info_message));
1080 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1084 req->len = htolel(sizeof(struct call_info_message));
1085 req->e = htolel(CALL_INFO_MESSAGE);
1088 ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName));
1091 ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
1094 ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
1097 ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
1099 req->data.callinfo.instance = htolel(instance);
1100 req->data.callinfo.reference = htolel(callid);
1101 req->data.callinfo.type = htolel(calltype);
1102 transmit_response(s, req);
1105 static void transmit_connect(struct skinnysession *s)
1108 struct skinny_line *l = s->device->lines;
1110 req = req_alloc(sizeof(struct open_recieve_channel_message));
1112 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1115 req->len = htolel(sizeof(struct open_recieve_channel_message));
1116 req->e = htolel(OPEN_RECIEVE_CHANNEL_MESSAGE);
1117 req->data.openrecievechannel.conferenceId = 0;
1118 req->data.openrecievechannel.partyId = 0;
1119 req->data.openrecievechannel.packets = htolel(20);
1120 req->data.openrecievechannel.capability = htolel(convert_cap(l->capability));
1121 req->data.openrecievechannel.echo = 0;
1122 req->data.openrecievechannel.bitrate = 0;
1123 transmit_response(s, req);
1126 static void transmit_tone(struct skinnysession *s, int tone)
1131 req = req_alloc(sizeof(struct start_tone_message));
1136 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1140 req->len = htolel(sizeof(start_tone_message)+4);
1141 req->e = htolel(START_TONE_MESSAGE);
1142 req->data.starttone.tone = htolel(tone);
1144 req->len = htolel(4);
1145 req->e = htolel(STOP_TONE_MESSAGE);
1147 transmit_response(s, req);
1151 /* XXX need to properly deal with softkeys */
1152 static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey)
1155 int memsize = sizeof(struct select_soft_keys_message);
1157 req = req_alloc(memsize);
1159 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1162 memset(req, 0, memsize);
1163 req->len = htolel(sizeof(select_soft_keys_message)+4);
1164 req->e = htolel(SELECT_SOFT_KEYS_MESSAGE);
1165 req->data.selectsoftkey.instance = htolel(instance);
1166 req->data.selectsoftkey.reference = htolel(callid);
1167 req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
1168 transmit_response(s, req);
1172 static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int instance, int indication)
1176 req = req_alloc(sizeof(struct set_lamp_message));
1178 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1181 req->len = htolel(sizeof(set_lamp_message)+4);
1182 req->e = htolel(SET_LAMP_MESSAGE);
1183 req->data.setlamp.stimulus = htolel(stimulus);
1184 req->data.setlamp.stimulusInstance = htolel(instance);
1185 req->data.setlamp.deviceStimulus = htolel(indication);
1186 transmit_response(s, req);
1189 static void transmit_ringer_mode(struct skinnysession *s, int mode)
1193 req = req_alloc(sizeof(struct set_ringer_message));
1195 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1198 req->len = htolel(sizeof(set_ringer_message)+4);
1199 req->e = htolel(SET_RINGER_MESSAGE);
1200 req->data.setringer.ringerMode = htolel(mode);
1201 transmit_response(s, req);
1204 static void transmit_displaymessage(struct skinnysession *s, char *text)
1210 req->len = htolel(4);
1211 req->e = htolel(CLEAR_DISPLAY_MESSAGE);
1213 req = req_alloc(sizeof(struct displaytext_message));
1215 strncpy(req->data.displaytext.text, text, sizeof(req->data.displaytext.text)-1);
1216 req->len = htolel(sizeof(displaytext_message) + 4);
1217 req->e = htolel(DISPLAYTEXT_MESSAGE);
1219 ast_verbose("Displaying message '%s'\n", req->data.displaytext.text);
1224 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1227 transmit_response(s, req);
1230 static void transmit_displaynotify(struct skinnysession *s, char *text, int t)
1234 req = req_alloc(sizeof(struct display_notify_message));
1237 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1241 req->e = htolel(DISPLAY_NOTIFY_MESSAGE);
1242 req->len = htolel(sizeof(display_notify_message) + 4);
1243 strncpy(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage)-1);
1244 req->data.displaynotify.displayTimeout = htolel(t);
1247 ast_verbose("Displaying notify '%s'\n", text);
1250 transmit_response(s, req);
1253 static void transmit_displaypromptstatus(struct skinnysession *s, char *text, int t, int instance, int callid)
1257 req = req_alloc(sizeof(struct display_prompt_status_message));
1260 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1264 req->e = htolel(DISPLAY_PROMPT_STATUS_MESSAGE);
1265 req->len = htolel(sizeof(display_prompt_status_message) + 4);
1266 strncpy(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage)-1);
1267 req->data.displaypromptstatus.messageTimeout = htolel(t);
1268 req->data.displaypromptstatus.lineInstance = htolel(instance);
1269 req->data.displaypromptstatus.callReference = htolel(callid);
1272 ast_verbose("Displaying Prompt Status '%s'\n", text);
1275 transmit_response(s, req);
1278 static void transmit_diallednumber(struct skinnysession *s, char *text, int instance, int callid)
1282 req = req_alloc(sizeof(struct dialled_number_message));
1285 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
1289 req->e = htolel(DIALLED_NUMBER_MESSAGE);
1290 req->len = htolel(sizeof(dialled_number_message) + 4);
1291 strncpy(req->data.diallednumber.dialledNumber, text, sizeof(req->data.diallednumber.dialledNumber)-1);
1292 req->data.diallednumber.lineInstance = htolel(instance);
1293 req->data.diallednumber.callReference = htolel(callid);
1295 transmit_response(s, req);
1298 static int has_voicemail(struct skinny_line *l)
1300 return ast_app_has_voicemail(l->mailbox, NULL);
1304 static void do_housekeeping(struct skinnysession *s)
1308 struct skinny_subchannel *sub;
1309 struct skinny_line *l = s->device->lines;
1311 sub = find_subchannel_by_line(l);
1312 transmit_displaymessage(s, NULL);
1314 if (has_voicemail(sub->parent)) {
1316 ast_verbose("Checking for voicemail Skinny %s@%s\n", sub->parent->name, sub->parent->parent->name);
1318 ast_app_messagecount(sub->parent->mailbox, &new, &old);
1320 ast_verbose("Skinny %s@%s has voicemail!\n", sub->parent->name, sub->parent->parent->name);
1322 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
1324 transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF);
1329 /* I do not believe skinny can deal with video.
1330 Anyone know differently? */
1331 static struct ast_rtp *skinny_get_vrtp_peer(struct ast_channel *chan)
1336 static struct ast_rtp *skinny_get_rtp_peer(struct ast_channel *chan)
1338 struct skinny_subchannel *sub;
1339 sub = chan->tech_pvt;
1340 if (sub && sub->rtp) {
1346 static int skinny_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
1348 struct skinny_subchannel *sub;
1349 sub = chan->tech_pvt;
1351 /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */
1357 static struct ast_rtp_protocol skinny_rtp = {
1359 .get_rtp_info = skinny_get_rtp_peer,
1360 .get_vrtp_info = skinny_get_vrtp_peer,
1361 .set_rtp_peer = skinny_set_rtp_peer,
1364 static int skinny_do_debug(int fd, int argc, char *argv[])
1367 return RESULT_SHOWUSAGE;
1370 ast_cli(fd, "Skinny Debugging Enabled\n");
1371 return RESULT_SUCCESS;
1374 static int skinny_no_debug(int fd, int argc, char *argv[])
1377 return RESULT_SHOWUSAGE;
1380 ast_cli(fd, "Skinny Debugging Disabled\n");
1381 return RESULT_SUCCESS;
1384 static int skinny_show_devices(int fd, int argc, char *argv[])
1386 struct skinny_device *d;
1387 struct skinny_line *l;
1389 char iabuf[INET_ADDRSTRLEN];
1392 return RESULT_SHOWUSAGE;
1394 ast_mutex_lock(&devicelock);
1397 ast_cli(fd, "Name DeviceId IP TypeId R Model NL\n");
1398 ast_cli(fd, "-------------------- ---------------- --------------- ------ - ------ --\n");
1402 while(l) { numlines++; l = l->next; }
1404 ast_cli(fd, "%-20s %-16s %-16s %6X %c %-6s %2d\n",
1407 ast_inet_ntoa(iabuf, sizeof(iabuf), d->addr.sin_addr),
1409 d->registered?'Y':'N',
1415 ast_mutex_unlock(&devicelock);
1416 return RESULT_SUCCESS;
1419 static int skinny_show_lines(int fd, int argc, char *argv[])
1421 struct skinny_device *d;
1422 struct skinny_line *l;
1425 return RESULT_SHOWUSAGE;
1427 ast_mutex_lock(&devicelock);
1432 ast_cli(fd, "%-20s %2d %-20s %-20s %c %c\n",
1437 l->sub->owner?'Y':'N',
1438 l->sub->rtp?'Y':'N');
1443 ast_mutex_unlock(&devicelock);
1444 return RESULT_SUCCESS;
1447 static char show_devices_usage[] =
1448 "Usage: skinny show devices\n"
1449 " Lists all devices known to the Skinny subsystem.\n";
1451 static char show_lines_usage[] =
1452 "Usage: skinny show lines\n"
1453 " Lists all lines known to the Skinny subsystem.\n";
1455 static char debug_usage[] =
1456 "Usage: skinny debug\n"
1457 " Enables dumping of Skinny packets for debugging purposes\n";
1459 static char no_debug_usage[] =
1460 "Usage: skinny no debug\n"
1461 " Disables dumping of Skinny packets for debugging purposes\n";
1463 static struct ast_cli_entry cli_show_devices =
1464 { { "skinny", "show", "devices", NULL }, skinny_show_devices, "Show defined Skinny devices", show_devices_usage };
1466 static struct ast_cli_entry cli_show_lines =
1467 { { "skinny", "show", "lines", NULL }, skinny_show_lines, "Show defined Skinny lines per device", show_lines_usage };
1469 static struct ast_cli_entry cli_debug =
1470 { { "skinny", "debug", NULL }, skinny_do_debug, "Enable Skinny debugging", debug_usage };
1472 static struct ast_cli_entry cli_no_debug =
1473 { { "skinny", "no", "debug", NULL }, skinny_no_debug, "Disable Skinny debugging", no_debug_usage };
1476 static struct skinny_paging_device *build_paging_device(char *cat, struct ast_variable *v)
1482 static struct skinny_device *build_device(char *cat, struct ast_variable *v)
1484 struct skinny_device *d;
1485 struct skinny_line *l;
1486 struct skinny_subchannel *sub;
1489 d = malloc(sizeof(struct skinny_device));
1491 memset(d, 0, sizeof(struct skinny_device));
1492 strncpy(d->name, cat, sizeof(d->name) - 1);
1494 if (!strcasecmp(v->name, "host")) {
1495 if (ast_get_ip(&d->addr, v->value)) {
1499 } else if (!strcasecmp(v->name, "port")) {
1500 d->addr.sin_port = htons(atoi(v->value));
1501 } else if (!strcasecmp(v->name, "device")) {
1502 strncpy(d->id, v->value, sizeof(d->id)-1);
1503 } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
1504 d->ha = ast_append_ha(v->name, v->value, d->ha);
1505 } else if (!strcasecmp(v->name, "context")) {
1506 strncpy(context, v->value, sizeof(context) - 1);
1507 } else if (!strcasecmp(v->name, "version")) {
1508 strncpy(d->version_id, v->value, sizeof(d->version_id) -1);
1509 } else if (!strcasecmp(v->name, "nat")) {
1510 nat = ast_true(v->value);
1511 } else if (!strcasecmp(v->name, "model")) {
1512 strncpy(d->model, v->value, sizeof(d->model) - 1);
1513 } else if (!strcasecmp(v->name, "callerid")) {
1514 if (!strcasecmp(v->value, "asreceived")) {
1518 ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
1520 } else if (!strcasecmp(v->name, "language")) {
1521 strncpy(language, v->value, sizeof(language)-1);
1522 } else if (!strcasecmp(v->name, "accountcode")) {
1523 strncpy(accountcode, v->value, sizeof(accountcode)-1);
1524 } else if (!strcasecmp(v->name, "amaflags")) {
1525 y = ast_cdr_amaflags2int(v->value);
1527 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
1531 } else if (!strcasecmp(v->name, "musiconhold")) {
1532 strncpy(musicclass, v->value, sizeof(musicclass)-1);
1533 } else if (!strcasecmp(v->name, "callgroup")) {
1534 cur_callergroup = ast_get_group(v->value);
1535 } else if (!strcasecmp(v->name, "pickupgroup")) {
1536 cur_pickupgroup = ast_get_group(v->value);
1537 } else if (!strcasecmp(v->name, "immediate")) {
1538 immediate = ast_true(v->value);
1539 } else if (!strcasecmp(v->name, "cancallforward")) {
1540 cancallforward = ast_true(v->value);
1541 } else if (!strcasecmp(v->name, "mailbox")) {
1542 strncpy(mailbox, v->value, sizeof(mailbox) -1);
1543 } else if (!strcasecmp(v->name, "callreturn")) {
1544 callreturn = ast_true(v->value);
1545 } else if (!strcasecmp(v->name, "callwaiting")) {
1546 callwaiting = ast_true(v->value);
1547 } else if (!strcasecmp(v->name, "transfer")) {
1548 transfer = ast_true(v->value);
1549 } else if (!strcasecmp(v->name, "threewaycalling")) {
1550 threewaycalling = ast_true(v->value);
1551 } else if (!strcasecmp(v->name, "mwiblink")) {
1552 mwiblink = ast_true(v->value);
1553 } else if (!strcasecmp(v->name, "linelabel")) {
1554 strncpy(linelabel, v->value, sizeof(linelabel)-1);
1555 } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) {
1556 l = malloc(sizeof(struct skinny_line));;
1558 memset(l, 0, sizeof(struct skinny_line));
1559 ast_mutex_init(&l->lock);
1560 strncpy(l->name, v->value, sizeof(l->name) - 1);
1562 /* XXX Should we check for uniqueness?? XXX */
1563 strncpy(l->context, context, sizeof(l->context) - 1);
1564 strncpy(l->cid_num, cid_num, sizeof(l->cid_num) - 1);
1565 strncpy(l->cid_name, cid_name, sizeof(l->cid_name) - 1);
1566 strncpy(l->label, linelabel, sizeof(l->label) - 1);
1567 strncpy(l->language, language, sizeof(l->language) - 1);
1568 strncpy(l->musicclass, musicclass, sizeof(l->musicclass)-1);
1569 strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
1570 strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
1571 if (!ast_strlen_zero(mailbox)) {
1572 ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
1575 l->capability = capability;
1577 if (!strcasecmp(v->name, "trunk")) {
1578 l->type = TYPE_TRUNK;
1580 l->type = TYPE_LINE;
1582 l->immediate = immediate;
1583 l->callgroup = cur_callergroup;
1584 l->pickupgroup = cur_pickupgroup;
1585 l->callreturn = callreturn;
1586 l->cancallforward = cancallforward;
1587 l->callwaiting = callwaiting;
1588 l->transfer = transfer;
1589 l->threewaycalling = threewaycalling;
1590 l->mwiblink = mwiblink;
1591 l->onhooktime = time(NULL);
1593 /* ASSUME we're onhook at this point*/
1594 l->hookstate = SKINNY_ONHOOK;
1596 for (i = 0; i < MAX_SUBS; i++) {
1597 sub = malloc(sizeof(struct skinny_subchannel));
1599 ast_verbose(VERBOSE_PREFIX_3 "Allocating Skinny subchannel '%d' on %s@%s\n", i, l->name, d->name);
1600 memset(sub, 0, sizeof(struct skinny_subchannel));
1601 ast_mutex_init(&sub->lock);
1603 /* Make a call*ID */
1604 sub->callid = callnums;
1606 sub->cxmode = SKINNY_CX_INACTIVE;
1611 /* XXX Should find a way to clean up our memory */
1612 ast_log(LOG_WARNING, "Out of memory allocating subchannel");
1619 /* XXX Should find a way to clean up our memory */
1620 ast_log(LOG_WARNING, "Out of memory allocating line");
1624 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
1630 ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
1633 if (d->addr.sin_addr.s_addr && !ntohs(d->addr.sin_port)) {
1634 d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
1636 if (d->addr.sin_addr.s_addr) {
1637 if (ast_ouraddrfor(&d->addr.sin_addr, &d->ourip)) {
1638 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
1641 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
1647 static int skinny_register(skinny_req *req, struct skinnysession *s)
1649 struct skinny_device *d;
1651 ast_mutex_lock(&devicelock);
1654 if (!strcasecmp(req->data.reg.name, d->id)
1655 && ast_apply_ha(d->ha, &(s->sin))) {
1657 d->type = letohl(req->data.reg.type);
1658 if (ast_strlen_zero(d->version_id)) {
1659 strncpy(d->version_id, version_id, sizeof(d->version_id) - 1);
1667 ast_mutex_unlock(&devicelock);
1674 static void start_rtp(struct skinny_subchannel *sub)
1676 ast_mutex_lock(&sub->lock);
1677 /* Allocate the RTP */
1678 sub->rtp = ast_rtp_new(sched, io, 1, 0);
1679 if (sub->rtp && sub->owner) {
1680 sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
1683 ast_rtp_setnat(sub->rtp, sub->nat);
1685 /* Create the RTP connection */
1686 transmit_connect(sub->parent->parent->session);
1687 ast_mutex_unlock(&sub->lock);
1690 static void *skinny_ss(void *data)
1692 struct ast_channel *chan = data;
1693 struct skinny_subchannel *sub = chan->tech_pvt;
1694 struct skinny_line *l = sub->parent;
1695 struct skinnysession *s = l->parent->session;
1696 char exten[AST_MAX_EXTENSION] = "";
1698 int timeout = firstdigittimeout;
1702 if (option_verbose > 2) {
1703 ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, l->parent->name);
1705 while(len < AST_MAX_EXTENSION-1) {
1706 res = ast_waitfordigit(chan, timeout);
1710 ast_verbose("Skinny(%s@%s): waitfordigit returned < 0\n", l->name, l->parent->name);
1712 ast_indicate(chan, -1);
1719 if (!ast_ignore_pattern(chan->context, exten)) {
1720 transmit_tone(s, SKINNY_SILENCE);
1722 if (ast_exists_extension(chan, chan->context, exten, 1, l->cid_num)) {
1723 if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, l->cid_num)) {
1725 /* Record this as the forwarding extension */
1726 strncpy(l->call_forward, exten, sizeof(l->call_forward) - 1);
1727 if (option_verbose > 2) {
1728 ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
1729 l->call_forward, chan->name);
1731 transmit_tone(s, SKINNY_DIALTONE);
1735 ast_safe_sleep(chan, 500);
1736 ast_indicate(chan, -1);
1737 ast_safe_sleep(chan, 1000);
1738 memset(exten, 0, sizeof(exten));
1739 transmit_tone(s, SKINNY_DIALTONE);
1743 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
1744 if (!ast_strlen_zero(l->cid_num)) {
1745 if (!l->hidecallerid) {
1746 chan->cid.cid_num = strdup(l->cid_num);
1747 chan->cid.cid_ani = strdup(l->cid_num);
1749 ast_setstate(chan, AST_STATE_RING);
1750 res = ast_pbx_run(chan);
1752 ast_log(LOG_WARNING, "PBX exited non-zero\n");
1753 transmit_tone(s, SKINNY_REORDER);
1759 /* It's a match, but they just typed a digit, and there is an ambiguous match,
1760 so just set the timeout to matchdigittimeout and wait some more */
1761 timeout = matchdigittimeout;
1763 } else if (res == 0) {
1764 ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
1765 transmit_tone(s, SKINNY_REORDER);
1768 } else if (l->callwaiting && !strcmp(exten, "*70")) {
1769 if (option_verbose > 2) {
1770 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
1772 /* Disable call waiting if enabled */
1774 transmit_tone(s, SKINNY_DIALTONE);
1776 memset(exten, 0, sizeof(exten));\
1777 timeout = firstdigittimeout;
1778 } else if (!strcmp(exten,ast_pickup_ext())) {
1779 /* Scan all channels and see if any there
1780 * ringing channqels with that have call groups
1781 * that equal this channels pickup group
1783 if (ast_pickup_call(chan)) {
1784 ast_log(LOG_WARNING, "No call pickup possible...\n");
1785 transmit_tone(s, SKINNY_REORDER);
1789 } else if (!l->hidecallerid && !strcmp(exten, "*67")) {
1790 if (option_verbose > 2) {
1791 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
1793 /* Disable Caller*ID if enabled */
1794 l->hidecallerid = 1;
1795 if (chan->cid.cid_num) {
1796 free(chan->cid.cid_num);
1798 chan->cid.cid_num = NULL;
1799 if (chan->cid.cid_name) {
1800 free(chan->cid.cid_name);
1802 chan->cid.cid_name = NULL;
1803 transmit_tone(s, SKINNY_DIALTONE);
1805 memset(exten, 0, sizeof(exten));
1806 timeout = firstdigittimeout;
1807 } else if (l->callreturn && !strcmp(exten, "*69")) {
1809 if (!ast_strlen_zero(l->lastcallerid)) {
1810 res = ast_say_digit_str(chan, l->lastcallerid, "", chan->language);
1813 transmit_tone(s, SKINNY_DIALTONE);
1816 } else if (!strcmp(exten, "*78")) {
1817 /* Do not disturb */
1818 if (option_verbose > 2) {
1819 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
1821 transmit_tone(s, SKINNY_DIALTONE);
1824 memset(exten, 0, sizeof(exten));
1826 } else if (!strcmp(exten, "*79")) {
1827 /* Do not disturb */
1828 if (option_verbose > 2) {
1829 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
1831 transmit_tone(s, SKINNY_DIALTONE);
1834 memset(exten, 0, sizeof(exten));
1836 } else if (l->cancallforward && !strcmp(exten, "*72")) {
1837 transmit_tone(s, SKINNY_DIALTONE);
1839 memset(exten, 0, sizeof(exten));
1841 } else if (l->cancallforward && !strcmp(exten, "*73")) {
1842 if (option_verbose > 2) {
1843 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
1845 transmit_tone(s, SKINNY_DIALTONE);
1846 memset(l->call_forward, 0, sizeof(l->call_forward));
1848 memset(exten, 0, sizeof(exten));
1850 } else if (!strcmp(exten, ast_parking_ext()) &&
1852 ast_bridged_channel(sub->next->owner)) {
1853 /* This is a three way call, the main call being a real channel,
1854 and we're parking the first call. */
1855 ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
1856 if (option_verbose > 2) {
1857 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
1860 } else if (!ast_strlen_zero(l->lastcallerid) && !strcmp(exten, "*60")) {
1861 if (option_verbose > 2) {
1862 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", l->lastcallerid);
1864 res = ast_db_put("blacklist", l->lastcallerid, "1");
1866 transmit_tone(s, SKINNY_DIALTONE);
1867 memset(exten, 0, sizeof(exten));
1870 } else if (l->hidecallerid && !strcmp(exten, "*82")) {
1871 if (option_verbose > 2) {
1872 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
1874 /* Enable Caller*ID if enabled */
1875 l->hidecallerid = 0;
1876 if (chan->cid.cid_num) {
1877 free(chan->cid.cid_num);
1879 if (!ast_strlen_zero(l->cid_num)) {
1880 chan->cid.cid_num = strdup(l->cid_num);
1882 if (chan->cid.cid_name) {
1883 free(chan->cid.cid_name);
1885 if (!ast_strlen_zero(l->cid_name)) {
1886 chan->cid.cid_name = strdup(l->cid_name);
1888 transmit_tone(s, SKINNY_DIALTONE);
1890 memset(exten, 0, sizeof(exten));
1891 timeout = firstdigittimeout;
1892 } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
1893 ((exten[0] != '*') || (!ast_strlen_zero(exten) > 2))) {
1894 ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
1895 transmit_tone(s, SKINNY_REORDER);
1896 /* hang out for 3 seconds to let congestion play */
1897 ast_safe_sleep(chan, 3000);
1901 timeout = gendigittimeout;
1903 if (len && !ast_ignore_pattern(chan->context, exten)) {
1904 ast_indicate(chan, -1);
1913 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
1917 struct skinny_line *l;
1918 struct skinny_subchannel *sub;
1919 struct skinnysession *session;
1921 sub = ast->tech_pvt;
1923 session = l->parent->session;
1925 if (!l->parent->registered) {
1926 ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
1930 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
1931 ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
1936 ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
1940 ast_queue_control(ast, AST_CONTROL_BUSY);
1944 switch (l->hookstate) {
1945 case SKINNY_OFFHOOK:
1946 tone = SKINNY_CALLWAITTONE;
1949 tone = SKINNY_ALERT;
1952 ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
1956 transmit_lamp_indication(session, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
1957 transmit_ringer_mode(session, SKINNY_RING_INSIDE);
1959 if (ast->cid.cid_num) {
1960 char ciddisplay[41];
1962 size_t size = sizeof(ciddisplay);
1964 /* For now, we'll assume that if it is 10 numbers, it is a standard NANPA number */
1965 if (strlen(ast->cid.cid_num) == 10) {
1966 ast_build_string(&work, &size, "(xxx)xxx-xxxx %s",
1967 ast->cid.cid_name ? ast->cid.cid_name : "");
1968 memcpy(&ciddisplay[1], ast->cid.cid_num, 3);
1969 memcpy(&ciddisplay[5], &ast->cid.cid_num[3], 3);
1970 memcpy(&ciddisplay[9], &ast->cid.cid_num[6], 4);
1972 if (strlen(ast->cid.cid_num) < 41) {
1973 ast_build_string(&work, &size, "%s -- %s", ast->cid.cid_num,
1974 ast->cid.cid_name ? ast->cid.cid_name : "");
1976 strncpy(ciddisplay, "Number too long!", 15);
1980 ast_verbose("Trying to send: '%s'\n",ciddisplay);
1982 transmit_displaymessage(session, ciddisplay);
1984 transmit_displaymessage(session, "Unknown Name");
1986 transmit_tone(session, tone);
1987 transmit_callstate(session, l->instance, SKINNY_RINGIN, sub->callid);
1988 transmit_displaypromptstatus(session, "Ring-In", 0, l->instance, sub->callid);
1989 transmit_callinfo(session, ast->cid.cid_name, ast->cid.cid_num, l->cid_name, l->cid_num, l->instance, sub->callid, 1);
1991 /* XXX need to deal with softkeys */
1993 ast_setstate(ast, AST_STATE_RINGING);
1994 ast_queue_control(ast, AST_CONTROL_RINGING);
1999 static int skinny_hangup(struct ast_channel *ast)
2001 struct skinny_subchannel *sub = ast->tech_pvt;
2002 struct skinny_line *l = sub->parent;
2003 struct skinnysession *s = l->parent->session;
2006 ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
2008 if (!ast->tech_pvt) {
2009 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
2013 if (l->parent->registered) {
2014 if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_OFFHOOK)) {
2015 sub->parent->hookstate = SKINNY_ONHOOK;
2016 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
2017 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
2018 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
2019 } else if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_ONHOOK)) {
2020 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
2021 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
2022 transmit_ringer_mode(s, SKINNY_RING_OFF);
2023 transmit_tone(s, SKINNY_SILENCE);
2024 transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
2028 ast_mutex_lock(&sub->lock);
2030 ast->tech_pvt = NULL;
2031 sub->alreadygone = 0;
2034 ast_rtp_destroy(sub->rtp);
2037 ast_mutex_unlock(&sub->lock);
2041 static int skinny_answer(struct ast_channel *ast)
2044 struct skinny_subchannel *sub = ast->tech_pvt;
2045 struct skinny_line *l = sub->parent;
2046 struct skinnysession *s = l->parent->session;
2048 sub->cxmode = SKINNY_CX_SENDRECV;
2052 ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, l->parent->name, sub->callid);
2053 if (ast->_state != AST_STATE_UP) {
2054 ast_setstate(ast, AST_STATE_UP);
2056 transmit_tone(s, SKINNY_NOTONE);
2057 transmit_callstate(s, l->instance, SKINNY_CONNECTED, sub->callid);
2058 transmit_displaypromptstatus(s, "Connected", 0, l->instance, sub->callid);
2062 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
2064 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
2065 struct ast_frame *f;
2066 f = ast_rtp_read(sub->rtp);
2068 /* We already hold the channel lock */
2069 if (f->frametype == AST_FRAME_VOICE) {
2070 if (f->subclass != sub->owner->nativeformats) {
2071 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
2072 sub->owner->nativeformats = f->subclass;
2073 ast_set_read_format(sub->owner, sub->owner->readformat);
2074 ast_set_write_format(sub->owner, sub->owner->writeformat);
2081 static struct ast_frame *skinny_read(struct ast_channel *ast)
2083 struct ast_frame *fr;
2084 struct skinny_subchannel *sub = ast->tech_pvt;
2085 ast_mutex_lock(&sub->lock);
2086 fr = skinny_rtp_read(sub);
2087 ast_mutex_unlock(&sub->lock);
2091 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
2093 struct skinny_subchannel *sub = ast->tech_pvt;
2095 if (frame->frametype != AST_FRAME_VOICE) {
2096 if (frame->frametype == AST_FRAME_IMAGE) {
2099 ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
2103 if (!(frame->subclass & ast->nativeformats)) {
2104 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
2105 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
2110 ast_mutex_lock(&sub->lock);
2112 res = ast_rtp_write(sub->rtp, frame);
2114 ast_mutex_unlock(&sub->lock);
2119 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
2121 struct skinny_subchannel *sub = newchan->tech_pvt;
2122 ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
2123 if (sub->owner != oldchan) {
2124 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
2127 sub->owner = newchan;
2131 static int skinny_senddigit(struct ast_channel *ast, char digit)
2134 struct skinny_subchannel *sub = ast->tech_pvt;
2137 sprintf(tmp, "%d", digit);
2138 transmit_tone(sub->parent->parent->session, digit);
2143 static char *control2str(int ind) {
2144 static char tmp[100];
2147 case AST_CONTROL_HANGUP:
2148 return "Other end has hungup";
2149 case AST_CONTROL_RING:
2150 return "Local ring";
2151 case AST_CONTROL_RINGING:
2152 return "Remote end is ringing";
2153 case AST_CONTROL_ANSWER:
2154 return "Remote end has answered";
2155 case AST_CONTROL_BUSY:
2156 return "Remote end is busy";
2157 case AST_CONTROL_TAKEOFFHOOK:
2158 return "Make it go off hook";
2159 case AST_CONTROL_OFFHOOK:
2160 return "Line is off hook";
2161 case AST_CONTROL_CONGESTION:
2162 return "Congestion (circuits busy)";
2163 case AST_CONTROL_FLASH:
2164 return "Flash hook";
2165 case AST_CONTROL_WINK:
2167 case AST_CONTROL_OPTION:
2168 return "Set a low-level option";
2169 case AST_CONTROL_RADIO_KEY:
2171 case AST_CONTROL_RADIO_UNKEY:
2172 return "Un-Key Radio";
2173 case AST_CONTROL_PROGRESS:
2174 return "Remote end is making Progress";
2175 case AST_CONTROL_PROCEEDING:
2176 return "Remote end is proceeding";
2177 case AST_CONTROL_HOLD:
2179 case AST_CONTROL_UNHOLD:
2184 snprintf(tmp, 100, "UNKNOWN-%d", ind);
2189 static int skinny_indicate(struct ast_channel *ast, int ind)
2191 struct skinny_subchannel *sub = ast->tech_pvt;
2192 struct skinny_line *l = sub->parent;
2193 struct skinnysession *s = l->parent->session;
2196 ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
2199 case AST_CONTROL_RINGING:
2200 if (ast->_state != AST_STATE_UP) {
2201 if (!sub->progress) {
2202 transmit_tone(s, SKINNY_ALERT);
2203 transmit_callstate(s, l->instance, SKINNY_RINGOUT, sub->callid);
2204 transmit_diallednumber(s, ast->exten, l->instance, sub->callid);
2205 transmit_displaypromptstatus(s, "Ring Out", 0, l->instance, sub->callid);
2206 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
2212 case AST_CONTROL_BUSY:
2213 if (ast->_state != AST_STATE_UP) {
2214 transmit_tone(s, SKINNY_BUSYTONE);
2215 transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
2216 sub->alreadygone = 1;
2217 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
2221 case AST_CONTROL_CONGESTION:
2222 if (ast->_state != AST_STATE_UP) {
2223 transmit_tone(s, SKINNY_REORDER);
2224 transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
2225 sub->alreadygone = 1;
2226 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
2230 case AST_CONTROL_PROGRESS:
2231 if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
2232 transmit_tone(s, SKINNY_ALERT);
2233 transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
2234 transmit_displaypromptstatus(s, "Call Progress", 0, l->instance, sub->callid);
2235 transmit_callinfo(s, ast->cid.cid_name, ast->cid.cid_num, ast->exten, ast->exten, l->instance, sub->callid, 2); /* 2 = outgoing from phone */
2241 transmit_tone(s, SKINNY_SILENCE);
2243 case AST_CONTROL_PROCEEDING:
2246 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
2252 static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state)
2254 struct ast_channel *tmp;
2255 struct skinny_line *l = sub->parent;
2258 tmp = ast_channel_alloc(1);
2260 tmp->tech = &skinny_tech;
2261 tmp->nativeformats = l->capability;
2262 if (!tmp->nativeformats)
2263 tmp->nativeformats = capability;
2264 fmt = ast_best_codec(tmp->nativeformats);
2265 ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
2266 ast_string_field_build(tmp, name, "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid);
2268 tmp->fds[0] = ast_rtp_fd(sub->rtp);
2270 ast_setstate(tmp, state);
2271 if (state == AST_STATE_RING) {
2274 tmp->writeformat = fmt;
2275 tmp->rawwriteformat = fmt;
2276 tmp->readformat = fmt;
2277 tmp->rawreadformat = fmt;
2278 tmp->tech_pvt = sub;
2279 if (!ast_strlen_zero(l->language))
2280 ast_string_field_set(tmp, language, l->language);
2281 if (!ast_strlen_zero(l->accountcode))
2282 ast_string_field_set(tmp, accountcode, l->accountcode);
2284 tmp->amaflags = l->amaflags;
2286 ast_mutex_lock(&usecnt_lock);
2288 ast_mutex_unlock(&usecnt_lock);
2289 ast_update_use_count();
2290 tmp->callgroup = l->callgroup;
2291 tmp->pickupgroup = l->pickupgroup;
2292 ast_string_field_set(tmp, call_forward, l->call_forward);
2293 strncpy(tmp->context, l->context, sizeof(tmp->context)-1);
2294 strncpy(tmp->exten,l->exten, sizeof(tmp->exten)-1);
2295 if (!ast_strlen_zero(l->cid_num)) {
2296 tmp->cid.cid_num = strdup(l->cid_num);
2298 if (!ast_strlen_zero(l->cid_name)) {
2299 tmp->cid.cid_name = strdup(l->cid_name);
2302 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
2304 if (state != AST_STATE_DOWN) {
2305 if (ast_pbx_start(tmp)) {
2306 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
2312 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
2317 static int handle_message(skinny_req *req, struct skinnysession *s)
2319 struct skinny_subchannel *sub;
2320 struct ast_channel *c;
2321 struct ast_frame f = { 0, };
2322 struct sockaddr_in sin;
2323 struct sockaddr_in us;
2324 struct skinny_line *lines;
2328 char iabuf[INET_ADDRSTRLEN];
2334 int stimulusInstance;
2341 button_defs_t *b, *buse;
2343 if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
2344 ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
2349 switch(letohl(req->e)) {
2351 /* no response necessary */
2353 case REGISTER_MESSAGE:
2355 ast_verbose("Device %s is attempting to register\n", req->data.reg.name);
2357 res = skinny_register(req, s);
2359 ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", req->data.reg.name);
2360 memcpy(&name, req->data.reg.name, sizeof(req->data.reg.name));
2361 memset(req, 0, sizeof(skinny_req));
2362 req->len = htolel(sizeof(register_rej_message)+4);
2363 req->e = htolel(REGISTER_REJ_MESSAGE);
2364 snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
2365 transmit_response(s, req);
2368 if (option_verbose > 2) {
2369 ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfuly registered\n", s->device->name);
2371 memset(req, 0, SKINNY_MAX_PACKET);
2372 req->len = htolel(sizeof(register_ack_message)+4);
2373 req->e = htolel(REGISTER_ACK_MESSAGE);
2374 req->data.regack.res[0] = '0';
2375 req->data.regack.res[1] = '\0';
2376 req->data.regack.keepAlive = htolel(keep_alive);
2377 strncpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate) - 1);
2378 req->data.regack.res2[0] = '0';
2379 req->data.regack.res2[1] = '\0';
2380 req->data.regack.secondaryKeepAlive = htolel(keep_alive);
2381 transmit_response(s, req);
2383 ast_verbose("Requesting capabilities\n");
2385 memset(req, 0, SKINNY_MAX_PACKET);
2386 req->len = htolel(4);
2387 req->e = htolel(CAPABILITIES_REQ_MESSAGE);
2388 transmit_response(s, req);
2390 case UNREGISTER_MESSAGE:
2391 /* XXX Acutally unregister the device */
2393 case IP_PORT_MESSAGE:
2394 /* no response necessary */
2396 case STIMULUS_MESSAGE:
2397 stimulus = letohl(req->data.stimulus.stimulus);
2398 stimulusInstance = letohl(req->data.stimulus.stimulusInstance);
2401 case STIMULUS_REDIAL:
2402 /* If we can keep an array of dialed frames we can implement a quick
2403 and dirty redial, feeding the frames we last got into the queue
2406 ast_verbose("Recieved Stimulus: Redial(%d)\n", stimulusInstance);
2409 case STIMULUS_SPEEDDIAL:
2411 ast_verbose("Recieved Stimulus: SpeedDial(%d)\n", stimulusInstance);
2415 /* start moh? set RTP to 0.0.0.0? */
2417 ast_verbose("Recieved Stimulus: Hold(%d)\n", stimulusInstance);
2420 case STIMULUS_TRANSFER:
2422 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
2424 transmit_tone(s, SKINNY_DIALTONE);
2425 /* XXX figure out how to transfer */
2427 case STIMULUS_CONFERENCE:
2429 ast_verbose("Recieved Stimulus: Transfer(%d)\n", stimulusInstance);
2431 transmit_tone(s, SKINNY_DIALTONE);
2432 /* XXX determine the best way to pull off a conference. Meetme? */
2434 case STIMULUS_VOICEMAIL:
2436 ast_verbose("Recieved Stimulus: Voicemail(%d)\n", stimulusInstance);
2438 /* XXX Find and dial voicemail extension */
2440 case STIMULUS_CALLPARK:
2442 ast_verbose("Recieved Stimulus: Park Call(%d)\n", stimulusInstance);
2444 /* XXX Park the call */
2446 case STIMULUS_FORWARDALL:
2447 /* Why is DND under FORWARDALL ? */
2449 /* Do not disturb */
2450 transmit_tone(s, SKINNY_DIALTONE);
2451 if (s->device->lines->dnd != 0){
2452 if (option_verbose > 2) {
2453 ast_verbose(VERBOSE_PREFIX_3 "Disabling DND on %s@%s\n",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name);
2455 s->device->lines->dnd = 0;
2456 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
2457 transmit_displaynotify(s, "DnD disabled",10);
2459 if (option_verbose > 2) {
2460 ast_verbose(VERBOSE_PREFIX_3 "Enabling DND on %s@%s\n",find_subchannel_by_line(s->device->lines)->parent->name,find_subchannel_by_line(s->device->lines)->parent->name);
2462 s->device->lines->dnd = 1;
2463 transmit_lamp_indication(s, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_OFF);
2464 transmit_displaynotify(s, "DnD enabled",10);
2467 case STIMULUS_FORWARDBUSY:
2468 case STIMULUS_FORWARDNOANSWER:
2469 /* Gonna be fun, not */
2471 ast_verbose("Recieved Stimulus: Forward (%d)\n", stimulusInstance);
2474 case STIMULUS_DISPLAY:
2475 /* Not sure what this is */
2477 ast_verbose("Recieved Stimulus: Display(%d)\n", stimulusInstance);
2482 ast_verbose("Recieved Stimulus: Line(%d)\n", stimulusInstance);
2484 sub = find_subchannel_by_line(s->device->lines);
2485 /* turn the speaker on */
2486 transmit_speaker_mode(s, 1);
2489 ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", stimulus, stimulusInstance);
2493 case VERSION_REQ_MESSAGE:
2495 ast_verbose("Version Request\n");
2497 memset(req, 0, SKINNY_MAX_PACKET);
2498 req->len = htolel(sizeof(version_res_message)+4);
2499 req->e = htolel(VERSION_RES_MESSAGE);
2500 snprintf(req->data.version.version, sizeof(req->data.version.version), s->device->version_id);
2501 transmit_response(s, req);
2503 case SERVER_REQUEST_MESSAGE:
2505 ast_verbose("Recieved Server Request\n");
2507 memset(req, 0, SKINNY_MAX_PACKET);
2508 req->len = htolel(sizeof(server_res_message)+4);
2509 req->e = htolel(SERVER_RES_MESSAGE);
2510 memcpy(req->data.serverres.server[0].serverName, ourhost,
2511 sizeof(req->data.serverres.server[0].serverName));
2512 req->data.serverres.serverListenPort[0] = htolel(ourport);
2513 req->data.serverres.serverIpAddr[0] = htolel(__ourip.s_addr);
2514 transmit_response(s, req);
2516 case BUTTON_TEMPLATE_REQ_MESSAGE:
2518 ast_verbose("Buttontemplate requested\n");
2520 sub = find_subchannel_by_line(s->device->lines);
2521 memset(req, 0, SKINNY_MAX_PACKET);
2522 req->e = htolel(BUTTON_TEMPLATE_RES_MESSAGE);
2523 req->len = htolel(sizeof(button_template_res_message)+4);
2525 /* Find a matching button definition, default to first in the
2528 for(b=button_defs; b->type; b++) {
2529 if (!strcmp(s->device->model, b->type)) {
2533 req->data.buttontemplate.buttonOffset = 0;
2534 req->data.buttontemplate.buttonCount = htolel(buse->num_buttons);
2535 req->data.buttontemplate.totalButtonCount = htolel(buse->num_buttons);
2536 for (i=0; i<42; i++) {
2537 if (i < buse->num_buttons) {
2538 memcpy(&(req->data.buttontemplate.definition[i]),
2539 &(buse->button_def[i]),
2540 sizeof(button_definition));
2542 memcpy(&(req->data.buttontemplate.definition[i]),
2544 sizeof(button_definition));
2549 ast_verbose("Sending %s template to %s@%s (%s)\n",
2552 sub->parent->parent->name,
2555 transmit_response(s, req);
2557 case SOFT_KEY_SET_REQ_MESSAGE:
2559 ast_verbose("Received SoftKeySetReq\n");
2561 memset(req, 0, SKINNY_MAX_PACKET);
2562 req->len = htolel(sizeof(soft_key_sets)+4);
2563 req->e = htolel(SOFT_KEY_SET_RES_MESSAGE);
2564 req->data.softkeysets.softKeySetOffset = 0;
2565 req->data.softkeysets.softKeySetCount = htolel(11);
2566 req->data.softkeysets.totalSoftKeySetCount = htolel(11);
2567 /* XXX Wicked hack XXX */
2568 memcpy(req->data.softkeysets.softKeySetDefinition,
2570 sizeof(req->data.softkeysets.softKeySetDefinition));
2571 transmit_response(s,req);
2573 case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
2575 ast_verbose("Recieved SoftKey Template Request\n");
2577 memset(req, 0, SKINNY_MAX_PACKET);
2578 req->len = htolel(sizeof(soft_key_template)+4);
2579 req->e = htolel(SOFT_KEY_TEMPLATE_RES_MESSAGE);
2580 req->data.softkeytemplate.softKeyOffset = 0;
2581 req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition));
2582 req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(soft_key_template_definition));
2583 memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
2584 soft_key_template_default,
2585 sizeof(soft_key_template_default));
2586 transmit_response(s,req);
2588 case TIME_DATE_REQ_MESSAGE:
2590 ast_verbose("Received Time/Date Request\n");
2592 memset(req, 0, SKINNY_MAX_PACKET);
2593 req->len = htolel(sizeof(definetimedate_message)+4);
2594 req->e = htolel(DEFINETIMEDATE_MESSAGE);
2596 cmtime = localtime(&timer);
2597 req->data.definetimedate.year = htolel(cmtime->tm_year+1900);
2598 req->data.definetimedate.month = htolel(cmtime->tm_mon+1);
2599 req->data.definetimedate.dayofweek = htolel(cmtime->tm_wday);
2600 req->data.definetimedate.day = htolel(cmtime->tm_mday);
2601 req->data.definetimedate.hour = htolel(cmtime->tm_hour);
2602 req->data.definetimedate.minute = htolel(cmtime->tm_min);
2603 req->data.definetimedate.seconds = htolel(cmtime->tm_sec);
2604 transmit_response(s, req);
2606 case SPEED_DIAL_STAT_REQ_MESSAGE:
2607 /* Not really sure how Speed Dial's are different than the
2608 Softkey templates */
2609 speedDialNum = letohl(req->data.speeddialreq.speedDialNumber);
2610 memset(req, 0, SKINNY_MAX_PACKET);
2611 req->len = htolel(sizeof(speed_dial_stat_res_message)+4);
2612 req->e = htolel(SPEED_DIAL_STAT_RES_MESSAGE);
2614 /* XXX Do this right XXX */
2615 /* If the redial function works the way I think it will, a modification of it
2616 can work here was well. Yikes. */
2617 req->data.speeddialreq.speedDialNumber = speedDialNum;
2618 snprintf(req->data.speeddial.speedDialDirNumber, sizeof(req->data.speeddial.speedDialDirNumber), "31337");
2619 snprintf(req->data.speeddial.speedDialDisplayName, sizeof(req->data.speeddial.speedDialDisplayName),"Asterisk Rules!");
2621 transmit_response(s, req);
2623 case LINE_STATE_REQ_MESSAGE:
2624 lineNumber = letohl(req->data.line.lineNumber);
2626 ast_verbose("Received LineStateReq\n");
2628 memset(req, 0, SKINNY_MAX_PACKET);
2629 req->len = htolel(sizeof(line_stat_res_message)+4);
2630 req->e = htolel(LINE_STAT_RES_MESSAGE);
2631 sub = find_subchannel_by_line(s->device->lines);
2633 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
2636 lines = sub->parent;
2637 ast_mutex_lock(&devicelock);
2638 for (i=1; i < lineNumber; i++) {
2639 lines = lines->next;
2641 ast_mutex_unlock(&devicelock);
2642 req->data.linestat.linenumber = letohl(lineNumber);
2643 memcpy(req->data.linestat.lineDirNumber, lines->name,
2644 sizeof(req->data.linestat.lineDirNumber));
2645 memcpy(req->data.linestat.lineDisplayName, lines->label,
2646 sizeof(req->data.linestat.lineDisplayName));
2647 transmit_response(s,req);
2649 case CAPABILITIES_RES_MESSAGE:
2651 ast_verbose("Received CapabilitiesRes\n");
2653 /* XXX process the capabilites */
2655 case KEEP_ALIVE_MESSAGE:
2656 memset(req, 0, SKINNY_MAX_PACKET);
2657 req->len = htolel(4);
2658 req->e = htolel(KEEP_ALIVE_ACK_MESSAGE);
2659 transmit_response(s, req);
2662 case OFFHOOK_MESSAGE:
2663 transmit_ringer_mode(s,SKINNY_RING_OFF);
2664 transmit_lamp_indication(s, STIMULUS_LINE, s->device->lines->instance, SKINNY_LAMP_ON);
2665 sub = find_subchannel_by_line(s->device->lines);
2667 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
2670 sub->parent->hookstate = SKINNY_OFFHOOK;
2672 if (sub->outgoing) {
2673 /* We're answering a ringing call */
2674 ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
2675 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
2676 transmit_tone(s, SKINNY_SILENCE);
2677 transmit_callstate(s, s->device->lines->instance, SKINNY_CONNECTED, sub->callid);
2679 ast_setstate(sub->owner, AST_STATE_UP);
2680 /* XXX select the appropriate soft key here */
2683 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
2685 ast_verbose("Attempting to Clear display on Skinny %s@%s\n",sub->parent->name, sub->parent->parent->name);
2687 transmit_displaymessage(s, NULL); /* clear display */
2688 transmit_tone(s, SKINNY_DIALTONE);
2689 c = skinny_new(sub, AST_STATE_DOWN);
2691 /* start the switch thread */
2692 if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
2693 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
2697 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
2700 ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
2704 case ONHOOK_MESSAGE:
2705 sub = find_subchannel_by_line(s->device->lines);
2706 if (sub->parent->hookstate == SKINNY_ONHOOK) {
2707 /* Somthing else already put us back on hook */
2710 sub->cxmode = SKINNY_CX_RECVONLY;
2711 sub->parent->hookstate = SKINNY_ONHOOK;
2712 transmit_callstate(s, s->device->lines->instance, sub->parent->hookstate,sub->callid);
2714 ast_verbose("Skinny %s@%s went on hook\n",sub->parent->name, sub->parent->parent->name);
2716 if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
2717 /* We're allowed to transfer, we have two active calls and */
2718 /* we made at least one of the calls. Let's try and transfer */
2721 if ((res = attempt_transfer(p)) < 0) {
2722 if (p->sub->next->owner) {
2723 sub->next->alreadygone = 1;
2724 ast_queue_hangup(sub->next->owner,1);
2727 ast_log(LOG_WARNING, "Transfer attempt failed\n");
2732 /* Hangup the current call */
2733 /* If there is another active call, skinny_hangup will ring the phone with the other call */
2735 sub->alreadygone = 1;
2736 ast_queue_hangup(sub->owner);
2738 ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
2739 sub->parent->name, sub->parent->parent->name, sub->callid);
2742 if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->next->rtp)) {
2746 case KEYPAD_BUTTON_MESSAGE:
2747 digit = letohl(req->data.keypad.button);
2749 ast_verbose("Collected digit: [%d]\n", digit);
2751 f.frametype = AST_FRAME_DTMF;
2754 } else if (digit == 15) {
2756 } else if (digit >=0 && digit <= 9) {
2759 /* digit=10-13 (A,B,C,D ?), or
2760 * digit is bad value
2762 * probably should not end up here, but set
2763 * value for backward compatibility, and log
2767 ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
2771 sub = find_subchannel_by_line(s->device->lines);
2773 /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
2774 ast_queue_frame(sub->owner, &f);
2775 if (sub->next->owner) {
2776 ast_queue_frame(sub->next->owner, &f);
2779 ast_verbose("No owner: %s\n", s->device->lines->name);
2782 case OPEN_RECIEVE_CHANNEL_ACK_MESSAGE:
2783 ast_verbose("Recieved Open Recieve Channel Ack\n");
2784 status = letohl(req->data.openrecievechannelack.status);
2786 ast_log(LOG_ERROR, "Open Recieve Channel Failure\n");
2790 memcpy(addr, req->data.openrecievechannelack.ipAddr, sizeof(addr));
2791 port = htolel(req->data.openrecievechannelack.port);
2792 sin.sin_family = AF_INET;
2793 /* I smell endian problems */
2794 memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr));
2795 sin.sin_port = htons(port);
2797 ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
2799 sub = find_subchannel_by_line(s->device->lines);
2801 ast_rtp_set_peer(sub->rtp, &sin);
2802 ast_rtp_get_us(sub->rtp, &us);
2804 ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
2807 memset(req, 0, SKINNY_MAX_PACKET);
2808 req->len = htolel(sizeof(start_media_transmission_message)+4);
2809 req->e = htolel(START_MEDIA_TRANSMISSION_MESSAGE);
2810 req->data.startmedia.conferenceId = 0;
2811 req->data.startmedia.passThruPartyId = 0;
2812 memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4); /* Endian? */
2813 req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
2814 req->data.startmedia.packetSize = htolel(20);
2815 req->data.startmedia.payloadType = htolel(convert_cap(s->device->lines->capability));
2816 req->data.startmedia.qualifier.precedence = htolel(127);
2817 req->data.startmedia.qualifier.vad = 0;
2818 req->data.startmedia.qualifier.packets = 0;
2819 req->data.startmedia.qualifier.bitRate = 0;
2820 transmit_response(s, req);
2823 ast_verbose("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e));
2830 static void destroy_session(struct skinnysession *s)
2832 struct skinnysession *cur, *prev = NULL;
2833 ast_mutex_lock(&sessionlock);
2844 prev->next = cur->next;
2846 sessions = cur->next;
2851 ast_mutex_destroy(&s->lock);
2854 ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
2856 ast_mutex_unlock(&sessionlock);
2859 static int get_input(struct skinnysession *s)
2863 struct pollfd fds[1];
2866 fds[0].events = POLLIN;
2867 res = poll(fds, 1, -1);
2870 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
2871 } else if (res > 0) {
2872 memset(s->inbuf,0,sizeof(s->inbuf));
2873 res = read(s->fd, s->inbuf, 4);
2875 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
2878 dlen = letohl(*(int *)s->inbuf);
2879 if (dlen+8 > sizeof(s->inbuf)) {
2880 dlen = sizeof(s->inbuf) - 8;
2882 *(int *)s->inbuf = htolel(dlen);
2883 res = read(s->fd, s->inbuf+4, dlen+4);
2884 ast_mutex_unlock(&s->lock);
2885 if (res != (dlen+4)) {
2886 ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
2893 static skinny_req *skinny_req_parse(struct skinnysession *s)
2897 req = malloc(SKINNY_MAX_PACKET);
2899 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
2902 memset(req, 0, sizeof(skinny_req));
2903 /* +8 to account for reserved and length fields */
2904 memcpy(req, s->inbuf, letohl(*(int*)(s->inbuf))+8);
2905 if (letohl(req->e) < 0) {
2906 ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
2913 static void *skinny_session(void *data)
2917 struct skinnysession *s = data;
2918 char iabuf[INET_ADDRSTRLEN];
2920 ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
2927 req = skinny_req_parse(s);
2931 res = handle_message(req, s);
2937 ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
2942 static void *accept_thread(void *ignore)
2945 struct sockaddr_in sin;
2947 struct skinnysession *s;
2950 pthread_attr_t attr;
2952 pthread_attr_init(&attr);
2953 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2956 sinlen = sizeof(sin);
2957 as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
2959 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
2962 p = getprotobyname("tcp");
2964 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
2965 ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
2968 s = malloc(sizeof(struct skinnysession));
2970 ast_log(LOG_WARNING, "Failed to allocate Skinny session: %s\n", strerror(errno));
2973 memset(s, 0, sizeof(struct skinnysession));
2974 memcpy(&s->sin, &sin, sizeof(sin));
2975 ast_mutex_init(&s->lock);
2977 ast_mutex_lock(&sessionlock);
2980 ast_mutex_unlock(&sessionlock);
2982 if (ast_pthread_create(&tcp_thread, NULL, skinny_session, s)) {
2987 ast_verbose("killing accept thread\n");
2993 static void *do_monitor(void *data)
2997 /* This thread monitors all the interfaces which are not yet in use
2998 (and thus do not have a separate thread) indefinitely */
2999 /* From here on out, we die whenever asked */
3001 pthread_testcancel();
3002 /* Wait for sched or io */
3003 res = ast_sched_wait(sched);
3004 if ((res < 0) || (res > 1000)) {
3007 res = ast_io_wait(io, res);
3008 ast_mutex_lock(&monlock);
3010 ast_sched_runq(sched);
3012 ast_mutex_unlock(&monlock);
3019 static int restart_monitor(void)
3021 /* If we're supposed to be stopped -- stay stopped */
3022 if (monitor_thread == AST_PTHREADT_STOP)
3024 if (ast_mutex_lock(&monlock)) {
3025 ast_log(LOG_WARNING, "Unable to lock monitor\n");
3028 if (monitor_thread == pthread_self()) {
3029 ast_mutex_unlock(&monlock);
3030 ast_log(LOG_WARNING, "Cannot kill myself\n");
3033 if (monitor_thread != AST_PTHREADT_NULL) {
3034 /* Wake up the thread */
3035 pthread_kill(monitor_thread, SIGURG);
3037 /* Start a new monitor */
3038 if (ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
3039 ast_mutex_unlock(&monlock);
3040 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
3044 ast_mutex_unlock(&monlock);
3048 static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause)
3051 struct skinny_subchannel *sub;
3052 struct ast_channel *tmpc = NULL;
3057 format &= capability;
3059 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
3062 strncpy(tmp, dest, sizeof(tmp) - 1);
3063 if (ast_strlen_zero(tmp)) {
3064 ast_log(LOG_NOTICE, "Skinny channels require a device\n");
3067 sub = find_subchannel_by_name(tmp);
3069 ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
3072 if (option_verbose > 2) {
3073 ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
3074 ast_verbose(VERBOSE_PREFIX_3 "Skinny cw: %d, dnd: %d, so: %d, sno: %d\n",
3075 sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
3077 tmpc = skinny_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
3079 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
3085 static int reload_config(void)
3088 struct ast_config *cfg;
3089 struct ast_variable *v;
3092 char iabuf[INET_ADDRSTRLEN];
3093 struct skinny_device *d;
3094 int oldport = ntohs(bindaddr.sin_port);
3096 if (gethostname(ourhost, sizeof(ourhost))) {
3097 ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
3100 cfg = ast_config_load(config);
3102 /* We *must* have a config file otherwise stop immediately */
3104 ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
3107 /* load the general section */
3108 memset(&bindaddr, 0, sizeof(bindaddr));
3109 v = ast_variable_browse(cfg, "general");
3111 /* Create the interface list */
3112 if (!strcasecmp(v->name, "bindaddr")) {
3113 if (!(hp = ast_gethostbyname(v->value, &ahp))) {
3114 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
3116 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
3118 } else if (!strcasecmp(v->name, "keepAlive")) {
3119 keep_alive = atoi(v->value);
3120 } else if (!strcasecmp(v->name, "dateFormat")) {
3121 strncpy(date_format, v->value, sizeof(date_format) - 1);
3122 } else if (!strcasecmp(v->name, "allow")) {
3123 format = ast_getformatbyname(v->value);
3125 ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
3127 capability |= format;
3129 } else if (!strcasecmp(v->name, "disallow")) {
3130 format = ast_getformatbyname(v->value);
3132 ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
3134 capability &= ~format;
3136 } else if (!strcasecmp(v->name, "port")) {
3137 if (sscanf(v->value, "%d", &ourport) == 1) {
3138 bindaddr.sin_port = htons(ourport);
3140 ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
3145 if (ntohl(bindaddr.sin_addr.s_addr)) {
3146 memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
3148 hp = ast_gethostbyname(ourhost, &ahp);
3150 ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
3151 ast_config_destroy(cfg);
3154 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
3156 if (!ntohs(bindaddr.sin_port)) {
3157 bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
3159 bindaddr.sin_family = AF_INET;
3161 /* load the device sections */
3162 cat = ast_category_browse(cfg, NULL);
3164 if (!strcasecmp(cat, "general")) {
3167 } else if (!strncasecmp(cat, "paging-", 7)) {
3168 p = build_paging_device(cat, ast_variable_browse(cfg, cat));
3173 d = build_device(cat, ast_variable_browse(cfg, cat));
3175 if (option_verbose > 2) {
3176 ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
3178 ast_mutex_lock(&devicelock);
3181 ast_mutex_unlock(&devicelock);
3184 cat = ast_category_browse(cfg, cat);
3186 ast_mutex_lock(&netlock);
3187 if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
3191 if (skinnysock < 0) {
3192 skinnysock = socket(AF_INET, SOCK_STREAM, 0);
3193 if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
3194 ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s", errno, strerror(errno));
3195 ast_config_destroy(cfg);
3198 if (skinnysock < 0) {
3199 ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
3201 if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
3202 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
3203 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
3207 ast_config_destroy(cfg);
3210 if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
3211 ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
3212 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port),
3216 ast_config_destroy(cfg);
3219 if (option_verbose > 1) {
3220 ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n",
3221 ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port));
3223 ast_pthread_create(&accept_t,NULL, accept_thread, NULL);
3226 ast_mutex_unlock(&netlock);
3227 ast_config_destroy(cfg);
3231 void delete_devices(void)
3233 struct skinny_device *d, *dlast;
3234 struct skinny_line *l, *llast;
3235 struct skinny_subchannel *sub, *slast;
3237 ast_mutex_lock(&devicelock);
3239 /* Delete all devices */
3240 for (d=devices;d;) {
3241 /* Delete all lines for this device */
3242 for (l=d->lines;l;) {
3243 /* Delete all subchannels for this line */
3244 for (sub=l->sub;sub;) {
3247 ast_mutex_destroy(&slast->lock);
3252 ast_mutex_destroy(&llast->lock);
3260 ast_mutex_unlock(&devicelock);
3276 for (; res < (sizeof(soft_key_template_default) / sizeof(soft_key_template_default[0])); res++) {
3277 soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
3279 /* load and parse config */
3280 res = reload_config();
3282 ast_rtp_proto_register(&skinny_rtp);
3283 ast_cli_register(&cli_show_devices);
3284 ast_cli_register(&cli_show_lines);
3285 ast_cli_register(&cli_debug);
3286 ast_cli_register(&cli_no_debug);
3287 sched = sched_context_create();
3289 ast_log(LOG_WARNING, "Unable to create schedule context\n");
3291 io = io_context_create();
3293 ast_log(LOG_WARNING, "Unable to create I/O context\n");
3295 /* And start the monitor for the first time */
3298 /* Announce our presence to Asterisk */
3300 /* Make sure we can register our skinny channel type */
3301 if (ast_channel_register(&skinny_tech)) {
3302 ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
3312 struct skinny_session *session, s;
3313 struct skinny_subchannel *sub;
3314 struct skinny_line *line = session;
3316 /* close all IP connections */
3317 if (!ast_mutex_lock(&devicelock)) {
3318 /* Terminate tcp listener thread */
3320 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
3323 if (!ast_mutex_lock(&monlock)) {
3324 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
3325 pthread_cancel(monitor_thread);
3326 pthread_kill(monitor_thread, SIGURG);
3327 pthread_join(monitor_thread, NULL);
3329 monitor_thread = AST_PTHREADT_STOP;
3330 ast_mutex_unlock(&monlock);
3332 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
3335 if (!ast_mutex_lock(&iflock)) {
3336 /* Destroy all the interfaces and free their memory */
3341 /* Free associated memory */
3342 ast_mutex_destroy(&pl->lock);
3346 ast_mutex_unlock(&iflock);
3348 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
3352 ast_rtp_proto_register(&skinny_rtp);
3353 ast_channel_unregister(&skinny_tech);
3354 ast_cli_register(&cli_show_devices);
3355 ast_cli_register(&cli_show_lines);
3356 ast_cli_register(&cli_debug);
3357 ast_cli_register(&cli_no_debug);
3371 return ASTERISK_GPL_KEY;
3376 return (char *) desc;