modified: chan_lcr.c
[lcr.git] / chan_lcr.c
index 4abb766..493fd76 100644 (file)
@@ -42,12 +42,12 @@ with that reference.
 #include <sys/un.h>
 #include "extension.h"
 #include "message.h"
-#include "admin.h"
+#include "lcrsocket.h"
 #include "cause.h"
 #include "bchannel.h"
 #include "chan_lcr.h"
 
-int sock;
+int lcr_sock = -1;
 
 struct admin_list {
        struct admin_list *next;
@@ -112,6 +112,28 @@ void free_call(struct chan_call *call)
        }
 }
 
+unsigned short new_brige_id(void)
+{
+       struct chan_call *call;
+       unsigned short id = 1;
+
+       /* search for lowest bridge id that is not in use and not 0 */
+       while(id)
+       {
+               call = call_first;
+               while(call)
+               {
+                       if (call->bridge_id == id)
+                               break;
+                       call = call->next;
+               }
+               if (!call)
+                       break;
+               id++;
+       }
+       return(id);
+}
+
 
 /*
  * receive bchannel data
@@ -195,6 +217,8 @@ int receive_message(int message_type, unsigned long ref, union parameter *param)
                        {
                                bchannel->ref = ref;
                                call->bchannel_handle = param->bchannel.handle;
+#warning hier muesen alle stati gesetzt werden falls sie vor dem b-kanal verfügbar waren
+                               bchannel_join(call->bridge_id);
                        }
                        if (bchannel_create(bchannel))
                                bchannel_activate(bchannel, 1);
@@ -208,6 +232,7 @@ int receive_message(int message_type, unsigned long ref, union parameter *param)
                        case BCHANNEL_REMOVE:
                        if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
                        {
+                               alle fprintf nach ast_log
                                fprintf(stderr, "error: bchannel handle %x not assigned.\n", param->bchannel.handle);
                                return(-1);
                        }
@@ -279,15 +304,57 @@ int receive_message(int message_type, unsigned long ref, union parameter *param)
        /* handle messages */
        switch(message_type)
        {
-#warning we must see if ref is a reply or a request, do we??
+               case MESSAGE_SETUP:
+todo
+               break;
+
+               case MESSAGE_OVERLAP:
+todo
+               break;
+
+               case MESSAGE_PROCEEDING:
+todo
+               break;
+
+               case MESSAGE_ALERTING:
+todo
+               break;
+
+               case MESSAGE_CONNECT:
+todo
+               break;
+
+               case MESSAGE_DISCONNECT:
+todo
+               break;
+
                case MESSAGE_RELEASE:
-#warning release call
+todo
                free_call(call);
                return(0);
 
-               case MESSAGE_SETUP:
-#warning handle incoming setup, send to asterisk
+               case MESSAGE_INFORMATION:
+todo
                break;
+
+               case MESSAGE_FACILITY:
+todo
+               break;
+
+               case MESSAGE_PATTERN:
+todo
+               break;
+
+               case MESSAGE_NOPATTERN:
+todo
+               break;
+
+               case MESSAGE_AUDIOPATH:
+todo
+               break;
+
+               default:
+unhandled
        }
        return(0);
 }
@@ -370,23 +437,24 @@ int handle_socket(void)
 }
 
 /*
- * main function
+ * open and close socket
  */
