]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
many bug fixes and inbound calling: SKINNY/line@device
authorJeremy McNamara <jj@nufone.net>
Sat, 13 Sep 2003 23:30:30 +0000 (23:30 +0000)
committerJeremy McNamara <jj@nufone.net>
Sat, 13 Sep 2003 23:30:30 +0000 (23:30 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1507 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_skinny.c

index 05637c8e6efe49c210811d3fc107f7c60d3881f8..3784b06dec0ee65aca93364a6dcc5a80c3963909 100755 (executable)
@@ -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 */