** **
\*****************************************************************************/
+/*
+
+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>
#include "extension.h"
#include "message.h"
#include "admin.h"
+#include "cause.h"
+#include "asterisk_client.h"
int sock;
} *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_addr(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;
*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 (find_bchannel_addr(param->bchannel.addr))
+ {
+ fprintf(stderr, "error: bchannel addr %x already assigned.\n", param->bchannel.addr);
+ return(-1);
+ }
+ /* create bchannel */
+ bchannel = alloc_bchannel();
+ bchannel->addr = param->bchannel.addr;
+ /* in case, ref is not set, this bchannel instance must
+ * be created until it is removed again by LCR */
+ bchannel->ref = ref;
+ /* link to call */
+ if ((call = find_call_ref(ref)))
+ {
+ call->addr = param->bchannel.addr;
+ }
+
+#warning open stack
+ /* acknowledge */
+ newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
+ newparam.bchannel.addr = param->bchannel.addr;
+ send_message(MESSAGE_BCHANNEL, 0, &newparam);
+ break;
+
+ case BCHANNEL_REMOVE:
+ if (!(bchannel = find_bchannel_addr(param->bchannel.addr)))
+ {
+ fprintf(stderr, "error: bchannel addr %x already assigned.\n", param->bchannel.addr);
+ 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.addr = param->bchannel.addr;
+ 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
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
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)
}
/* enque hello message */
- memset(&hello_param, 0, sizeof(hello_param));
- admin_asterisk(MESSAGE_HELLO, &hello_param);
+ memset(¶m, 0, sizeof(param));
+ SCPY(param.hello.application, "asterisk");
+ send_message(MESSAGE_HELLO, 0, ¶m);
while(42)
{