-int main(int argc, char *argv[])
+int open_socket(void)
 {
+       int ret;
+       int sock;
        char *socket_name = SOCKET_NAME;
        int conn;
        struct sockaddr_un sock_address;
        int ret;
        unsigned long on = 1;
        union parameter param;
-       int work;
 
        /* open socket */
        if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
        {
-               fprintf(stderr, "Failed to create socket.\n");
-               exit(EXIT_FAILURE);
+               ast_log(LOG_ERROR, "Failed to create socket.\n");
+               return(sock);
        }
 
        /* set socket address and name */
@@ -398,16 +466,16 @@ int main(int argc, char *argv[])
        if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
        {
                close(sock);
-               fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
-               exit(EXIT_FAILURE);
+               ast_log(LOG_ERROR, "Failed to connect to socket \"%s\". Is LCR running?\n", sock_address.sun_path);
+               return(conn);
        }
 
        /* set non-blocking io */
-       if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
+       if ((ret = ioctl(sock, FIONBIO, (unsigned char *)(&on))) < 0)
        {
                close(sock);
-               fprintf(stderr, "Failed to set socket into non-blocking IO.\n");
-               exit(EXIT_FAILURE);
+               ast_log(LOG_ERROR, "Failed to set socket into non-blocking IO.\n");
+               return(ret);
        }
 
        /* enque hello message */
@@ -415,10 +483,21 @@ int main(int argc, char *argv[])
        strcpy(param.hello.application, "asterisk");
        send_message(MESSAGE_HELLO, 0, &param);
 
-       /* bchannel */
-       if (!bchannel_initialize())
-               goto bchannel_failed;
-       
+       return(sock);
+}
+
+void close_socket(int sock)
+{
+       /* close socket */
+       if (socket >= 0)        
+               close(sock);
+}
+
+
+void lcr_thread(void)
+{
+       int work;
+
        while(42)
        {
                work = 0;
@@ -438,21 +517,366 @@ int main(int argc, char *argv[])
                if (!work)
                        usleep(30000);
        }
+}
 
-       bchannel_deinitialize();
-       bchannel_failed:
+/* call from asterisk (new instance) */
+static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
+{
+       int port=0;
+       int r;
+       struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast);
+       struct misdn_bchannel *newbc;
+       char *opts=NULL, *ext;
+       char dest_cp[256];
        
-       /* close socket */      
-       close(sock);
-       /* now we say good bye */
-       if (ret)
        {
-               printf("%s\n", ret);
-               exit(EXIT_FAILURE);
+               strncpy(dest_cp,dest,sizeof(dest_cp)-1);
+               dest_cp[sizeof(dest_cp)]=0;
+
+               ext=dest_cp;
+               strsep(&ext,"/");
+               if (ext) {
+                       opts=ext;
+                       strsep(&opts,"/");
+               }  else {
+                       ast_log(LOG_WARNING, "Malformed dialstring\n");
+                       return -1;
+               }
+       }
+
+       if (!ast) {
+               ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
+               return -1;
+       }
+
+       if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest  ) {
+               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+               ast->hangupcause=41;
+               ast_setstate(ast, AST_STATE_DOWN);
+               return -1;
+       }
+
+       if (!ch) {
+               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+               ast->hangupcause=41;
+               ast_setstate(ast, AST_STATE_DOWN);
+               return -1;
+       }
+       
+       newbc=ch->bc;
+       
+       if (!newbc) {
+               ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
+               ast->hangupcause=41;
+               ast_setstate(ast, AST_STATE_DOWN);
+               return -1;
+       }
+       
+       port=newbc->port;
+
+       
+       chan_misdn_log(1, port, "* CALL: %s\n",dest);
+       
+       chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context);
+       
+       chan_misdn_log(3, port, " --> * adding2newbc ext %s\n",ast->exten);
+       if (ast->exten) {
+               int l = sizeof(newbc->dad);
+               strncpy(ast->exten,ext,sizeof(ast->exten));
+
+               strncpy(newbc->dad,ext,l);
+
+               newbc->dad[l-1] = 0;
        }
