/* * Asterisk -- A telephony toolkit for Linux. * * Implementation of UNISTIM Control Protocol * * Copyright (C) 2005, Marc Olivier Chouinard. * Bastian Nagel * * Marc Olivier Chouinard * Bastian Nagel * * This code is base on the chan_mgcp from Asterisk, * and the UNISTIM protocol code is taken from GPL code made by * Cedric Hans . * * I only took what was already there, and packaged them together * * This program is free software, distributed under the terms of * the GNU General Public License */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DWORD unsigned int #define WORD unsigned short #define WSAEVENT unsigned int #define INFINITE -1 #define UNISTIM_OFFHOOK 1 #define UNISTIM_ONHOOK 2 #define UNISTIM_RINGOUT 3 #define UNISTIM_RINGIN 4 #define UNISTIM_CONNECTED 5 #define UNISTIM_BUSY 6 #define UNISTIM_CONGESTION 7 #define UNISTIM_HOLD 8 #define UNISTIM_CALLWAIT 9 #define UNISTIM_TRANSFER 10 #define UNISTIM_PARK 11 #define UNISTIM_PROGRESS 12 #define UNISTIM_INVALID 14 #define UNISTIM_SILENCE 0 #define UNISTIM_DIALTONE 33 #define UNISTIM_BUSYTONE 35 #define UNISTIM_ALERT 36 #define UNISTIM_REORDER 37 #define UNISTIM_CALLWAITTONE 45 #define UNISTIM_TONE_SILENCE 0 #define UNISTIM_TONE_DIAL 1 #define UNISTIM_TONE_RING 2 #define FAV_BLINK_FAST 0x20 #define FAV_BLINK_SLOW 0x40 #define FAV_MAX_LENGTH 0x0A #define FAV_ICON_NONE 0x00 #define FAV_ICON_HANGUP_BLACK 0x20 #define FAV_ICON_HANGUP_WHITE 0x21 #define FAV_ICON_SPEAKER_HANGUP_BLACK 0x22 #define FAV_ICON_SPEAKER_HANGUP_WHITE 0x23 #define FAV_ICON_PICKUP_BLACK 0x24 #define FAV_ICON_PICKUP_WHITE 0x25 #define FAV_ICON_HANDS_FREE_BLACK 0x26 #define FAV_ICON_HANDS_FREE_WHITE 0x27 #define FAV_ICON_SPEAKER_PICKUP_BLACK 0x28 #define FAV_ICON_SPEAKER_PICKUP_WHITE 0x29 #define FAV_ICON_PHONE_BLACK 0x2A #define FAV_ICON_PHONE_WHITE 0x2B #define FAV_ICON_SPEAKER_HANDS_FREE_BLACK 0x2C #define FAV_ICON_SPEAKER_HANDS_FREE_WHITE 0x2D #define FAV_ICON_UNKWN0 0x2E #define FAV_ICON_UNKWN1 0x2F #define FAV_ICON_HOME 0x30 #define FAV_ICON_CITY 0x31 #define FAV_ICON_SHARP 0x32 #define FAV_ICON_PAGER 0x33 #define FAV_ICON_CALL_CENTER 0x34 #define FAV_ICON_FAX 0x35 #define FAV_ICON_MAILBOX 0x36 #define FAV_ICON_ELECTRIC_PHONE 0x37 #define FAV_ICON_COMPUTER 0x38 #define FAV_ICON_FORWARD 0x39 #define FAV_ICON_LOCKED 0x3A #define FAV_ICON_TRASH 0x3B #define FAV_ICON_INBOX 0x3C #define FAV_ICON_OUTBOX 0x3D #define FAV_ICON_UNKWN 0x3E #define FAV_ICON_BOX 0x3F #define LED_TOP_OFF 0x00 #define LED_TOP_ON 0x01 #define LED_TOP_FLASH 0x02 #define LED_SPEAKER_OFF 0x08 #define LED_SPEAKER_ON 0x09 #define LED_MUTE_OFF 0x18 #define LED_MUTE ON 0x19 #define LED_MUTE_FLASH 0x0a #define MAX_BUF_SIZE 64 // Size of the transmit buffer #define MAX_BUF_NUMBER 30 // Number of slots for the transmit queue #define SIZE_HEADER 6 #define TEXT_LENGTH_MAX 24 #define TEXT_LINE0 0x00 #define TEXT_LINE1 0x20 #define TEXT_LINE2 0x40 #define TEXT_NORMAL 0x05 #define TEXT_INVERSE 0x25 #define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */ #define NB_MAX_RETRANSMIT 8 // Try x times before removing the phone #define DEFAULT_CODEC 0x00 // G711 µLaw #define PING_TIMER 90000 // Ping every x milliseconds #define DEFAULT_CONTEXT "default" #define DEFAULT_UNISTIM_CA_PORT 2727 #define UNISTIM_MAX_PACKET 2000 #define RESPONSE_TIMEOUT 30 /* in seconds */ #define MAX_SUBS 2 #define SUB_REAL 0 #define SUB_ALT 1 #define TYPE_TRUNK 1 #define TYPE_LINE 2 #ifndef IPTOS_MINCOST #define IPTOS_MINCOST 0x02 #endif enum PhoneState { STATE_INIT, STATE_AUTHDENY, STATE_MAINPAGE, STATE_DIALPAGE, STATE_DIALING, STATE_RINGING, STATE_CALL, STATE_BADNUMBER, STATE_SELECTCODEC }; enum ReceiverState { STATE_HANGUP, STATE_PICKUP_NOSPEAKER, STATE_NOPICKUP_SPEAKER, STATE_PICKUP_SPEAKER }; enum PhoneKey { KEY_0 = 0x40, KEY_1 = 0x41, KEY_2 = 0x42, KEY_3 = 0x43, KEY_4 = 0x44, KEY_5 = 0x45, KEY_6 = 0x46, KEY_7 = 0x47, KEY_8 = 0x48, KEY_9 = 0x49, KEY_STAR = 0x4a, KEY_SHARP = 0x4b, KEY_UP = 0x4c, KEY_DOWN = 0x4d, KEY_RIGHT = 0x4e, KEY_LEFT = 0x4f, KEY_QUIT = 0x50, KEY_COPY = 0x51, KEY_FUNC1 = 0x54, KEY_FUNC2 = 0x55, KEY_FUNC3 = 0x56, KEY_FUNC4 = 0x57, KEY_WAIT = 0x5b, KEY_HANGUP = 0x5c, KEY_MUTE = 0x5d, KEY_HEADPHN = 0x5e, KEY_LOUDSPK = 0x5f, KEY_FAV0 = 0x60, KEY_FAV1 = 0x61, KEY_FAV2 = 0x62, KEY_FAV3 = 0x63, KEY_FAV4 = 0x64, KEY_FAV5 = 0x65, KEY_COMPUTR = 0x7b, KEY_CONF = 0x7c, KEY_SNDHIST = 0x7d, KEY_RCVHIST = 0x7e, KEY_INDEX = 0x7f }; /*--------------------------------- --|KEY5 __________|__________ KEY2|-- --|KEY4 __________|__________ KEY1|-- --|KEY3 __________|__________ KEY0|-- --------------------------------- | Title DateTime | | TextLine0 | | TextLine1 | | TextLine3 | --------------------------------- | KEY? KEY? KEY? KEY? | ---------------------------------*/ /*---------------------------------------------------------------------------------------------------------------------------------------------------*/ /* */ /*---------------------------------------------------------------------------------------------------------------------------------------------------*/ unsigned char buffsend[64] = {0x00, 0x00, 0xaa, 0xbb, 0x02, 0x01}; unsigned char PacketRcvDiscovery[] = { 0xff, 0xff, 0xff, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 }; unsigned char PacketSendDiscoveryACK[] = { 0x00, 0x00, /*Initial Seq (2 bytes)*/0x00, 0x00, 0x00, 0x01 }; unsigned char PacketRecvFirmVersion[] = { 0x00, 0x00, 0x00, 0x13, 0x9a, 0x0a, 0x02}; unsigned char PacketRecvPressedKey[] = { 0x00, 0x00, 0x00, 0x13, 0x99, 0x04, 0x00}; unsigned char PacketRecvPickUp[] = { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x04}; unsigned char PacketRecvHangUp[] = { 0x00, 0x00, 0x00, 0x13, 0x99, 0x03, 0x03}; unsigned char PacketRecvR2[] = { 0x00, 0x00, 0x00, 0x13, 0x96, 0x03, 0x03 }; unsigned char PacketRecvR0[] = { 0xff, 0xff, 0xff, 0xff, 0x9e, 0x03, 0x08 }; unsigned char PacketRecvR1[] = { 0xff, 0xff, 0xff, 0xff }; unsigned char PacketRecvMacAddr[] = { 0xff, 0xff, 0xff, 0xff, 0x9a, 0x0d, 0x07, 0x31, 0x38 /*MacAddr*/ }; unsigned char PacketSendDateTime[] = { 0x11, 0x09, 0x02, 0x0a, /*Month*/0x05, /*Day*/0x06, /*Hour*/0x07, /*Minutes*/0x08, 0x32, 0x17, 0x04, 0x24, 0x07, 0x19, 0x04, 0x07, 0x00, 0x19, 0x05, 0x09, 0x3e, 0x0f, 0x16, 0x05, 0x00, 0x80, 0x00, 0x1e, 0x05, 0x12, 0x00, 0x78 }; unsigned char PacketSendDateTime2[] = { 0x17, 0x04, 0x17, 0x3d, 0x11, 0x09, 0x02, 0x0a, /*Month*/0x05, /*Day*/0x06, /*Hour*/0x07, /*Minutes*/0x08, 0x32 }; unsigned char PacketSendDateTime3[] = { 0x11, 0x09, 0x02, 0x02, /*Month*/0x05, /*Day*/0x06, /*Hour*/0x07, /*Minutes*/0x08, 0x32 }; // G729 = 0x12 unsigned char PacketSendCall[] = { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00, 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16, 0x0a, 0x38, 0x00, 0x12, 0xca, 0x03, 0xc0, 0xc3, 0xc5, 0x16, 0x16, 0x30, 0x00, 0x00, /*codec */0x12, 0x12, 0x02, 0x5c, 0x00, /*port*/0x0f, 0xa0, 0x9c, 0x41, /*port*/0x0f, 0xa0, 0x9c, 0x41, /* IP Address */ 0x0a, 0x01, 0x16, 0x66 }; // port : 0x0f, 0xa0 unsigned char PacketSendOpenAudioStreamTX[] = { 0x16, 0x1a, 0x30, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x06, 0x06, 0x01, 0x14, 0x50, 0x14, 0x51, 0x14, 0x50, 0x14, 0x51, 0x00, 0x00, 0x00, 0x00 }; unsigned char PacketSendOpenAudioStreamRX[] = { 0x16, 0x1a, 0x30, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0xb8, 0xb8, 0x06, 0x06, 0x01, 0x14, 0x50, 0x14, 0x51, 0x14, 0x50, 0x14, 0x51, 0x00, 0x00, 0x00, 0x00 }; unsigned char PacketSendCloseAudioStreamTX[] = { 0x16, 0x05, 0x31, 0xff, 0x00 }; unsigned char PacketSendCloseAudioStreamRX[] = { 0x16, 0x05, 0x31, 0x00, 0xff }; unsigned char PacketSendStreamBasedToneDialCad[] = { 0x16, 0x0a, 0x1e, 0x00, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x2b }; unsigned char PacketSendStreamBasedToneDialFreq[] = { 0x16, 0x06, 0x1d, 0x00, 0x0d, 0x70 }; unsigned char PacketSendStreamBasedToneRingCad[] = { 0x16, 0x0a, 0x1e, 0x00, 0x2f, 0xc0, 0x2f, 0xc0, 0x2f, 0xc0 }; unsigned char PacketSendStreamBasedToneRingFreq[] = { 0x16, 0x06, 0x1d, 0x00, 0x0d, 0x70 }; unsigned char PacketSendVocoderParm[] = { 0x16, 0x08, 0x38, 0x00, 0x00, 0xe0, 0x00, 0xa0 }; unsigned char PacketSendVocoderParm2[] = { 0x16, 0x06, 0x38, 0x00, 0x00, 0x80 }; unsigned char PacketSendStreamBasedToneOn[] = { 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 }; unsigned char PacketSendStreamBasedToneOff[] = { 0x16, 0x05, 0x1c, 0x00, 0x00 }; unsigned char PacketSendEnableSpker[] = { 0x16, 0x06, 0x32, 0xc2, 0x03, 0x00 }; unsigned char PacketSendDisableSpker[]= { 0x16, 0x06, 0x32, 0xc0, 0x03, 0x00 }; unsigned char PacketSendMute[] = { 0x16, 0x05, 0x04, 0x00, 0x00 }; unsigned char PacketSendStartTimer[] = { 0x17, 0x05, 0x0b, 0x05, 0x00, 0x17, 0x08, 0x16, 0x44, 0x75, 0x72, 0xe9, 0x65 }; unsigned char PacketSendStopTimer[] = { 0x17, 0x05, 0x0b, 0x02, 0x00 }; unsigned char PacketSendEnableRecvr[] = { 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 }; unsigned char PacketSendConnectTransducer[] = { 0x16, 0x06, 0x32, 0xc0, 0x01, /*on/off?*/0x00 }; unsigned char PacketSendRing[] = { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x1c, 0x00, 0x00, 0x16, 0x04, 0x1a, 0x01, 0x16, 0x05, 0x12, 0x13, 0x18, 0x16, 0x04, 0x18, 0x20, 0x16, 0x04, 0x10, 0x00 }; unsigned char PacketSendNoRing[] = { 0x16, 0x04, 0x1a, 0x00, 0x16, 0x04, 0x11, 0x00 }; unsigned char PacketSendEndCall[] = { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, 0x16, 0x05, 0x31, 0x00, 0x00, 0x19, 0x04, 0x00, 0x10, 0x19, 0x04, 0x00, 0x18, 0x16, 0x05, 0x04, 0x00, 0x00, 0x16, 0x04, 0x37, 0x10 }; unsigned char PacketSendTitle[] = { 0x17, 0x10, 0x19, 0x02, /*text*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text*/}; unsigned char PacketSendText[] = { 0x17, 0x1e, 0x1b, 0x04, /*pos*/0x00, /*inverse*/0x25, /*text*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*end_text*/0x17, 0x04, 0x10, 0x87 }; unsigned char PacketSendStatus[] = { 0x17, 0x20, 0x19, 0x08, /*text*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /*end_text*/}; unsigned char PacketSendFavorite[] = { 0x17, 0x0f, 0x19, 0x10, /*pos*/0x01, /*name*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /*end_name*/0x19, 0x05, 0x0f,/*pos*/ 0x01, /*icone*/0x00 }; unsigned char PacketSendKeyLabel[] = { 0x17, 0x0f, 0x19, 0x10, /*pos*/0x00, /*name*/0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; unsigned char PacketSendIcon[] = { 0x17, 0x05, 0x14, /*pos*/0x00, /*icon*/0x25 }; // display an icon in front of the text zone unsigned char PacketSendIconUpdate[] = { 0x19, 0x05, 0x0f, /*pos*/0x00, /*icon*/0x00 }; unsigned char PacketSendLEDUpdate[] = { 0x19, 0x04, 0x00, 0x00 }; unsigned char PacketSendDateTimeFormat[] = { 0x17, 0x04, 0x17, /*format*/0x32 }; unsigned char PacketSendMonthLabelsDownload[] = { 0x17, 0x0a, 0x15, 0x46, 0x65, 0x62, 0x4d, /*lang?*/0xe4, 0x72, 0x20 }; unsigned char PacketSendSetPosCursor[]= { 0x17, 0x06, 0x10, 0x81, 0x04, /*pos*/ 0x20 }; unsigned char PacketSendBlinkCursor[] = { 0x17, 0x04, 0x10, 0x86 }; unsigned char PacketSendS0[] = { 0x1a, 0x04, 0x01, 0x08 }; // Query Basic Manager -> get Hardware ID unsigned char PacketSendS1[] = { 0x1a, 0x07, 0x07, 0x00, 0x00, 0x00, 0x13 }; // Assign Terminal ID unsigned char PacketSendS2[] = { 0x1a, 0x04, 0x01, 0x04 }; // Query Basic Manager -> get Firmware Version 0x9a 0x0a 0x02 fw 0x30 0x30 0x30 0x30 0x30 0x30 0x30 (every byte -0x30) unsigned char PacketSendS3[] = { 0x1a, 0x04, 0x01, 0x10 }; // Query Basic Manager -> get IT Type unsigned char PacketSendS4[] = { 0x16, 0x04, 0x1a, 0x00, /**/0x16, 0x04, 0x11, 0x00, /**/0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, /**/0x16, 0x05, 0x1c, 0x00, 0x00, /* Stream Based tone OFF */ /**/0x17, 0x05, 0x0b, 0x00, 0x00, /* Timer ??? */ /**/0x19, 0x04, 0x00, 0x00, /* LED Update */ /**/0x19, 0x04, 0x00, 0x08, /* LED Update */ /**/0x19, 0x04, 0x00, 0x10, /* LED Update */ /**/0x19, 0x04, 0x00, 0x18, /* LED Update */ /**/0x16, 0x05, 0x31, 0x00, 0x00, /* Close Audio Stream ??? */ /**/0x16, 0x05, 0x04, 0x00, 0x00 }; /* Mute/Unmute */ unsigned char PacketSendS7[] = { 0x17, 0x06, 0x0f, 0x30, 0x07, 0x07 }; unsigned char PacketSendS8[] = { 0x17, 0x04, 0x24, 0x08 }; /* Display Contrast */ unsigned char PacketSendS9[] = { 0x16, 0x06, 0x32, 0xdf, 0x00, 0xff, /**/0x19, 0x04, 0x00, 0x10, /* LED Update */ /**/0x16, 0x05, 0x1c, 0x00, 0x00 }; /* Stream Based Tone Off */ unsigned char PacketSendS12[] = { 0x17, 0x04, 0x04, 0x00 }; /* Arrow */ unsigned char PacketSendPing[] = { 0x1e, 0x05, 0x12, 0x00, 0x78 }; /*---------------------------------------------------------------------------------------------------------------------------------------------------*/ /* */ /*---------------------------------------------------------------------------------------------------------------------------------------------------*/ typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME; typedef struct _WSAOVERLAPPED { DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; WSAEVENT hEvent; } WSAOVERLAPPED, *LPWSAOVERLAPPED; static struct ast_device_list { ASTOBJ_CONTAINER_COMPONENTS(struct unistim_device); } devicel; static struct ast_conn_list { ASTOBJ_CONTAINER_COMPONENTS(struct unistim_conn); } connl; static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs); static struct ast_rtp *unistim_get_rtp_peer(struct ast_channel *chan); static struct ast_rtp_protocol unistim_rtp = { get_rtp_info: unistim_get_rtp_peer, set_rtp_peer: unistim_set_rtp_peer, }; /* Protect the device list */ //AST_MUTEX_DEFINE_STATIC(devicelock); typedef struct __WSABUF { u_long len; char *buf; } WSABUF, * LPWSABUF; struct unistim_pvt { char name[80]; ast_mutex_t lock; struct ast_codec_pref prefs; int capability; unsigned int callid; struct ast_channel *owner; struct unistim_line *parent; struct ast_rtp *rtp; time_t lastouttime; int progress; int ringing; int lastout; int cxmode; int nat; int outgoing; int alreadygone; struct unistim_pvt *next; }; struct unistim_request { int len; char data[UNISTIM_MAX_PACKET]; struct sockaddr_in *addr_from; struct unistim_request *next; }; struct unistim_conn { ASTOBJ_COMPONENTS(struct unistim_conn); struct sockaddr_in addr; /* IP address of peer */ struct unistim_device *device; unsigned short seq_phone; // sequence number for the next packet (when we receive a request) unsigned short seq_server; // sequence number for the next packet (when we send a request) unsigned short last_seq_ack; // sequence number of the last ACK received unsigned long tick_next_ping; // time for the next ping int poke; // poke int last_buf_available; // number of a free slot int nb_retransmit; // number of retransmition int state; // state of the phone (see PhoneState) int receiver_state; // state of the receiver (see ReceiverState) WSABUF wsabufsend[MAX_BUF_NUMBER]; WSAOVERLAPPED wsaoverlap[MAX_BUF_NUMBER]; // Structure used for overlapped socket struct unistim_pvt *pvt; char buf[MAX_BUF_NUMBER][MAX_BUF_SIZE]; // Buffer array used to keep the lastest non-acked paquets char cdigits[24]; }; struct unistim_line { char name[80]; ast_mutex_t lock; char label[42]; /* Label that shows next to the line buttons */ struct unistim_pvt *pvt; /* pointer to our current connection, channel and stuff */ char accountcode[80]; char exten[AST_MAX_EXTENSION]; /* Extention where to start */ char context[AST_MAX_EXTENSION]; char language[MAX_LANGUAGE]; char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */ char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */ char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */ char call_forward[AST_MAX_EXTENSION]; char mailbox[AST_MAX_EXTENSION]; char musicclass[MAX_LANGUAGE]; int curtone; /* Current tone being played */ ast_group_t callgroup; ast_group_t pickupgroup; int callwaiting; int transfer; int threewaycalling; int cancallforward; int callreturn; int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */ int hascallerid; int hidecallerid; int amaflags; int type; int instance; int group; int needdestroy; int capability; int nonCodecCapability; int onhooktime; int msgstate; /* voicemail message state */ int immediate; int hookstate; int progress; struct unistim_line *next; struct unistim_device *parent; }; struct unistim_device { ASTOBJ_COMPONENTS(struct unistim_device); char firmware[80]; /* Version of the firmware */ struct unistim_conn *conn; char context[80]; /* Default context for incoming calls */ char language[MAX_LANGUAGE]; /* Default language for this user */ char cid_num[80]; /* Caller ID num */ char cid_name[80]; /* Caller ID name */ char accountcode[20]; /* Account code */ char musicclass[MAX_LANGUAGE]; /* Music on Hold class */ char name_fav[6][11]; char key_func[6][8]; char key_name[6][11]; char key_num[6][24]; struct ast_codec_pref prefs; /* codec prefs */ struct unistim_line *lines; int amaflags; /* AMA flags for billing */ int capability; /* Codec capability */ time_t lastmsgcheck; /* Last time we checked for MWI */ struct sockaddr_in addr; /* IP address of peer */ struct in_addr mask; struct ast_ha *ha; /* ACL setting */ }; struct unistimsession { pthread_t t; ast_mutex_t lock; struct sockaddr_in sin; int fd; char inbuf[UNISTIM_MAX_PACKET]; struct unistim_device *device; struct unistimsession *next; } *session = NULL; static void SendRing(struct unistim_conn *conn, struct ast_callerid cid); static void SendNoRing(struct unistim_conn *conn); static void SendTone(struct unistim_conn *conn, int tone); static void SendIcon(struct unistim_conn *conn, unsigned char pos, unsigned char status); static void SendIconUpdate(struct unistim_conn *conn, unsigned char pos, unsigned char status); static void SendText(unsigned char pos, unsigned char inverse, struct unistim_conn *conn, char *text); static void SendMWI(struct unistim_conn *conn); static void SendEnableReceiver(struct unistim_conn *conn); static void SendStartTimer(struct unistim_conn *conn); static void SendStopTimer(struct unistim_conn *conn); static void SendCallRequest(struct unistim_conn *conn); static void SendEndCall(struct unistim_conn *conn); static void SendActiveLoudSpeaker(struct unistim_conn *conn); static void SendEnableLoudSpeaker(struct unistim_conn *conn); static void SendDisableLoudSpeaker(struct unistim_conn *conn); static void start_rtp(struct unistim_pvt *pvt); static int unistim_do_reload(void); static int unistim_reload(int fd, int argc, char *argv[]); void SendClient(int size, char *data, struct unistim_conn *conn); void SendPing(struct unistim_conn *conn); static char default_context[AST_MAX_EXTENSION] = DEFAULT_CONTEXT; static char default_language[MAX_LANGUAGE] = ""; static char global_musicclass[MAX_LANGUAGE] = ""; /* Global music on hold class */ static char context[AST_MAX_EXTENSION] = "default"; static char language[MAX_LANGUAGE] = ""; static char musicclass[MAX_LANGUAGE] = ""; static char cid_num[AST_MAX_EXTENSION] = ""; static char cid_name[AST_MAX_EXTENSION] = ""; static char linelabel[AST_MAX_EXTENSION] =""; //static char accountcode[20] = ""; static char mailbox[AST_MAX_EXTENSION]; static int nat = 0; static int callnums = 1; static int dtmfmode = 0; static int firstdigittimeout = 16000; static int gendigittimeout = 8000; static char *desc = "UNISTIM Control Protocol (UNISTIM)"; static char *type = "UNISTIM"; static char *tdesc = "UNISTIM Control Protocol (UNISTIM)"; static char *config = "unistim.conf"; int count = 0; int sdeviceobjs; // Count of STATIC devices loaded char codec_number; /* Not used. Dosn't hurt for us to always send cid */ /*static int use_callerid = 1;*/ /*static int cur_signalling = -1;*/ /*static unsigned int cur_group = 0;*/ /* XXX Is this needed? */ /* Doesn't look like the dsp stuff for */ /* dtmfmode is actually hooked up. */ /*static int relaxdtmf = 0;*/ static int tos = 0; static int usecnt =0; AST_MUTEX_DEFINE_STATIC(usecnt_lock); /* SC: transaction id should always be positive */ /* Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical. */ AST_MUTEX_DEFINE_STATIC(netlock); AST_MUTEX_DEFINE_STATIC(monlock); /* This is the thread for the monitor which checks for input on the channels which are not currently in use. */ static pthread_t monitor_thread = AST_PTHREADT_NULL; static int restart_monitor(void); /* Just about everybody seems to support ulaw, so make it a nice default */ static int capability = AST_FORMAT_ULAW; static char ourhost[256]; static struct in_addr __ourip; static int ourport; static int unistimdebug = 0; static struct sched_context *sched; static struct io_context *io; AST_MUTEX_DEFINE_STATIC(unistim_reload_lock); static int unistim_reloading = 0; static int unistimsock = -1; static struct sockaddr_in bindaddr; /*----------------------------------------------------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------------------------------------------------*/ static int unistim_conn_addrcmp(char *name, struct sockaddr_in *sin) { /* We know name is the first field, so we can cast */ struct unistim_conn *p = (struct unistim_conn *)name; return inaddrcmp(&p->addr, sin); } static int unistim_device_addrcmp(char *name, struct sockaddr_in *sin) { /* We know name is the first field, so we can cast */ struct unistim_device *p = (struct unistim_device *)name; return inaddrcmp(&p->addr, sin); } static struct unistim_conn *find_conn(const char *conn, struct sockaddr_in *sin) { struct unistim_conn *p = NULL; if (conn) p = ASTOBJ_CONTAINER_FIND(&connl,conn); else p = ASTOBJ_CONTAINER_FIND_FULL(&connl,sin,name,sip_addr_hashfunc,1,unistim_conn_addrcmp); return(p); } static struct unistim_device *find_device(const char *device, struct sockaddr_in *sin) { struct unistim_device *p = NULL; if (device) p = ASTOBJ_CONTAINER_FIND(&devicel,device); else p = ASTOBJ_CONTAINER_FIND_FULL(&devicel,sin,name,sip_addr_hashfunc,1,unistim_device_addrcmp); return(p); } static struct unistim_line *find_line_by_name(struct unistim_conn *conn, char *name) { struct unistim_line *l = conn->device->lines; while (l) { if (!strcasecmp(l->name, name)) return l; l = l->next; } return NULL; } static struct unistim_pvt *find_pvt_by_line(struct unistim_line *l) { struct unistim_pvt *pvt = l->pvt; return pvt; } static struct unistim_pvt *find_pvt_by_name(char *dest) { struct unistim_line *l; struct unistim_device *d; char line[256]; char *at; char *device; strncpy(line, dest, sizeof(line) - 1); at = strchr(line, '@'); if (!at) { ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest); return NULL; } *at = '\0'; at++; device = at; ast_log(LOG_NOTICE, "searching for device: %s\n", device); d = find_device(device, NULL); if (d) { ast_log(LOG_NOTICE, "Found device: %s\n", d->name); /* Found the device */ l = d->lines; while (l) { /* Search for the right line */ ast_log(LOG_NOTICE, "SEARCHING %s:%s\n", l->name, line); if (!strcasecmp(l->name, line)) { return l->pvt; } l = l->next; } } return NULL; } static int unistim_write(struct ast_channel *ast, struct ast_frame *frame) { struct unistim_pvt *pvt = ast->pvt->pvt; int res = 0; if (frame->frametype != AST_FRAME_VOICE) { } else { if (!(frame->subclass & ast->nativeformats)) { ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n", frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat); return 0; } } if (pvt) { ast_mutex_lock(&pvt->lock); if (pvt->rtp) { res = ast_rtp_write(pvt->rtp, frame); } ast_mutex_unlock(&pvt->lock); } return res; } static struct ast_frame *unistim_read(struct ast_channel *ast) { struct ast_frame *fr; struct unistim_pvt *pvt = ast->pvt->pvt; ast_mutex_lock(&pvt->lock); fr = ast_rtp_read(pvt->rtp); if (pvt->owner) { if (fr->frametype == AST_FRAME_VOICE) { if (fr->subclass != pvt->owner->nativeformats) { ast_log(LOG_NOTICE, "----------- Format changed to %d\n", fr->subclass); pvt->owner->nativeformats = fr->subclass; ast_set_read_format(pvt->owner, AST_FORMAT_ULAW); ast_set_write_format(pvt->owner, AST_FORMAT_ULAW); } } } ast_mutex_unlock(&pvt->lock); return fr; } static char *control2str(int ind) { switch (ind) { case AST_CONTROL_HANGUP: return "Other end has hungup"; case AST_CONTROL_RING: return "Local ring"; case AST_CONTROL_RINGING: return "Remote end is ringing"; case AST_CONTROL_ANSWER: return "Remote end has answered"; case AST_CONTROL_BUSY: return "Remote end is busy"; case AST_CONTROL_TAKEOFFHOOK: return "Make it go off hook"; case AST_CONTROL_OFFHOOK: return "Line is off hook"; case AST_CONTROL_CONGESTION: return "Congestion (circuits busy)"; case AST_CONTROL_FLASH: return "Flash hook"; case AST_CONTROL_WINK: return "Wink"; case AST_CONTROL_OPTION: return "Set a low-level option"; case AST_CONTROL_RADIO_KEY: return "Key Radio"; case AST_CONTROL_RADIO_UNKEY: return "Un-Key Radio"; case -1: return "Stop tone"; } return "UNKNOWN"; } static int unistim_indicate(struct ast_channel *ast, int ind) { struct unistim_pvt *pvt = ast->pvt->pvt; // struct unistim_line *l = pvt->parent; ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name); switch(ind) { case AST_CONTROL_RINGING: if (ast->_state != AST_STATE_UP) { if (!pvt->progress) { SendTone(pvt->parent->parent->conn, UNISTIM_TONE_RING); pvt->ringing = 1; break; } } return -1; case AST_CONTROL_BUSY: if (ast->_state != AST_STATE_UP) { SendTone(pvt->parent->parent->conn, UNISTIM_TONE_DIAL); pvt->alreadygone = 1; ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV); break; } return -1; case AST_CONTROL_CONGESTION: if (ast->_state != AST_STATE_UP) { SendTone(pvt->parent->parent->conn, UNISTIM_TONE_RING); pvt->alreadygone = 1; ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV); break; } return -1; case AST_CONTROL_PROGRESS: if ((ast->_state != AST_STATE_UP) && !pvt->progress && !pvt->outgoing) { // transmit_callstate(s, l->instance, SKINNY_PROGRESS, sub->callid); pvt->progress = 1; break; } return -1; case -1: SendTone(pvt->parent->parent->conn, UNISTIM_TONE_SILENCE); break; case AST_CONTROL_PROCEEDING: break; default: ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); return -1; } return 0; } static int unistim_hangup(struct ast_channel *ast) { int i; struct unistim_pvt *pvt = ast->pvt->pvt; SendNoRing(pvt->parent->parent->conn); SendDisableLoudSpeaker(pvt->parent->parent->conn); SendEndCall(pvt->parent->parent->conn); SendStopTimer(pvt->parent->parent->conn); for (i=0;i<=5;i++) { if (!strcasecmp(pvt->parent->name, pvt->parent->parent->conn->device->key_num[i])) SendIconUpdate(pvt->parent->parent->conn, i, FAV_ICON_NONE); } SendText(TEXT_LINE0, TEXT_NORMAL, pvt->parent->parent->conn, ""); SendText(TEXT_LINE1, TEXT_NORMAL, pvt->parent->parent->conn, ""); SendText(TEXT_LINE2, TEXT_NORMAL, pvt->parent->parent->conn, ""); ast_mutex_lock(&pvt->lock); pvt->owner = NULL; ast->pvt->pvt = NULL; pvt->alreadygone = 0; pvt->outgoing = 0; if (pvt->rtp) { ast_rtp_destroy(pvt->rtp); pvt->rtp = NULL; } ast_mutex_unlock(&pvt->lock); return 0; } static int unistim_answer(struct ast_channel *ast) { int res = 0; struct unistim_pvt *pvt = ast->pvt->pvt; struct unistim_line *l = pvt->parent; if (!pvt->rtp) { start_rtp(pvt); } ast_log(LOG_NOTICE,"-----------------------------------------------------\n"); ast_verbose("unistim_answer(%s) on %s@%s-%d\n", ast->name, l->name, l->parent->name, pvt->callid); if (ast->_state != AST_STATE_UP) { ast_setstate(ast, AST_STATE_UP); } //ast_bridged_channel(pvt->owner); return res; } static int unistim_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs) { return 0; } static struct ast_rtp *unistim_get_rtp_peer(struct ast_channel *chan) { struct unistim_pvt *p; struct ast_rtp *rtp = NULL; p = chan->pvt->pvt; if (p) { ast_mutex_lock(&p->lock); rtp = p->rtp; ast_mutex_unlock(&p->lock); } return rtp; } static int unistim_call(struct ast_channel *ast, char *dest, int timeout) { int res = 0; int tone = 0; int i; struct unistim_line *l; struct unistim_pvt *pvt; pvt = ast->pvt->pvt; l = pvt->parent; // if (!l->parent->registered) { // ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest); // return -1; // } if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name); return -1; } ast_log(LOG_NOTICE,"------------------>>>>>>>>>>>> unistim_call(%s) - dest: %s - l->name: %s\n", ast->name, dest, l->name); switch (l->hookstate) { case UNISTIM_OFFHOOK: tone = UNISTIM_CALLWAITTONE; break; case UNISTIM_ONHOOK: tone = UNISTIM_ALERT; break; default: ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate); break; } SendRing(pvt->parent->parent->conn, ast->cid); for (i=0;i<=5;i++) { if (!strcasecmp(l->name, pvt->parent->parent->conn->device->key_num[i])) SendIconUpdate(pvt->parent->parent->conn, i, FAV_ICON_HANGUP_BLACK); } ast_setstate(ast, AST_STATE_RINGING); ast_queue_control(ast, AST_CONTROL_RINGING); pvt->outgoing = 1; return res; } static struct ast_channel *unistim_new(struct unistim_pvt *pvt, int state) { struct ast_channel *tmp; struct unistim_line *l = pvt->parent; int fmt; l = pvt->parent; tmp = ast_channel_alloc(1); if (tmp) { // ast_mutex_lock(&pvt->lock); // tmp->nativeformats = ast_codec_choose(&pvt->prefs, l->capability, 1); // tmp->nativeformats = ast_codec_choose(&pvt->prefs, capability, 1); // if (!tmp->nativeformats) // tmp->nativeformats = ast_codec_choose(&pvt->prefs, capability, 1); // ast_mutex_unlock(&pvt->lock); fmt = AST_FORMAT_ULAW; tmp->nativeformats = 4; // fmt = ast_best_codec(tmp->nativeformats); snprintf(tmp->name, sizeof(tmp->name), "UNISTIM/%s@%s-%d", l->name, l->parent->name, pvt->callid); if (pvt->rtp) tmp->fds[0] = ast_rtp_fd(pvt->rtp); // tmp->writeformat = AST_FORMAT_ULAW; // tmp->pvt->rawwriteformat = AST_FORMAT_ULAW; // tmp->readformat = AST_FORMAT_ULAW; // tmp->nativeformats = ast_codec_choose(&pvt->prefs, AST_FORMAT_ULAW | AST_FORMAT_ALAW, 1); // ast_parse_allow_disallow(&pvt->prefs, &pvt->capability, "ulaw", 1); // fmt = AST_FORMAT_ULAW; tmp->type = type; ast_setstate(tmp, state); if (state == AST_STATE_RING) tmp->rings = 1; tmp->writeformat = fmt; tmp->pvt->rawwriteformat = fmt; tmp->readformat = fmt; tmp->pvt->rawreadformat = fmt; tmp->pvt->pvt = pvt; tmp->pvt->call = unistim_call; tmp->pvt->hangup = unistim_hangup; tmp->pvt->answer = unistim_answer; tmp->pvt->read = unistim_read; tmp->pvt->write = unistim_write; tmp->pvt->indicate = unistim_indicate; // tmp->pvt->fixup = unistim_fixup; // tmp->pvt->send_digit = unistim_senddigit; // tmp->pvt->bridge = ast_rtp_bridge; if (!ast_strlen_zero(l->language)) strncpy(tmp->language, l->language, sizeof(tmp->language)-1); if (!ast_strlen_zero(l->accountcode)) strncpy(tmp->accountcode, l->accountcode, sizeof(tmp->accountcode)-1); if (l->amaflags) tmp->amaflags = l->amaflags; pvt->owner = tmp; strncpy(tmp->context, l->context, sizeof(tmp->context)-1); strncpy(tmp->call_forward, l->call_forward, sizeof(tmp->call_forward)-1); strncpy(tmp->exten,l->exten, sizeof(tmp->exten)-1); if (!ast_strlen_zero(l->cid_num)) { tmp->cid.cid_num = strdup(l->cid_num); } if (!ast_strlen_zero(l->cid_name)) { tmp->cid.cid_name = strdup(l->cid_name); } tmp->priority = 1; if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); ast_hangup(tmp); tmp = NULL; } } } else { ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); } return tmp; } static struct ast_channel *unistim_request(const char *type, int format, void *data, int *cause) { int oldformat; struct unistim_pvt *pvt; struct ast_channel *tmpc = NULL; char tmp[256]; char *dest = data; oldformat = format; format &= capability; if (!format) { ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format); return NULL; } strncpy(tmp, dest, sizeof(tmp) - 1); if (ast_strlen_zero(tmp)) { ast_log(LOG_NOTICE, "UNISTIM channels require a device\n"); return NULL; } pvt = find_pvt_by_name(tmp); if (!pvt) { ast_log(LOG_NOTICE, "No available lines on: %s\n", dest); return NULL; } tmpc = unistim_new(pvt->owner ? pvt->next : pvt, AST_STATE_DOWN); if (!tmpc) { ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp); } restart_monitor(); /* and finish */ return tmpc; } void loadkey(struct unistim_device *device, char *value, int key) { char line[32]; char *div; strncpy(line, value, sizeof(line) - 1); div = strchr(line, ':'); if (!div) { ast_log(LOG_NOTICE, "Key '%s' has no : !\n", value); return; } *div = '\0'; div++; strncpy(device->key_func[key], line, strlen(line)); strncpy(device->key_num[key], div, strlen(div)); ast_log(LOG_NOTICE, "Func: %s - Num: %s\n", device->key_func[key], device->key_num[key]); } static int unistim_show_lines(int fd, int argc, char *argv[]) { struct unistim_line *l; int haslines = 0; char iabuf[INET_ADDRSTRLEN]; if (argc != 3) return RESULT_SHOWUSAGE; ASTOBJ_CONTAINER_TRAVERSE(&devicel, 1, do { ASTOBJ_RDLOCK(iterator); ast_cli(fd, "-> Device '%s' at %s \n", iterator->name, ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr)); l = iterator->lines; while (l) { ast_cli(fd, " -> Line '%s' in '%s' with cfw to '%s' is %s\n", l->name, l->context, l->call_forward, l->pvt->owner ? "active" : "idle"); haslines = 1; l = l->next; } if (!haslines) { ast_cli(fd, " << No Lines Defined >> \n"); } ASTOBJ_UNLOCK(iterator); } while(0) ); return RESULT_SUCCESS; } static char show_lines_usage[] = "Usage: unistim show lines\n" " Lists all lines known to the unistim subsystem.\n"; static struct ast_cli_entry cli_show_lines = { { "unistim", "show", "lines", NULL }, unistim_show_lines, "Show defined unistim lines per device", show_lines_usage }; //-------------------------------------------------------------------------------------------------------------------------------- static struct unistim_device *build_device(const char *name, struct ast_variable *v) { struct unistim_device *device; struct unistim_line *l; struct unistim_pvt *pvt; int i; struct ast_ha *oldha = NULL; ast_log(LOG_NOTICE,"Added user name \"%s\"\n", name); device = (struct unistim_device *) malloc(sizeof(struct unistim_device)); if (device) { memset(device, 0, sizeof(struct unistim_device)); ASTOBJ_INIT(device); strncpy(device->name, name, sizeof(device->name)-1); oldha = device->ha; device->ha = NULL; strncpy(device->context, default_context, sizeof(device->context)-1); strncpy(device->language, default_language, sizeof(device->language)-1); strncpy(device->musicclass, global_musicclass, sizeof(device->musicclass)-1); while(v) { if (!strcasecmp(v->name, "context")) { strncpy(device->context, v->value, sizeof(device->context) - 1); } else if (!strcasecmp(v->name, "callerid")) { ast_callerid_split(v->value, device->cid_name, sizeof(device->cid_name), device->cid_num, sizeof(device->cid_num)); } else if (!strcasecmp(v->name, "language")) { strncpy(device->language, v->value, sizeof(device->language)-1); } else if (!strcasecmp(v->name, "mailbox")) { strncpy(mailbox, v->value, sizeof(mailbox)-1); } else if (!strcasecmp(v->name, "label")) { strncpy(linelabel, v->value, sizeof(linelabel)-1); } else if (!strcasecmp(v->name, "key0")) { loadkey(device, v->value, 0); } else if (!strcasecmp(v->name, "key1")) { loadkey(device, v->value, 1); } else if (!strcasecmp(v->name, "key2")) { loadkey(device, v->value, 2); } else if (!strcasecmp(v->name, "key3")) { loadkey(device, v->value, 3); } else if (!strcasecmp(v->name, "key4")) { loadkey(device, v->value, 4); } else if (!strcasecmp(v->name, "key5")) { loadkey(device, v->value, 5); } else if (!strcasecmp(v->name, "musiconhold")) { strncpy(device->musicclass, v->value, sizeof(device->musicclass)-1); } else if (!strcasecmp(v->name, "accountcode")) { strncpy(device->accountcode, v->value, sizeof(device->accountcode)-1); } else if (!strcasecmp(v->name, "allow")) { ast_parse_allow_disallow(&device->prefs, &device->capability, v->value, 1); } else if (!strcasecmp(v->name, "disallow")) { ast_parse_allow_disallow(&device->prefs, &device->capability, v->value, 0); } else if (!strcasecmp(v->name, "trunk") || !strcasecmp(v->name, "line")) { l = malloc(sizeof(struct unistim_line)); if (l) { memset(l, 0, sizeof(struct unistim_line)); strncpy(l->name, v->value, sizeof(l->name) - 1); strncpy(l->context, context, sizeof(l->context) - 1); strncpy(l->cid_num, cid_num, sizeof(l->cid_num) - 1); strncpy(l->cid_name, cid_name, sizeof(l->cid_name) - 1); strncpy(l->label, linelabel, sizeof(l->label) - 1); strncpy(l->language, language, sizeof(l->language) - 1); strncpy(l->musicclass, musicclass, sizeof(l->musicclass)-1); strncpy(l->mailbox, mailbox, sizeof(l->mailbox)-1); if (!ast_strlen_zero(mailbox)) { ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, device->name, l->name); } l->capability = capability; for (i = 0; i < MAX_SUBS; i++) { pvt = malloc(sizeof(struct unistim_pvt)); if (pvt) { ast_verbose(VERBOSE_PREFIX_3 "Allocating Skinny subchannel '%d' on %s@%s\n", i, l->name, device->name); memset(pvt, 0, sizeof(struct unistim_pvt)); pvt->parent = l; //arent = l; pvt->callid = callnums; callnums++; pvt->nat = nat; pvt->next = l->pvt; l->pvt = pvt; } else { ast_log(LOG_WARNING, "Out of memory allocating subchannel"); return NULL; } } l->parent = device; l->next = device->lines; device->lines = l; } } v = v->next; } ast_free_ha(oldha); return device; } return NULL; } void SendPing(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending ping\n"); memcpy(buffsend+SIZE_HEADER, PacketSendPing, sizeof(PacketSendPing)); SendClient(SIZE_HEADER + sizeof(PacketSendPing), buffsend, conn); SendMWI(conn); } static int conn_poke_device(void *data) { struct unistim_conn *conn = data; SendPing(conn); // sip_poke_peer(peer); conn->poke = -1; return 0; } void SendRawClient(int size, char *data, struct sockaddr_in *addr_from) { ast_log(LOG_NOTICE,"Sent RAW packet to client \n"); if(sendto(unistimsock, data, size, 0, (struct sockaddr *)addr_from, sizeof(*addr_from)) == -1) ast_log(LOG_NOTICE, "Error sending datas\n"); } static struct unistim_conn *build_conn(struct sockaddr_in *sin) { struct unistim_conn *conn; int tmp; conn = (struct unistim_conn *) malloc(sizeof(struct unistim_conn)); if (conn) { memset(conn, 0, sizeof(struct unistim_conn)); memcpy(&conn->addr, sin, sizeof(conn->addr)); conn->seq_phone = (short)0x0000; conn->seq_server = (short)0x0000; conn->last_seq_ack = (short)0x000; conn->last_buf_available = 0; conn->nb_retransmit = 0; conn->state = STATE_INIT; conn->receiver_state = STATE_HANGUP; // conn->tick_next_ping = GetTickCount() + PING_TIMER; conn->device = NULL; conn->poke = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, conn_poke_device, conn); for(tmp = 0; tmp < MAX_BUF_NUMBER ; tmp++) { conn->wsabufsend[tmp].buf = conn->buf[tmp]; } ASTOBJ_INIT(conn); } return conn; } void SendRetransmit(struct unistim_conn *conn) { int i; if(++conn->nb_retransmit >= NB_MAX_RETRANSMIT) { ast_log(LOG_NOTICE, "Too many retransmit - freeing client"); //CloseClient(pte); return; } //conn->timeout = GetTickCount() + RETRANSMIT_TIMER; for (i = conn->last_buf_available - (conn->seq_server - conn->last_seq_ack) ; i < conn->last_buf_available ; i++) { ast_log(LOG_NOTICE,"Retransmit slot #%d\n", i); SendRawClient(conn->wsabufsend[i].len, conn->wsabufsend[i].buf, &conn->addr); } return; } void SendClient(int size, char *data, struct unistim_conn *conn) { int buf_pos = conn->last_buf_available; unsigned short *sdata = (unsigned short*)data; sdata[1] = htons(++(conn->seq_server)); conn->wsabufsend[buf_pos].len = size; memcpy(conn->wsabufsend[buf_pos].buf, data, size); conn->wsaoverlap[buf_pos].hEvent = 0; if(sendto(unistimsock, conn->wsabufsend[buf_pos].buf, conn->wsabufsend[buf_pos].len, 0, (struct sockaddr *) &conn->addr, sizeof(struct sockaddr_in)) == -1) ast_log(LOG_NOTICE, "Error sending datas\n"); conn->last_buf_available++; } // inverse : TEXT_INVERSE : yes, TEXT_NORMAL : no void SendFavorite(unsigned char pos, unsigned char status, struct unistim_conn *conn, char *text) { int i; ast_log(LOG_NOTICE, "Sending Favorite pos %d with status 0x%.2x\n", pos, status); memcpy(buffsend+SIZE_HEADER, PacketSendFavorite, sizeof(PacketSendFavorite)); buffsend[10] = pos; buffsend[24] = pos; buffsend[25] = status; i = strlen(text); if(i > FAV_MAX_LENGTH) i = FAV_MAX_LENGTH; memcpy(buffsend+FAV_MAX_LENGTH+1, text, i); SendClient(SIZE_HEADER + sizeof(PacketSendFavorite), buffsend, conn); } static void SendKeyLabel(struct unistim_conn *conn, unsigned char pos, char *text) { int i; char tmp[FAV_MAX_LENGTH] = "\0"; memcpy(buffsend+SIZE_HEADER, PacketSendKeyLabel, sizeof(PacketSendKeyLabel)); buffsend[10] = pos; if (pos <= 2) { strncpy(tmp, " ", 10-strlen(text)); strncat(tmp, text, sizeof(tmp)); i = strlen(tmp); if(i > FAV_MAX_LENGTH) i = FAV_MAX_LENGTH; memcpy(buffsend+FAV_MAX_LENGTH+1, tmp, i); ast_log(LOG_NOTICE, "Sending KeyLabel pos %d with text [%s]\n", pos, tmp); } else { i = strlen(text); if(i > FAV_MAX_LENGTH) i = FAV_MAX_LENGTH; memcpy(buffsend+FAV_MAX_LENGTH+1, text, i); ast_log(LOG_NOTICE, "Sending KeyLabel pos %d with text [%s]\n", pos, text); } SendClient(SIZE_HEADER + sizeof(PacketSendKeyLabel), buffsend, conn); } static void SendIcon(struct unistim_conn *conn, unsigned char pos, unsigned char status) { ast_log(LOG_NOTICE, "Icon pos %d with status 0x%.2x\n", pos, status); memcpy(buffsend+SIZE_HEADER, PacketSendIcon, sizeof(PacketSendIcon)); buffsend[9] = pos; buffsend[10] = status; SendClient(SIZE_HEADER + sizeof(PacketSendIcon), buffsend, conn); } static void SendIconUpdate(struct unistim_conn *conn, unsigned char pos, unsigned char status) { ast_log(LOG_NOTICE, "Icon Update pos %d with status 0x%.2x\n", pos, status); memcpy(buffsend+SIZE_HEADER, PacketSendIconUpdate, sizeof(PacketSendIconUpdate)); buffsend[9] = pos; buffsend[10] = status; SendClient(SIZE_HEADER + sizeof(PacketSendIconUpdate), buffsend, conn); } static void SendLEDUpdate(struct unistim_conn *conn, unsigned char pos) { ast_log(LOG_NOTICE, "LED Update pos %d\n", pos); memcpy(buffsend+SIZE_HEADER, PacketSendLEDUpdate, sizeof(PacketSendLEDUpdate)); buffsend[9] = pos; SendClient(SIZE_HEADER + sizeof(PacketSendLEDUpdate), buffsend, conn); } static void SendTextTitle( struct unistim_conn *conn, char *text) { int i; ast_log(LOG_NOTICE,"Sending title text\n"); memcpy(buffsend+SIZE_HEADER, PacketSendTitle, sizeof(PacketSendTitle)); i = strlen(text); if(i > 12) i = 12; memcpy(buffsend+10, text, i); SendClient(SIZE_HEADER + sizeof(PacketSendTitle), buffsend, conn); } static void SendStartTimer(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending start timer\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStartTimer, sizeof(PacketSendStartTimer)); SendClient(SIZE_HEADER + sizeof(PacketSendStartTimer), buffsend, conn); } static void SendStopTimer(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending stop timer\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStopTimer, sizeof(PacketSendStopTimer)); SendClient(SIZE_HEADER + sizeof(PacketSendStopTimer), buffsend, conn); } static void SendText(unsigned char pos, unsigned char inverse, struct unistim_conn *conn, char *text) { int i; ast_log(LOG_NOTICE, "Sending text at pos %d, inverse flag %d\n", pos, inverse); memcpy(buffsend+SIZE_HEADER, PacketSendText, sizeof(PacketSendText)); buffsend[10] = pos; buffsend[11] = inverse; i = strlen(text); if(i > TEXT_LENGTH_MAX) i = TEXT_LENGTH_MAX; memcpy(buffsend+12, text, i); SendClient(SIZE_HEADER + sizeof(PacketSendText), buffsend, conn); } static void SendTextStatus(struct unistim_conn *conn, char *text) { int i; ast_log(LOG_NOTICE, "Sending status text\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStatus, sizeof(PacketSendStatus)); i = strlen(text); if(i > 28) i = 28; memcpy(buffsend+10, text, i); SendClient(SIZE_HEADER + sizeof(PacketSendStatus), buffsend, conn); } static void SendMWI(struct unistim_conn *conn) { char text[12]; int newmsgs, oldmsgs; ast_app_messagecount(conn->device->lines->mailbox, &newmsgs, &oldmsgs); if (newmsgs || oldmsgs) { sprintf(text, "%d/%d New/Old", newmsgs, oldmsgs); SendLEDUpdate(conn, LED_TOP_FLASH); } else { sprintf(text, "No Messages"); SendLEDUpdate(conn, LED_TOP_OFF); } SendTextTitle(conn, text); } static void SendTone(struct unistim_conn *conn, int tone) { if (tone == UNISTIM_TONE_SILENCE) { /* None */ ast_log(LOG_NOTICE, "Sending Stream Based Tone Off\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneOff, sizeof(PacketSendStreamBasedToneOff)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneOff), buffsend, conn); } else if (tone == UNISTIM_TONE_DIAL) { /* Dial */ ast_log(LOG_NOTICE, "Sending Connect Transducer\n"); memcpy(buffsend+SIZE_HEADER, PacketSendConnectTransducer, sizeof(PacketSendConnectTransducer)); SendClient(SIZE_HEADER + sizeof(PacketSendConnectTransducer), buffsend, conn); ast_log(LOG_NOTICE, "Sending Stream Based Tone Cadence Download\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneDialCad, sizeof(PacketSendStreamBasedToneDialCad)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneDialCad), buffsend, conn); ast_log(LOG_NOTICE, "Sending Stream Based Tone Frequency Component List Download\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneDialFreq, sizeof(PacketSendStreamBasedToneDialFreq)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneDialFreq), buffsend, conn); ast_log(LOG_NOTICE, "Sending Stream Based Tone On\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneOn, sizeof(PacketSendStreamBasedToneOn)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneOn), buffsend, conn); } else if (tone == UNISTIM_TONE_RING) { /* Ring */ // ast_log(LOG_NOTICE, "Sending Connect Transducer\n"); // memcpy(buffsend+SIZE_HEADER, PacketSendConnectTransducer, sizeof(PacketSendConnectTransducer)); // SendClient(SIZE_HEADER + sizeof(PacketSendConnectTransducer), buffsend, conn); ast_log(LOG_NOTICE, "Sending Stream Based Tone Cadence Download\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneRingCad, sizeof(PacketSendStreamBasedToneRingCad)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneRingCad), buffsend, conn); ast_log(LOG_NOTICE, "Sending Stream Based Tone Frequency Component List Download\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneRingFreq, sizeof(PacketSendStreamBasedToneRingFreq)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneRingFreq), buffsend, conn); ast_log(LOG_NOTICE, "Sending Stream Based Tone On\n"); memcpy(buffsend+SIZE_HEADER, PacketSendStreamBasedToneOn, sizeof(PacketSendStreamBasedToneOn)); SendClient(SIZE_HEADER + sizeof(PacketSendStreamBasedToneOn), buffsend, conn); } } static void SendRing(struct unistim_conn *conn, struct ast_callerid cid) { ast_log(LOG_NOTICE, "Sending ring packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendRing, sizeof(PacketSendRing)); SendClient(SIZE_HEADER + sizeof(PacketSendRing), buffsend, conn); ast_log(LOG_NOTICE, "Sending ring packet done\n"); if (cid.cid_name) SendText(TEXT_LINE0, TEXT_NORMAL, conn, cid.cid_name); if (cid.cid_num) SendText(TEXT_LINE1, TEXT_NORMAL, conn, cid.cid_num); } void GetLocalTime(SYSTEMTIME *systime) { struct tm *stm; time_t cur_time = time(0); if((stm = localtime(&cur_time)) == 0) { ast_log(LOG_NOTICE, "Error in localtime()\n"); return; } systime->wYear = stm->tm_year; systime->wMonth = stm->tm_mon + 1; systime->wDayOfWeek = stm->tm_wday; systime->wDay = stm->tm_mday; systime->wHour = stm->tm_hour; systime->wMinute = stm->tm_min; systime->wSecond = stm->tm_sec; systime->wMilliseconds = 0; return; } static void SendEnableLoudSpeaker(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending enable loud speaker packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendEnableSpker, sizeof(PacketSendEnableSpker)); SendClient(SIZE_HEADER + sizeof(PacketSendEnableSpker), buffsend, conn); SendLEDUpdate(conn, LED_SPEAKER_ON); } static void SendDisableLoudSpeaker(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending enable loud speaker packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendDisableSpker, sizeof(PacketSendDisableSpker)); SendClient(SIZE_HEADER + sizeof(PacketSendDisableSpker), buffsend, conn); SendLEDUpdate(conn, LED_SPEAKER_OFF); } static void SendActiveLoudSpeaker(struct unistim_conn *conn) { if (conn->receiver_state == STATE_HANGUP || conn->receiver_state == STATE_PICKUP_NOSPEAKER) { ast_log(LOG_NOTICE, "Sending active loud speaker packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendEnableSpker, sizeof(PacketSendEnableSpker)); SendClient(SIZE_HEADER + sizeof(PacketSendEnableSpker), buffsend, conn); SendLEDUpdate(conn, LED_SPEAKER_ON); if(conn->receiver_state == STATE_HANGUP) { conn->receiver_state = STATE_NOPICKUP_SPEAKER; SendIconUpdate(conn, 0, FAV_ICON_SPEAKER_HANGUP_BLACK); } else if (conn->receiver_state == STATE_PICKUP_NOSPEAKER) { conn->receiver_state = STATE_PICKUP_SPEAKER; SendIconUpdate(conn, 0, FAV_ICON_SPEAKER_PICKUP_BLACK); } } else { ast_log(LOG_NOTICE, "Sending deactive loud speaker packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendDisableSpker, sizeof(PacketSendDisableSpker)); SendClient(SIZE_HEADER + sizeof(PacketSendDisableSpker), buffsend, conn); SendLEDUpdate(conn, LED_SPEAKER_OFF); if (conn->receiver_state == STATE_NOPICKUP_SPEAKER) { conn->receiver_state = STATE_HANGUP; SendIconUpdate(conn, 0, FAV_ICON_NONE); } else if (conn->receiver_state == STATE_PICKUP_SPEAKER) { conn->receiver_state = STATE_PICKUP_NOSPEAKER; SendIconUpdate(conn, 0, FAV_ICON_PICKUP_BLACK); } } } static void SendEndCall(struct unistim_conn *conn) { ast_log(LOG_NOTICE,"Sending end call\n"); memcpy(buffsend+SIZE_HEADER, PacketSendEndCall, sizeof(PacketSendEndCall)); SendClient(SIZE_HEADER + sizeof(PacketSendEndCall), buffsend, conn); } static void SendCallRequest(struct unistim_conn *conn) { struct sockaddr_in sin; sin.sin_family = AF_INET; struct sockaddr_in rsin; rsin.sin_family = AF_INET; memcpy(&sin.sin_addr, &conn->pvt->parent->parent->addr.sin_addr, sizeof(sin)); sin.sin_port = htons(5200); ast_rtp_get_us(conn->pvt->rtp, &rsin); u_long *lbuf = (u_long*)((char*)buffsend); // ast_log(LOG_NOTICE, "Sending call request\n"); // memcpy(buffsend+SIZE_HEADER, PacketSendCall, sizeof(PacketSendCall)); struct in_addr addr; memcpy(&addr, &__ourip, sizeof(addr)); // memcpy(&addr, &conn->pvt->parent->parent->addr.sin_addr, sizeof(addr)); // lbuf[13] = addr.s_addr; // port 0x0f, 0xa0, 0x9c, 0x41, |||port 0x0f, 0xa0, 0x9c, 0x41, // Codec // buffsend[40] = 0; // buffsend[41] = 0; // port PHONE // FROM PHONE = SOURCE // buffsend[45] = 0x9c; // buffsend[46] = 0x41; // FROM PHONE = DESTINATION // buffsend[50] = (htons(addr_astrtp->sin_port) & 0x00ff); // buffsend[49] = (htons(addr_astrtp->sin_port) & 0xff00) >> 8; // ast_log(LOG_NOTICE, "PACKETS #0x%.2x #0x%.2x\n",buffsend[49],buffsend[50]); // TO PHONE = ??? // buffsend[47] = (htons(addr_astrtp->sin_port) & 0xff00) >> 8; // buffsend[48] = (htons(addr_astrtp->sin_port) & 0x00ff); // TO PHONE = ??? // buffsend[51] = 0x9c; // buffsend[52] = 0x41; // // SendClient(SIZE_HEADER + sizeof(PacketSendCall), buffsend, conn); ast_log(LOG_NOTICE, "------------------SEND Mute Unmute\n"); memcpy(buffsend+SIZE_HEADER, PacketSendMute, sizeof(PacketSendMute)); SendClient(SIZE_HEADER + sizeof(PacketSendMute), buffsend, conn); ast_log(LOG_NOTICE, "------------------SEND VocoderParm\n"); memcpy(buffsend+SIZE_HEADER, PacketSendVocoderParm, sizeof(PacketSendVocoderParm)); SendClient(SIZE_HEADER + sizeof(PacketSendVocoderParm), buffsend, conn); ast_log(LOG_NOTICE, "------------------SEND VocoderParm2\n"); memcpy(buffsend+SIZE_HEADER, PacketSendVocoderParm2, sizeof(PacketSendVocoderParm2)); SendClient(SIZE_HEADER + sizeof(PacketSendVocoderParm2), buffsend, conn); ast_log(LOG_NOTICE, "------------------SEND TX\n"); memcpy(buffsend+SIZE_HEADER, PacketSendOpenAudioStreamTX, sizeof(PacketSendOpenAudioStreamTX)); buffsend[24] = (htons(rsin.sin_port) & 0xff00) >> 8; buffsend[25] = (htons(rsin.sin_port) & 0x00ff); ast_log(LOG_NOTICE, "--lbuf 0-> 0x%08x 1-> 0x%08x 2-> 0x%08x 3-> 0x%08x\n", (u_int)lbuf[0], (u_int)lbuf[1], (u_int)lbuf[2], (u_int)lbuf[3]); ast_log(LOG_NOTICE, "--lbuf 4-> 0x%08x 5-> 0x%08x 6-> 0x%08x 7-> 0x%08x\n", (u_int)lbuf[4], (u_int)lbuf[5], (u_int)lbuf[6], (u_int)lbuf[7]); ast_log(LOG_NOTICE, "--addr 0x%08x\n", (u_int)addr.s_addr); lbuf[7] = addr.s_addr; ast_log(LOG_NOTICE, "PACKETS #0x%.2x #0x%.2x - %d %d %d %d\n",buffsend[24],buffsend[25], buffsend[28], buffsend[29], buffsend[30], buffsend[31]); SendClient(SIZE_HEADER + sizeof(PacketSendOpenAudioStreamTX), buffsend, conn); ast_log(LOG_NOTICE, "------------------SEND RX\n"); memcpy(buffsend+SIZE_HEADER, PacketSendOpenAudioStreamRX, sizeof(PacketSendOpenAudioStreamRX)); buffsend[24] = (htons(rsin.sin_port) & 0xff00) >> 8; buffsend[25] = (htons(rsin.sin_port) & 0x00ff); lbuf[7] = addr.s_addr; ast_log(LOG_NOTICE, "PACKETS #0x%.2x #0x%.2x\n",buffsend[24],buffsend[25]); SendClient(SIZE_HEADER + sizeof(PacketSendOpenAudioStreamRX), buffsend, conn); } static void SendNoRing(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending no ring packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendNoRing, sizeof(PacketSendNoRing)); SendClient(SIZE_HEADER + sizeof(PacketSendNoRing), buffsend, conn); } static void SendDateTime(struct unistim_conn *conn) { SYSTEMTIME systime; ast_log(LOG_NOTICE, "Sending Time & Date\n"); memcpy(buffsend+SIZE_HEADER, PacketSendDateTime, sizeof(PacketSendDateTime)); GetLocalTime(&systime); buffsend[10] = (unsigned char)systime.wMonth; buffsend[11] = (unsigned char)systime.wDay; buffsend[12] = (unsigned char)systime.wHour; buffsend[13] = (unsigned char)systime.wMinute; SendClient(SIZE_HEADER + sizeof(PacketSendDateTime), buffsend, conn); } static void SendDateTime2(struct unistim_conn *conn) { SYSTEMTIME systime; ast_log(LOG_NOTICE, "Sending Time & Date #2\n"); memcpy(buffsend+SIZE_HEADER, PacketSendDateTime2, sizeof(PacketSendDateTime2)); GetLocalTime(&systime); buffsend[14] = (unsigned char)systime.wMonth; buffsend[15] = (unsigned char)systime.wDay; buffsend[16] = (unsigned char)systime.wHour; buffsend[17] = (unsigned char)systime.wMinute; SendClient(SIZE_HEADER + sizeof(PacketSendDateTime2), buffsend, conn); } static void SendDateTime3(struct unistim_conn *conn) { SYSTEMTIME systime; ast_log(LOG_NOTICE, "Sending Time & Date #3\n"); memcpy(buffsend+SIZE_HEADER, PacketSendDateTime3, sizeof(PacketSendDateTime3)); GetLocalTime(&systime); buffsend[10] = (unsigned char)systime.wMonth; buffsend[11] = (unsigned char)systime.wDay; buffsend[12] = (unsigned char)systime.wHour; buffsend[13] = (unsigned char)systime.wMinute; SendClient(SIZE_HEADER + sizeof(PacketSendDateTime3), buffsend, conn); } static void RcvR0(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "R0 received\n"); ast_log(LOG_NOTICE, "Sending S0\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS0, sizeof(PacketSendS0)); SendClient(SIZE_HEADER + sizeof(PacketSendS0), buffsend, conn); return; } static void RcvR2(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "R2 received\n"); ast_log(LOG_NOTICE, "Sending S4\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS4, sizeof(PacketSendS4)); SendClient(SIZE_HEADER + sizeof(PacketSendS4), buffsend, conn); SendDateTime2(conn); SendDateTime3(conn); ast_log(LOG_NOTICE, "Sending S7\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS7, sizeof(PacketSendS7)); SendClient(SIZE_HEADER + sizeof(PacketSendS7), buffsend, conn); ast_log(LOG_NOTICE, "Sending S8\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS8, sizeof(PacketSendS8)); SendClient(SIZE_HEADER + sizeof(PacketSendS8), buffsend, conn); ast_log(LOG_NOTICE, "Sending S9\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS9, sizeof(PacketSendS9)); SendClient(SIZE_HEADER + sizeof(PacketSendS9), buffsend, conn); SendNoRing(conn); ast_log(LOG_NOTICE, "Sending S8\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS8, sizeof(PacketSendS8)); SendClient(SIZE_HEADER + sizeof(PacketSendS8), buffsend, conn); ast_log(LOG_NOTICE, "Sending S7\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS7, sizeof(PacketSendS7)); SendClient(SIZE_HEADER + sizeof(PacketSendS7), buffsend, conn); ast_log(LOG_NOTICE, "Sending LED Update\n"); memcpy(buffsend+SIZE_HEADER, PacketSendLEDUpdate, sizeof(PacketSendLEDUpdate)); SendClient(SIZE_HEADER + sizeof(PacketSendLEDUpdate), buffsend, conn); ast_log(LOG_NOTICE, "Sending S8\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS8, sizeof(PacketSendS8)); SendClient(SIZE_HEADER + sizeof(PacketSendS8), buffsend, conn); ast_log(LOG_NOTICE,"TEST: %s\n", conn->device->name); if (conn->device) { SendText(TEXT_LINE0, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE1, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE2, TEXT_NORMAL, conn, ""); SendTextStatus(conn, ""); SendTextTitle(conn, "Open i2004"); int key; for (key=0;key<=5;key++) { SendKeyLabel(conn, key, conn->device->key_num[key]); // SendFavorite(key, 0, conn, conn->device->key_num[key]); } } else { SendText(TEXT_LINE0, TEXT_NORMAL, conn, "Sorry but this phone is "); SendText(TEXT_LINE1, TEXT_NORMAL, conn, "not registred into the"); SendText(TEXT_LINE2, TEXT_NORMAL, conn, "database."); SendTextStatus(conn, ""); SendTextTitle(conn, "Open i2004"); } ast_log(LOG_NOTICE, "Sending S12\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS12, sizeof(PacketSendS12)); SendClient(SIZE_HEADER + sizeof(PacketSendS12), buffsend, conn); return; } static void RcvMacAddr(struct unistim_conn *conn, char *buf) { char addrmac[19]; int tmp, i = 0; struct unistim_device *device; ast_log(LOG_NOTICE, "MAC ADDRESS RECEIVED\n"); for(tmp = 15 ; tmp < 15+SIZE_HEADER ; tmp++) { sprintf(&addrmac[i], "%.2x", (unsigned char)buf[tmp]); i+=2; } ast_log(LOG_NOTICE, "MAC ADDRESS RECEIVED = \"%s\"\n",addrmac); device = find_device(addrmac,NULL); if (device) { memcpy(&device->addr, &conn->addr, sizeof(device->addr)); conn->device = device; device->conn = conn; } ast_log(LOG_NOTICE, "Sending S1\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS1, sizeof(PacketSendS1)); SendClient(SIZE_HEADER + sizeof(PacketSendS1), buffsend, conn); ast_log(LOG_NOTICE, "Sending S2\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS2, sizeof(PacketSendS2)); SendClient(SIZE_HEADER + sizeof(PacketSendS2), buffsend, conn); ast_log(LOG_NOTICE, "Sending S3\n"); memcpy(buffsend+SIZE_HEADER, PacketSendS3, sizeof(PacketSendS3)); SendClient(SIZE_HEADER + sizeof(PacketSendS3), buffsend, conn); SendDateTime(conn); return; } static void SendEnableReceiver(struct unistim_conn *conn) { ast_log(LOG_NOTICE, "Sending enable receiver packet\n"); memcpy(buffsend+SIZE_HEADER, PacketSendEnableRecvr, sizeof(PacketSendEnableRecvr)); SendClient(SIZE_HEADER + sizeof(PacketSendEnableRecvr), buffsend, conn); } static void *unistim_ss(void *data) { struct ast_channel *chan = data; struct unistim_pvt *pvt = chan->pvt->pvt; struct unistim_line *l = pvt->parent; char exten[AST_MAX_EXTENSION] = ""; int len = 0; int timeout = firstdigittimeout; int res; while(len < AST_MAX_EXTENSION-1) { res = ast_waitfordigit(chan, timeout); timeout = 0; ast_log(LOG_NOTICE, "-------------------------------------------collect digit %d\n", res); if (res < 0) { ast_indicate(chan, -1); ast_hangup(chan); return NULL; } else if (res) { exten[len++] = res; exten[len] = '\0'; SendText(TEXT_LINE1, TEXT_NORMAL, l->parent->conn, exten); } if (!ast_ignore_pattern(chan->context, exten)) { // SendTone(l->parent->conn, UNISTIM_TONE_SILENCE); } if (ast_exists_extension(chan, chan->context, exten, 1, l->cid_num)) { if(!res || !ast_matchmore_extension(chan, chan->context, exten, 1, l->cid_num)) { SendTone(l->parent->conn, UNISTIM_TONE_RING); strncpy(chan->exten, exten, sizeof(chan->exten)-1); ast_setstate(chan, AST_STATE_RING); res = ast_pbx_run(chan); return NULL; } } //weiter if (!timeout) timeout = gendigittimeout; if (len && !ast_ignore_pattern(chan->context, exten)) ast_indicate(chan, -1); } ast_hangup(chan); return NULL; } static void handle_key(int key, struct unistim_conn *conn) { struct ast_frame f = { 0, }; struct unistim_pvt *pvt; struct unistim_line *l; ast_log(LOG_NOTICE, "Key with func: %s and num: %s pressed\n", conn->device->key_func[key], conn->device->key_num[key]); if (!strcasecmp(conn->device->key_func[key], "adl")) { char numb[24] = ""; int i; strncpy(numb, conn->device->key_num[key], strlen(conn->device->key_num[key])); ast_log(LOG_NOTICE, "-------------%s - %d \n", numb, strlen(numb)); for (i=0;i<=strlen(numb);i++) { f.frametype = AST_FRAME_DTMF; f.subclass = numb[i]; f.src = "unistim"; pvt = find_pvt_by_line(conn->device->lines); if (pvt->owner) { ast_queue_frame(pvt->owner, &f); if (pvt->next->owner) { ast_queue_frame(pvt->next->owner, &f); } } } } else if (!strcasecmp(conn->device->key_func[key], "line")) { l = find_line_by_name(conn, conn->device->key_num[key]); pvt = l->pvt; pvt->parent->hookstate = UNISTIM_OFFHOOK; // conn->receiver_state = STATE_PICKUP_NOSPEAKER; if (pvt->outgoing) { SendNoRing(conn); SendIconUpdate(conn, key, FAV_ICON_SPEAKER_HANGUP_BLACK); SendStartTimer(conn); SendEnableReceiver(conn); if (!pvt->rtp) { start_rtp(pvt); } else { /* do/should we need to anything if there already is an RTP allocated? */ } SendEnableLoudSpeaker(conn); ast_setstate(pvt->owner, AST_STATE_UP); ast_queue_control(pvt->owner, AST_STATE_UP); } } } static void process_request(int size, unsigned char *buf, struct unistim_conn *conn) { struct unistim_pvt *pvt; struct ast_frame f = { 0, }; struct ast_channel *c; pthread_t t; if(memcmp(buf + SIZE_HEADER, PacketRecvR0, sizeof(PacketRecvR0)) == 0) { RcvR0(conn); return; } if(memcmp(buf + SIZE_HEADER, PacketRecvR2, sizeof(PacketRecvR2)) == 0) { RcvR2(conn); return; } if(memcmp(buf + SIZE_HEADER, PacketRecvMacAddr, sizeof(PacketRecvMacAddr)) == 0) { RcvMacAddr(conn, buf); return; } if(memcmp(buf + SIZE_HEADER, PacketRecvFirmVersion, sizeof(PacketRecvFirmVersion)) == 0) { buf[size] = 0; ast_log(LOG_NOTICE, "Got the firmware version : '%s'\n", buf + 13); return; } if(memcmp(buf + SIZE_HEADER, PacketRecvPickUp, sizeof(PacketRecvPickUp)) == 0) { SendNoRing(conn); pvt = find_pvt_by_line(conn->device->lines); pvt->parent->hookstate = UNISTIM_OFFHOOK; conn->receiver_state = STATE_PICKUP_NOSPEAKER; if (pvt->outgoing) { SendStartTimer(conn); if (!pvt->rtp) { start_rtp(pvt); } else { /* do/should we need to anything if there already is an RTP allocated? */ } SendEnableReceiver(conn); ast_setstate(pvt->owner, AST_STATE_UP); ast_queue_control(pvt->owner, AST_STATE_UP); } else { SendText(TEXT_LINE0, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE1, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE2, TEXT_NORMAL, conn, ""); if (!pvt->owner) { // SendIconUpdate(conn, 0, FAV_ICON_PICKUP_BLACK); SendTone(conn, UNISTIM_TONE_DIAL); c = unistim_new(pvt, AST_STATE_DOWN); if (c) { /*start switch*/ if (ast_pthread_create(&t, NULL, unistim_ss, c)) { ast_log(LOG_WARNING, "Unable to create switch thread\n"); ast_hangup(c); } /*send conn->cdidgits*/ if (conn->cdigits) { int i; char numb[24]; sprintf(numb, "%s", conn->cdigits); strncpy(conn->cdigits, "" , sizeof(conn->cdigits)); for (i=0;i<=strlen(numb);i++) { f.frametype = AST_FRAME_DTMF; f.subclass = numb[i]; f.src = "unistim"; pvt = find_pvt_by_line(conn->device->lines); if (pvt->owner) { ast_queue_frame(pvt->owner, &f); if (pvt->next->owner) { ast_queue_frame(pvt->next->owner, &f); } } } } } } } return; } if(memcmp(buf + SIZE_HEADER, PacketRecvHangUp, sizeof(PacketRecvHangUp)) == 0) { conn->receiver_state = STATE_HANGUP; pvt = find_pvt_by_line(conn->device->lines); SendStopTimer(conn); SendEndCall(conn); SendIconUpdate(conn, 0, FAV_ICON_NONE); SendText(TEXT_LINE0, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE1, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE2, TEXT_NORMAL, conn, ""); SendTone(conn, UNISTIM_TONE_SILENCE); if (pvt->owner) { pvt->alreadygone = 1; ast_queue_hangup(pvt->owner); } else { } // ast_queue_control(conn->pvt->owner, AST_CONTROL_HANGUP); return; } if(memcmp(buf + SIZE_HEADER, PacketRecvPressedKey, sizeof(PacketRecvPressedKey)) == 0) { char keycode = buf[13]; ast_log(LOG_NOTICE, "Key pressed : keycode = 0x%.2x - current state : %d\n", keycode, 0); if(keycode >= 0x40 && keycode <= 0x4b) { int digit; char d; if (keycode == 0x4a) d = '*'; else if (keycode == 0x4b) d = '#'; else { digit = keycode - 0x40; d = '0' + digit; } f.frametype = AST_FRAME_DTMF; f.subclass = d; f.src = "unistim"; pvt = find_pvt_by_line(conn->device->lines); if (pvt->owner) { ast_queue_frame(pvt->owner, &f); if (pvt->next->owner) { ast_queue_frame(pvt->next->owner, &f); } } else { if (strlen(conn->cdigits) < 24) { ast_log(LOG_NOTICE, "Collect Digit %d\n", d); sprintf(conn->cdigits, "%s%c", conn->cdigits, d); SendText(TEXT_LINE1, TEXT_NORMAL, conn, conn->cdigits); } else { ast_log(LOG_NOTICE, "Collect Digit FULL\n"); } } return; } if(keycode == KEY_COMPUTR) { struct unistim_line *l; l = find_line_by_name(conn, "150"); l->cancallforward = ast_true("yes"); strncpy(l->call_forward, "8500", sizeof(l->call_forward) - 1); ast_log(LOG_NOTICE, "CFW %s to %s\n", l->name, l->call_forward); SendIconUpdate(conn, 0, FAV_ICON_FORWARD); } if (keycode == KEY_LOUDSPK) { SendNoRing(conn); pvt = find_pvt_by_line(conn->device->lines); pvt->parent->hookstate = UNISTIM_OFFHOOK; // conn->receiver_state = STATE_NOPICKUP_SPEAKER; if (pvt->outgoing) { SendStartTimer(conn); if (!pvt->rtp) { start_rtp(pvt); } else { /* do/should we need to anything if there already is an RTP allocated? */ } SendEnableReceiver(conn); ast_setstate(pvt->owner, AST_STATE_UP); ast_queue_control(pvt->owner, AST_STATE_UP); } else { SendText(TEXT_LINE0, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE1, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE2, TEXT_NORMAL, conn, ""); if (!pvt->owner) { SendIconUpdate(conn, 0, FAV_ICON_PICKUP_BLACK); SendTone(conn, UNISTIM_TONE_DIAL); c = unistim_new(pvt, AST_STATE_DOWN); if (c) { /*start switch*/ if (ast_pthread_create(&t, NULL, unistim_ss, c)) { ast_log(LOG_WARNING, "Unable to create switch thread\n"); ast_hangup(c); } /*send conn->cdidgits*/ if (conn->cdigits) { int i; char numb[24]; sprintf(numb, "%s", conn->cdigits); strncpy(conn->cdigits, "" , sizeof(conn->cdigits)); for (i=0;i<=strlen(numb);i++) { f.frametype = AST_FRAME_DTMF; f.subclass = numb[i]; f.src = "unistim"; pvt = find_pvt_by_line(conn->device->lines); if (pvt->owner) { ast_queue_frame(pvt->owner, &f); if (pvt->next->owner) { ast_queue_frame(pvt->next->owner, &f); } } } } } } } SendActiveLoudSpeaker(conn); } if (keycode == KEY_FUNC1) { } if (keycode == KEY_FUNC2) { } if (keycode == KEY_FUNC3) { } if (keycode == KEY_FUNC4) { ast_log(LOG_NOTICE, "Sending Month Labels Download\n"); memcpy(buffsend+SIZE_HEADER, PacketSendMonthLabelsDownload, sizeof(PacketSendMonthLabelsDownload)); SendClient(SIZE_HEADER + sizeof(PacketSendMonthLabelsDownload), buffsend, conn); ast_log(LOG_NOTICE, "Sending Format Date Time\n"); memcpy(buffsend+SIZE_HEADER, PacketSendDateTimeFormat, sizeof(PacketSendDateTimeFormat)); SendClient(SIZE_HEADER + sizeof(PacketSendDateTimeFormat), buffsend, conn); } if (keycode == KEY_FAV0) { handle_key(0, conn); } if (keycode == KEY_FAV1) { handle_key(1, conn); } if (keycode == KEY_FAV2) { handle_key(2, conn); } if (keycode == KEY_FAV3) { handle_key(3, conn); } if (keycode == KEY_FAV4) { handle_key(4, conn); } if (keycode == KEY_FAV5) { handle_key(5, conn); } if (keycode == KEY_HANGUP) { // ast_queue_control(conn->pvt->owner, AST_CONTROL_HANGUP); SendStopTimer(conn); SendEndCall(conn); SendIconUpdate(conn, 0, FAV_ICON_NONE); SendText(TEXT_LINE0, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE1, TEXT_NORMAL, conn, ""); SendText(TEXT_LINE2, TEXT_NORMAL, conn, ""); } if (keycode == KEY_WAIT) { pvt = find_pvt_by_line(conn->device->lines); if (pvt->owner && ast_bridged_channel(pvt->owner)) { ast_moh_start(ast_bridged_channel(pvt->owner), NULL); } } } } static void parse(struct unistim_request *req) { /* Divide fields by NULL's */ struct unistim_conn *conn; short seq; char *c; char iabuf[INET_ADDRSTRLEN]; // unsigned short seq; unsigned short *sbuf = (unsigned short*)req->data; c = req->data; char tmpbuf[255]; strcpy(tmpbuf, ast_inet_ntoa(iabuf, sizeof(iabuf), req->addr_from->sin_addr)); conn = find_conn(NULL,req->addr_from); if (conn) { if (conn->poke > -1) { ast_sched_del(sched, conn->poke); } conn->poke = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, conn_poke_device, conn); } // if (!conn) { // conn = build_conn(req->addr_from); // if (conn) { // ASTOBJ_CONTAINER_LINK(&connl,conn) // } // } if (req->len < 10) { if (req->len == 0) { ast_log(LOG_NOTICE, "%s READ ERROR\n",tmpbuf); } else { ast_log(LOG_NOTICE, "%s Packet too short - ignore\n",tmpbuf); } return; } if (sbuf[0] == 0xffff) { ast_log(LOG_NOTICE, "Found a discover packet\n"); if(req->len != sizeof(PacketRcvDiscovery)) { ast_log(LOG_NOTICE, "%s invalid discovery packet\n", tmpbuf); } else { if(memcmp(req->data, PacketRcvDiscovery, sizeof(PacketRcvDiscovery)) == 0) { ast_log(LOG_NOTICE, "Discovery packet received - Sending Discovery ACK\n"); if (conn) { if(conn->state == STATE_INIT) { // SendRawClient(sizeof(PacketSendDiscoveryACK), PacketSendDiscoveryACK, &conn->addr); } else { // TODO : NEED TO DELETE OLD OBJECT conn = build_conn(req->addr_from); if (conn) { ASTOBJ_CONTAINER_LINK(&connl,conn); SendRawClient(sizeof(PacketSendDiscoveryACK), PacketSendDiscoveryACK, &conn->addr); } } } else { conn = build_conn(req->addr_from); if (conn) { ASTOBJ_CONTAINER_LINK(&connl,conn); SendRawClient(sizeof(PacketSendDiscoveryACK), PacketSendDiscoveryACK, &conn->addr); } } return; } ast_log(LOG_NOTICE,"%s Invalid discovery packet\n", tmpbuf); } return; } if (!conn) { ast_log(LOG_NOTICE,"%s Not a discovery packet from an unknown source : ignoring\n", tmpbuf); return; } if(sbuf[0] != 0) { ast_log(LOG_NOTICE, "Receiving packet that start with something not 0x0000\n"); return; } if(req->data[5] != 2) { ast_log(LOG_NOTICE, "%s Wrong direction : got 0x%.2x expected 0x02\n", tmpbuf, req->data[5]); } seq = ntohs(sbuf[1]); if(req->data[4] == 1) { // ast_log(LOG_NOTICE, "ACK Packet Received for packet #0x%.4x\n",seq); conn->nb_retransmit = 0; if ((conn->last_seq_ack) + 1 == seq) { conn->last_seq_ack++; if (conn->last_buf_available == 1) { conn->last_buf_available--; //SetPingTimer(pte); } else if (conn->last_seq_ack + 1 == conn->seq_server + 1) { conn->last_buf_available = 0; //SetPingTimer(pte); } return; } if (conn->last_seq_ack > seq) { ast_log(LOG_NOTICE,"%s Warning : ACK received for an already ACKed packet : #0x%.4x\n", tmpbuf, conn->last_seq_ack); return; } if(conn->seq_server < seq) { ast_log(LOG_NOTICE,"%s Error : ACK received a non-existant packet : #0x%.4x\n", tmpbuf, conn->seq_server); return; } ast_log(LOG_NOTICE,"%s Warning : ACK lost\n", tmpbuf); conn->last_seq_ack = seq; return; } if (req->data[4] == 2) { ast_log(LOG_NOTICE, "Request received\n"); if(conn->seq_phone == seq) { req->data[4] = 1; req->data[5] = 1; SendRawClient(SIZE_HEADER, req->data, &conn->addr); conn->seq_phone++; process_request(req->len, req->data, conn); return; } if (conn->seq_phone > seq) { ast_log(LOG_NOTICE, "%s Warning : received a retransmitted packet : #0x%.4x (we are at #0x%.4x)\n", tmpbuf, seq, conn->seq_phone); req->data[4] = 1; req->data[5] = 1; SendRawClient(SIZE_HEADER, req->data, &conn->addr); return; } ast_log(LOG_NOTICE, "%s Warning : we lost a packet : received #0x%.4x (we are at #0x%.4x)\n", tmpbuf, seq, conn->seq_phone); return; } if (req->data[4] == 0) { ast_log(LOG_NOTICE, "%s Retransmit request for packet #0x%.4x\n", tmpbuf, seq); if (conn->last_seq_ack > seq) { ast_log(LOG_NOTICE, "%s Error : received a request for an already ACKed packet : #0x%.4x\n", tmpbuf, conn->last_seq_ack); return; } if (conn->seq_server < seq) { ast_log(LOG_NOTICE, "%s Error : received a request for a non-existant packet : #0x%.4x\n", tmpbuf, conn->seq_server); return; } SendRetransmit(conn); return; } ast_log(LOG_NOTICE, "Found nothing\n"); return; } static int unistimsock_read(int *id, int fd, short events, void *ignore) { struct unistim_request req; struct sockaddr_in sin; int res; int len; char iabuf[INET_ADDRSTRLEN]; len = sizeof(sin); memset(&req, 0, sizeof(req)); int rval,flag; flag = O_NONBLOCK; if ((rval = fcntl(unistimsock, F_GETFL, 0)) == -1) ast_log(LOG_WARNING, "Unable to get Flags\n"); if (fcntl(unistimsock, F_SETFL, rval | flag) == -1) ast_log(LOG_WARNING, "Unable to SET Flags\n"); res = recvfrom(unistimsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len); if (res < 0) { if (errno != ECONNREFUSED) ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno)); ast_log(LOG_WARNING, "No packet found\n"); return 1; } req.data[res] = '\0'; req.len = res; req.addr_from = &sin; if (unistimdebug) { ast_verbose("UNISTIM read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); } parse(&req); return 1; } static int *unistimsock_read_id = NULL; static void *do_monitor(void *data) { int res; int reloading; codec_number = DEFAULT_CODEC; /* Add an I/O event to our UDP socket */ if (unistimsock > -1) unistimsock_read_id = ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL); /* This thread monitors all the frame relay interfaces which are not yet in use (and thus do not have a separate thread) indefinitely */ /* From here on out, we die whenever asked */ for(;;) { /* Check for a reload request */ ast_mutex_lock(&unistim_reload_lock); reloading = unistim_reloading; unistim_reloading = 0; ast_mutex_unlock(&unistim_reload_lock); if (reloading) { if (option_verbose > 0) ast_verbose(VERBOSE_PREFIX_1 "Reloading UNISTIM\n"); unistim_do_reload(); /* Add an I/O event to our UDP socket */ if (unistimsock > -1) unistimsock_read_id = ast_io_add(io, unistimsock, unistimsock_read, AST_IO_IN, NULL); } /* Check for interfaces needing to be killed */ /* Don't let anybody kill us right away. Nobody should lock the interface list and wait for the monitor list, but the other way around is okay. */ ast_mutex_lock(&monlock); /* Lock the network interface */ ast_mutex_lock(&netlock); /* Okay, now that we know what to do, release the network lock */ ast_mutex_unlock(&netlock); /* And from now on, we're okay to be killed, so release the monitor lock as well */ ast_mutex_unlock(&monlock); pthread_testcancel(); /* Wait for sched or io */ res = ast_sched_wait(sched); /* SC: copied from chan_sip.c */ if ((res < 0) || (res > 1000)) res = 1000; res = ast_io_wait(io, res); ast_mutex_lock(&monlock); if (res >= 0) ast_sched_runq(sched); ast_mutex_unlock(&monlock); // ast_log(LOG_NOTICE, "Monitor\n"); } /* Never reached */ return NULL; } static int restart_monitor(void) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); /* If we're supposed to be stopped -- stay stopped */ if (monitor_thread == AST_PTHREADT_STOP) return 0; if (ast_mutex_lock(&monlock)) { ast_log(LOG_WARNING, "Unable to lock monitor\n"); return -1; } if (monitor_thread == pthread_self()) { ast_mutex_unlock(&monlock); ast_log(LOG_WARNING, "Cannot kill myself\n"); return -1; } if (monitor_thread != AST_PTHREADT_NULL) { /* Wake up the thread */ pthread_kill(monitor_thread, SIGURG); } else { /* Start a new monitor */ if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) { ast_mutex_unlock(&monlock); ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); return -1; } } ast_mutex_unlock(&monlock); return 0; } static void start_rtp(struct unistim_pvt *pvt) { ast_mutex_lock(&pvt->lock); /* Allocate the RTP */ pvt->rtp = ast_rtp_new(sched, io, 1, 0); if (pvt->rtp && pvt->owner) pvt->owner->fds[0] = ast_rtp_fd(pvt->rtp); if (pvt->rtp) ast_rtp_setnat(pvt->rtp, pvt->nat); /* Create the RTP connection */ struct sockaddr_in rsin; //ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype); //dest.sin_port = rsin.sin_port; struct sockaddr_in sin; sin.sin_family = AF_INET; memcpy(&sin.sin_addr, &pvt->parent->parent->addr.sin_addr, sizeof(sin)); sin.sin_port = htons(5200); ast_rtp_set_peer(pvt->rtp, &sin); ast_rtp_get_us(pvt->rtp, &rsin); pvt->parent->parent->conn->pvt = pvt; ast_log(LOG_NOTICE, "----------PORT REQUEST---------->%hd\n",htons(rsin.sin_port)); SendTone(pvt->parent->parent->conn, UNISTIM_TONE_SILENCE); SendStartTimer(pvt->parent->parent->conn); SendCallRequest(pvt->parent->parent->conn); ast_mutex_unlock(&pvt->lock); } static int reload_config(void) { struct ast_config *cfg; struct ast_variable *v; struct unistim_device *device; char iabuf[INET_ADDRSTRLEN]; char *cat; struct ast_hostent ahp; struct hostent *hp; int format; if (gethostname(ourhost, sizeof(ourhost))) { ast_log(LOG_WARNING, "Unable to get hostname, UNISTIM disabled\n"); return 0; } cfg = ast_config_load(config); /* We *must* have a config file otherwise stop immediately */ if (!cfg) { ast_log(LOG_NOTICE, "Unable to load config %s, UNISTIM disabled\n", config); return 0; } memset(&bindaddr, 0, sizeof(bindaddr)); dtmfmode = 0; v = ast_variable_browse(cfg, "general"); while(v) { /* Create the interface list */ if (!strcasecmp(v->name, "bindaddr")) { if (!(hp = ast_gethostbyname(v->value, &ahp))) { ast_log(LOG_WARNING, "Invalid address: %s\n", v->value); } else { memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr)); } } else if (!strcasecmp(v->name, "allow")) { format = ast_getformatbyname(v->value); if (format < 1) ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value); else capability |= format; } else if (!strcasecmp(v->name, "disallow")) { format = ast_getformatbyname(v->value); if (format < 1) ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value); else capability &= ~format; } else if (!strcasecmp(v->name, "tos")) { if (sscanf(v->value, "%i", &format) == 1) tos = format & 0xff; else if (!strcasecmp(v->value, "lowdelay")) tos = IPTOS_LOWDELAY; else if (!strcasecmp(v->value, "throughput")) tos = IPTOS_THROUGHPUT; else if (!strcasecmp(v->value, "reliability")) tos = IPTOS_RELIABILITY; else if (!strcasecmp(v->value, "mincost")) tos = IPTOS_MINCOST; else if (!strcasecmp(v->value, "none")) tos = 0; else ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno); } else if (!strcasecmp(v->name, "port")) { if (sscanf(v->value, "%i", &ourport) == 1) { bindaddr.sin_port = htons(ourport); } else { ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config); } } v = v->next; } cat = ast_category_browse(cfg, NULL); while(cat) { if (strcasecmp(cat, "general")) { device = build_device(cat, ast_variable_browse(cfg, cat)); if (device) { ASTOBJ_CONTAINER_LINK(&devicel,device); } /* FS: process queue and IO */ if (monitor_thread == pthread_self()) { if (sched) ast_sched_runq(sched); if (io) ast_io_wait(io, 10); } } cat = ast_category_browse(cfg, cat); } if (ntohl(bindaddr.sin_addr.s_addr)) { memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip)); } else { hp = ast_gethostbyname(ourhost, &ahp); if (!hp) { ast_log(LOG_WARNING, "Unable to get our IP address, UNISTIM disabled\n"); ast_config_destroy(cfg); return 0; } memcpy(&__ourip, hp->h_addr, sizeof(__ourip)); } if (!ntohs(bindaddr.sin_port)) bindaddr.sin_port = ntohs(DEFAULT_UNISTIM_CA_PORT); bindaddr.sin_family = AF_INET; ast_mutex_lock(&netlock); if (unistimsock > -1) close(unistimsock); if (unistimsock_read_id != NULL) ast_io_remove(io, unistimsock_read_id); unistimsock_read_id = NULL; unistimsock = socket(AF_INET, SOCK_DGRAM, 0); if (unistimsock < 0) { ast_log(LOG_WARNING, "Unable to create UNISTIM socket: %s\n", strerror(errno)); } else { if (bind(unistimsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) { ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port), strerror(errno)); close(unistimsock); unistimsock = -1; } else { if (option_verbose > 1) { ast_verbose(VERBOSE_PREFIX_2 "UNISTIM Listening on %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), bindaddr.sin_addr), ntohs(bindaddr.sin_port)); ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos); } if (setsockopt(unistimsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos); } } ast_mutex_unlock(&netlock); ast_config_destroy(cfg); return 0; } int load_module() { int res; sched = sched_context_create(); if (!sched) { ast_log(LOG_WARNING, "Unable to create schedule context\n"); return -1; } io = io_context_create(); if (!io) { ast_log(LOG_WARNING, "Unable to create I/O context\n"); return -1; } if (!(res = reload_config())) { /* Make sure we can register our skinny channel type */ if (ast_channel_register(type, tdesc, capability, unistim_request)) { ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); return -1; } unistim_rtp.type = type; ast_rtp_proto_register(&unistim_rtp); ast_cli_register(&cli_show_lines); /* And start the monitor for the first time */ restart_monitor(); } return res; } static int unistim_do_reload(void) { reload_config(); return 0; } static int unistim_reload(int fd, int argc, char *argv[]) { ast_mutex_lock(&unistim_reload_lock); if (unistim_reloading) { ast_verbose("Previous unistim reload not yet done\n"); } else unistim_reloading = 1; ast_mutex_unlock(&unistim_reload_lock); restart_monitor(); return 0; } int reload(void) { unistim_reload(0, 0, NULL); return 0; } int unload_module() { return -1; } int usecount() { int res; ast_mutex_lock(&usecnt_lock); res = usecnt; ast_mutex_unlock(&usecnt_lock); return res; } char *key() { return ASTERISK_GPL_KEY; } char *description() { return desc; }