unified socket application interface (for asterisk and maybe other apps)
[lcr.git] / admin_server.c
index 1d8f400..6292e12 100644 (file)
@@ -1,11 +1,11 @@
 /*****************************************************************************\
 **                                                                           **
-** PBX4Linux                                                                 **
+** Linux Call Router                                                         **
 **                                                                           **
 **---------------------------------------------------------------------------**
 ** Copyright: Andreas Eversberg                                              **
 **                                                                           **
-** Socket link                                                               **
+** Socket link server                                                        **
 **                                                                           **
 \*****************************************************************************/
 
@@ -33,7 +33,7 @@ char *socket_name = SOCKET_NAME;
 int sock = -1;
 struct sockaddr_un sock_address;
 
-struct admin_list *admin_list = NULL;
+struct admin_list *admin_first = NULL;
 
 /*
  * initialize admin socket 
@@ -86,11 +86,33 @@ int admin_init(void)
 
 /*
  * free connection
+ * also releases all remote joins
  */
 void free_connection(struct admin_list *admin)
 {
        struct admin_queue *response;
        void *temp;
+       union parameter param;
+       class Join *join, *joinnext;
+
+       /* free remote joins */
+       if (admin->remote[0])
+       {
+               join = join_first;
+               while(join)
+               {
+                       joinnext = join->next;
+                       if (join->j_type==JOIN_TYPE_REMOTE && !strcmp(((class JoinRemote *)join)->j_remote, admin->remote))
+                       {
+                               memset(&param, 0, sizeof(param));
+                               param.disconnectinfo.cause = CAUSE_OUTOFORDER;
+                               param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                               ((class JoinRemote *)join)->message_remote(0, MESSAGE_RELEASE, &param);
+                               /* join is now destroyed, so we go to next join */
+                       }
+                       join = joinnext;
+               }
+       }
 
        if (admin->sock >= 0)
        {
@@ -104,12 +126,12 @@ void free_connection(struct admin_list *admin)
 //#warning
 //     printf("%x\n", response);
                temp = response->next;
-               free(response);
+               FREE(response, 0);
                memuse--;
                response = (struct admin_queue *)temp;
        }
 //     printf("new2\n", response);
-       free(admin);
+       FREE(admin, 0);
 //     printf("new3\n", response);
        memuse--;
 }
@@ -122,7 +144,7 @@ void admin_cleanup(void)
 {
        struct admin_list *admin, *next;;
 
-       admin = admin_list;
+       admin = admin_first;
        while(admin)
        {
 //printf("clean\n");
@@ -160,11 +182,8 @@ int admin_interface(struct admin_queue **responsep)
                err = -1;
        }
        /* create state response */
-       response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
-       if (!response)
-               return(-1);
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
        memuse++;
-       memset(response, 0, sizeof(admin_queue));
        response->num = 1;
        /* message */
        response->am[0].message = ADMIN_RESPONSE_CMD_INTERFACE;
@@ -236,8 +255,8 @@ int admin_route(struct admin_queue **responsep)
                                case ACTION_EXTERNAL:
                                apppbx->e_action = &action_external;
                                break;
-                               case ACTION_CHAN:
-                               apppbx->e_action = &action_chan;
+                               case ACTION_REMOTE:
+                               apppbx->e_action = &action_remote;
                                break;
                                case ACTION_VBOX_RECORD:
                                apppbx->e_action = &action_vbox;
@@ -254,7 +273,15 @@ int admin_route(struct admin_queue **responsep)
                        apppbx->e_callback = 0;
                        apppbx->e_action = NULL;
                        apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
-                       printlog("%3d  endpoint ADMIN Kicking due to reload of routing.\n", apppbx->ea_endpoint->ep_serial);
+                       start_trace(0,
+                               NULL,
+                               numberrize_callerinfo(apppbx->e_callerinfo.id, apppbx->e_callerinfo.ntype),
+                               apppbx->e_dialinginfo.id,
+                               DIRECTION_NONE,
+                               CATEGORY_EP,
+                               apppbx->ea_endpoint->ep_serial,
+                               "KICK (reload routing)");
+                       end_trace();
                }
 
                apppbx->e_action_timeout = NULL;