+       newbc->rad[0]=0;
+       chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n",AST_CID_P(ast));
+       if (ast_strlen_zero(newbc->oad) && AST_CID_P(ast) ) {
+
+               if (AST_CID_P(ast)) {
+                       int l = sizeof(newbc->oad);
+                       strncpy(newbc->oad,AST_CID_P(ast), l);
+                       newbc->oad[l-1] = 0;
+               }
+       }
+
+       {
+               struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast);
+               if (!ch) { ast_verbose("No chan_list in misdn_call\n"); return -1;}
+               
+               newbc->capability=ast->transfercapability;
+               pbx_builtin_setvar_helper(ast,"TRANSFERCAPABILITY",ast_transfercapability2str(newbc->capability));
+               if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
+                       chan_misdn_log(2, port, " --> * Call with flag Digital\n");
+               }
+               
+
+               /* update screening and presentation */ 
+               update_config(ch,ORG_AST);
+               
+               /* fill in some ies from channel vary*/
+               import_ch(ast, newbc, ch);
+               
+               /* Finally The Options Override Everything */
+               if (opts)
+                       misdn_set_opt_exec(ast,opts);
+               else
+                       chan_misdn_log(2,port,"NO OPTS GIVEN\n");
+
+               /*check for bridging*/
+               int bridging;
+               misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int));
+               if (bridging && ch->other_ch) {
+                       chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
+                       *ch->bc->pipeline=0;
+                       *ch->other_ch->bc->pipeline=0;
+               }
+               
+               r=misdn_lib_send_event( newbc, EVENT_SETUP );
+               
+               /** we should have l3id after sending setup **/
+               ch->l3id=newbc->l3_id;
+       }
+       
+       if ( r == -ENOCHAN  ) {
+               chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
+               chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n",newbc?newbc->pid:-1);
+               ast->hangupcause=34;
+               ast_setstate(ast, AST_STATE_DOWN);
+               return -1;
+       }
+       
+       chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n",newbc?newbc->pid:1);
+
+       ast_setstate(ast, AST_STATE_DIALING);
+       ast->hangupcause=16;
+
+wenn pattern available soll gestoppt werden, sonst nicht:      
+       if (newbc->nt) stop_bc_tones(ch);
+
+       ch->state=MISDN_CALLING;
+       
+       return 0; 
+}
+
+
+static struct ast_channel_tech misdn_tech = {
+       .type="lcr",
+       .description="Channel driver for connecting to Linux-Call-Router",
+       .capabilities= je nach option?AST_FORMAT_ALAW:AST_FORMAT_ULAW ,
+       .requester=lcr_request,
+       .send_digit=lcr_digit,
+       .call=lcr_call,
+       .bridge=lcr_bridge, 
+       .hangup=lcr_hangup,
+       .answer=lcr_answer,
+       .read=lcr_read,
+       .write=lcr_write,
+       .indicate=lcr_indication,
+       .fixup=lcr_fixup,
+       .send_text=lcr_send_text,
+       .properties=0
+};
+
+/*
+ * cli
+ */
+static int cli_show_lcr (int fd, int argc, char *argv[])
+{
+}
+
+static int cli_show_calls (int fd, int argc, char *argv[])
+{
+}
+
+static int cli_reload_routing (int fd, int argc, char *argv[])
+{
 }
 
+static int cli_reload_interfaces (int fd, int argc, char *argv[])
+{
+}
 
+static int cli_port_block (int fd, int argc, char *argv[])
+{
+}
 
