backup
[lcr.git] / asterisk_client.c
index def6545..c430c30 100644 (file)
@@ -9,6 +9,25 @@
 **                                                                           **
 \*****************************************************************************/
 
+/*
+
+How does it work:
+
+To connect, open a socket and send a MESSAGE_HELLO to admin socket with
+the application name. This name is unique an can be used for routing calls.
+
+To make a call, send a MESSAGE_NEWREF and a new reference is received.
+When receiving a call, a new reference is received.
+The reference is received with MESSAGE_NEWREF.
+
+Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference.
+
+To release call and reference, send or receive MESSAGE_RELEASE.
+From that point on, the ref is not valid, so no other message may be sent
+with that reference.
+
+*/
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -25,6 +44,8 @@
 #include "extension.h"
 #include "message.h"
 #include "admin.h"
+#include "cause.h"
+#include "asterisk_client.h"
 
 int sock;
 
@@ -34,9 +55,122 @@ struct admin_list {
 } *admin_first = NULL;
 
 /*
- * enque message from asterisk
+ * channel and call instances
+ */
+struct chan_bchannel *bchannel_first;
+struct chan_call *call_first;
+
+struct chan_bchannel *find_bchannel_handle(unsigned long addr)
+{
+       struct chan_bchannel *bchannel = bchannel_first;
+
+       while(bchannel)
+       {
+               if (bchannel->addr == addr)
+                       break;
+               bchannel = bchannel->next;
+       }
+       return(bchannel);
+}
+
+struct chan_bchannel *find_bchannel_ref(unsigned long ref)
+{
+       struct chan_bchannel *bchannel = bchannel_first;
+
+       while(bchannel)
+       {
+               if (bchannel->ref == ref)
+                       break;
+               bchannel = bchannel->next;
+       }
+       return(bchannel);
+}
+
+struct chan_call *find_call_ref(unsigned long ref)
+{
+       struct chan_call *call = call_first;
+
+       while(call)
+       {
+               if (call->ref == ref)
+                       break;
+               call = call->next;
+       }
+       return(call);
+}
+
+struct chan_call *find_call_addr(unsigned long addr)
+{
+       struct chan_call *call = call_first;
+
+       while(call)
+       {
+               if (call->addr == addr)
+                       break;
+               call = call->next;
+       }
+       return(call);
+}
+
+struct chan_bchannel *alloc_bchannel(void)
+{
+       struct chan_bchannel **bchannelp = &bchannel_first;
+
+       while(*bchannelp)
+               bchannelp = &((*bchannelp)->next);
+
+       *bchannelp = (struct chan_bchannel *)MALLOC(sizeof(struct chan_bchannel));
+       return(*bchannelp);
+}
+
+void free_bchannel(struct chan_bchannel *bchannel)
+{
+       struct chan_bchannel **temp = &bchannel_first;
+
+       while(*temp)
+       {
+               if (*temp == bchannel)
+               {
+                       *temp = (*temp)->next;
+                       free(bchannel);
+                       return;
+               }
+               temp = &((*temp)->next);
+       }
+}
+
+struct chan_call *alloc_call(void)
+{
+       struct chan_call **callp = &call_first;
+
+       while(*callp)
+               callp = &((*callp)->next);
+
+       *callp = (struct chan_call *)MALLOC(sizeof(struct chan_call));
+       return(*callp);
+}
+
+void free_call(struct chan_call *call)
+{
+       struct chan_call **temp = &call_first;
+
+       while(*temp)
+       {
+               if (*temp == call)
+               {
+                       *temp = (*temp)->next;
+                       free(call);
+                       return;
+               }
+               temp = &((*temp)->next);
+       }
+}
+
+
+/*
+ * enque message to LCR
  */
-int admin_asterisk(int message_type, union parameter *param)
+int send_message(int message_type, unsigned long ref, union parameter *param)
 {
        struct admin_list *admin, **adminp;
 
@@ -47,11 +181,140 @@ int admin_asterisk(int message_type, union parameter *param)
        *adminp = admin;
 
        admin->msg.type = message_type;
+       admin->msg.ref = ref;
        memcpy(&admin->msg.param, param, sizeof(union parameter));
 
        return(0);
 }
 