@@ -266,11 +293,8 @@ int admin_route(struct admin_queue **responsep)
 
        response:
        /* create state response */
-       response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
-       if (!response)
-               return(-1);
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
        memuse++;
-       memset(response, 0, sizeof(admin_queue));
        response->num = 1;
        /* message */
        response->am[0].message = ADMIN_RESPONSE_CMD_ROUTE;
@@ -296,11 +320,8 @@ int admin_dial(struct admin_queue **responsep, char *message)
        char                    *p;             /* pointer to dialing digits */
 
        /* create state response */
-       response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
-       if (!response)
-               return(-1);
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
        memuse++;
-       memset(response, 0, sizeof(admin_queue));
        response->num = 1;
        /* message */
        response->am[0].message = ADMIN_RESPONSE_CMD_DIAL;
@@ -333,6 +354,114 @@ int admin_dial(struct admin_queue **responsep, char *message)
 
 
 /*
+ * do tracing
+ */
+int admin_trace(struct admin_list *admin, struct admin_trace_req *trace)
+{
+       memcpy(&admin->trace, trace, sizeof(struct admin_trace_req));
+       return(0);
+}
+
+
+/*
+ * do blocking
+ * 
+ * 0 = make port available
+ * 1 = make port administratively blocked
+ * 2 = unload port
+ * the result is returned:
+ * 0 = port is now available
+ * 1 = port is now blocked
+ * 2 = port cannot be loaded or has been unloaded
+ * -1 = port doesn't exist
+ */
+int admin_block(struct admin_queue **responsep, int portnum, int block)
+{
+       struct admin_queue      *response;      /* response pointer */
+       struct interface        *interface;
+       struct interface_port   *ifport;
+
+       /* create block response */
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
+       memuse++;
+       response->num = 1;
+       /* message */
+       response->am[0].message = ADMIN_RESPONSE_CMD_BLOCK;
+       response->am[0].u.x.portnum = portnum;
+
+       /* search for port */
+       interface = interface_first;
+       while(interface)
+       {
+               ifport = interface->ifport;
+               while(ifport)
+               {
+                       if (ifport->portnum == portnum)
+                               break;
+                       ifport = ifport->next;
+               }
+               if (ifport)
+                       break;
+               interface = interface->next;
+       }
+       /* not found, we return -1 */
+       if (!ifport)
+       {
+               response->am[0].u.x.block = -1;
+               response->am[0].u.x.error = 1;
+               SPRINT(response->am[0].u.x.message, "Port %d does not exist.", portnum);
+               goto out;
+       }
+
+       /* no interface */
+       if (!ifport->mISDNport)
+       {
+               /* not loaded anyway */
+               if (block >= 2)
+               {
+                       response->am[0].u.x.block = 2;
+                       goto out;
+               }
+
+               /* try loading interface */
+               ifport->block = block;
+               load_port(ifport);
+
+               /* port cannot load */
+               if (ifport->block >= 2)
+               {
+                       response->am[0].u.x.block = 2;
+                       response->am[0].u.x.error = 1;
+                       SPRINT(response->am[0].u.x.message, "Port %d will not load.", portnum);
+                       goto out;
+               }
+
+               /* port loaded */
+               response->am[0].u.x.block = ifport->block;
+               goto out;
+       }
+
+       /* if we shall unload interface */
+       if (block >= 2)
+       {
+               mISDNport_close(ifport->mISDNport);
+               ifport->mISDNport = 0;
+               ifport->block = 2;
+               goto out;
+       }
+       
+       /* port new blocking state */
+       ifport->block = response->am[0].u.x.block = block;
+
+       out:
+       /* attach to response chain */
+       *responsep = response;
+       responsep = &response->next;
+       return(0);
+}
+
+
+/*
  * do release
  */
 int admin_release(struct admin_queue **responsep, char *message)
