aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_skinny.c
diff options
context:
space:
mode:
authorjeremy <jeremy@f38db490-d61c-443f-a65b-d21fe96a405b>2003-09-13 23:30:30 +0000
committerjeremy <jeremy@f38db490-d61c-443f-a65b-d21fe96a405b>2003-09-13 23:30:30 +0000
commit1df3aaa77a78b1d053a2dfdb1881c3becae1dfaf (patch)
treec1934b142340e709466b498f3d3e9500f98c56fd /channels/chan_skinny.c
parent8a8d27a2dfa1536f7273579dc7f4886bf9c4cfed (diff)
many bug fixes and inbound calling: SKINNY/line@device
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@1507 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_skinny.c')
-rwxr-xr-xchannels/chan_skinny.c235
1 files changed, 165 insertions, 70 deletions
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 05637c8e6..3784b06de 100755
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -478,7 +478,6 @@ struct hostent *hp;
static int skinnysock = -1;
static pthread_t tcp_thread;
static pthread_t accept_t;
-static ast_mutex_t devicelock = AST_MUTEX_INITIALIZER;
static char context[AST_MAX_EXTENSION] = "default";
static char language[MAX_LANGUAGE] = "";
static char musicclass[MAX_LANGUAGE] = "";
@@ -528,6 +527,17 @@ static int callnums = 1;
#define SKINNY_REORDER 37
#define SKINNY_CALLWAITTONE 45
+#define SKINNY_LAMP_OFF 1
+#define SKINNY_LAMP_ON 2
+#define SKINNY_LAMP_WINK 3
+#define SKINNY_LAMP_FLASH 4
+#define SKINNY_LAMP_BLINK 5
+
+#define SKINNY_RING_OFF 1
+#define SKINNY_RING_INSIDE 2
+#define SKINNY_RING_OUTSIDE 3
+#define SKINNY_RING_FEATURE 4
+
#define TYPE_TRUNK 1
#define TYPE_LINE 2
@@ -571,9 +581,12 @@ static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it's doing something critical. */
static ast_mutex_t monlock = AST_MUTEX_INITIALIZER;
-
+/* Protect the network socket */
static ast_mutex_t netlock = AST_MUTEX_INITIALIZER;
+/* Protect the session list */
static ast_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
+/* Protect the device list */
+static ast_mutex_t devicelock = AST_MUTEX_INITIALIZER;
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use. */
@@ -679,7 +692,7 @@ static skinny_req *req_alloc(size_t size)
return req;
}
-static struct skinny_subchannel *find_subchannel(struct skinny_line *l)
+static struct skinny_subchannel *find_subchannel_by_line(struct skinny_line *l)
{
/* Need to figure out how to determine which sub we want */
@@ -687,6 +700,59 @@ static struct skinny_subchannel *find_subchannel(struct skinny_line *l)
return sub;
}
+static struct skinny_subchannel *find_subchannel_by_name(char *dest)
+{
+ struct skinny_line *l;
+ struct skinny_device *d;
+ char line[256];
+ char *at;
+ char *device;
+
+ printf("dest: %s\n", dest);
+
+ 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;
+
+ printf("line: %s\n", line);
+ printf("device: %s\n", device);
+
+ ast_mutex_lock(&devicelock);
+ d = devices;
+ while(d) {
+ if (!strcasecmp(d->name, device)) {
+ if (skinnydebug) {
+ printf("Found device: %s\n", d->name);
+ }
+ /* Found the device */
+ l = d->lines;
+ while (l) {
+ /* Search for the right line */
+ if (!strcasecmp(l->name, line)) {
+ ast_mutex_unlock(&devicelock);
+ if (skinnydebug) {
+ printf("Found line: %s\n", l->name);
+ }
+ return l->sub;
+ }
+ printf("line cycle\n");
+ l = l->next;
+ }
+ }
+ printf("device cycle\n");
+ d = d->next;
+ }
+ /* Device not found*/
+ ast_mutex_unlock(&devicelock);
+ return NULL;
+}
+
static int transmit_response(struct skinnysession *s, skinny_req *req)
{
int res = 0;
@@ -713,7 +779,7 @@ static void transmit_speaker_mode(struct skinnysession *s, int mode)
{
skinny_req *req;
- req = req_alloc(sizeof(struct set_ringer_message));
+ req = req_alloc(sizeof(struct set_speaker_message));
if (!req) {
ast_log(LOG_ERROR, "Unable to allocate skinny_request, this is bad\n");
return;
@@ -838,7 +904,7 @@ static void transmit_lamp_indication(struct skinnysession *s, int instance, int
}
req->len = sizeof(set_lamp_message)+4;
req->e = SET_LAMP_MESSAGE;
- req->data.setlamp.stimulus = 9; // magic number
+ req->data.setlamp.stimulus = 0x9; // magic number
req->data.setlamp.stimulusInstance = instance;
req->data.setlamp.deviceStimulus = indication;
transmit_response(s, req);
@@ -859,9 +925,6 @@ static void transmit_ringer_mode(struct skinnysession *s, int mode)
transmit_response(s, req);
}
-
-
-
/* I do not believe skinny can deal with video.
Anyone know differently? */
static struct ast_rtp *skinny_get_vrtp_peer(struct ast_channel *chan)
@@ -1369,9 +1432,16 @@ static void *skinny_ss(void *data)
static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
{
- int res;
+ int res = 0;
+ int tone = 0;
struct skinny_line *l;
struct skinny_subchannel *sub;
+ struct skinnysession *session;
+
+ 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;
+ }
if (skinnydebug) {
ast_verbose(VERBOSE_PREFIX_3 "skinny_call(%s)\n", ast->name);
@@ -1379,48 +1449,60 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
sub = ast->pvt->pvt;
l = sub->parent;
+ session = l->parent->session;
- switch (l->hookstate) {
+ if (l->dnd) {
+ ast_queue_control(ast, AST_CONTROL_BUSY, 0);
+ return 0;
+ }
+
+ switch (l->hookstate) {
case SKINNY_OFFHOOK:
- // call waiting
+ tone = SKINNY_CALLWAITTONE;
break;
case SKINNY_ONHOOK:
+ tone = SKINNY_ALERT;
+ break;
default:
- // ring
+ ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
break;
}
- 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;
- }
+ transmit_lamp_indication(session, l->instance, SKINNY_LAMP_BLINK);
+ transmit_ringer_mode(session, SKINNY_RING_INSIDE);
+ transmit_tone(session, tone);
+ transmit_callstate(session, l->instance, SKINNY_RINGIN, sub->callid);
+
+// Set the prompt
+// Select the active softkeys
+
+ ast_setstate(ast, AST_STATE_RINGING);
+ ast_queue_control(ast, AST_CONTROL_RINGING, 0);
- res = 0;
sub->outgoing = 1;
- sub->cxmode = SKINNY_CX_RECVONLY;
+// sub->cxmode = SKINNY_CX_RECVONLY;
if (l->type == TYPE_LINE) {
if (!sub->rtp) {
start_rtp(sub);
} else {
+ /* do we need to anything if there already is an RTP allocated? */
// transmit_modify_request(sub);
}
+#if 0
if (sub->next->owner && sub->next->callid) {
/* try to prevent a callwait from disturbing the other connection */
sub->next->cxmode = SKINNY_CX_RECVONLY;
// transmit_modify_request(sub->next);
}
-
-// transmit_notify_request_with_callerid(sub, tone, ast->callerid);
- ast_setstate(ast, AST_STATE_RINGING);
- ast_queue_control(ast, AST_CONTROL_RINGING, 0);
-
+
/* not sure what this doing */
if (sub->next->owner && sub->next->callid) {
/* Put the connection back in sendrecv */
sub->next->cxmode = SKINNY_CX_SENDRECV;
// transmit_modify_request(sub->next);
}
+#endif
} else {
ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
@@ -1719,7 +1801,13 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
time_t timer;
struct tm *cmtime;
pthread_t t;
-
+
+ if ( (!s->device) && (req->e != REGISTER_MESSAGE && req->e != ALARM_MESSAGE)) {
+ ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
+ free(req);
+ return 0;
+ }
+
switch(req->e) {
case ALARM_MESSAGE:
@@ -1804,7 +1892,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
if (skinnydebug)
printf("Recieved Stimulus: Line\n");
- sub = find_subchannel(s->device->lines);
+ sub = find_subchannel_by_line(s->device->lines);
transmit_speaker_mode(s, 1); // Turn on
break;
default:
@@ -1921,7 +2009,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
memset(req, 0, SKINNY_MAX_PACKET);
req->len = sizeof(line_stat_res_message)+4;
req->e = LINE_STAT_RES_MESSAGE;
- sub = find_subchannel(s->device->lines);
+ sub = find_subchannel_by_line(s->device->lines);
if (!sub) {
ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
return 0;
@@ -1951,38 +2039,44 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
transmit_response(s, req);
break;
case OFFHOOK_MESSAGE:
- transmit_ringer_mode(s,1); // Ring off
- transmit_lamp_indication(s, s->device->lines->instance, 2); // Lamp on
+ transmit_ringer_mode(s,SKINNY_RING_OFF);
+ transmit_lamp_indication(s, s->device->lines->instance, SKINNY_LAMP_ON);
- sub = find_subchannel(s->device->lines);
+ sub = find_subchannel_by_line(s->device->lines);
if (!sub) {
ast_log(LOG_NOTICE, "No available lines on: %s\n", s->device->name);
return 0;
}
sub->parent->hookstate = SKINNY_OFFHOOK;
- if (!sub->owner) {
+
if (sub->outgoing) {
- // deal with asterisk skinny outbound calls
- } else {
transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
- transmit_tone(s, SKINNY_DIALTONE);
- c = skinny_new(sub, AST_STATE_DOWN);
- if (c) {
- /* start switch */
- if (pthread_create(&t, NULL, skinny_ss, c)) {
- ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
- ast_hangup(c);
+ transmit_tone(s, SKINNY_SILENCE);
+ ast_setstate(sub->owner, AST_STATE_UP);
+ // select soft keys
+ } else {
+ if (!sub->owner) {
+
+ transmit_callstate(s, s->device->lines->instance, SKINNY_OFFHOOK, sub->callid);
+ transmit_tone(s, SKINNY_DIALTONE);
+ c = skinny_new(sub, AST_STATE_DOWN);
+ if(c) {
+ /* start switch */
+ if (pthread_create(&t, NULL, skinny_ss, c)) {
+ ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
+ ast_hangup(c);
+ }
+ } else {
+ ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
}
+
} else {
- ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", sub->parent->name, s->device->name);
+ ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
}
}
- } else {
- ast_log(LOG_DEBUG, "Current sub [%s] already has owner\n", sub->owner->name);
- }
break;
case ONHOOK_MESSAGE:
- sub = find_subchannel(s->device->lines);
+ sub = find_subchannel_by_line(s->device->lines);
if (sub->parent->hookstate == SKINNY_ONHOOK) {
/* Somthing else already put us back on hook */
break;
@@ -2022,9 +2116,9 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
}
if ((sub->parent->hookstate == SKINNY_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
if (has_voicemail(sub->parent)) {
- transmit_lamp_indication(s, s->device->lines->instance, 4); // Flash
+ transmit_lamp_indication(s, s->device->lines->instance, SKINNY_LAMP_FLASH);
} else {
- transmit_lamp_indication(s, s->device->lines->instance, 1); // Off
+ transmit_lamp_indication(s, s->device->lines->instance, SKINNY_LAMP_OFF);
}
}
break;
@@ -2043,7 +2137,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
}
f.subclass = d;
f.src = "skinny";
- sub = find_subchannel(s->device->lines);
+ sub = find_subchannel_by_line(s->device->lines);
if (sub->owner) {
/* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
@@ -2069,7 +2163,7 @@ static int handle_message(skinny_req *req, struct skinnysession *s)
memcpy(&sin.sin_addr, addr, sizeof(sin.sin_addr)); // Endian?
sin.sin_port = htons(port);
- sub = find_subchannel(s->device->lines);
+ sub = find_subchannel_by_line(s->device->lines);
ast_rtp_set_peer(sub->rtp, &sin);
ast_rtp_get_us(sub->rtp, &us);
@@ -2138,21 +2232,22 @@ static int get_input(struct skinnysession *s)
res = ast_select(s->fd + 1, &fds, NULL, NULL, NULL);
- if (res < 0) {
- ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
- } else if (res > 0) {
- ast_mutex_lock(&s->lock);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
+ } else if (res > 0) {
memset(s->inbuf,0,sizeof(s->inbuf));
- res = read(s->fd, s->inbuf, 4);
- dlen = *(int *)s->inbuf;
- if (res < 1) {
- return -1;
- }
- res = read(s->fd, s->inbuf+4, dlen+4);
- ast_mutex_unlock(&s->lock);
- if (res < 1) {
- return -1;
- }
+ res = read(s->fd, s->inbuf, 4);
+ if (res != 4) {
+ ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
+ return -1;
+ }
+ dlen = *(int *)s->inbuf;
+ res = read(s->fd, s->inbuf+4, dlen+4);
+ ast_mutex_unlock(&s->lock);
+ if (res != (dlen+4)) {
+ ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
+ return -1;
+ }
}
return res;
@@ -2172,6 +2267,7 @@ static skinny_req *skinny_req_parse(struct skinnysession *s)
memcpy(req, s->inbuf, *(int*)(s->inbuf)+8); // +8
if (req->e < 0) {
ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
+ free(req);
return NULL;
}
return req;
@@ -2325,7 +2421,6 @@ static struct ast_channel *skinny_request(char *type, int format, void *data)
{
int oldformat;
struct skinny_subchannel *sub;
- struct skinny_device *d = NULL;
struct ast_channel *tmpc = NULL;
char tmp[256];
char *dest = data;
@@ -2336,16 +2431,16 @@ static struct ast_channel *skinny_request(char *type, int format, void *data)
ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
return NULL;
}
- strncpy(tmp, dest, sizeof(tmp) - 1); // XXX FIX
+
+ strncpy(tmp, dest, sizeof(tmp) - 1);
if (!strlen(tmp)) {
- ast_log(LOG_NOTICE, "Skinny channels require something!?\n");
+ ast_log(LOG_NOTICE, "Skinny channels require a device\n");
return NULL;
}
- sub = find_subchannel(d->lines);
-
+ sub = find_subchannel_by_name(tmp);
if (!sub) {
- ast_log(LOG_NOTICE, "No available lines on: %s\n", d->name);
+ ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
return NULL;
}
@@ -2376,14 +2471,14 @@ static int reload_config(void)
if (gethostname(ourhost, sizeof(ourhost))) {
ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled\n");
- return 0;
+ return 1;
}
cfg = ast_load(config);
/* We *must* have a config file otherwise stop immediately */
if (!cfg) {
ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled\n", config);
- return 0;
+ return 1;
}
/* load the general section */