+/*
+ * message received from LCR
+ */
+int receive_message(int message_type, unsigned long ref, union parameter *param)
+{
+       union parameter newparam;
+       struct chan_bchannel *bchannel;
+       struct chan_call *call;
+
+       memset(&newparam, 0, sizeof(union parameter));
+
+       /* handle bchannel message*/
+       if (message_type == MESSAGE_BCHANNEL)
+       {
+               switch(param->bchannel.type)
+               {
+                       case BCHANNEL_ASSIGN:
+                       if ((bchannel = find_bchannel_handle(param->bchannel.handle)))
+                       {
+                               fprintf(stderr, "error: bchannel handle %x already assigned.\n", param->bchannel.handle);
+                               return(-1);
+                       }
+                       /* create bchannel */
+                       bchannel = alloc_bchannel();
+                       bchannel->addr = param->bchannel.handle;
+                       /* in case, ref is not set, this bchannel instance must
+                        * be created until it is removed again by LCR */
+                       /* link to call */
+                       if ((call = find_call_ref(ref)))
+                       {
+                               bchannel->ref = ref;
+                               call->addr = param->bchannel.handle;
+                       }
+
+#warning open stack
+                       /* acknowledge */
+                       newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
+                       newparam.bchannel.handle = param->bchannel.handle;
+                       send_message(MESSAGE_BCHANNEL, 0, &newparam);
+                       break;
+
+                       case BCHANNEL_REMOVE:
+                       if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
+                       {
+                               fprintf(stderr, "error: bchannel handle %x not assigned.\n", param->bchannel.handle);
+                               return(-1);
+                       }
+                       /* unlink from call */
+                       if ((call = find_call_ref(bchannel->ref)))
+                       {
+                               call->addr = 0;
+                       }
+                       /* remove bchannel */
+                       free_bchannel(bchannel);
+#warning close stack
+                       /* acknowledge */
+                       newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
+                       newparam.bchannel.handle = param->bchannel.handle;
+                       send_message(MESSAGE_BCHANNEL, 0, &newparam);
+                       
+                       break;
+
+                       default:
+                       fprintf(stderr, "received unknown bchannel message %d\n", param->bchannel.type);
+               }
+               return(0);
+       }
+
+       /* handle new ref */
+       if (message_type == MESSAGE_NEWREF)
+       {
+               if (param->direction)
+               {
+                       /* new ref from lcr */
+                       if (!ref || find_call_ref(ref))
+                       {
+                               fprintf(stderr, "illegal new ref %d received\n", ref);
+                               return(-1);
+                       }
+                       call = alloc_call();
+                       call->ref = ref;
+               } else
+               {
+                       /* new ref, as requested from this remote application */
+                       call = find_call_ref(0);
+                       if (!call)
+                       {
+                               /* send release, if ref does not exist */
+                               newparam.disconnectinfo.cause = CAUSE_NORMAL;
+                               newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                               send_message(MESSAGE_RELEASE, ref, &newparam);
+                               return(0);
+                       }
+                       call->ref = ref;
+#warning process call (send setup, if pending)
+               }
+               return(0);
+       }
+
+       /* check ref */
+       if (!ref)
+       {
+               fprintf(stderr, "received message %d without ref\n", message_type);
+               return(-1);
+       }
+       call = find_call_ref(ref);
+       if (!call)
+       {
+               /* ignore ref that is not used (anymore) */
+               return(0);
+       }
+
+       /* handle messages */
+       switch(message_type)
+       {
+#warning we must see if ref is a reply or a request, do we??
+               case MESSAGE_RELEASE:
+#warning release call
+               free_call(call);
+               return(0);
+
+               case MESSAGE_SETUP:
+#warning handle incoming setup, send to asterisk
+               break;
+       }
+       return(0);
+}
+
 
 /* asterisk handler
  * warning! not thread safe
@@ -83,6 +346,7 @@ int handle_socket(void)
                        fprintf(stderr, "Socket received illegal message %d\n", msg.message);
                        return(-1); // socket error
                }
+               receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
                printf("message received %d\n", msg.u.msg.type);
                work = 1;
        } else
@@ -138,7 +402,7 @@ int main(int argc, char *argv[])
        struct sockaddr_un sock_address;
        int ret;
        unsigned long on = 1;
-       union parameter hello_param;
+       union parameter param;
 
        /* open socket */
        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
@@ -169,8 +433,9 @@ int main(int argc, char *argv[])
        }
 
        /* enque hello message */
-       memset(&hello_param, 0, sizeof(hello_param));
-       admin_asterisk(MESSAGE_HELLO, &hello_param);
+       memset(&param, 0, sizeof(param));
+       SCPY(param.hello.application, "asterisk");
+       send_message(MESSAGE_HELLO, 0, &param);
 
        while(42)
        {