2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of the Skinny protocol
6 * Asterisk is Copyright (C) 1999-2003 Mark Spencer
8 * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
19 #include <asterisk/lock.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/channel_pvt.h>
22 #include <asterisk/config.h>
23 #include <asterisk/logger.h>
24 #include <asterisk/module.h>
25 #include <asterisk/pbx.h>
26 #include <asterisk/options.h>
27 #include <asterisk/lock.h>
28 #include <asterisk/sched.h>
29 #include <asterisk/io.h>
30 #include <asterisk/rtp.h>
31 #include <asterisk/acl.h>
32 #include <asterisk/callerid.h>
33 #include <asterisk/cli.h>
34 #include <asterisk/say.h>
35 #include <asterisk/cdr.h>
36 #include <asterisk/astdb.h>
37 #include <asterisk/parking.h>
38 #include <asterisk/app.h>
39 #include <asterisk/musiconhold.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <sys/ioctl.h>
49 #include <arpa/inet.h>
50 #include <sys/signal.h>
51 #include <asterisk/dsp.h>
54 /************************************************************************************/
55 /* Skinny/Asterisk Protocol Settings */
56 /************************************************************************************/
57 static char *desc = "Skinny Client Control Protocol (Skinny)";
58 static char *tdesc = "Skinny Client Control Protocol (Skinny)";
59 static char *type = "Skinny";
60 static char *config = "skinny.conf";
62 /* Just about everybody seems to support ulaw, so make it a nice default */
63 static int capability = AST_FORMAT_ULAW;
65 #define DEFAULT_SKINNY_PORT 2000
66 #define DEFAULT_SKINNY_BACKLOG 2 // was 200
67 #define SKINNY_MAX_PACKET 1000
69 static int keep_alive = 120;
70 static char date_format[6] = "D-M-Y";
71 static char version_id[16] = "P002F202";
73 // these should be in an include file, but dunno what to include
74 typedef unsigned char UINT8;
75 typedef unsigned short UINT16;
76 typedef unsigned int UINT32;
78 /************************************************************************************/
79 /* Protocol Messages */
80 /************************************************************************************/
82 #define KEEP_ALIVE_MESSAGE 0x0000
83 /* no additional struct */
85 #define REGISTER_MESSAGE 0x0001
86 typedef struct register_message {
95 #define IP_PORT_MESSAGE 0x0002
97 #define KEYPAD_BUTTON_MESSAGE 0x0003
98 typedef struct keypad_button_message {
100 } keypad_button_message;
102 #define STIMULUS_MESSAGE 0x0005
103 typedef struct stimulus_message {
105 int stimulusInstance;
108 #define OFFHOOK_MESSAGE 0x0006
109 #define ONHOOK_MESSAGE 0x0007
111 #define CAPABILITIES_RES_MESSAGE 0x0010
112 typedef struct station_capabilities {
119 } station_capabilities;
121 typedef struct capabilities_res_message {
123 struct station_capabilities caps[18];
124 } capabilities_res_message;
126 #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
127 typedef struct speed_dial_stat_req_message {
129 } speed_dial_stat_req_message;
131 #define LINE_STATE_REQ_MESSAGE 0x000B
132 typedef struct line_state_req_message {
134 } line_state_req_message;
136 #define TIME_DATE_REQ_MESSAGE 0x000D
137 #define VERSION_REQ_MESSAGE 0x000F
138 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
139 #define SERVER_REQUEST_MESSAGE 0x0012
140 #define ALARM_MESSAGE 0x0020
142 #define OPEN_RECIEVE_CHANNEL_ACK_MESSAGE 0x0022
143 typedef struct open_recieve_channel_ack_message {
148 } open_recieve_channel_ack_message;
150 #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
151 #define UNREGISTER_MESSAGE 0x0027
152 #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
154 #define REGISTER_ACK_MESSAGE 0x0081
155 typedef struct register_ack_message {
157 char dateTemplate[6];
159 int secondaryKeepAlive;
161 } register_ack_message;
163 #define START_TONE_MESSAGE 0x0082
164 typedef struct start_tone_message {
166 } start_tone_message;
168 #define STOP_TONE_MESSAGE 0x0083
170 #define SET_RINGER_MESSAGE 0x0085
171 typedef struct set_ringer_message {
173 } set_ringer_message;
175 #define SET_LAMP_MESSAGE 0x0086
176 typedef struct set_lamp_message {
178 int stimulusInstance;
182 #define SET_SPEAKER_MESSAGE 0x0088
183 typedef struct set_speaker_message {
185 } set_speaker_message;
187 #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
188 typedef struct media_qualifier {
195 typedef struct start_media_transmission_message {
202 media_qualifier qualifier;
203 } start_media_transmission_message;
205 #define CALL_INFO_MESSAGE 0x008F
206 typedef struct call_info_message {
207 char callingPartyName[40];
208 char callingParty[24];
209 char calledPartyName[40];
210 char calledParty[24];
214 char originalCalledPartyName[40];
215 char originalCalledParty[24];
218 #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
219 typedef struct speed_dial_stat_res_message {
221 char speedDialDirNumber[24];
222 char speedDialDisplayName[40];
223 } speed_dial_stat_res_message;
225 #define LINE_STAT_RES_MESSAGE 0x0092
226 typedef struct line_stat_res_message {
228 char lineDirNumber[24];
229 char lineDisplayName[42];
231 } line_stat_res_message;
233 #define DEFINETIMEDATE_MESSAGE 0x0094
234 typedef struct definetimedate_message {
235 int year; /* since 1900 */
237 int dayofweek; /* monday = 1 */
244 } definetimedate_message;
246 #define DISPLAYTEXT_MESSAGE 0x0099
247 typedef struct displaytext_message {
249 } displaytext_message;
251 #define REGISTER_REJ_MESSAGE 0x009D
252 typedef struct register_rej_message {
254 } register_rej_message;
256 #define CAPABILITIES_REQ_MESSAGE 0x009B
258 #define SERVER_RES_MESSAGE 0x009E
259 typedef struct server_identifier {
263 typedef struct server_res_message {
264 server_identifier server[5];
265 int serverListenPort[5];
267 } server_res_message;
269 #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
270 static const char *button_definition_hack = {
271 "\x01\x09\x01\x02\x02\x02\x03\x02\x04\x02\x05\x02\x06\x02\x07\x02"
272 "\x08\x02\x09\x02\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff"
273 "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff"
274 "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff"
275 "\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff"
279 typedef struct buttondefinition {
280 UINT8 instanceNumber;
281 UINT8 buttonDefinition;
284 typedef struct button_template_res_message {
287 UINT32 totalButtonCount;
288 button_definition definition[42];
289 } button_template_res_message;
291 #define VERSION_RES_MESSAGE 0x0098
292 typedef struct version_res_message {
294 } version_res_message;
296 #define KEEP_ALIVE_ACK_MESSAGE 0x0100
298 #define OPEN_RECIEVE_CHANNEL_MESSAGE 0x0105
299 typedef struct open_recieve_channel_message {
306 } open_recieve_channel_message;
308 #define CLOSE_RECIEVE_CHANNEL_MESSAGE 0x0106
309 typedef struct close_recieve_channel_message {
312 } close_recieve_channel_message;
315 #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
316 static const char *soft_key_template_hack = {
317 "\x52\x65\x64\x69\x61\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
318 "\x01\x00\x00\x00\x4e\x65\x77\x43\x61\x6c\6c\\x00\x00\x00\x00\x00"
319 "\x00\x00\x00\x00\x02\x00\x00\x00\x48\x6f\x6c\x64\x00\x00\x00\x00"
320 "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x54\x72\x6e\x73"
321 "\x66\x65\x72\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00"
322 "\x43\x46\x77\x64\x41\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"
323 "\x00\x00\x00\x43\x46\x77\x64\x20\x42\x75\x73\x79\x00\x00\x00\x00"
324 "\x00\x00\x00\x06\x00\x00\x00\x43\x46\x77\x64\x4e\x6f\x41\x6e\x73"
325 "\x77\x65\x72\x00\x00\x00\x00\x07\x00\x00\x00\x3c\x3c\x00\x00\x00"
326 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x45"
327 "\x6e\x64\x43\x61\x6c\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09"
328 "\x00\x00\x00\x52\x65\x73\x75\x6d\x65\x00\x00\x00\x00\x00\x00\x00"
329 "\x00\x00\x0a\x00\x00\x00\x41\x6e\x73\x77\x65\x72\x00\x00\x00\x00"
330 "\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x49\x6e\x66\x6f\x00\x00"
331 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x43\x6f"
332 "\x6e\x66\x72\x6e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x00"
333 "\x00\x50\x61\x72\x6b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
334 "\x00\x0e\x00\x00\x00\x4a\x6f\x69\x6e\x00\x00\x00\x00\x00\x00\x00"
335 "\x00\x00\x00\x00\x0f\x00\x00\x00\x4d\x65\x65\x74\x4d\x65\x00\x00"
336 "\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x50\x69\x63\x6b"
337 "\x55\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00"
338 "\x47\x50\x69\x63\x6b\x55\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00"
339 "\x12\x00\x00\x00\x52\x6d\x4c\x73\x43\x00\x00\x00\x00\x00\x00\x00"
340 "\x00\x00\x00\x13\x00\x00\x00\x42\x61\x72\x67\x65\x00\x00\x00\x00"
341 "\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x42\x61\x72\x67\x65"
342 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00"
345 typedef struct soft_key_template_definition {
346 char softKeyLabel[16];
348 } soft_key_template_definition;
350 typedef struct soft_key_template {
353 int totalSoftKeyCount;
354 soft_key_template_definition softKeyTemplateDefinition[32];
357 #define SOFT_KEY_SET_RES_MESSAGE 0x0109
358 static const char *soft_key_set_hack = {
359 "\x01\x02\x05\x03\x09\x0a\x0b\x10\x11\x12\x04\x0e\x0d\x00\x00\x00"
360 "\x2d\x01\x2e\x01\x31\x01\x2f\x01\x35\x01\x36\x01\x37\x01\x3c\x01"
361 "\x3d\x01\x3e\x01\x30\x01\x3a\x01\x39\x01\x00\x00\x00\x00\x00\x00"
362 "\x03\x09\x04\x0e\x0d\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
363 "\x2f\x01\x35\x01\x30\x01\x3a\x01\x39\x01\x3f\x01\x00\x00\x00\x00"
364 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
365 "\x0a\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
366 "\x36\x01\x2e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
367 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
368 "\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
369 "\x37\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
370 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
371 "\x01\x09\x05\x10\x11\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
372 "\x2d\x01\x35\x01\x31\x01\x3c\x01\x3d\x01\x3e\x01\x00\x00\x00\x00"
373 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
374 "\x00\x09\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
375 "\x00\x00\x35\x01\x30\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
376 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
377 "\x08\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
378 "\x34\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
379 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
380 "\x00\x09\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
381 "\x00\x00\x35\x01\x39\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
382 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
383 "\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
384 "\x00\x00\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
385 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
386 "\x01\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
387 "\x2d\x01\x35\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
388 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
389 "\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
390 "\x41\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
391 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
394 typedef struct soft_key_set_definition {
395 UINT8 softKeyTemplateIndex[16];
396 UINT16 softKeyInfoIndex[16];
397 } soft_key_set_definition;
399 typedef struct soft_key_sets {
400 UINT32 softKeySetOffset;
401 UINT32 softKeySetCount;
402 UINT32 totalSoftKeySetCount;
403 soft_key_set_definition softKeySetDefinition[16];
407 #define SELECT_SOFT_KEYS_MESSAGE 0x0110
408 typedef struct select_soft_keys_message {
413 } select_soft_keys_message;
415 #define CALL_STATE_MESSAGE 0x0111
416 typedef struct call_state_message {
420 } call_state_message;
422 #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
423 typedef struct activate_call_plane_message {
425 } activate_call_plane_message;
427 /* packet composition */
433 speed_dial_stat_req_message speeddialreq;
434 register_message reg;
435 register_ack_message regack;
436 register_rej_message regrej;
437 capabilities_res_message caps;
438 version_res_message version;
439 button_template_res_message buttontemplate;
440 displaytext_message displaytext;
441 definetimedate_message definetimedate;
442 start_tone_message starttone;
443 speed_dial_stat_res_message speeddial;
444 line_state_req_message line;
445 line_stat_res_message linestat;
446 soft_key_sets softkeysets;
447 soft_key_template softkeytemplate;
448 server_res_message serverres;
449 set_lamp_message setlamp;
450 set_ringer_message setringer;
451 call_state_message callstate;
452 keypad_button_message keypad;
453 select_soft_keys_message selectsoftkey;
454 activate_call_plane_message activatecallplane;
455 stimulus_message stimulus;
456 set_speaker_message setspeaker;
457 call_info_message callinfo;
458 start_media_transmission_message startmedia;
459 open_recieve_channel_message openrecievechannel;
460 open_recieve_channel_ack_message openrecievechannelack;
461 close_recieve_channel_message closerecievechannel;
465 /************************************************************************************/
466 /* Asterisk specific globals */
467 /************************************************************************************/
469 static int skinnydebug = 1; /* XXX for now, enable debugging default */
471 /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
472 static struct sockaddr_in bindaddr;
473 static char ourhost[256];
475 static struct in_addr __ourip;
477 static int skinnysock = -1;
478 static pthread_t tcp_thread;
479 static pthread_t accept_t;
480 static ast_mutex_t devicelock = AST_MUTEX_INITIALIZER;
481 static char context[AST_MAX_EXTENSION] = "default";
482 static char language[MAX_LANGUAGE] = "";
483 static char musicclass[MAX_LANGUAGE] = "";
484 static char callerid[AST_MAX_EXTENSION] = "";
485 static char linelabel[AST_MAX_EXTENSION] ="";
487 static unsigned int cur_callergroup = 0;
488 static unsigned int cur_pickupgroup = 0;
489 static int immediate = 0;
490 static int callwaiting = 0;
491 static int callreturn = 0;
492 static int threewaycalling = 0;
493 /* This is for flashhook transfers */
494 static int transfer = 0;
495 static int cancallforward = 0;
496 /*static int busycount = 3;*/
497 static char accountcode[20] = "";
498 static char mailbox[AST_MAX_EXTENSION];
499 static int amaflags = 0;
500 static int callnums = 1;
506 #define SKINNY_SPEAKERON 1
507 #define SKINNY_SPEAKEROFF 2
509 #define SKINNY_OFFHOOK 1
510 #define SKINNY_ONHOOK 2
511 #define SKINNY_RINGOUT 3
512 #define SKINNY_RINGIN 4
513 #define SKINNY_CONNECTED 5
514 #define SKINNY_BUSY 6
515 #define SKINNY_CONGESTION 7
516 #define SKINNY_HOLD 8
517 #define SKINNY_CALLWAIT 9
518 #define SKINNY_TRANSFER 10
519 #define SKINNY_PARK 11
520 #define SKINNY_PROGRESS 12
521 #define SKINNY_INVALID 14
523 #define SKINNY_SILENCE 0
524 #define SKINNY_DIALTONE 33
525 #define SKINNY_BUSYTONE 35
526 #define SKINNY_ALERT 36
527 #define SKINNY_REORDER 37
528 #define SKINNY_CALLWAITTONE 45
533 #define STIMULUS_REDIAL 1
534 #define STIMULUS_SPEEDDIAL 2
535 #define STIMULUS_HOLD 3
536 #define STIMULUS_TRANSFER 4
537 #define STIMULUS_FORWARDALL 5
538 #define STIMULUS_FORWARDBUSY 6
539 #define STIMULUS_FORWARDNOANSWER 7
540 #define STIMULUS_DISPLAY 8
541 #define STIMULUS_LINE 9
543 /* Skinny rtp stream modes */
544 #define SKINNY_CX_SENDONLY 0
545 #define SKINNY_CX_RECVONLY 1
546 #define SKINNY_CX_SENDRECV 2
547 #define SKINNY_CX_CONF 3
548 #define SKINNY_CX_CONFERENCE 3
549 #define SKINNY_CX_MUTE 4
550 #define SKINNY_CX_INACTIVE 4
552 static char *skinny_cxmodes[] = {
560 /* driver scheduler */
561 static struct sched_context *sched;
562 static struct io_context *io;
564 /* usage count and locking */
565 static int usecnt = 0;
566 static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
568 /* Protect the monitoring thread, so only one process can kill or start it, and not
569 when it's doing something critical. */
570 static ast_mutex_t monlock = AST_MUTEX_INITIALIZER;
572 static ast_mutex_t netlock = AST_MUTEX_INITIALIZER;
573 static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
575 /* This is the thread for the monitor which checks for input on the channels
576 which are not currently in use. */
577 static pthread_t monitor_thread = 0;
579 /* Wait up to 16 seconds for first digit */
580 static int firstdigittimeout = 16000;
582 /* How long to wait for following digits */
583 static int gendigittimeout = 8000;
585 /* How long to wait for an extra digit, if there is an ambiguous match */
586 static int matchdigittimeout = 3000;
588 struct skinny_subchannel {
591 struct ast_channel *owner;
592 struct skinny_line *parent;
600 struct skinny_subchannel *next; /* for our circular linked list */
606 char label[42]; /* Label that shows next to the line buttons */
607 struct skinny_subchannel *sub; /* pointer to our current connection, channel and stuff */
608 char accountcode[80];
609 char exten[AST_MAX_EXTENSION]; /* Extention where to start */
610 char context[AST_MAX_EXTENSION];
611 char language[MAX_LANGUAGE];
612 char callerid[AST_MAX_EXTENSION]; /* Caller*ID */
613 char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */
614 char call_forward[AST_MAX_EXTENSION];
615 char mailbox[AST_MAX_EXTENSION];
616 char musicclass[MAX_LANGUAGE];
617 int curtone; /* Current tone */
618 unsigned int callgroup;
619 unsigned int pickupgroup;
625 int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */
634 int nonCodecCapability;
636 int msgstate; /* voicemail message state */
640 struct skinny_line *next;
641 struct skinny_device *parent;
644 static struct skinny_device {
645 /* A device containing one or more lines */
650 struct sockaddr_in addr;
651 struct in_addr ourip;
652 struct skinny_line *lines;
654 struct skinnysession *session;
655 struct skinny_device *next;
658 struct skinnysession {
661 struct sockaddr_in sin;
663 char inbuf[SKINNY_MAX_PACKET];
664 struct skinny_device *device;
665 struct skinnysession *next;
668 static skinny_req *req_alloc(size_t size)
671 req = malloc(size+12);
675 memset(req, 0, size+12);
679 static struct skinny_subchannel *find_subchannel(struct skinny_line *l)
681 /* Need to figure out how to determine which sub we want */
683 struct skinny_subchannel *sub = l->sub;
687 static int transmit_response(struct skinnysession *s, skinny_req *req)
690 ast_mutex_lock(&s->lock);
692 printf("writing packet type %d (%d bytes) to socket %d\n", req->e, req->len+8, s->fd);
694 res = write(s->fd, req, req->len+8);
695 if (res != req->len+8) {
696 ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, req->len+8, strerror(errno));
698 ast_mutex_unlock(&s->lock);
702 /* XXX Do this right*/
703 static int convert_cap(int capability)
705 return 4; // ulaw (this is not the same as asterisk's '4' :)
709 static void transmit_speaker_mode(struct skinnysession *s, int mode)
713 req = req_alloc(sizeof(struct set_ringer_message));
715 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
718 req->len = sizeof(set_speaker_message)+4;
719 req->e = SET_SPEAKER_MESSAGE;
720 req->data.setspeaker.mode = mode;
721 transmit_response(s, req);
724 static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid)
727 int memsize = sizeof(struct call_state_message);
729 req = req_alloc(memsize);
731 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
734 if (state == SKINNY_ONHOOK) {
735 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
737 req->len = sizeof(call_state_message)+4;
738 req->e = CALL_STATE_MESSAGE;
739 req->data.callstate.callState = state;
740 req->data.callstate.lineInstance = instance;
741 req->data.callstate.callReference = callid;
742 transmit_response(s, req);
743 if (state == SKINNY_OFFHOOK) {
744 memset(req, 0, memsize);
745 req->len = sizeof(activate_call_plane_message)+4;
746 req->e = ACTIVATE_CALL_PLANE_MESSAGE;
747 req->data.activatecallplane.lineInstance = instance;
748 transmit_response(s, req);
749 } else if (state == SKINNY_ONHOOK) {
750 memset(req, 0, memsize);
751 req->len = sizeof(activate_call_plane_message)+4;
752 req->e = ACTIVATE_CALL_PLANE_MESSAGE;
753 req->data.activatecallplane.lineInstance = 0;
754 transmit_response(s, req);
755 memset(req, 0, memsize);
756 req->len = sizeof(close_recieve_channel_message)+4;
757 req->e = CLOSE_RECIEVE_CHANNEL_MESSAGE;
758 req->data.closerecievechannel.conferenceId = 0;
759 req->data.closerecievechannel.partyId = 0;
760 transmit_response(s, req);
764 static void transmit_connect(struct skinnysession *s)
767 struct skinny_line *l = s->device->lines;
769 req = req_alloc(sizeof(struct open_recieve_channel_message));
771 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
774 req->len = sizeof(struct call_info_message);
775 req->e = OPEN_RECIEVE_CHANNEL_MESSAGE;
776 req->data.openrecievechannel.conferenceId = 0;
777 req->data.openrecievechannel.partyId = 0;
778 req->data.openrecievechannel.packets = 20;
779 req->data.openrecievechannel.capability = convert_cap(l->capability);
780 req->data.openrecievechannel.echo = 0;
781 req->data.openrecievechannel.bitrate = 0;
782 transmit_response(s, req);
785 static void transmit_tone(struct skinnysession *s, int tone)
790 req = req_alloc(sizeof(struct start_tone_message));
794 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
798 req->len = sizeof(start_tone_message)+4;
799 req->e = START_TONE_MESSAGE;
800 req->data.starttone.tone = tone; // da tone
803 req->e = STOP_TONE_MESSAGE;
805 transmit_response(s, req);
808 static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey)
811 int memsize = sizeof(struct select_soft_keys_message);
813 req = req_alloc(memsize);
815 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
818 memset(req, 0, memsize);
819 req->len = sizeof(select_soft_keys_message)+4;
820 req->e = SELECT_SOFT_KEYS_MESSAGE;
821 req->data.selectsoftkey.instance = instance;
822 req->data.selectsoftkey.reference = callid;
823 req->data.selectsoftkey.softKeySetIndex = softkey;
824 transmit_response(s, req);
827 static void transmit_lamp_indication(struct skinnysession *s, int instance, int indication)
831 req = req_alloc(sizeof(struct set_lamp_message));
833 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
836 req->len = sizeof(set_lamp_message)+4;
837 req->e = SET_LAMP_MESSAGE;
838 req->data.setlamp.stimulus = 9; // magic number
839 req->data.setlamp.stimulusInstance = instance;
840 req->data.setlamp.deviceStimulus = indication;
841 transmit_response(s, req);
844 static void transmit_ringer_mode(struct skinnysession *s, int mode)
848 req = req_alloc(sizeof(struct set_ringer_message));
850 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
853 req->len = sizeof(set_ringer_message)+4;
854 req->e = SET_RINGER_MESSAGE;
855 req->data.setringer.ringerMode = mode;
856 transmit_response(s, req);
862 /* I do not believe skinny can deal with video.
863 Anyone know differently? */
864 static struct ast_rtp *skinny_get_vrtp_peer(struct ast_channel *chan)
869 static struct ast_rtp *skinny_get_rtp_peer(struct ast_channel *chan)
871 struct skinny_subchannel *sub;
872 sub = chan->pvt->pvt;
878 static int skinny_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp)
880 struct skinny_subchannel *sub;
881 sub = chan->pvt->pvt;
883 /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */
889 static struct ast_rtp_protocol skinny_rtp = {
890 get_rtp_info: skinny_get_rtp_peer,
891 get_vrtp_info: skinny_get_vrtp_peer,
892 set_rtp_peer: skinny_set_rtp_peer,
895 static int skinny_do_debug(int fd, int argc, char *argv[])
898 return RESULT_SHOWUSAGE;
900 ast_cli(fd, "Skinny Debugging Enabled\n");
901 return RESULT_SUCCESS;
904 static int skinny_no_debug(int fd, int argc, char *argv[])
907 return RESULT_SHOWUSAGE;
909 ast_cli(fd, "Skinny Debugging Disabled\n");
910 return RESULT_SUCCESS;
913 static int skinny_show_lines(int fd, int argc, char *argv[])
915 struct skinny_device *d;
916 struct skinny_line *l;
919 return RESULT_SHOWUSAGE;
920 ast_mutex_lock(&devicelock);
924 ast_cli(fd, "Device '%s' at %s\n", d->name, d->addr.sin_addr.s_addr);
926 ast_cli(fd, " -- '%s@%s in '%s' is %s\n", l->name, d->name, l->context, l->sub->owner ? "active" : "idle");
931 ast_cli(fd, " << No Lines Defined >> ");
935 ast_mutex_unlock(&devicelock);
936 return RESULT_SUCCESS;
939 static char show_lines_usage[] =
940 "Usage: skinny show lines\n"
941 " Lists all lines known to the Skinny subsystem.\n";
943 static char debug_usage[] =
944 "Usage: skinny debug\n"
945 " Enables dumping of Skinny packets for debugging purposes\n";
947 static char no_debug_usage[] =
948 "Usage: skinny no debug\n"
949 " Disables dumping of Skinny packets for debugging purposes\n";
951 static struct ast_cli_entry cli_show_lines =
952 { { "skinny", "show", "lines", NULL }, skinny_show_lines, "Show defined Skinny lines per device", show_lines_usage };
953 static struct ast_cli_entry cli_debug =
954 { { "skinny", "debug", NULL }, skinny_do_debug, "Enable Skinny debugging", debug_usage };
955 static struct ast_cli_entry cli_no_debug =
956 { { "skinny", "no", "debug", NULL }, skinny_no_debug, "Disable Skinny debugging", no_debug_usage };
958 static struct skinny_device *build_device(char *cat, struct ast_variable *v)
960 struct skinny_device *d;
961 struct skinny_line *l;
962 struct skinny_subchannel *sub;
965 d = malloc(sizeof(struct skinny_device));
967 memset(d, 0, sizeof(struct skinny_device));
968 strncpy(d->name, cat, sizeof(d->name) - 1);
970 if (!strcasecmp(v->name, "host")) {
971 if (ast_get_ip(&d->addr, v->value)) {
975 } else if (!strcasecmp(v->name, "port")) {
976 d->addr.sin_port = htons(atoi(v->value));
977 } else if (!strcasecmp(v->name, "device")) {
978 strncpy(d->id, v->value, sizeof(d->id)-1);
979 } else if (!strcasecmp(v->name, "permit") ||
980 !strcasecmp(v->name, "deny")) {
981 d->ha = ast_append_ha(v->name, v->value, d->ha);
982 } else if (!strcasecmp(v->name, "context")) {
983 strncpy(context, v->value, sizeof(context) - 1);
984 } else if (!strcasecmp(v->name, "nat")) {
985 nat = ast_true(v->value);
986 } else if (!strcasecmp(v->name, "callerid")) {
987 if (!strcasecmp(v->value, "asreceived"))
988 strcpy(callerid, "");
990 strncpy(callerid, v->value, sizeof(callerid) - 1);
991 } else if (!strcasecmp(v->name, "language")) {
992 strncpy(language, v->value, sizeof(language)-1);
993 } else if (!strcasecmp(v->name, "accountcode")) {
994 strncpy(accountcode, v->value, sizeof(accountcode)-1);
995 } else if (!strcasecmp(v->name, "amaflags")) {
996 y = ast_cdr_amaflags2int(v->value);
998 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
1002 } else if (!strcasecmp(v->name, "musiconhold")) {
1003 strncpy(musicclass, v->value, sizeof(musicclass)-1);
1004 } else if (!strcasecmp(v->name, "callgroup")) {
1005 cur_callergroup = ast_get_group(v->value);
1006 } else if (!strcasecmp(v->name, "pickupgroup")) {
1007 cur_pickupgroup = ast_get_group(v->value);
1008 } else if (!strcasecmp(v->name, "immediate")) {
1009 immediate = ast_true(v->value);
1010 } else if (!strcasecmp(v->name, "cancallforward")) {
1011 cancallforward = ast_true(v->value);
1012 } else if (!strcasecmp(v->name, "mailbox")) {
1013 strncpy(mailbox, v->value, sizeof(mailbox) -1);
1014 } else if (!strcasecmp(v->name, "callreturn")) {
1015 callreturn = ast_true(v->value);
1016 } else if (!strcasecmp(v->name, "immediate")) {
1017 immediate = ast_true(v->value);
1018 } else if (!strcasecmp(v->name, "callwaiting")) {
1019 callwaiting = ast_true(v->value);
1020 } else if (!strcasecmp(v->name, "transfer")) {
1021 transfer = ast_true(v->value);
1022 } else if (!strcasecmp(v->name, "threewaycalling")) {
1023 threewaycalling = ast_true(v->value);
1024 } else if (!strcasecmp(v->name, "linelabel")) {
1025 strncpy(linelabel, v->value, sizeof(linelabel)-1);
1026 } else if (!strcasecmp(v->name, "trunk") ||
1027 !strcasecmp(v->name, "line")) {
1028 l = malloc(sizeof(struct skinny_line));;
1030 memset(l, 0, sizeof(struct skinny_line));
1031 strncpy(l->name, v->value, sizeof(l->name) - 1);
1033 /* XXX Should we check for uniqueness?? XXX */
1035 strncpy(l->context, context, sizeof(l->context) - 1);
1036 strncpy(l->callerid, callerid, sizeof(l->callerid) - 1);
1037 strncpy(l->label, linelabel, sizeof(l->label) - 1);
1038 strncpy(l->language, language, sizeof(l->language) - 1);
1039 strncpy(l->musicclass, musicclass, sizeof(l->musicclass)-1);
1040 strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1);
1041 if (strlen(mailbox)) {
1042 ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
1045 l->capability = capability;
1047 if (!strcasecmp(v->name, "trunk"))
1048 l->type = TYPE_TRUNK;
1050 l->type = TYPE_LINE;
1052 l->immediate = immediate;
1053 l->callgroup = cur_callergroup;
1054 l->pickupgroup = cur_pickupgroup;
1055 l->callreturn = callreturn;
1056 l->cancallforward = cancallforward;
1057 l->callwaiting = callwaiting;
1058 l->transfer = transfer;
1059 l->threewaycalling = threewaycalling;
1061 l->onhooktime = time(NULL);
1063 /* ASSUME we're onhook at this point*/
1064 l->hookstate = SKINNY_ONHOOK;
1066 for (i = 0; i < MAX_SUBS; i++) {
1067 sub = malloc(sizeof(struct skinny_subchannel));
1069 ast_verbose(VERBOSE_PREFIX_3 "Allocating Skinny subchannel '%d' on %s@%s\n", i, l->name, d->name);
1070 memset(sub, 0, sizeof(struct skinny_subchannel));
1072 /* Make a call*ID */
1073 sub->callid = callnums;
1075 sub->cxmode = SKINNY_CX_INACTIVE;
1080 /* XXX Should find a way to clean up our memory */
1081 ast_log(LOG_WARNING, "Out of memory allocating subchannel");
1088 /* XXX Should find a way to clean up our memory */
1089 ast_log(LOG_WARNING, "Out of memory allocating line");
1093 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
1098 ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
1102 if (d->addr.sin_addr.s_addr && !ntohs(d->addr.sin_port))
1103 d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
1104 if (d->addr.sin_addr.s_addr) {
1105 if (ast_ouraddrfor(&d->addr.sin_addr, &d->ourip)) {
1106 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
1109 memcpy(&d->ourip, &__ourip, sizeof(d->ourip));
1115 static int has_voicemail(struct skinny_line *l)
1117 return ast_app_has_voicemail(l->mailbox);
1120 static int skinny_register(skinny_req *req, struct skinnysession *s)
1122 struct skinny_device *d;
1124 ast_mutex_lock(&devicelock);
1127 if (!strcasecmp(req->data.reg.name, d->id)) {
1128 /* XXX Deal with IP authentication */
1130 d->type = req->data.reg.type;
1137 ast_mutex_unlock(&devicelock);
1145 static void start_rtp(struct skinny_subchannel *sub)
1147 ast_mutex_lock(&sub->lock);
1148 /* Allocate the RTP */
1149 sub->rtp = ast_rtp_new(sched, io, 1, 0);
1150 if (sub->rtp && sub->owner)
1151 sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
1153 ast_rtp_setnat(sub->rtp, sub->nat);
1155 /* Create the RTP connections */
1156 transmit_connect(sub->parent->parent->session);
1157 ast_mutex_unlock(&sub->lock);
1161 static void *skinny_ss(void *data)
1163 struct ast_channel *chan = data;
1164 struct skinny_subchannel *sub = chan->pvt->pvt;
1165 struct skinny_line *l = sub->parent;
1166 struct skinnysession *s = l->parent->session;
1167 char exten[AST_MAX_EXTENSION] = "";
1169 int timeout = firstdigittimeout;
1173 if (option_verbose > 2)
1174 ast_verbose( VERBOSE_PREFIX_3 "Starting simple switch on '%s@%s'\n", l->name, l->parent->name);
1176 while(len < AST_MAX_EXTENSION-1) {
1177 res = ast_waitfordigit(chan, timeout);
1181 printf("Skinny(%s@%s): waitfordigit returned < 0\n", l->name, l->parent->name);
1182 ast_indicate(chan, -1);
1189 if (!ast_ignore_pattern(chan->context, exten)) {
1190 transmit_tone(s, SKINNY_SILENCE);
1192 if (ast_exists_extension(chan, chan->context, exten, 1, l->callerid)) {
1193 if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, l->callerid)) {
1195 /* Record this as the forwarding extension */
1196 strncpy(l->call_forward, exten, sizeof(l->call_forward));
1197 if (option_verbose > 2) {
1198 ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
1199 l->call_forward, chan->name);
1201 transmit_tone(s, SKINNY_DIALTONE);
1205 ast_indicate(chan, -1);
1207 memset(exten, 0, sizeof(exten));
1208 transmit_tone(s, SKINNY_DIALTONE);
1212 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
1213 if (strlen(l->callerid)) {
1214 if (!l->hidecallerid)
1215 chan->callerid = strdup(l->callerid);
1216 chan->ani = strdup(l->callerid);
1218 ast_setstate(chan, AST_STATE_RING);
1219 res = ast_pbx_run(chan);
1221 ast_log(LOG_WARNING, "PBX exited non-zero\n");
1222 transmit_tone(s, SKINNY_REORDER);
1227 /* It's a match, but they just typed a digit, and there is an ambiguous match,
1228 so just set the timeout to matchdigittimeout and wait some more */
1229 timeout = matchdigittimeout;
1231 } else if (res == 0) {
1232 ast_log(LOG_DEBUG, "Not enough digits (and no ambiguous match)...\n");
1233 transmit_tone(s, SKINNY_REORDER);
1236 } else if (l->callwaiting && !strcmp(exten, "*70")) {
1237 if (option_verbose > 2) {
1238 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
1240 /* Disable call waiting if enabled */
1242 transmit_tone(s, SKINNY_DIALTONE);
1244 memset(exten, 0, sizeof(exten));
1245 timeout = firstdigittimeout;
1247 } else if (!strcmp(exten,ast_pickup_ext())) {
1248 /* Scan all channels and see if any there
1249 * ringing channqels with that have call groups
1250 * that equal this channels pickup group
1252 if (ast_pickup_call(chan)) {
1253 ast_log(LOG_WARNING, "No call pickup possible...\n");
1254 transmit_tone(s, SKINNY_REORDER);
1259 } else if (!l->hidecallerid && !strcmp(exten, "*67")) {
1260 if (option_verbose > 2) {
1261 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
1263 /* Disable Caller*ID if enabled */
1264 l->hidecallerid = 1;
1266 free(chan->callerid);
1267 chan->callerid = NULL;
1268 transmit_tone(s, SKINNY_DIALTONE);
1270 memset(exten, 0, sizeof(exten));
1271 timeout = firstdigittimeout;
1272 } else if (l->callreturn && !strcmp(exten, "*69")) {
1274 if (strlen(l->lastcallerid)) {
1275 res = ast_say_digit_str(chan, l->lastcallerid, "", chan->language);
1278 transmit_tone(s, SKINNY_DIALTONE);
1281 } else if (!strcmp(exten, "*78")) {
1282 /* Do not disturb */
1283 if (option_verbose > 2) {
1284 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
1286 transmit_tone(s, SKINNY_DIALTONE);
1289 memset(exten, 0, sizeof(exten));
1291 } else if (!strcmp(exten, "*79")) {
1292 /* Do not disturb */
1293 if (option_verbose > 2) {
1294 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
1296 transmit_tone(s, SKINNY_DIALTONE);
1299 memset(exten, 0, sizeof(exten));
1301 } else if (l->cancallforward && !strcmp(exten, "*72")) {
1302 transmit_tone(s, SKINNY_DIALTONE);
1304 memset(exten, 0, sizeof(exten));
1306 } else if (l->cancallforward && !strcmp(exten, "*73")) {
1307 if (option_verbose > 2) {
1308 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
1310 transmit_tone(s, SKINNY_DIALTONE);
1311 memset(l->call_forward, 0, sizeof(l->call_forward));
1313 memset(exten, 0, sizeof(exten));
1315 } else if (!strcmp(exten, ast_parking_ext()) &&
1317 sub->next->owner->bridge) {
1318 /* This is a three way call, the main call being a real channel,
1319 and we're parking the first call. */
1320 ast_masq_park_call(sub->next->owner->bridge, chan, 0, NULL);
1321 if (option_verbose > 2) {
1322 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
1325 } else if (strlen(l->lastcallerid) && !strcmp(exten, "*80")) {
1326 if (option_verbose > 2) {
1327 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", l->lastcallerid);
1329 res = ast_db_put("blacklist", l->lastcallerid, "1");
1331 transmit_tone(s, SKINNY_DIALTONE);
1332 memset(exten, 0, sizeof(exten));
1335 } else if (l->hidecallerid && !strcmp(exten, "*82")) {
1336 if (option_verbose > 2) {
1337 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
1339 /* Enable Caller*ID if enabled */
1340 l->hidecallerid = 0;
1342 free(chan->callerid);
1343 if (strlen(l->callerid))
1344 chan->callerid = strdup(l->callerid);
1345 transmit_tone(s, SKINNY_DIALTONE);
1347 memset(exten, 0, sizeof(exten));
1348 timeout = firstdigittimeout;
1349 } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->callerid) &&
1350 ((exten[0] != '*') || (strlen(exten) > 2))) {
1351 ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", exten, chan->callerid ? chan->callerid : "<Unknown Caller>", chan->context);
1352 transmit_tone(s, SKINNY_REORDER);
1353 sleep(3); // hang out for 3 seconds to let congestion play
1357 timeout = gendigittimeout;
1358 if (len && !ast_ignore_pattern(chan->context, exten))
1359 ast_indicate(chan, -1);
1367 static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
1370 struct skinny_line *l;
1371 struct skinny_subchannel *sub;
1374 ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
1377 sub = ast->pvt->pvt;
1380 switch (l->hookstate) {
1381 case SKINNY_OFFHOOK:
1390 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
1391 ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
1397 sub->cxmode = SKINNY_CX_RECVONLY;
1398 if (l->type == TYPE_LINE) {
1402 // transmit_modify_request(sub);
1405 if (sub->next->owner && sub->next->callid) {
1406 /* try to prevent a callwait from disturbing the other connection */
1407 sub->next->cxmode = SKINNY_CX_RECVONLY;
1408 // transmit_modify_request(sub->next);
1411 // transmit_notify_request_with_callerid(sub, tone, ast->callerid);
1412 ast_setstate(ast, AST_STATE_RINGING);
1413 ast_queue_control(ast, AST_CONTROL_RINGING, 0);
1415 /* not sure what this doing */
1416 if (sub->next->owner && sub->next->callid) {
1417 /* Put the connection back in sendrecv */
1418 sub->next->cxmode = SKINNY_CX_SENDRECV;
1419 // transmit_modify_request(sub->next);
1423 ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
1430 static int skinny_hangup(struct ast_channel *ast)
1432 struct skinny_subchannel *sub = ast->pvt->pvt;
1433 struct skinny_line *l = sub->parent;
1434 struct skinnysession *s = l->parent->session;
1437 ast_verbose("skinny_hangup(%s) on %s@%s\n", ast->name, l->name, l->parent->name);
1439 if (!ast->pvt->pvt) {
1440 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
1443 if ((sub->parent->type = TYPE_LINE) && (sub->parent->hookstate == SKINNY_OFFHOOK)) {
1444 sub->parent->hookstate = SKINNY_ONHOOK;
1445 transmit_callstate(s, l->instance, SKINNY_ONHOOK, sub->callid);
1446 transmit_speaker_mode(s, SKINNY_SPEAKEROFF);
1448 ast_mutex_lock(&sub->lock);
1450 ast->pvt->pvt = NULL;
1451 sub->alreadygone = 0;
1453 sub->cxmode = SKINNY_CX_INACTIVE;
1455 ast_rtp_destroy(sub->rtp);
1458 ast_mutex_unlock(&sub->lock);
1462 static int skinny_answer(struct ast_channel *ast)
1465 struct skinny_subchannel *sub = ast->pvt->pvt;
1466 struct skinny_line *l = sub->parent;
1467 sub->cxmode = SKINNY_CX_SENDRECV;
1471 // transmit_modify_request(sub);
1473 ast_verbose("skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, l->parent->name, sub->callid);
1474 if (ast->_state != AST_STATE_UP) {
1475 ast_setstate(ast, AST_STATE_UP);
1477 // transmit_notify_request(sub, "");
1478 // transmit_modify_request(sub);
1483 static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
1485 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
1486 struct ast_frame *f;
1487 f = ast_rtp_read(sub->rtp);
1489 /* We already hold the channel lock */
1490 if (f->frametype == AST_FRAME_VOICE) {
1491 if (f->subclass != sub->owner->nativeformats) {
1492 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
1493 sub->owner->nativeformats = f->subclass;
1494 ast_set_read_format(sub->owner, sub->owner->readformat);
1495 ast_set_write_format(sub->owner, sub->owner->writeformat);
1503 static struct ast_frame *skinny_read(struct ast_channel *ast)
1505 struct ast_frame *fr;
1506 struct skinny_subchannel *sub = ast->pvt->pvt;
1507 ast_mutex_lock(&sub->lock);
1508 fr = skinny_rtp_read(sub);
1509 ast_mutex_unlock(&sub->lock);
1513 static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
1515 struct skinny_subchannel *sub = ast->pvt->pvt;
1517 if (frame->frametype != AST_FRAME_VOICE) {
1518 if (frame->frametype == AST_FRAME_IMAGE)
1521 ast_log(LOG_WARNING, "Can't send %d type frames with SKINNY write\n", frame->frametype);
1525 if (!(frame->subclass & ast->nativeformats)) {
1526 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
1527 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
1532 ast_mutex_lock(&sub->lock);
1534 res = ast_rtp_write(sub->rtp, frame);
1536 ast_mutex_unlock(&sub->lock);
1541 static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1543 struct skinny_subchannel *sub = newchan->pvt->pvt;
1544 ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
1545 if (sub->owner != oldchan) {
1546 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
1549 sub->owner = newchan;
1553 static int skinny_senddigit(struct ast_channel *ast, char digit)
1555 // struct skinny_subchannel *sub = ast->pvt->pvt;
1559 // transmit_notify_request(sub, tmp);
1563 static char *control2str(int ind) {
1565 case AST_CONTROL_HANGUP:
1566 return "Other end has hungup";
1567 case AST_CONTROL_RING:
1568 return "Local ring";
1569 case AST_CONTROL_RINGING:
1570 return "Remote end is ringing";
1571 case AST_CONTROL_ANSWER:
1572 return "Remote end has answered";
1573 case AST_CONTROL_BUSY:
1574 return "Remote end is busy";
1575 case AST_CONTROL_TAKEOFFHOOK:
1576 return "Make it go off hook";
1577 case AST_CONTROL_OFFHOOK:
1578 return "Line is off hook";
1579 case AST_CONTROL_CONGESTION:
1580 return "Congestion (circuits busy)";
1581 case AST_CONTROL_FLASH:
1582 return "Flash hook";
1583 case AST_CONTROL_WINK:
1585 case AST_CONTROL_OPTION:
1586 return "Set a low-level option";
1587 case AST_CONTROL_RADIO_KEY:
1589 case AST_CONTROL_RADIO_UNKEY:
1590 return "Un-Key Radio";
1598 static int skinny_indicate(struct ast_channel *ast, int ind)
1600 struct skinny_subchannel *sub = ast->pvt->pvt;
1601 struct skinny_line *l = sub->parent;
1602 struct skinnysession *s = l->parent->session;
1605 ast_verbose(VERBOSE_PREFIX_3 "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
1608 case AST_CONTROL_RINGING:
1609 transmit_tone(s, SKINNY_ALERT);
1610 transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid);
1612 case AST_CONTROL_BUSY:
1613 transmit_tone(s, SKINNY_BUSYTONE);
1614 transmit_callstate(s, l->instance, SKINNY_BUSY, sub->callid);
1616 case AST_CONTROL_CONGESTION:
1617 transmit_tone(s, SKINNY_REORDER);
1618 transmit_callstate(s, l->instance, SKINNY_CONGESTION, sub->callid);
1621 transmit_tone(s, SKINNY_SILENCE);
1624 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
1630 static struct ast_channel *skinny_new(struct skinny_subchannel *sub, int state)
1632 struct ast_channel *tmp;
1633 struct skinny_line *l = sub->parent;
1636 tmp = ast_channel_alloc(1);
1638 tmp->nativeformats = l->capability;
1639 if (!tmp->nativeformats)
1640 tmp->nativeformats = capability;
1641 fmt = ast_best_codec(tmp->nativeformats);
1642 snprintf(tmp->name, sizeof(tmp->name), "Skinny/%s@%s-%d", l->name, l->parent->name, sub->callid);
1644 tmp->fds[0] = ast_rtp_fd(sub->rtp);
1646 ast_setstate(tmp, state);
1647 if (state == AST_STATE_RING)
1649 tmp->writeformat = fmt;
1650 tmp->pvt->rawwriteformat = fmt;
1651 tmp->readformat = fmt;
1652 tmp->pvt->rawreadformat = fmt;
1653 tmp->pvt->pvt = sub;
1654 tmp->pvt->call = skinny_call;
1655 tmp->pvt->hangup = skinny_hangup;
1656 tmp->pvt->answer = skinny_answer;
1657 tmp->pvt->read = skinny_read;
1658 tmp->pvt->write = skinny_write;
1659 tmp->pvt->indicate = skinny_indicate;
1660 tmp->pvt->fixup = skinny_fixup;
1661 tmp->pvt->send_digit = skinny_senddigit;
1662 // tmp->pvt->bridge = ast_rtp_bridge;
1663 if (strlen(l->language))
1664 strncpy(tmp->language, l->language, sizeof(tmp->language)-1);
1665 if (strlen(l->accountcode))
1666 strncpy(tmp->accountcode, l->accountcode, sizeof(tmp->accountcode)-1);
1668 tmp->amaflags = l->amaflags;
1670 ast_mutex_lock(&usecnt_lock);
1672 ast_mutex_unlock(&usecnt_lock);
1673 ast_update_use_count();
1674 tmp->callgroup = l->callgroup;
1675 tmp->pickupgroup = l->pickupgroup;
1676 strncpy(tmp->call_forward, l->call_forward, sizeof(tmp->call_forward));
1677 strncpy(tmp->context, l->context, sizeof(tmp->context)-1);
1678 strncpy(tmp->exten,l->exten, sizeof(tmp->exten)-1);
1679 if (strlen(l->callerid))
1680 tmp->callerid = strdup(l->callerid);
1682 if (state != AST_STATE_DOWN) {
1683 if (ast_pbx_start(tmp)) {
1684 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
1690 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
1696 static int handle_message(skinny_req *req, struct skinnysession *s)
1698 struct skinny_subchannel *sub;
1699 struct ast_channel *c;
1700 struct ast_frame f = { 0, };
1701 struct sockaddr_in sin;
1702 struct sockaddr_in us;
1703 struct skinny_line *lines;
1712 int stimulusInstance;
1724 printf("Recieved AlarmMessage\n");
1726 case REGISTER_MESSAGE:
1728 printf("Device %s is attempting to register\n", req->data.reg.name);
1729 res = skinny_register(req, s);
1731 ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", req->data.reg.name);
1732 memcpy(&name, req->data.reg.name, sizeof(req->data.reg.name));
1733 memset(req, 0, sizeof(skinny_req));
1734 req->len = sizeof(register_rej_message)+4;
1735 req->e = REGISTER_REJ_MESSAGE;
1736 sprintf(req->data.regrej.errMsg, "No Authority: %s", name);
1737 transmit_response(s, req);
1740 if (option_verbose > 2)
1741 ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfuly registered\n", s->device->name);
1742 memset(req, 0, SKINNY_MAX_PACKET);
1743 req->len = sizeof(register_ack_message)+4;
1744 req->e = REGISTER_ACK_MESSAGE;
1745 strcpy(req->data.regack.res, "0");
1746 req->data.regack.keepAlive = keep_alive;
1747 strcpy(req->data.regack.dateTemplate, date_format);
1748 strcpy(req->data.regack.res2, "0");
1749 req->data.regack.secondaryKeepAlive = keep_alive;
1750 transmit_response(s, req);
1752 printf ("Requesting capabilities\n");
1753 memset(req, 0, SKINNY_MAX_PACKET);
1755 req->e = CAPABILITIES_REQ_MESSAGE;
1756 transmit_response(s, req);
1758 case UNREGISTER_MESSAGE:
1759 /* XXX Acutally unregister the device */
1761 case IP_PORT_MESSAGE:
1763 case STIMULUS_MESSAGE:
1764 stimulus = req->data.stimulus.stimulus;
1765 stimulusInstance = req->data.stimulus.stimulusInstance;
1768 case STIMULUS_REDIAL:
1769 // XXX how we gonna deal with redial ?!?!
1771 printf("Recieved Stimulus: Redial\n");
1774 case STIMULUS_SPEEDDIAL:
1777 printf("Recieved Stimulus: SpeedDial\n");
1782 printf("Recieved Stimulus: Hold\n");
1784 case STIMULUS_TRANSFER:
1786 printf("Recieved Stimulus: Transfer\n");
1788 case STIMULUS_FORWARDALL:
1789 case STIMULUS_FORWARDBUSY:
1790 case STIMULUS_FORWARDNOANSWER:
1793 printf("Recieved Stimulus: Forward (%d)\n", stimulus);
1795 case STIMULUS_DISPLAY:
1798 printf("Recieved Stimulus: Display\n");
1802 printf("Recieved Stimulus: Line\n");
1804 sub = find_subchannel(s->device->lines);
1805 transmit_speaker_mode(s, 1); // Turn on
1808 printf("RECEIVED UNKNOWN STIMULUS: %d\n", stimulus);
1814 case VERSION_REQ_MESSAGE:
1816 printf ("Version Request\n");
1817 memset(req, 0, SKINNY_MAX_PACKET);
1818 req->len = sizeof(version_res_message)+4;
1819 req->e = VERSION_RES_MESSAGE;
1820 sprintf(req->data.version.version, version_id);
1821 transmit_response(s, req);
1823 case SERVER_REQUEST_MESSAGE:
1825 printf ("Recieved Server Request\n");
1826 memset(req, 0, SKINNY_MAX_PACKET);
1827 req->len = sizeof(server_res_message)+4;
1828 req->e = SERVER_RES_MESSAGE;
1829 memcpy(req->data.serverres.server[0].serverName, ourhost,
1830 sizeof(req->data.serverres.server[0].serverName));
1831 req->data.serverres.serverListenPort[0] = ourport;
1832 req->data.serverres.serverIpAddr[0] = __ourip.s_addr;
1833 transmit_response(s, req);
1835 case BUTTON_TEMPLATE_REQ_MESSAGE:
1837 printf ("Buttontemplate requested\n");
1838 memset(req, 0, SKINNY_MAX_PACKET);
1839 req->len = sizeof(button_template_res_message)+4;
1840 req->e = BUTTON_TEMPLATE_RES_MESSAGE;
1841 req->data.buttontemplate.buttonOffset = 0;
1842 req->data.buttontemplate.buttonCount = 10;
1843 req->data.buttontemplate.totalButtonCount = 10;
1844 /* XXX Figure out how to do this correctly */
1845 memcpy(req->data.buttontemplate.definition,
1846 button_definition_hack,
1847 sizeof(req->data.buttontemplate.definition));
1848 transmit_response(s, req);
1850 case SOFT_KEY_SET_REQ_MESSAGE:
1852 printf ("Received SoftKeySetReq\n");
1853 memset(req, 0, SKINNY_MAX_PACKET);
1854 req->len = sizeof(soft_key_sets)+4;
1855 req->e = SOFT_KEY_SET_RES_MESSAGE;
1856 req->data.softkeysets.softKeySetOffset = 0;
1857 req->data.softkeysets.softKeySetCount = 11;
1858 req->data.softkeysets.totalSoftKeySetCount = 11;
1859 /* XXX Wicked hack XXX */
1860 memcpy(req->data.softkeysets.softKeySetDefinition,
1862 sizeof(req->data.softkeysets.softKeySetDefinition));
1863 transmit_response(s,req);
1865 case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
1867 printf ("Recieved SoftKey Template Request\n");
1868 memset(req, 0, SKINNY_MAX_PACKET);
1869 req->len = sizeof(soft_key_template)+4;
1870 req->e = SOFT_KEY_TEMPLATE_RES_MESSAGE;
1871 req->data.softkeytemplate.softKeyOffset = 0;
1872 req->data.softkeytemplate.softKeyCount = 21;
1873 req->data.softkeytemplate.totalSoftKeyCount = 21;
1874 /* XXX Another wicked hack XXX */
1875 memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
1876 soft_key_template_hack,
1877 sizeof(req->data.softkeytemplate.softKeyTemplateDefinition));
1878 transmit_response(s,req);
1880 case TIME_DATE_REQ_MESSAGE:
1882 printf ("Received Time/Date Request\n");
1883 memset(req, 0, SKINNY_MAX_PACKET);
1884 req->len = sizeof(definetimedate_message)+4;
1885 req->e = DEFINETIMEDATE_MESSAGE;
1887 cmtime = localtime(&timer);
1888 req->data.definetimedate.year = cmtime->tm_year+1900;
1889 req->data.definetimedate.month = cmtime->tm_mon+1;
1890 req->data.definetimedate.dayofweek = cmtime->tm_wday;
1891 req->data.definetimedate.day = cmtime->tm_mday;
1892 req->data.definetimedate.hour = cmtime->tm_hour;
1893 req->data.definetimedate.minute = cmtime->tm_min;
1894 req->data.definetimedate.seconds = cmtime->tm_sec;
1895 transmit_response(s, req);
1897 case SPEED_DIAL_STAT_REQ_MESSAGE:
1898 /* Not really sure how Speed Dial's are different than the
1899 Softkey templates */
1900 speedDialNum = req->data.speeddialreq.speedDialNumber;
1902 // printf ("Recieved SpeedDialStatReq: %d\n", speedDialNum);
1903 memset(req, 0, SKINNY_MAX_PACKET);
1904 req->len = sizeof(speed_dial_stat_res_message)+4;
1905 req->e = SPEED_DIAL_STAT_RES_MESSAGE;
1907 /* XXX Do this right XXX */
1908 req->data.speeddialreq.speedDialNumber = speedDialNum;
1909 sprintf(req->data.speeddial.speedDialDirNumber, "31337");
1910 sprintf(req->data.speeddial.speedDialDisplayName, "Asterisk Rules!");
1912 transmit_response(s, req);
1914 case LINE_STATE_REQ_MESSAGE:
1915 lineNumber = req->data.line.lineNumber;
1917 printf ("Received LineStateReq\n");
1918 memset(req, 0, SKINNY_MAX_PACKET);
1919 req->len = sizeof(line_stat_res_message)+4;
1920 req->e = LINE_STAT_RES_MESSAGE;
1921 sub = find_subchannel(s->device->lines);
1923 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
1926 lines = sub->parent;
1927 ast_mutex_lock(&devicelock);
1928 for (i=1; i < lineNumber; i++) {
1929 lines = lines->next;
1931 ast_mutex_unlock(&devicelock);
1932 req->data.linestat.linenumber = lineNumber;
1933 memcpy(req->data.linestat.lineDirNumber, lines->name,
1934 sizeof(req->data.linestat.lineDirNumber));
1935 memcpy(req->data.linestat.lineDisplayName, lines->label,
1936 sizeof(req->data.linestat.lineDisplayName));
1937 transmit_response(s,req);
1939 case CAPABILITIES_RES_MESSAGE:
1941 printf ("Received CapabilitiesRes\n");
1942 // zien wat ie kan en verwerken (handshake)
1944 case KEEP_ALIVE_MESSAGE:
1945 memset(req, 0, SKINNY_MAX_PACKET);
1947 req->e = KEEP_ALIVE_ACK_MESSAGE;
1948 transmit_response(s, req);
1950 case OFFHOOK_MESSAGE:
1951 transmit_ringer_mode(s,1); // Ring off
1952 transmit_lamp_indication(s, s->device->lines->instance, 2); // Lamp on
1954 sub = find_subchannel(s->device->lines);
1956 ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
1959 sub->parent->hookstate = SKINNY_OFFHOOK;
1961 if (sub->outgoing) {
1962 // deal with asterisk skinny outbound calls
1964 transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
1965 transmit_tone(s, SKINNY_DIALTONE);
1966 c = skinny_new(sub, AST_STATE_DOWN);
1969 if (pthread_create(&t, NULL, skinny_ss, c)) {
1970 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
1974 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
1978 ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
1981 case ONHOOK_MESSAGE:
1982 sub = find_subchannel(s->device->lines);
1983 if (sub->parent->hookstate == SKINNY_ONHOOK) {
1984 /* Somthing else already put us back on hook */
1987 sub->cxmode = SKINNY_CX_RECVONLY;
1988 sub->parent->hookstate = SKINNY_ONHOOK;
1989 transmit_callstate(s, s->device->lines->instance, sub->parent->hookstate,sub->callid);
1991 printf("Skinny %s@%s went on hook\n",sub->parent->name, sub->parent->parent->name);
1993 // transmit_modify_request(sub);
1995 if (sub->parent->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
1996 /* We're allowed to transfer, we have two active calls and */
1997 /* we made at least one of the calls. Let's try and transfer */
1999 if ((res = attempt_transfer(p)) < 0) {
2000 if (p->sub->next->owner) {
2001 sub->next->alreadygone = 1;
2002 ast_queue_hangup(sub->next->owner,1);
2005 ast_log(LOG_WARNING, "Transfer attempt failed\n");
2010 /* Hangup the current call */
2011 /* If there is another active call, skinny_hangup will ring the phone with the other call */
2013 sub->alreadygone = 1;
2014 ast_queue_hangup(sub->owner, 1);
2016 ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
2017 sub->parent->name, sub->parent->parent->name, sub->callid);
2020 if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
2021 if (has_voicemail(sub->parent)) {
2022 transmit_lamp_indication(s, s->device->lines->instance, 4); // Flash
2024 transmit_lamp_indication(s, s->device->lines->instance, 1); // Off
2028 case KEYPAD_BUTTON_MESSAGE:
2029 digit = req->data.keypad.button;
2031 printf("Collected digit: [%d]\n", digit);
2033 f.frametype = AST_FRAME_DTMF;
2036 } else if (digit == 15) {
2039 sprintf(&d, "%d", digit);
2043 sub = find_subchannel(s->device->lines);
2046 /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
2047 ast_queue_frame(sub->owner, &f, 1);
2048 if (sub->next->owner) {
2049 ast_queue_frame(sub->next->owner, &f, 1);
2052 printf("No owner: %s\n", s->device->lines->name);
2055 case OPEN_RECIEVE_CHANNEL_ACK_MESSAGE:
2056 printf("Recieved Open Recieve Channel Ack\n");
2057 status = req->data.openrecievechannelack.status;
2059 ast_log(LOG_ERROR, "Open Recieve Channel Failure\n");
2062 memcpy(addr, req->data.openrecievechannelack.ipAddr, sizeof(addr));
2063 port = req->data.openrecievechannelack.port;
2065 sin.sin_family = AF_INET;
2066 memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr)); // Endian?
2067 sin.sin_port = htons(port);
2069 sub = find_subchannel(s->device->lines);
2070 ast_rtp_set_peer(sub->rtp, &sin);
2071 ast_rtp_get_us(sub->rtp, &us);
2073 printf("us port: %d\n", ntohs(us.sin_port));
2074 printf("sin port: %d\n", ntohs(sin.sin_port));
2077 memset(req, 0, SKINNY_MAX_PACKET);
2078 req->len = sizeof(start_media_transmission_message)+4;
2079 req->e = START_MEDIA_TRANSMISSION_MESSAGE;
2080 req->data.startmedia.conferenceId = 0;
2081 req->data.startmedia.passThruPartyId = 0;
2082 memcpy(req->data.startmedia.remoteIp, &s->device->ourip, 4); // Endian?
2083 req->data.startmedia.remotePort = ntohs(us.sin_port);
2084 req->data.startmedia.packetSize = 20;
2085 req->data.startmedia.payloadType = convert_cap(s->device->lines->capability);
2086 req->data.startmedia.qualifier.precedence = 127;
2087 req->data.startmedia.qualifier.vad = 0;
2088 req->data.startmedia.qualifier.packets = 0;
2089 req->data.startmedia.qualifier.bitRate = 0;
2090 transmit_response(s, req);
2093 printf("RECEIVED UNKNOWN MESSAGE TYPE: %x\n", req->e);
2102 static void destroy_session(struct skinnysession *s)
2104 struct skinnysession *cur, *prev = NULL;
2105 ast_mutex_lock(&sessionlock);
2115 prev->next = cur->next;
2117 sessions = cur->next;
2122 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
2123 ast_mutex_unlock(&sessionlock);
2126 static int get_input(struct skinnysession *s)
2134 FD_SET(s->fd, &fds);
2136 res = ast_select(s->fd + 1, &fds, NULL, NULL, NULL);
2139 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
2140 } else if (res > 0) {
2141 ast_mutex_lock(&s->lock);
2142 memset(s->inbuf,0,sizeof(s->inbuf));
2143 res = read(s->fd, s->inbuf, 4);
2144 dlen = *(int *)s->inbuf;
2148 res = read(s->fd, s->inbuf+4, dlen+4);
2149 ast_mutex_unlock(&s->lock);
2159 static skinny_req *skinny_req_parse(struct skinnysession *s)
2163 req = malloc(SKINNY_MAX_PACKET);
2165 ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
2168 memset(req, 0, sizeof(skinny_req));
2169 memcpy(req, s->inbuf, *(int*)(s->inbuf)+8); // +8
2171 ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
2177 static void *skinny_session(void *data)
2181 struct skinnysession *s = data;
2183 ast_verbose(VERBOSE_PREFIX_3 "Starting Skinny session from %s\n", inet_ntoa(s->sin.sin_addr));
2190 req = skinny_req_parse(s);
2194 res = handle_message(req, s);
2200 ast_log(LOG_NOTICE, "Skinny Session returned: %s\n", strerror(errno));
2205 static void *accept_thread(void *ignore)
2208 struct sockaddr_in sin;
2210 struct skinnysession *s;
2213 pthread_attr_t attr;
2215 pthread_attr_init(&attr);
2216 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2219 sinlen = sizeof(sin);
2220 as = accept(skinnysock, &sin, &sinlen);
2222 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
2225 p = getprotobyname("tcp");
2227 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
2228 ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
2231 s = malloc(sizeof(struct skinnysession));
2233 ast_log(LOG_WARNING, "Failed to allocate Skinny session: %s\n", strerror(errno));
2236 memset(s, 0, sizeof(struct skinnysession));
2237 memcpy(&s->sin, &sin, sizeof(sin));
2238 ast_mutex_init(&s->lock);
2240 ast_mutex_lock(&sessionlock);
2243 ast_mutex_unlock(&sessionlock);
2245 if (pthread_create(&tcp_thread, NULL, skinny_session, s))
2251 printf("killing accept thread\n");
2257 static void *do_monitor(void *data)
2262 /* Add an I/O event to our TCP socket */
2263 if (skinnysock > -1) {
2264 ast_io_add(io, skinnysock, accept_thread, AST_IO_IN, NULL);
2266 ast_log(LOG_WARNING, "Unable to create I/O socket event\n");
2271 /* This thread monitors all the interfaces which are not yet in use
2272 (and thus do not have a separate thread) indefinitely */
2273 /* From here on out, we die whenever asked */
2275 pthread_testcancel();
2276 /* Wait for sched or io */
2277 res = ast_sched_wait(sched);
2278 if ((res < 0) || (res > 1000))
2280 res = ast_io_wait(io, res);
2281 ast_mutex_lock(&monlock);
2283 ast_sched_runq(sched);
2284 ast_mutex_unlock(&monlock);
2291 static int restart_monitor(void)
2294 /* If we're supposed to be stopped -- stay stopped */
2295 if (monitor_thread == -2)
2297 if (ast_mutex_lock(&monlock)) {
2298 ast_log(LOG_WARNING, "Unable to lock monitor\n");
2301 if (monitor_thread == pthread_self()) {
2302 ast_mutex_unlock(&monlock);
2303 ast_log(LOG_WARNING, "Cannot kill myself\n");
2306 if (monitor_thread) {
2307 /* Wake up the thread */
2308 pthread_kill(monitor_thread, SIGURG);
2310 /* Start a new monitor */
2311 if (pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
2312 ast_mutex_unlock(&monlock);
2313 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
2317 ast_mutex_unlock(&monlock);
2321 static struct ast_channel *skinny_request(char *type, int format, void *data)
2324 struct skinny_subchannel *sub;
2325 struct skinny_device *d = NULL;
2326 struct ast_channel *tmpc = NULL;
2331 format &= capability;
2333 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
2336 strncpy(tmp, dest, sizeof(tmp) - 1); // XXX FIX
2338 ast_log(LOG_NOTICE, "Skinny channels require something!?\n");
2342 sub = find_subchannel(d->lines);
2345 ast_log(LOG_NOTICE, "No available lines on: %s\n", d->name);
2349 if (option_verbose > 2) {
2350 ast_verbose(VERBOSE_PREFIX_3 "skinny_request(%s)\n", tmp);
2351 ast_verbose(VERBOSE_PREFIX_3 "Skinny cw: %d, dnd: %d, so: %d, sno: %d\n",
2352 sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
2356 if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
2357 ((!sub->parent->callwaiting) && (sub->owner)) ||
2358 (sub->parent->dnd && (!strlen(sub->parent->call_forward)))) {
2359 if (sub->parent->hookstate == SKINNY_ONHOOK) {
2360 if (has_voicemail(sub->parent)) {
2361 // transmit_notify_request(sub,"vmwi(+)");
2363 // transmit_notify_request(sub,"vmwi(-)");
2368 tmpc = skinny_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
2370 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
2377 static int reload_config()
2380 struct ast_config *cfg;
2381 struct ast_variable *v;
2384 struct skinny_device *d;
2385 int oldport = ntohs(bindaddr.sin_port);
2387 if (gethostname(ourhost, sizeof(ourhost))) {
2388 ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
2391 cfg = ast_load(config);
2393 /* We *must* have a config file otherwise stop immediately */
2395 ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
2399 /* load the general section */
2400 memset(&bindaddr, 0, sizeof(bindaddr));
2401 v = ast_variable_browse(cfg, "general");
2403 /* Create the interface list */
2404 if (!strcasecmp(v->name, "bindaddr")) {
2405 if (!(hp = gethostbyname(v->value))) {
2406 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
2408 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
2410 } else if (!strcasecmp(v->name, "keepAlive")) {
2411 keep_alive = atoi(v->value);
2412 } else if (!strcasecmp(v->name, "dateFormat")) {
2413 strncpy(date_format, v->value, sizeof(date_format) - 1);
2414 } else if (!strcasecmp(v->name, "versionId")) {
2415 strncpy(version_id, v->value, sizeof(version_id) - 1);
2416 } else if (!strcasecmp(v->name, "allow")) {
2417 format = ast_getformatbyname(v->value);
2419 ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
2421 capability |= format;
2422 } else if (!strcasecmp(v->name, "disallow")) {
2423 format = ast_getformatbyname(v->value);
2425 ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
2427 capability &= ~format;
2428 } else if (!strcasecmp(v->name, "port")) {
2429 if (sscanf(v->value, "%i", &ourport) == 1) {
2430 bindaddr.sin_port = htons(ourport);
2432 ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
2438 if (ntohl(bindaddr.sin_addr.s_addr)) {
2439 memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
2441 hp = gethostbyname(ourhost);
2443 ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
2446 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
2448 if (!ntohs(bindaddr.sin_port))
2449 bindaddr.sin_port = ntohs(DEFAULT_SKINNY_PORT);
2450 bindaddr.sin_family = AF_INET;
2452 /* load the device sections */
2453 cat = ast_category_browse(cfg, NULL);
2455 if (strcasecmp(cat, "general")) {
2456 d = build_device(cat, ast_variable_browse(cfg, cat));
2458 if (option_verbose > 2) {
2459 ast_verbose(VERBOSE_PREFIX_3 "Added device '%s'\n", d->name);
2461 ast_mutex_lock(&devicelock);
2464 ast_mutex_unlock(&devicelock);
2467 cat = ast_category_browse(cfg, cat);
2469 ast_mutex_lock(&netlock);
2470 if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
2474 if (skinnysock < 0) {
2475 skinnysock = socket(AF_INET, SOCK_STREAM, 0);
2476 if(!setsockopt(skinnysock,SOL_SOCKET,SO_REUSEADDR,&on,0)) {
2477 ast_log(LOG_ERROR, "Set Socket Options failed: %s", strerror(errno));
2481 if (skinnysock < 0) {
2482 ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
2484 if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
2485 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
2486 inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
2493 if (listen(skinnysock,DEFAULT_SKINNY_BACKLOG)) {
2494 ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
2495 inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
2502 if (option_verbose > 1)
2503 ast_verbose(VERBOSE_PREFIX_2 "Skinny listening on %s:%d\n",
2504 inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
2506 pthread_create(&accept_t,NULL, accept_thread, NULL);
2510 ast_mutex_unlock(&netlock);
2513 /* and unload the configuration when were done */
2524 /* load and parse config */
2525 res = reload_config();
2527 /* Announce our presence to Asterisk */
2529 /* Make sure we can register our skinny channel type */
2530 if (ast_channel_register(type, tdesc, capability, skinny_request)) {
2531 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
2535 skinny_rtp.type = type;
2536 ast_rtp_proto_register(&skinny_rtp);
2537 ast_cli_register(&cli_show_lines);
2538 ast_cli_register(&cli_debug);
2539 ast_cli_register(&cli_no_debug);
2540 sched = sched_context_create();
2542 ast_log(LOG_WARNING, "Unable to create schedule context\n");
2544 io = io_context_create();
2546 ast_log(LOG_WARNING, "Unable to create I/O context\n");
2548 /* And start the monitor for the first time */
2557 struct skinny_subchannel *p, *pl;
2559 ast_channel_unregister(type);
2560 ast_verbose("Skinny module unloading\n");
2562 /* First, take us out of the channel loop */
2563 ast_channel_unregister(type);
2565 /* close all IP connections */
2566 if (!ast_mutex_lock(&devicelock)) {
2567 /* Hangup all interfaces if they have an owner */
2571 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2575 ast_mutex_unlock(&iflock);
2577 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2580 if (!ast_mutex_lock(&monlock)) {
2581 if (monitor_thread) {
2582 pthread_cancel(monitor_thread);
2583 pthread_kill(monitor_thread, SIGURG);
2584 pthread_join(monitor_thread, NULL);
2586 monitor_thread = -2;
2587 ast_mutex_unlock(&monlock);
2589 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2593 if (!ast_mutex_lock(&iflock)) {
2594 /* Destroy all the interfaces and free their memory */
2599 /* Free associated memory */
2603 ast_mutex_unlock(&iflock);
2605 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2609 /* if we're still here something was fscked up */
2616 ast_mutex_lock(&usecnt_lock);
2618 ast_mutex_unlock(&usecnt_lock);
2624 return ASTERISK_GPL_KEY;