@@ -342,11 +471,8 @@ int admin_release(struct admin_queue **responsep, char *message)
        class EndpointAppPBX    *apppbx;
 
        /* create state response */
-       response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
-       if (!response)
-               return(-1);
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
        memuse++;
-       memset(response, 0, sizeof(admin_queue));
        response->num = 1;
        /* message */
        response->am[0].message = ADMIN_RESPONSE_CMD_RELEASE;
@@ -385,14 +511,10 @@ int admin_call(struct admin_list *admin, struct admin_message *msg)
        class Endpoint          *epoint;
        class EndpointAppPBX    *apppbx;
 
-       if (!(epoint = new Endpoint(0,0)))
-               return(-1);
-
-        if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint)))
-        {
-                PERROR("no memory for application\n");
-                exit(-1);
-        }
+       if (!(epoint = new Endpoint(0, 0, 0)))
+               FATAL("No memory for Endpoint instance\n");
+       if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint)))
+               FATAL("No memory for Endpoint Application instance\n");
        apppbx->e_adminid = admin->sockserial;
        admin->epointid = epoint->ep_serial;
        SCPY(apppbx->e_callerinfo.id, nationalize_callerinfo(msg->u.call.callerid, &apppbx->e_callerinfo.ntype));
@@ -409,7 +531,7 @@ int admin_call(struct admin_list *admin, struct admin_message *msg)
        apppbx->e_capainfo.bearer_info1 = msg->u.call.bc_info1;
        apppbx->e_capainfo.hlc = msg->u.call.hlc;
        apppbx->e_capainfo.exthlc = msg->u.call.exthlc;
-       SCPY(apppbx->e_dialinginfo.number, msg->u.call.dialing);
+       SCPY(apppbx->e_dialinginfo.id, msg->u.call.dialing);
        SCPY(apppbx->e_dialinginfo.interfaces, msg->u.call.interface);
        apppbx->e_dialinginfo.sending_complete = 1;
 