+static int cli_port_unblock (int fd, int argc, char *argv[])
+{
+}
+
+static int cli_port_unload (int fd, int argc, char *argv[])
+{
+}
+
+static struct ast_cli_entry cli_show_lcr =
+{ {"lcr", "show", "lcr", NULL},
+ lcr_show_lcr,
+ "Shows current states of LCR core",
+ "Usage: lcr show lcr\n",
+};
+
+static struct ast_cli_entry cli_show_calls =
+{ {"lcr", "show", "calls", NULL},
+ lcr_show_calls,
+ "Shows current calls made by LCR and Asterisk",
+ "Usage: lcr show calls\n",
+};
+
+static struct ast_cli_entry cli_reload_routing =
+{ {"lcr", "reload", "routing", NULL},
+ lcr_reload_routing,
+ "Reloads routing conf of LCR, current uncomplete calls will be disconnected",
+ "Usage: lcr reload routing\n",
+};
+
+static struct ast_cli_entry cli_reload_interfaces =
+{ {"lcr", "reload", "interfaces", NULL},
+ lcr_reload_interfaces,
+ "Reloads interfaces conf of LCR",
+ "Usage: lcr reload interfaces\n",
+};
+
+static struct ast_cli_entry cli_port_block =
+{ {"lcr", "port", "block", NULL},
+ lcr_port_block,
+ "Blocks LCR port for further calls",
+ "Usage: lcr port block \"<port>\"\n",
+};
+
+static struct ast_cli_entry cli_port_unblock =
+{ {"lcr", "port", "unblock", NULL},
+ lcr_port_unblock,
+ "Unblocks or loads LCR port, port is opened my mISDN",
+ "Usage: lcr port unblock \"<port>\"\n",
+};
+
+static struct ast_cli_entry cli_port_unload =
+{ {"lcr", "port", "unload", NULL},
+ lcr_port_unload,
+ "Unloads LCR port, port is closes by mISDN",
+ "Usage: lcr port unload \"<port>\"\n",
+};
+
+
+/*
+ * module loading and destruction
+ */
+int load_module(void)
+{
+//     ast_mutex_init(&release_lock);
+
+//     lcr_cfg_update_ptp();
+
+       if (!(lcr_sock = open_socket())) {
+               ast_log(LOG_ERROR, "Unable to connect %s\n", misdn_type);
+               lcr_sock = -1;
+               /* continue with closed socket */
+       }
+
+       if (!bchannel_initialize()) {
+               ast_log(LOG_ERROR, "Unable to open mISDN device\n");
+               unload_module();
+               return -1;
+       }
+       mISDN_created = 1;
+
+       if (ast_channel_register(&lcr_tech)) {
+               ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
+               unload_module();
+               return -1;
+       }
+  
+       ast_cli_register(&cli_show_lcr);
+       ast_cli_register(&cli_show_calls);
+
+       ast_cli_register(&cli_reload_routing);
+       ast_cli_register(&cli_reload_interfaces);
+       ast_cli_register(&cli_port_block);
+       ast_cli_register(&cli_port_unblock);
+       ast_cli_register(&cli_port_unload);
+  
+       ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
+                                "misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n"
+                                "Sets mISDN opts. and optargs\n"
+                                "\n"
+                                "The available options are:\n"
+                                "    d - Send display text on called phone, text is the optparam\n"
+                                "    n - don't detect dtmf tones on called channel\n"
+                                "    h - make digital outgoing call\n" 
+                                "    c - make crypted outgoing call, param is keyindex\n"
+                                "    e - perform echo cancelation on this channel,\n"
+                                "        takes taps as arguments (32,64,128,256)\n"
+                                "    s - send Non Inband DTMF as inband\n"
+                                "   vr - rxgain control\n"
+                                "   vt - txgain control\n"
+               );
+
+       
+       lcr_cfg_get( 0, LCR_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
+
+       chan_lcr_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n");
+
+       return 0;
+}
+
+int unload_module(void)
+{
+       /* First, take us out of the channel loop */
+       ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
+       
+       misdn_tasks_destroy();
+       
+       if (!g_config_initialized) return 0;
+       
+       ast_cli_unregister(&cli_show_lcr);
+       ast_cli_unregister(&cli_show_calls);
+       ast_cli_unregister(&cli_reload_routing);
+       ast_cli_unregister(&cli_reload_interfaces);
+       ast_cli_unregister(&cli_port_block);
+       ast_cli_unregister(&cli_port_unblock);
+       ast_unregister_application("misdn_set_opt");
+  
+       ast_channel_unregister(&lcr_tech);
+
+       if (mISDN_created) {
+               bchannel_deinitialize();
+               mISDN_created = 0;
+       }
+
+       if (lcr_sock >= 0) {
+               close(lcr_sock);
+               lcr_sock = -1;
+       }
+
+       was ist mit dem mutex
+       
+       return 0;
+}
+
+int reload(void)
+{
+       reload_config();
+
+       return 0;
+}
+
+int usecount(void)
+{
+       int res;
+       ast_mutex_lock(&usecnt_lock);
+       res = usecnt;
+       ast_mutex_unlock(&usecnt_lock);
+       return res;
+}
+
+char *description(void)
+{
+       return desc;
+}
+
+char *key(void)
+{
+       return ASTERISK_GPL_KEY;
+}