@@ -430,7 +552,7 @@ void admin_call_response(int adminid, int message, char *connected, int cause, i
        /* searching for admin id
         * maybe there is no admin instance, because the calling port was not
         * initiated by admin_call */
-       admin = admin_list;
+       admin = admin_first;
        while(admin)
        {
                if (adminid == admin->sockserial)
@@ -450,11 +572,8 @@ void admin_call_response(int adminid, int message, char *connected, int cause, i
        }
 
        /* create state response */
-       response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
-       if (!response)
-               return;
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
        memuse++;
-       memset(response, 0, sizeof(admin_queue));
        response->num = 1;
        /* message */
        response->am[0].message = message;
@@ -472,6 +591,141 @@ void admin_call_response(int adminid, int message, char *connected, int cause, i
 
 
 /*
+ * send data to the remote socket join instance
+ */
+int admin_message_to_join(struct admin_msg *msg, char *remote)
+{
+       class Join                      *join;
+       struct admin_list               *admin;
+
+       /* hello message */
+       if (msg->type == MESSAGE_HELLO)
+       {
+               if (remote[0])
+               {
+                       PERROR("Remote application repeats hello message.\n");
+                       return(-1);
+               }
+               /* look for second application */
+               admin = admin_first;
+               while(admin)
+               {
+                       if (!strcmp(admin->remote, msg->param.hello.application))
+                               break;
+                       admin = admin->next;
+               }
+               if (admin)
+               {
+                       PERROR("Remote application connects twice??? (ignoring)\n");
+                       return(-1);
+               }
+               /* set asterisk socket instance */
+               SCPY(remote, msg->param.hello.application);
+               return(0);
+       }
+
+       /* check we already have no application name */
+       if (!remote[0])
+       {
+               PERROR("Remote application did not send us a hello message.\n");
+               return(-1);
+       }
+
+       /* new join */
+       if (msg->type == MESSAGE_NEWREF)
+       {
+               /* create new join instance */
+               join = new JoinRemote(0, remote); // must have no serial, because no endpoint is connected
+               if (!join)
+                       FATAL("No memory for remote join instance\n");
+               return(0);
+       }
+
+       /* check for ref */
+       if (!msg->ref)
+       {
+               PERROR("Remote application did not send us a valid ref with a message.\n");
+               return(-1);
+       }
+
+       /* find join instance */
+       join = join_first;
+       while(join)
+       {
+               if (join->j_serial == msg->ref)
+                       break;
+               join = join->next;
+       }
+
+       /* check application */
+       if (join->j_type != JOIN_TYPE_REMOTE)
+       {
+               PERROR("Ref %d does not belong to a remote join instance.\n", msg->ref);
+               return(-1);
+       }
+       if (!!strcmp(remote, ((class JoinRemote *)join)->j_remote))
+       {
+               PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, ((class JoinRemote *)join)->j_remote, remote);
+               return(-1);
+       }
+
+       /* send message */
+       ((class JoinRemote *)join)->message_remote(msg->ref, msg->type, &msg->param);
+
+       return(0);
+}
+
+
+/*
+ * this function is called for every message to remote socket
+ */
+int admin_message_from_join(char *remote, unsigned long ref, int message_type, union parameter *param)
+{
+       struct admin_list       *admin;
+       struct admin_queue      *response, **responsep; /* response pointer */
+
+       /* searching for admin id
+        * maybe there is no given remote application
+        */
+       admin = admin_first;
+       while(admin)
+       {
+               if (admin->remote[0] && !strcmp(admin->remote, remote))
+                       break;
+               admin = admin->next;
+       }
+       /* no given remote application connected */
+       if (!admin)
+               return(-1);
+
+       /* seek to end of response list */
+       response = admin->response;
+       responsep = &admin->response;
+       while(response)
+       {
+               responsep = &response->next;
+               response = response->next;
+       }
+
+       /* create state response */
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
+       memuse++;
+       response->num = 1;
+
+       /* message */
+       response->am[0].u.msg.type = message_type;
+       response->am[0].u.msg.ref = ref;
+       memcpy(&response->am[0].u.msg.param, param, sizeof(union parameter));
+
+       /* attach to response chain */
+       *responsep = response;
+       responsep = &response->next;
+
+       return(0);
+}
+
+
+/*
  * do state debugging
  */
 int admin_state(struct admin_queue **responsep)
@@ -479,20 +733,20 @@ int admin_state(struct admin_queue **responsep)
 
        class Port              *port;
        class EndpointAppPBX    *apppbx;
-       class Call              *call;
+       class Join              *join;
        class Pdss1             *pdss1;
+       struct interface        *interface;
+       struct interface_port   *ifport;
        struct mISDNport        *mISDNport;
        int                     i;
        int                     num;
        int                     anybusy;
        struct admin_queue      *response;
+       struct admin_list       *admin;
 
        /* create state response */
-       response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
-       if (!response)
-               return(-1);
+       response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
        memuse++;
-       memset(response, 0, sizeof(admin_queue));
        response->num = 1;
        /* message */
        response->am[0].message = ADMIN_RESPONSE_STATE;
@@ -503,23 +757,38 @@ int admin_state(struct admin_queue **responsep)
        /* log file */
        SCPY(response->am[0].u.s.logfile, options.log);
        /* interface count */
-       mISDNport = mISDNport_first;
        i = 0;
-       while(mISDNport)
+       interface = interface_first;
+       while(interface)
        {
-               i++;
-               mISDNport = mISDNport->next;
+               ifport = interface->ifport;
+               while(ifport)
+               {
+                       i++;
+                       ifport = ifport->next;
+               }
+               interface = interface->next;
        }
        response->am[0].u.s.interfaces = i;
-       /* call count */
-       call = call_first;
+       /* remote connection count */
+       i = 0;
+       admin = admin_first;
+       while(admin)
+       {
+               if (admin->remote[0])
+                       i++;
+               admin = admin->next;
+       }
+       response->am[0].u.s.remotes = i;
+       /* join count */
+       join = join_first;
        i = 0;
-       while(call)
+       while(join)
        {
                i++;
-               call = call->next;
+               join = join->next;
        }
-       response->am[0].u.s.calls = i;
+       response->am[0].u.s.joins = i;
        /* apppbx count */
        apppbx = apppbx_first;
        i = 0;
@@ -530,8 +799,8 @@ int admin_state(struct admin_queue **responsep)
        }
        response->am[0].u.s.epoints = i;
        /* port count */
-       port = port_first;
        i = 0;
+       port = port_first;
        while(port)
        {
                i++;
@@ -543,68 +812,99 @@ int admin_state(struct admin_queue **responsep)
        responsep = &response->next;
 
        /* create response for all interfaces */
-       num = (response->am[0].u.s.interfaces)+(response->am[0].u.s.calls)+(response->am[0].u.s.epoints)+(response->am[0].u.s.ports);
-       response = (struct admin_queue *)malloc(sizeof(admin_queue)+(num*sizeof(admin_message)));
-       if (!response)
-               return(-1);
+       num = (response->am[0].u.s.interfaces)+(response->am[0].u.s.joins)+(response->am[0].u.s.epoints)+(response->am[0].u.s.ports);
+       if (num == 0)
+               return(0);
+       response = (struct admin_queue *)MALLOC(sizeof(admin_queue)+(num*sizeof(admin_message)));
        memuse++;
-       memset(response, 0, sizeof(admin_queue)+(num*sizeof(admin_queue)));
        response->num = num;
        *responsep = response;
        responsep = &response->next;
-       mISDNport = mISDNport_first;
+       interface = interface_first;
        num = 0;
-       while(mISDNport)
+       while(interface)
        {
-               /* message */
-               response->am[num].message = ADMIN_RESPONSE_S_INTERFACE;
-               /* portnum */
-               response->am[num].u.i.portnum = mISDNport->portnum;
-               /* interface */
-               SCPY(response->am[num].u.i.interface_name, mISDNport->interface_name);
-               /* iftype */
-               response->am[num].u.i.iftype = mISDNport->iftype;
-               /* ptp */
-               response->am[num].u.i.ptp = mISDNport->ptp;
-               /* ntmode */
-               response->am[num].u.i.ntmode = mISDNport->ntmode;
-               /* pri */
-               response->am[num].u.i.pri = mISDNport->pri;
-               /* use */
-               response->am[num].u.i.use = mISDNport->use;
-               /* l1link */
-               response->am[num].u.i.l1link = mISDNport->l1link;
-               /* l2link */
-               response->am[num].u.i.l2link = mISDNport->l2link;
-               /* channels */
-               response->am[num].u.i.channels = mISDNport->b_num;
-               /* channel info */
-               i = 0;
-               anybusy = 0;
-               while(i < mISDNport->b_num)
+               ifport = interface->ifport;
+               while(ifport)
                {
-                       response->am[num].u.i.busy[i] = mISDNport->b_state[i];
-                       if (mISDNport->b_port[i])
-                               response->am[num].u.i.port[i] = mISDNport->b_port[i]->p_serial;
-                       i++;
+                       /* message */
+                       response->am[num].message = ADMIN_RESPONSE_S_INTERFACE;
+                       /* interface */
+                       SCPY(response->am[num].u.i.interface_name, interface->name);
+                       /* portnum */
+                       response->am[num].u.i.portnum = ifport->portnum;
+                       /* iftype */
+                       response->am[num].u.i.extension = interface->extension;
+                       /* block */
+                       response->am[num].u.i.block = ifport->block;
+                       if (ifport->mISDNport)
+                       {
+                               mISDNport = ifport->mISDNport;
+
+                               /* ptp */
+                               response->am[num].u.i.ptp = mISDNport->ptp;
+                               /* ntmode */
+                               response->am[num].u.i.ntmode = mISDNport->ntmode;
+                               /* pri */
+                               response->am[num].u.i.pri = mISDNport->pri;
+                               /* use */
+                               response->am[num].u.i.use = mISDNport->use;
+                               /* l1link */
+                               response->am[num].u.i.l1link = mISDNport->l1link;
+                               /* l2link */
+                               response->am[num].u.i.l2link = mISDNport->l2link;
+                               /* channels */
+                               response->am[num].u.i.channels = mISDNport->b_num;
+                               /* channel info */
+                               i = 0;
+                               anybusy = 0;
+                               while(i < mISDNport->b_num)
+                               {
+                                       response->am[num].u.i.busy[i] = mISDNport->b_state[i];
+                                       if (mISDNport->b_port[i])
+                                               response->am[num].u.i.port[i] = mISDNport->b_port[i]->p_serial;
+                                       i++;
+                               }
+                       }
+                       num++;
+
+                       ifport = ifport->next;
                }
-               mISDNport = mISDNport->next;
-               num++;
+               interface = interface->next;
        }
 
-       /* create response for all calls */
-       call = call_first;
-       while(call)
+       /* create response for all remotes */
+       admin = admin_first;
+       while(admin)
+       {
+               if (admin->remote[0])
+               {
+                       /* message */
+                       response->am[num].message = ADMIN_RESPONSE_S_REMOTE;
+                       /* name */
+                       SCPY(response->am[num].u.r.name, admin->remote);
+                       /* */
+                       num++;
+               }
+               admin = admin->next;
+       }
+
+       /* create response for all joins */
+       join = join_first;
+       while(join)
        {
                /* message */
-               response->am[num].message = ADMIN_RESPONSE_S_CALL;
+               response->am[num].message = ADMIN_RESPONSE_S_JOIN;
                /* serial */
-               response->am[num].u.c.serial = call->c_serial;
+               response->am[num].u.j.serial = join->j_serial;
                /* partyline */
-               if (call->c_type == CALL_TYPE_PBX)
-                       response->am[num].u.c.partyline = ((class CallPBX *)call)->c_partyline;
+               if (join->j_type == JOIN_TYPE_PBX)
+                       response->am[num].u.j.partyline = ((class JoinPBX *)join)->j_partyline;
+               /* remote application */
+               if (join->j_type == JOIN_TYPE_REMOTE)
+                       SCPY(response->am[num].u.j.remote, ((class JoinRemote *)join)->j_remote);
                /* */
-               call = call->next;
+               join = join->next;
                num++;
        }
 
@@ -616,8 +916,8 @@ int admin_state(struct admin_queue **responsep)
                response->am[num].message = ADMIN_RESPONSE_S_EPOINT;
                /* serial */
                response->am[num].u.e.serial = apppbx->ea_endpoint->ep_serial;
-               /* call */
-               response->am[num].u.e.call = apppbx->ea_endpoint->ep_call_id;
+               /* join */
+               response->am[num].u.e.join = apppbx->ea_endpoint->ep_join_id;
                /* rx notification */
                response->am[num].u.e.rx_state = apppbx->e_rx_state;
                /* tx notification */
@@ -662,11 +962,11 @@ int admin_state(struct admin_queue **responsep)
                        response->am[num].u.e.state = ADMIN_STATE_IDLE;
                }
                /* terminal */
-               SCPY(response->am[num].u.e.terminal, apppbx->e_terminal);
+               SCPY(response->am[num].u.e.terminal, apppbx->e_ext.number);
                /* callerid */
                SCPY(response->am[num].u.e.callerid, apppbx->e_callerinfo.id);
                /* dialing */
-               SCPY(response->am[num].u.e.dialing, apppbx->e_dialinginfo.number);
+               SCPY(response->am[num].u.e.dialing, apppbx->e_dialinginfo.id);
                /* action string */
                if (apppbx->e_action)
                        SCPY(response->am[num].u.e.action, action_defs[apppbx->e_action->index].name);
@@ -776,26 +1076,21 @@ int admin_handle(void)
        {
                work = 1;
                /* insert new socket */
-               admin = (struct admin_list *)malloc(sizeof(struct admin_list));
-               if (admin)
+               admin = (struct admin_list *)MALLOC(sizeof(struct admin_list));
+               if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0)
                {
-                       if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0)
-                       {
 //#warning
 //     PERROR("DEBUG incomming socket %d, serial=%d\n", new_sock, sockserial);
-                               memuse++;
-                               fhuse++;
-                               memset(admin, 0, sizeof(struct admin_list));
-                               admin->sockserial = sockserial++;
-                               admin->next = admin_list;
-                               admin_list = admin;
-                               admin->sock = new_sock;
-                       } else {
-                               close(new_sock);
-                               free(admin);
-                       }
-               } else
+                       memuse++;
+                       fhuse++;
+                       admin->sockserial = sockserial++;
+                       admin->next = admin_first;
+                       admin_first = admin;
+                       admin->sock = new_sock;
+               } else {
                        close(new_sock);
+                       FREE(admin, sizeof(struct admin_list));
+               }
        } else
        {
                if (errno != EWOULDBLOCK)
@@ -807,8 +1102,8 @@ int admin_handle(void)
        }
 
        /* loop all current socket connections */
-       admin = admin_list;
-       adminp = &admin_list;
+       admin = admin_first;
+       adminp = &admin_first;
        while(admin)
        {
                /* read command */
@@ -851,7 +1146,7 @@ int admin_handle(void)
                        *adminp = admin->next;
                        free_connection(admin);
                        admin = *adminp;
-//PERROR("DEBUG (admin_list=%x)\n", admin_list);
+//PERROR("DEBUG (admin_first=%x)\n", admin_first);
                        continue;
                }
                if (len != sizeof(msg))
@@ -911,15 +1206,29 @@ int admin_handle(void)
                                PERROR("Failed to create state response for socket %d.\n", admin->sock);
                                goto response_error;
                        }
-                       case ADMIN_REQUEST_MESSAGE:
-                       if (admin_message(&admin->response) < 0)
+                       break;
+
+                       case ADMIN_TRACE_REQUEST:
+                       if (admin_trace(admin, &msg.u.trace_req) < 0)
                        {
-                               PERROR("Failed to create message response for socket %d.\n", admin->sock);
-                               response_error:
-                               *adminp = admin->next;
-                               free_connection(admin);
-                               admin = *adminp;
-                               continue;
+                               PERROR("Failed to create trace response for socket %d.\n", admin->sock);
+                               goto response_error;
+                       }
+                       break;
+
+                       case ADMIN_REQUEST_CMD_BLOCK:
+                       if (admin_block(&admin->response, msg.u.x.portnum, msg.u.x.block) < 0)
+                       {
+                               PERROR("Failed to create block response for socket %d.\n", admin->sock);
+                               goto response_error;
+                       }
+                       break;
+
+                       case ADMIN_MESSAGE:
+                       if (admin_message_to_join(&msg.u.msg, admin->remote) < 0)
+                       {
+                               PERROR("Failed to deliver message for socket %d.\n", admin->sock);
+                               goto response_error;
                        }
 #if 0
 #warning DEBUGGING
@@ -938,10 +1247,14 @@ int admin_handle(void)
                        break;
 
                        case ADMIN_CALL_SETUP:
-                       if (admin_call(admin, &msg))
+                       if (admin_call(admin, &msg) < 0)
                        {
                                PERROR("Failed to create call for socket %d.\n", admin->sock);
-                               goto response_error;
+                               response_error:
+                               *adminp = admin->next;
+                               free_connection(admin);
+                               admin = *adminp;
+                               continue;
                        }
                        break;
 
@@ -979,7 +1292,7 @@ int admin_handle(void)
                        {
                                temp = admin->response;
                                admin->response = admin->response->next;
-                               free(temp);
+                               FREE(temp, 0);
                                memuse--;
                        }
                }