#*****************************************************************************/
WITH-CRYPTO = 42 # comment this out, if no libcrypto should be used
+WITH-ASTERISK = 42 # comment this out, if you don't require built-in Asterisk channel driver.
# note: check your location and the names of libraries.
# select location to install
WIZZARD = ./wizzard
LCR = ./lcr
LCRADMIN = ./lcradmin
+ifdef WITH-ASTERISK
+CHAN_LCR = ./chan_lcr
+endif
LCRWATCH = ./lcrwatch
GEN = ./gentones
GENW = ./genwave
# @echo Please report any bug. To compile use \"make beta\".
# @exit
-all: $(LCR) $(LCRADMIN) $(GEN) $(GENW) $(GENRC) $(GENEXT)
+all: $(LCR) $(LCRADMIN) $(CHAN_LCR) $(GEN) $(GENW) $(GENRC) $(GENEXT)
@sh -c 'grep -n strcpy *.c* ; if test $$''? = 0 ; then echo "dont use strcpy, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n strncpy *.c* ; if test $$''? = 0 ; then echo "dont use strncpy, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n strcat *.c* ; if test $$''? = 0 ; then echo "dont use strcat, use makro instead." ; exit -1 ; fi'
callpbx.o: callpbx.cpp *.h Makefile
$(CC) -c $(CFLAGS) callpbx.cpp -o callpbx.o
-callchan.o: callchan.cpp *.h Makefile
- $(CC) -c $(CFLAGS) callchan.cpp -o callchan.o
+callasterisk.o: callasterisk.cpp *.h Makefile
+ $(CC) -c $(CFLAGS) callasterisk.cpp -o callasterisk.o
cause.o: cause.c *.h Makefile
$(CC) -c $(CFLAGS) cause.c -o cause.o
genext.o: genext.c *.h Makefile
$(CC) -c $(CFLAGS) genext.c -o genext.o
-#admin_client.o: admin_client.c *.h Makefile
-# $(CC) -c $(CFLAGS) admin_client.c -o admin_client.o
-
admin_server.o: admin_server.c *.h Makefile
$(CC) -c $(CFLAGS) admin_server.c -o admin_server.o
mail.o \
call.o \
callpbx.o \
- callchan.o \
+ callasterisk.o \
admin_server.o \
trace.o
$(LD) $(LIBDIR) \
mail.o \
call.o \
callpbx.o \
- callchan.o \
+ callasterisk.o \
admin_server.o \
trace.o \
$(LIBS) -o $(LCR)
$(CC) $(LIBDIR) $(CFLAGS) $(CURSES) -lm admin_client.c cause.c \
-o $(LCRADMIN)
+$(CHAN_LCR): asterisk_client.c *.h Makefile
+ $(CC) $(LIBDIR) $(CFLAGS) $(CURSES) -lm asterisk_client.c \
+ -o $(CHAN_LCR)
+
$(LCRWATCH): watch.c *.h Makefile
$(CC) $(LIBDIR) $(CFLAGS) -lm watch.c \
-o $(LCRWATCH)
-killall -9 -w -q lcr # the following error must be ignored
cp $(LCR) $(INSTALL_BIN)
cp $(LCRADMIN) $(INSTALL_BIN)
+ifdef WITH_ASTERISK
+ cp $(CHAN_LCR) $(INSTALL_BIN)
+endif
# cp $(LCRWATCH) $(INSTALL_BIN)
cp $(GEN) $(INSTALL_BIN)
cp $(GENW) $(INSTALL_BIN)
clean:
touch *
- rm -f $(LCR) $(LCRADMIN) $(LCRWATCH) $(GEN) $(GENW) $(GENRC) $(GENEXT)
+ rm -f $(LCR) $(LCRADMIN) $(CHAN_LCR) $(LCRWATCH) $(GEN) $(GENW) $(GENRC) $(GENEXT)
rm -f *.o
rm -f .*.c.sw* .*.cpp.sw* .*.h.sw*
rm -f bla nohup.out
-Read the documentation at ./doc/ and visit http://www.linux-call-router.de
+Read the documentation at http://www.linux-call-router.de
Changes in Version 20021228
- Timeout condition seems to work now.
- Timeout action seems to work now.
+New Verion for new name: LCR
+
+Changes in Version 1.0
+- Statefull b-channel open and closing
+- Rebuild audio flow
+ Made much simpler
+ Preloading and keeping transmit buffer for seamless tones and patterns.
+ Recording of what is actually transmitted and received by party.
+- Logging is replaced by trace
+- New isdn interface and port structure with many features
+ Interfaces can be changed at runtime.
+ Interfaces can be loaded and unloaded at runtime.
+- mISDN stack fixes
+- DDI in and out on all stacks
+- Layer 1 over IP supports interconnection via IP
+- Rebuild line and b-channel hunting with individual lists
+- Screen lists for changing caller IDs
+- Asterisk channel driver integrated
+- Multiplexing calls to multiple extensions
+- Removed all VoIP stuff to make core fast and stable (Use Asterisk for VoIP.)
+- Many bug fixes
+- Many minor improvements
+- New bugs of course...
/*
- * process init 'internal' / 'external' / 'chan' / 'vbox-record' / 'partyline'...
+ * process init 'internal' / 'external' / 'asterisk' / 'vbox-record' / 'partyline'...
*/
-void EndpointAppPBX::_action_init_call(int chan)
+void EndpointAppPBX::_action_init_call(int asterisk)
{
class Call *call;
struct port_list *portlist = ea_endpoint->ep_portlist;
+ struct admin_list *admin;
/* a created call, this should never happen */
if (ea_endpoint->ep_call_id)
/* create call */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new call instance.\n", ea_endpoint->ep_serial);
- if (chan)
- call = new CallChan(ea_endpoint);
+ if (asterisk)
+ {
+ admin = admin_list;
+ while(admin)
+ {
+ if (admin->asterisk)
+ break;
+ admin = admin->next;
+ }
+ if (!admin)
+ {
+ /* resource not available */
+ message_disconnect_port(portlist, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
+ new_state(EPOINT_STATE_OUT_DISCONNECT);
+ set_tone(portlist,"cause_22");
+ return;
+ }
+ call = new CallAsterisk(ea_endpoint->ep_serial);
+ }
else
call = new CallPBX(ea_endpoint);
if (!call)
- {
- /* resource not available */
- message_disconnect_port(portlist, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
- new_state(EPOINT_STATE_OUT_DISCONNECT);
- set_tone(portlist,"cause_22");
- return;
- }
+ FATAL("No memoy for Call instance.\n");
ea_endpoint->ep_call_id = call->c_serial;
}
void EndpointAppPBX::action_init_call(void)
/* create call */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new call instance.\n", ea_endpoint->ep_serial);
if (!(call = new CallPBX(ea_endpoint)))
- {
- PERROR("no memory for call, exitting");
- exit(-1);
- }
+ FATAL("No memory for Call object\n");
} else
{
//NOTE: callpbx must be set here
/* add relation to existing call */
if (!(relation=callpbx->add_relation()))
- {
- PERROR("no memory for call relation, exitting");
- exit(-1);
- }
+ FATAL("No memory for Call relation\n");
relation->type = RELATION_TYPE_SETUP;
relation->channel_state = CHANNEL_STATE_CONNECT;
relation->rx_state = NOTIFY_STATE_ACTIVE;
int l1link; /* down(0) or up(1) */
int l2link; /* down(0) or up(1) */
int channels;
- int busy[256]; /* if port is idle(0) busy(1) */
+ char busy[256]; /* if port is idle(0) busy(1) */
unsigned long port[256]; /* current port */
};
char text[1024];
};
-//struct admin_msg {
-// int type; /* type of message */
-// unsigned long ref; /* reference to individual endpoints */
-// union parameter param; /* parameter union */
-//};
+struct admin_msg {
+ int type; /* type of message */
+ unsigned long ref; /* reference to individual endpoints */
+ union parameter param; /* parameter union */
+};
struct admin_message {
int message; /* type of admin message */
struct admin_response_epoint e;
struct admin_response_call c;
struct admin_call call;
-// struct admin_msg msg;
+ struct admin_msg msg;
struct admin_trace_req trace_req;
struct admin_trace_rsp trace_rsp;
} u;
#include <sys/socket.h>
#include <sys/un.h>
#include <curses.h>
-#include "save.h"
+#include "macro.h"
#include "call.h"
#include "callpbx.h"
+#include "extension.h"
+#include "message.h"
#include "admin.h"
#include "cause.h"
return("Response not valid. Expecting state response.");
}
num = msg.u.s.interfaces + msg.u.s.calls + msg.u.s.epoints + msg.u.s.ports;
- if (!(m = (struct admin_message *)malloc(num*sizeof(struct admin_message))))
- {
- cleanup_curses();
- return("Not enough memory for messages.");
- }
+ m = (struct admin_message *)MALLOC(num*sizeof(struct admin_message));
off=0;
if (num)
{
if ((len = read(sock, ((unsigned char *)(m))+off, num*sizeof(struct admin_message)-off)) != num*(int)sizeof(struct admin_message)-off)
{
if (len <= 0) {
- free(m);
+ FREE(m, 0);
// fprintf(stderr, "got=%d expected=%d\n", i, num*sizeof(struct admin_message));
cleanup_curses();
return("Broken pipe while receiving state infos.");
// fprintf(stderr, "j=%d message=%d\n", j, m[j].message);
if (m[j].message != ADMIN_RESPONSE_S_INTERFACE)
{
- free(m);
+ FREE(m, 0);
cleanup_curses();
return("Response not valid. Expecting interface information.");
}
{
if (m[j].message != ADMIN_RESPONSE_S_CALL)
{
- free(m);
+ FREE(m, 0);
cleanup_curses();
return("Response not valid. Expecting call information.");
}
{
if (m[j].message != ADMIN_RESPONSE_S_EPOINT)
{
- free(m);
+ FREE(m, 0);
cleanup_curses();
return("Response not valid. Expecting endpoint information.");
}
{
if (m[j].message != ADMIN_RESPONSE_S_PORT)
{
- free(m);
+ FREE(m, 0);
cleanup_curses();
return("Response not valid. Expecting port information.");
}
end:
/* free memory */
- free(m);
+ FREE(m, 0);
/* display name/time */
// move(0, 0);
// hline(' ', COLS);
/*
* free connection
+ * also releases all asterisk joins
*/
void free_connection(struct admin_list *admin)
{
struct admin_queue *response;
void *temp;
+ union parameter param;
+ class Call *call, *callnext;
+
+ /* free asterisk joins */
+ if (admin->asterisk)
+ {
+ call = call_first;
+ while(call)
+ {
+ callnext = call->next;
+ if (call->c_type == CALL_TYPE_ASTERISK)
+ {
+ memset(¶m, 0, sizeof(param));
+ param.disconnectinfo.cause = CAUSE_OUTOFORDER;
+ param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ ((class CallAsterisk *)call)->message_asterisk(0, MESSAGE_RELEASE, ¶m);
+ /* call is now destroyed, so we go to next call */
+ }
+ call = callnext;
+ }
+ }
if (admin->sock >= 0)
{
//#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--;
}
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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_INTERFACE;
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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_ROUTE;
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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_DIAL;
struct interface_port *ifport;
/* create block 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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_BLOCK;
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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_RELEASE;
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));
}
/* 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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = message;
/*
+ * send data to the asterisk join instance
+ */
+int admin_message_to_join(struct admin_msg *msg)
+{
+ class Call *call;
+ struct admin_list *admin;
+
+ /* dummy callref means: asterisk is here */
+ if (msg->type == MESSAGE_HELLO)
+ {
+ /* look for second asterisk */
+ admin = admin_list;
+ while(admin)
+ {
+ if (admin->asterisk)
+ break;
+ admin = admin->next;
+ }
+ if (admin)
+ {
+ PERROR("Asterisk connects twice??? (ignoring)\n");
+ return(-1);
+ }
+ /* set asterisk socket instance */
+ admin->asterisk = 1;
+ }
+
+ /* find call instance */
+ call = call_first;
+ while(call)
+ {
+ if (call->c_serial == msg->ref)
+ break;
+ call = call->next;
+ }
+
+ /* create call instance if not existing */
+ if (!call)
+ {
+ if (msg->ref < 2000000000)
+ {
+ PERROR("Asterisk sends us unknown ref %d below 2000000000.\n", msg->ref);
+ return(-1);
+ }
+
+ /* create new call instance */
+ call = new CallAsterisk(0); // must have no serial, because no endpoint is connected
+ if (!call)
+ FATAL("No memory for Asterisk Call instance\n");
+ }
+
+ /* send message */
+ if (call->c_type != CALL_TYPE_ASTERISK)
+ FATAL("Call instance %d must be of type Call Asterisk\n", call->c_serial);
+ ((class CallAsterisk *)call)->message_asterisk(msg->ref, msg->type, &msg->param);
+
+ return(0);
+}
+
+
+/*
+ * this function is called for every message to asterisk
+ */
+int admin_message_from_join(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 asterisk instance
+ */
+ admin = admin_list;
+ while(admin)
+ {
+ if (admin->asterisk)
+ break;
+ admin = admin->next;
+ }
+ /* no asterisk 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)
struct admin_queue *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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_STATE;
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);
if (num == 0)
return(0);
- response = (struct admin_queue *)malloc(sizeof(admin_queue)+(num*sizeof(admin_message)));
- if (!response)
- return(-1);
+ response = (struct admin_queue *)MALLOC(sizeof(admin_queue)+(num*sizeof(admin_message)));
memuse++;
- memset(response, 0, sizeof(admin_queue)+(num*sizeof(admin_message)));
response->num = num;
*responsep = response;
responsep = &response->next;
{
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_list;
+ admin_list = admin;
+ admin->sock = new_sock;
+ } else {
close(new_sock);
+ FREE(admin, sizeof(struct admin_list));
+ }
} else
{
if (errno != EWOULDBLOCK)
}
break;
-#warning interface tbd
-#if 0
case ADMIN_MESSAGE:
- if (admin_message(&admin->response) < 0)
+ if (admin_message_to_join(&msg.u.msg) < 0)
{
- PERROR("Failed to create message response for socket %d.\n", admin->sock);
+ PERROR("Failed to deliver message for socket %d.\n", admin->sock);
goto response_error;
}
-#endif
#if 0
#warning DEBUGGING
{
{
temp = admin->response;
admin->response = admin->response->next;
- free(temp);
+ FREE(temp, 0);
memuse--;
}
}
struct admin_list *next;
int sock;
int sockserial;
+ int asterisk; /* socket is connected to asterisk */
struct admin_trace_req trace; /* stores trace, if detail != 0 */
unsigned long epointid;
struct admin_queue *response;
void admin_cleanup(void);
int admin_handle(void);
void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify);
+int admin_message_to_join(struct admin_message *msg);
+int admin_message_from_join(unsigned long ref, int message_type, union parameter *param);
/*****************************************************************************\
** **
-** PBX4Linux **
+** LCR **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
temp = temp->next;
}
if (temp == 0)
- {
- PERROR("error: endpoint not in endpoint's list, exitting.\n");
- exit(-1);
- }
+ FATAL("Endpoint not in endpoint's list.\n");
*tempp = next;
}
/* screen caller id
* out==0: incomming caller id, out==1: outgoing caller id
*/
-void EndpointAppPBX::screen(int out, char *id, int idsize, int *type, int *present)
+void EndpointAppPBX::screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
{
- struct interface *interface;
char *msn1;
struct interface_msn *ifmsn;
struct interface_screen *ifscreen;
char suffix[64];
- interface = interface_first;
- while(interface)
+ /* screen incoming caller id */
+ if (!out)
{
- if (!strcmp(e_callerinfo.interface, interface->name))
+ /* check for MSN numbers, use first MSN if no match */
+ msn1 = NULL;
+ ifmsn = interface->ifmsn;
+ while(ifmsn)
{
- break;
+ if (!msn1)
+ msn1 = ifmsn->msn;
+ if (!strcmp(ifmsn->msn, id))
+ {
+ break;
+ }
+ ifmsn = ifmsn->next;
+ }
+ if (ifmsn)
+ {
+ trace_header("SCREEN (found in list)", DIRECTION_IN);
+ add_trace("msn", NULL, "%s", id);
+ end_trace();
+ }
+ if (!ifmsn && msn1) // not in list, first msn given
+ {
+ trace_header("SCREEN (not found in list)", DIRECTION_IN);
+ add_trace("msn", "given", "%s", id);
+ add_trace("msn", "used", "%s", msn1);
+ end_trace();
+ UNCPY(id, msn1, idsize);
+ id[idsize-1] = '\0';
}
- interface = interface->next;
}
- if (interface)
+
+ /* check screen list */
+ if (out)
+ ifscreen = interface->ifscreen_out;
+ else
+ ifscreen = interface->ifscreen_in;
+ while (ifscreen)
{
- /* screen incoming caller id */
- if (!out)
+ if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
+ if (ifscreen->match_present==-1 || ifscreen->match_present==*present)
{
- /* check for MSN numbers, use first MSN if no match */
- msn1 = NULL;
- ifmsn = interface->ifmsn;
- while(ifmsn)
+ if (strchr(ifscreen->match,'%'))
{
- if (!msn1)
- msn1 = ifmsn->msn;
- if (!strcmp(ifmsn->msn, id))
- {
+ if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
break;
- }
- ifmsn = ifmsn->next;
- }
- if (ifmsn)
- {
- trace_header("SCREEN (found in list)", DIRECTION_IN);
- add_trace("msn", NULL, "%s", id);
- end_trace();
- }
- if (!ifmsn && msn1) // not in list, first msn given
+ } else
{
- trace_header("SCREEN (not found in list)", DIRECTION_IN);
- add_trace("msn", "given", "%s", id);
- add_trace("msn", "used", "%s", msn1);
- end_trace();
- UNCPY(id, msn1, idsize);
- id[idsize-1] = '\0';
+ if (!strcmp(ifscreen->match, id))
+ break;
}
}
-
- /* check screen list */
- if (out)
- ifscreen = interface->ifscreen_out;
- else
- ifscreen = interface->ifscreen_in;
- while (ifscreen)
+ ifscreen = ifscreen->next;
+ }
+ if (ifscreen) // match
+ {
+ trace_header("SCREEN (found in list)", out?DIRECTION_OUT:DIRECTION_IN);
+ switch(*type)
{
- if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
- if (ifscreen->match_present==-1 || ifscreen->match_present==*present)
- {
- if (strchr(ifscreen->match,'%'))
- {
- if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
- break;
- } else
- {
- if (!strcmp(ifscreen->match, id))
- break;
- }
- }
- ifscreen = ifscreen->next;
+ case INFO_NTYPE_UNKNOWN:
+ add_trace("given", "type", "unknown");
+ break;
+ case INFO_NTYPE_SUBSCRIBER:
+ add_trace("given", "type", "subscriber");
+ break;
+ case INFO_NTYPE_NATIONAL:
+ add_trace("given", "type", "national");
+ break;
+ case INFO_NTYPE_INTERNATIONAL:
+ add_trace("given", "type", "international");
+ break;
+ }
+ switch(*present)
+ {
+ case INFO_PRESENT_ALLOWED:
+ add_trace("given", "present", "allowed");
+ break;
+ case INFO_PRESENT_RESTRICTED:
+ add_trace("given", "present", "restricted");
+ break;
+ case INFO_PRESENT_NOTAVAIL:
+ add_trace("given", "present", "not available");
+ break;
}
- if (ifscreen) // match
+ add_trace("given", "id", "%s", id[0]?id:"<empty>");
+ if (ifscreen->result_type != -1)
{
- trace_header("SCREEN (found in list)", out?DIRECTION_OUT:DIRECTION_IN);
+ *type = ifscreen->result_type;
switch(*type)
{
case INFO_NTYPE_UNKNOWN:
- add_trace("given", "type", "unknown");
+ add_trace("used", "type", "unknown");
break;
case INFO_NTYPE_SUBSCRIBER:
- add_trace("given", "type", "subscriber");
+ add_trace("used", "type", "subscriber");
break;
case INFO_NTYPE_NATIONAL:
- add_trace("given", "type", "national");
+ add_trace("used", "type", "national");
break;
case INFO_NTYPE_INTERNATIONAL:
- add_trace("given", "type", "international");
+ add_trace("used", "type", "international");
break;
}
+ }
+ if (ifscreen->result_present != -1)
+ {
+ *present = ifscreen->result_present;
switch(*present)
{
case INFO_PRESENT_ALLOWED:
- add_trace("given", "present", "allowed");
+ add_trace("used", "present", "allowed");
break;
case INFO_PRESENT_RESTRICTED:
- add_trace("given", "present", "restricted");
+ add_trace("used", "present", "restricted");
break;
case INFO_PRESENT_NOTAVAIL:
- add_trace("given", "present", "not available");
+ add_trace("used", "present", "not available");
break;
}
- add_trace("given", "id", "%s", id[0]?id:"<empty>");
- if (ifscreen->result_type != -1)
- {
- *type = ifscreen->result_type;
- switch(*type)
- {
- case INFO_NTYPE_UNKNOWN:
- add_trace("used", "type", "unknown");
- break;
- case INFO_NTYPE_SUBSCRIBER:
- add_trace("used", "type", "subscriber");
- break;
- case INFO_NTYPE_NATIONAL:
- add_trace("used", "type", "national");
- break;
- case INFO_NTYPE_INTERNATIONAL:
- add_trace("used", "type", "international");
- break;
- }
- }
- if (ifscreen->result_present != -1)
- {
- *present = ifscreen->result_present;
- switch(*present)
- {
- case INFO_PRESENT_ALLOWED:
- add_trace("used", "present", "allowed");
- break;
- case INFO_PRESENT_RESTRICTED:
- add_trace("used", "present", "restricted");
- break;
- case INFO_PRESENT_NOTAVAIL:
- add_trace("used", "present", "not available");
- break;
- }
- }
- if (strchr(ifscreen->match,'%'))
- {
- SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
- UNCPY(id, ifscreen->result, idsize);
- id[idsize-1] = '\0';
- if (strchr(ifscreen->result,'%'))
- {
- *strchr(ifscreen->result,'%') = '\0';
- UNCAT(id, suffix, idsize);
- id[idsize-1] = '\0';
- }
- } else
+ }
+ if (strchr(ifscreen->match,'%'))
+ {
+ SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
+ UNCPY(id, ifscreen->result, idsize);
+ id[idsize-1] = '\0';
+ if (strchr(ifscreen->result,'%'))
{
- UNCPY(id, ifscreen->result, idsize);
+ *strchr(ifscreen->result,'%') = '\0';
+ UNCAT(id, suffix, idsize);
id[idsize-1] = '\0';
}
- add_trace("used", "id", "%s", id[0]?id:"<empty>");
- end_trace();
+ } else
+ {
+ UNCPY(id, ifscreen->result, idsize);
+ id[idsize-1] = '\0';
}
+ add_trace("used", "id", "%s", id[0]?id:"<empty>");
+ end_trace();
}
}
struct port_list *portlist;
struct message *message;
char cause[16];
- class Call *call;
/* message to test call */
admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", callcause, calllocation, 0);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (callcause %d location %d)\n", ea_endpoint->ep_serial, callcause, calllocation);
if (ea_endpoint->ep_call_id)
{
- call = find_call_id(ea_endpoint->ep_call_id);
- if (call)
- call->release(ea_endpoint->ep_serial, 0, calllocation, callcause);
+ message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = callcause;
+ message->param.disconnectinfo.location = calllocation;
+ message_put(message);
+ ea_endpoint->ep_call_id = 0;
}
- ea_endpoint->ep_call_id = 0;
e_call_pattern = 0;
#if 0
if (release != RELEASE_PORT_CALLONLY)
goto portbusy;
}
- /* see if link is up */
+ /* see if link is up on PTP*/
if (mISDNport->ptp && !mISDNport->l2link)
{
trace_header("CHANNEL SELECTION (port is ptp with layer 2 down, skipping)", DIRECTION_NONE);
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
if (!port)
- {
- PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port '%s' failed to create\n", ea_endpoint->ep_serial, mISDNport->ifport->interface->name);
- goto check_anycall_intern;
- }
+ FATAL("No memory for DSS1 Port instance\n");
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
memset(&dialinginfo, 0, sizeof(dialinginfo));
SCPY(dialinginfo.id, e_dialinginfo.id);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
/* alloc port */
if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
- {
- PERROR("EPOINT(%d) no mem for port\n", ea_endpoint->ep_serial);
- break;
- }
+ FATAL("No memory for VBOX Port instance\n");
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
} else
{
/* creating EXTERNAL port*/
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
- port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
+ if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force)))
+ FATAL("No memory for DSS1 Port instance\n");
earlyb = mISDNport->earlyb;
} else
{
/* hunt for mISDNport and create Port */
/* hunt for mISDNport and create Port */
mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
- if (mISDNport)
- {
- /* creating EXTERNAL port*/
- SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
- port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
- earlyb = mISDNport->earlyb;
- } else
+ if (!mISDNport)
{
trace_header("INTERFACE (too busy)", DIRECTION_NONE);
add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
end_trace();
goto check_anycall_extern;
}
- if (!port)
- {
- PERROR("EPOINT(%d) no memory for external port, exitting\n", ea_endpoint->ep_serial);
- exit(-1);
- }
+ /* creating EXTERNAL port*/
+ SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
+ if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force)))
+ FATAL("No memory for DSS1 Port instance\n");
+ earlyb = mISDNport->earlyb;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
memset(&dialinginfo, 0, sizeof(dialinginfo));
SCPY(dialinginfo.id, number);
char buffer[256];
int writeext; /* flags need to write extension after modification */
class Port *port;
+ struct interface *interface;
portlist->port_type = param->setup.port_type;
memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
e_dtmf = param->setup.dtmf;
/* screen incoming caller id */
- screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present);
+ interface = interface_first;
+ while(interface)
+ {
+ if (!strcmp(e_callerinfo.interface, interface->name))
+ {
+ break;
+ }
+ interface = interface->next;
+ }
+ if (interface)
+ screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
/* process extension */
if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
unsigned long port_id = portlist->port_id;
struct port_list *tportlist;
class Port *port;
+ struct interface *interface;
/* signal to call tool */
admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype), 0, 0, 0);
if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
tportlist = tportlist->next;
if (tportlist->port_id == port_id)
- {
- PERROR("EPOINT(%d) software error: this should not happen since the portlist list must not have two links to the same port - exitting.\n");
- exit(-1);
- }
+ FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
- message->param.disconnectinfo.cause = 26; /* non selected user clearing */
+ message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
logmessage(message);
e_start = now;
/* screen incoming connected id */
- screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present);
+ interface = interface_first;
+ while(interface)
+ {
+ if (!strcmp(e_connectinfo.interface, interface->name))
+ {
+ break;
+ }
+ interface = interface->next;
+ }
+ if (interface)
+ screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
/* screen connected name */
if (e_ext.name[0])
SCPY(e_connectinfo.extension, e_ext.number);
/* we store the connected port number */
- SCPY(e_extension_interface, e_connectinfo.interfaces);
+ SCPY(e_extension_interface, e_connectinfo.interface);
/* for internal and am calls, we get the extension's id */
if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE)
/* collect cause */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current multipoint cause %d location %d, received cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
- if (param->disconnectinfo.cause == CAUSE_REJECTED) /* call rejected */
- {
- e_multipoint_cause = CAUSE_REJECTED;
- e_multipoint_location = param->disconnectinfo.location;
- } else
- if (param->disconnectinfo.cause==CAUSE_NORMAL && e_multipoint_cause!=CAUSE_REJECTED) /* reject via hangup */
- {
- e_multipoint_cause = CAUSE_NORMAL;
- e_multipoint_location = param->disconnectinfo.location;
- } else
- if (param->disconnectinfo.cause==CAUSE_BUSY && e_multipoint_cause!=CAUSE_REJECTED && e_multipoint_cause!=CAUSE_NORMAL) /* busy */
- {
- e_multipoint_cause = CAUSE_BUSY;
- e_multipoint_location = param->disconnectinfo.location;
- } else
- if (param->disconnectinfo.cause==CAUSE_OUTOFORDER && e_multipoint_cause!=CAUSE_BUSY && e_multipoint_cause!=CAUSE_REJECTED && e_multipoint_cause!=CAUSE_NORMAL) /* no L1 */
- {
- e_multipoint_cause = CAUSE_OUTOFORDER;
- e_multipoint_location = param->disconnectinfo.location;
- } else
- if (param->disconnectinfo.cause!=CAUSE_NOUSER && e_multipoint_cause!=CAUSE_OUTOFORDER && e_multipoint_cause!=CAUSE_BUSY && e_multipoint_cause!=CAUSE_REJECTED && e_multipoint_cause!=CAUSE_NORMAL) /* anything but not 18 */
- {
- e_multipoint_cause = param->disconnectinfo.cause;
- e_multipoint_location = param->disconnectinfo.location;
- }
+ collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
/* check if we have more than one portlist relation and we just ignore the disconnect */
portlist = portlist->next;
}
if (!portlist)
- {
- PERROR("EPOINT(%d) software error: no portlist related to the calling port.\n", ea_endpoint->ep_serial);
- exit(-1);
- }
+ FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
if (message_type != MESSAGE_RELEASE)
{
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
ea_endpoint->free_portlist(portlist);
return; /* one relation removed */
}
- if (e_multipoint_cause)
- {
- cause = e_multipoint_cause;
- location = e_multipoint_location;
- } else
+ if (e_state == EPOINT_STATE_CONNECT)
{
+ /* use cause from port after connect */
cause = param->disconnectinfo.cause;
location = param->disconnectinfo.location;
+ } else
+ {
+ /* use multipoint cause if no connect yet */
+ cause = e_multipoint_cause;
+ location = e_multipoint_location;
}
e_cfnr_call = e_cfnr_release = 0;
switch(message_type)
{
case MESSAGE_DATA: /* data from port */
- /* send back to source for recording */
- if (port_id)
- {
- message = message_create(ea_endpoint->ep_serial, port_id, EPOINT_TO_PORT, message_type);
- memcpy(&message->param, param, sizeof(union parameter));
- message_put(message);
- }
-
/* check if there is a call */
if (!ea_endpoint->ep_call_id)
break;
/* continue if only one portlist */
if (ea_endpoint->ep_portlist->next != NULL)
break;
- message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
- memcpy(&message->param, param, sizeof(union parameter));
- message_put(message);
+ /* forward message */
+ message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, param);
break;
case MESSAGE_TONE_EOF: /* tone is end of file */
void EndpointAppPBX::call_connect(struct port_list *portlist, int message_type, union parameter *param)
{
struct message *message;
+ struct interface *interface;
new_state(EPOINT_STATE_CONNECT);
// UCPY(e_call_tone, "");
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
memcpy(&message->param, param, sizeof(union parameter));
/* screen incoming caller id */
- screen(1, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present);
+ interface = interface_first;
+ while(interface)
+ {
+ if (!strcmp(e_connectinfo.interface, interface->name))
+ {
+ break;
+ }
+ interface = interface->next;
+ }
+ if (interface)
+ screen(1, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(e_connectinfo));
/* screen clip if prefix is required */
void EndpointAppPBX::call_setup(struct port_list *portlist, int message_type, union parameter *param)
{
struct message *message;
+ struct interface *interface;
/* if we already in setup state, we just update the dialing with new digits */
if (e_state == EPOINT_STATE_OUT_SETUP
memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
/* screen incoming caller id */
- screen(1, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present);
+ interface = interface_first;
+ while(interface)
+ {
+ if (!strcmp(e_callerinfo.interface, interface->name))
+ {
+ break;
+ }
+ interface = interface->next;
+ }
+ if (interface)
+ screen(1, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
/* process (voice over) data calls */
if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO)
portlist = ea_endpoint->ep_portlist;
/* send MESSAGE_DATA to port */
- if (call_id == ea_endpoint->ep_call_id)
+ if (message_type == MESSAGE_DATA)
{
- if (message_type == MESSAGE_DATA)
+ if (call_id == ea_endpoint->ep_call_id) // still linked with call
{
/* skip if no port relation */
if (!portlist)
/* skip if more than one port relation */
if (portlist->next)
return;
- /* send audio data to port */
- message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DATA);
- memcpy(&message->param, param, sizeof(union parameter));
- message_put(message);
+ /* forward audio data to port */
+ message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
return;
}
}
/* now we send a release to the ringing endpoint */
message = message_create(ea_endpoint->ep_call_id, eapp->ea_endpoint->ep_serial, CALL_TO_EPOINT, MESSAGE_RELEASE);
- message->param.disconnectinfo.cause = 26; /* non selected user clearing */
+ message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
{
/* detach other endpoint on hold */
*other_relation_pointer = other_relation->next;
- memset(other_relation, 0, sizeof(struct call_relation));
- free(other_relation);
+ FREE(other_relation, sizeof(struct call_relation));
cmemuse--;
other_relation = *other_relation_pointer;
other_eapp->ea_endpoint->ep_call_id = NULL;
void message_disconnect_port(struct port_list *portlist, int cause, int location, char *display);
void logmessage(struct message *messsage);
void trace_header(char *name, int direction);
- void screen(int out, char *id, int idsize, int *type, int *present);
+ void screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface);
};
/*
* constructor for a new call
*/
-Call::Call(class Endpoint *epoint)
+Call::Call(void)
{
class Call **callp;
- if (!epoint)
- {
- PERROR("software error, epoint is NULL.\n");
- exit(-1);
- }
c_serial = call_serial++;
c_type = CALL_TYPE_NONE;
cl = cl->next;
}
if (!cl)
- {
- PERROR("software error, call not in chain! exitting\n");
- exit(-1);
- }
+ FATAL("software error, call not in chain!\n");
*clp = cl->next; /* detach from chain */
}
return(0);
}
-void Call::release(unsigned long epoint_id, int hold, int location, int cause)
-{
-}
-
/* free all call structures */
void call_free(void)
{
class Call
{
public:
- Call(class Endpoint *epoint);
+ Call();
virtual ~Call();
class Call *next; /* next node in list of calls */
virtual void message_epoint(unsigned long epoint_id, int message, union parameter *param);
virtual int handler(void);
- virtual void release(unsigned long epoint_id, int hold, int location, int cause);
unsigned long c_type; /* call type (pbx or asterisk) */
unsigned long c_serial; /* serial/unique number of call */
* constructor for a new call
* the call will have a relation to the calling endpoint
*/
-CallPBX::CallPBX(class Endpoint *epoint) : Call(epoint)
+CallPBX::CallPBX(class Endpoint *epoint) : Call()
{
struct call_relation *relation;
// char filename[256];
if (!epoint)
- {
- PERROR("software error, epoint is NULL.\n");
- exit(-1);
- }
+ FATAL("epoint is NULL.\n");
PDEBUG(DEBUG_CALL, "creating new call and connecting it to the endpoint.\n");
c_pid = getpid();
c_updatebridge = 0;
c_partyline = 0;
+ c_multicause = CAUSE_NOUSER;
+ c_multilocation = LOCATION_PRIVATE_LOCAL;
/* initialize a relation only to the calling interface */
- relation = c_relation = (struct call_relation *)calloc(1, sizeof(struct call_relation));
- if (!relation)
- {
- PERROR("no memory, exitting..\n");
- exit(-1);
- }
+ relation = c_relation = (struct call_relation *)MALLOC(sizeof(struct call_relation));
cmemuse++;
- memset(relation, 0, sizeof(struct call_relation));
relation->type = RELATION_TYPE_CALLING;
relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
while(relation)
{
rtemp = relation->next;
- memset(relation, 0, sizeof(struct call_relation));
- free(relation);
+ FREE(relation, sizeof(struct call_relation));
cmemuse--;
relation = rtemp;
}
class Endpoint *epoint;
struct port_list *portlist;
class Port *port;
- int allmISDN = 0; // set until a non-mISDN relation is found
-fix:
+#ifdef DEBUG_COREBRIDGE
+ int allmISDN = 0; // never set for debug purpose
+#else
+ int allmISDN = 1; // set until a non-mISDN relation is found
+#endif
relation = c_relation;
while(relation)
void CallPBX::bridge_data(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param)
{
struct call_relation *relation_to;
- struct message *message;
/* if we are alone */
if (!c_relation->next)
/* now we may send our data to the endpoint where it
* will be delivered to the port
*/
-//PDEBUG(DEBUG_CALL, "mixing from %d to %d\n", epoint_from, relation_to->epoint_id);
-printf("from %d, to %d\n", relation_from->epoint_id, relation_to->epoint_id);
- message = message_create(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, MESSAGE_DATA);
- memcpy(&message->param, param, sizeof(union parameter));
- message_put(message);
+//printf("from %d, to %d\n", relation_from->epoint_id, relation_to->epoint_id);
+ message_forward(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, param);
}
-
/* release call from endpoint
* if the call has two relations, all relations are freed and the call will be
- * destroyed
+ * destroyed
+ * on outgoing relations, the cause is collected, if not connected
+ * returns if call has been destroyed
*/
-void CallPBX::release(unsigned long epoint_id, int hold, int location, int cause)
+int CallPBX::release(struct call_relation *relation, int location, int cause)
{
- struct call_relation *relation, **relationpointer;
+ struct call_relation *reltemp, **relationpointer;
struct message *message;
-
class Call *call;
-
- if (!epoint_id)
- {
- PERROR("software error, epoint is NULL.\n");
- return;
- }
-
- if (options.deb & DEBUG_CALL)
- callpbx_debug(this, "call_release{before}");
-
- /* find relation */
- relation = c_relation;
- while(relation)
- {
- if (relation->epoint_id == epoint_id)
- break;
- relation = relation->next;
- }
- if (!relation)
- {
- PERROR("software error, epoint has a call with no relation to the epoint.\n");
- return;
- }
+ int destroy = 0;
/* remove from bridge */
if (relation->channel_state != CHANNEL_STATE_HOLD)
{
relation->channel_state = CHANNEL_STATE_HOLD;
c_updatebridge = 1; /* update bridge flag */
+ // note: if call is not released, bridge must be updated
}
/* detach given interface */
- relation = c_relation;
+ reltemp = c_relation;
relationpointer = &c_relation;
- while(relation)
+ while(reltemp)
{
/* endpoint of function call */
- if (relation->epoint_id == epoint_id)
- {
- *relationpointer = relation->next;
- memset(relation, 0, sizeof(struct call_relation));
- free(relation);
- cmemuse--;
- relation = *relationpointer;
- continue;
- }
- relationpointer = &relation->next;
- relation = relation->next;
+ if (relation == reltemp)
+ break;
+ relationpointer = &reltemp->next;
+ reltemp = reltemp->next;
}
+ if (!reltemp)
+ FATAL("relation not in list of our relations. this must not happen.\n");
+ *relationpointer = reltemp->next;
+ FREE(reltemp, sizeof(struct call_relation));
+ cmemuse--;
+ relation = reltemp = NULL; // just in case of reuse fault;
/* if no more relation */
if (!c_relation)
{
PDEBUG(DEBUG_CALL, "call is completely removed.\n");
/* there is no more endpoint related to the call */
+ destroy = 1;
delete this;
// end of call object!
PDEBUG(DEBUG_CALL, "call completely removed!\n");
message->param.disconnectinfo.cause = cause;
message->param.disconnectinfo.location = location;
message_put(message);
+ destroy = 1;
delete this;
// end of call object!
PDEBUG(DEBUG_CALL, "call completely removed!\n");
call = call->next;
}
PDEBUG(DEBUG_CALL, "call_release(): ended.\n");
+ return(destroy);
}
/* count number of relations in a call
PDEBUG(DEBUG_CALL, "removing relation.\n");
*tempp = relation->next;
- memset(temp, 0, sizeof(struct call_relation));
- free(temp);
+ FREE(temp, sizeof(struct call_relation));
cmemuse--;
}
while(relation->next)
relation = relation->next;
- relation->next = (struct call_relation *)calloc(1, sizeof(struct call_relation));
- if (!relation->next)
- {
- PERROR("no memory\n");
- return(NULL);
- }
+ relation->next = (struct call_relation *)MALLOC(sizeof(struct call_relation));
cmemuse++;
- memset(relation->next, 0, sizeof(struct call_relation));
/* the record pointer is set at the first time the data is received for the relation */
// if (options.deb & DEBUG_CALL)
void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
{
class Call *cl;
- struct call_relation *relation, *rel;
+ struct call_relation *relation, *reltemp;
int num;
int new_state;
struct message *message;
}
if (!relation)
{
-// PERROR("no relation back to the endpoint found, ignoring (call=%d, endpoint=%d\n", c_serial, epoint_id);
+ PDEBUG(DEBUG_CALL, "no relation back to the endpoint found, ignoring (call=%d, endpoint=%d)\n", c_serial, epoint_id);
return;
}
default:
/* send notification to all other endpoints */
- rel = c_relation;
- while(rel)
+ reltemp = c_relation;
+ while(reltemp)
{
- if (rel->epoint_id!=epoint_id && rel->epoint_id)
+ if (reltemp->epoint_id!=epoint_id && reltemp->epoint_id)
{
- message = message_create(c_serial, rel->epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
+ message = message_create(c_serial, reltemp->epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
memcpy(&message->param, param, sizeof(union parameter));
message_put(message);
}
- rel = rel->next;
+ reltemp = reltemp->next;
}
}
return;
/* now send audio data to the other endpoint */
bridge_data(epoint_id, relation, param);
return;
+
+ /* relations sends a connect */
+ case MESSAGE_CONNECT:
+ /* outgoing setup type becomes connected */
+ if (relation->type == RELATION_TYPE_SETUP)
+ relation->type = RELATION_TYPE_CONNECT;
+ /* release other relations in setup state */
+ release_again:
+ relation = c_relation;
+ while(relation)
+ {
+ if (relation->type == RELATION_TYPE_SETUP)
+ {
+ if (release(relation, LOCATION_PRIVATE_LOCAL, CAUSE_NONSELECTED))
+ return; // must return, because call IS destroyed
+ goto release_again;
+ }
+ relation = relation->next;
+ }
+ break; // continue with our message
+
+ /* release is sent by endpoint */
+ case MESSAGE_RELEASE:
+ if (relation->type == RELATION_TYPE_SETUP)
+ {
+ /* collect cause and send collected cause */
+ collect_cause(&c_multicause, &c_multilocation, param->disconnectinfo.cause, param->disconnectinfo.location);
+ release(relation, c_multilocation, c_multicause);
+ } else
+ {
+ /* send current cause */
+ release(relation, param->disconnectinfo.location, param->disconnectinfo.cause);
+ }
+ return; // must return, because call may be destroyed
}
/* process party line */
if (message_type == MESSAGE_DISCONNECT)
{
PDEBUG(DEBUG_CALL, "releasing after receiving disconnect, because call in partyline mode.\n");
-// remove_relation(relation);
message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = CAUSE_NORMAL;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
-// c_updatebridge = 1; /* update bridge flag */
return;
}
}
PDEBUG(DEBUG_CALL, "no endpoint found, so we will create an endpoint and send the setup message we have.\n");
/* create a new relation */
if (!(relation=add_relation()))
- {
- /* release due to error */
- ressource_error:
- relation = c_relation;
- while(relation)
- {
- message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
- message->param.disconnectinfo.cause = (relation->epoint_id==epoint_id)?CAUSE_RESSOURCEUNAVAIL:CAUSE_NORMAL;
- message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
- message_put(message);
- relation = relation->next;
- }
- delete this;
- return(-ENOMEM);
- }
+ FATAL("No memory for relation.\n");
relation->type = RELATION_TYPE_SETUP;
relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
/* create a new endpoint */
- epoint = new Endpoint(0, c_serial);
+ epoint = new Endpoint(0, c_serial, 0);
if (!epoint)
- {
- remove_relation(relation);
- goto ressource_error;
- }
+ FATAL("No memory for Endpoint instance\n");
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
- {
- PERROR("ERROR:No endpoint's app.\n");
- delete epoint;
- remove_relation(relation);
- goto ressource_error;
- }
+ FATAL("No memory for Endpoint Application instance\n");
relation->epoint_id = epoint->ep_serial;
/* send setup message to new endpoint */
//printf("JOLLY DEBUG: %d\n",call_countrelations(c_serial));
return(0);
}
+
~CallPBX();
void message_epoint(unsigned long epoint_id, int message, union parameter *param);
int handler(void);
- void release(unsigned long epoint_id, int hold, int location, int cause);
+ int release(struct call_relation *relation, int location, int cause);
char c_caller[32]; /* caller number */
char c_caller_id[32]; /* caller id to signal */
char c_dialed[1024]; /* dial string of (all) number(s) */
char c_todial[32]; /* overlap dialing (part not signalled yet) */
+ int c_multicause, c_multilocation;
int c_pid; /* pid of call to generate bridge id */
int c_updatebridge; /* bridge must be updated */
return(result);
}
+
+/*
+ * collect cause for multipoint
+ * used by Process, Endpoint and Join instance when multiplexing
+ */
+void collect_cause(int *multicause, int *multilocation, int newcause, int newlocation)
+{
+ if (newcause == CAUSE_REJECTED) /* call rejected */
+ {
+ *multicause = newcause;
+ *multilocation = newlocation;
+ } else
+ if (newcause==CAUSE_NORMAL && *multicause!=CAUSE_REJECTED) /* reject via hangup */
+ {
+ *multicause = newcause;
+ *multilocation = newlocation;
+ } else
+ if (newcause==CAUSE_BUSY && *multicause!=CAUSE_REJECTED && *multicause!=CAUSE_NORMAL) /* busy */
+ {
+ *multicause = newcause;
+ *multilocation = newlocation;
+ } else
+ if (newcause==CAUSE_OUTOFORDER && *multicause!=CAUSE_BUSY && *multicause!=CAUSE_REJECTED && *multicause!=CAUSE_NORMAL) /* no L1 */
+ {
+ *multicause = newcause;
+ *multilocation = newlocation;
+ } else
+ if (newcause!=CAUSE_NOUSER && *multicause!=CAUSE_OUTOFORDER && *multicause!=CAUSE_BUSY && *multicause!=CAUSE_REJECTED && *multicause!=CAUSE_NORMAL) /* anything but not 18 */
+ {
+ *multicause = newcause;
+ *multilocation = newlocation;
+ } else
+ if (newcause==CAUSE_NOUSER && *multicause==CAUSE_NOUSER) /* cause 18, but no cause yet, use the location */
+ {
+ *multilocation = newlocation;
+ }
+}
+
#define CAUSE_NOUSER 18
#define CAUSE_NOANSWER 19
#define CAUSE_REJECTED 21
+#define CAUSE_NONSELECTED 26
#define CAUSE_OUTOFORDER 27
#define CAUSE_INVALID 28
#define CAUSE_FACILITYREJECTED 29
extern struct isdn_cause isdn_cause[128];
extern struct isdn_location isdn_location[16];
char *get_isdn_cause(int cause, int location, int type);
+void collect_cause(int *multicause, int *multilocation, int newcause, int newlocation);
unsigned long crc = 0xffffffff;
if (!crc_initialized)
- {
- PERROR("crc not initialized, exitting...");
- exit(-1);
- }
+ FATAL("crc not initialized, exitting...");
while (len--)
crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data++];
/* exit process */
apppbx->ea_endpoint->ep_use--;
- memset(args, 0, sizeof(struct auth_args));
- free(args);
+ FREE(args, sizeof(struct auth_args));
amemuse--;
return(NULL);
}
return;
}
- arg = (struct auth_args *)calloc(1, sizeof(struct auth_args));
- if (!arg)
- {
- PERROR("failed to alloc memory.\n");
- e_crypt_keyengine_return = -1;
- return;
- }
-
+ arg = (struct auth_args *)MALLOC(sizeof(struct auth_args));
arg->apppbx = this;
arg->job = job;
e_crypt_keyengine_return = 0;
}
}
+
*/
static msg_t *create_l3msg(int prim, int mt, int dinfo, int size, int ntmode)
{
- int i = 0;
msg_t *dmsg;
Q931_info_t *qi;
iframe_t *frm;
if (!ntmode)
size = sizeof(Q931_info_t)+2;
- while(i < 10)
+ if (ntmode)
{
- if (ntmode)
+ dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
+ if (dmsg)
{
- dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
- if (dmsg)
- {
- return(dmsg);
- }
- } else
+ return(dmsg);
+ }
+ } else
+ {
+ dmsg = alloc_msg(size+256+mISDN_HEADER_LEN+DEFAULT_HEADROOM);
+ if (dmsg)
{
- dmsg = alloc_msg(size+256+mISDN_HEADER_LEN+DEFAULT_HEADROOM);
- if (dmsg)
- {
- memset(msg_put(dmsg,size+mISDN_HEADER_LEN), 0, size+mISDN_HEADER_LEN);
- frm = (iframe_t *)dmsg->data;
- frm->prim = prim;
- frm->dinfo = dinfo;
- qi = (Q931_info_t *)(dmsg->data + mISDN_HEADER_LEN);
- qi->type = mt;
- return(dmsg);
- }
+ memset(msg_put(dmsg,size+mISDN_HEADER_LEN), 0, size+mISDN_HEADER_LEN);
+ frm = (iframe_t *)dmsg->data;
+ frm->prim = prim;
+ frm->dinfo = dinfo;
+ qi = (Q931_info_t *)(dmsg->data + mISDN_HEADER_LEN);
+ qi->type = mt;
+ return(dmsg);
}
-
- if (!i)
- PERROR("cannot allocate memory, trying again...\n");
- i++;
- usleep(50000);
}
- PERROR("cannot allocate memory, system overloaded.\n");
- exit(-1);
+
+ FATAL("Cannot allocate memory, system overloaded.\n");
+ exit(0); // make gcc happy
}
msg_t *create_l2msg(int prim, int dinfo, int size) /* NT only */
{
- int i = 0;
msg_t *dmsg;
- while(i < 10)
- {
- dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
- if (dmsg)
- return(dmsg);
+ dmsg = prep_l3data_msg(prim, dinfo, size, 256, NULL);
+ if (dmsg)
+ return(dmsg);
- if (!i)
- PERROR("cannot allocate memory, trying again...\n");
- i++;
- usleep(50000);
- }
- PERROR("cannot allocate memory, system overloaded.\n");
- exit(-1);
+ FATAL("Cannot allocate memory, system overloaded.\n");
+ exit(0); // make gcc happy
}
/*
dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, p_m_d_l3id, sizeof(RELEASE_COMPLETE_t), p_m_d_ntmode);
release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
+ enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
new_state(PORT_STATE_RELEASE);
{
/* nt-library now gives us the id via CC_SETUP */
if (dinfo&(~0xff) == 0xff00)
- {
- PERROR("fatal software error: l3-stack gives us a process id 0xff00-0xffff\n");
- exit(-1);
- }
+ FATAL("l3-stack gives us a process id 0xff00-0xffff\n");
l1l2l3_trace_header(p_m_mISDNport, this, CC_NEW_CR | INDICATION, DIRECTION_IN);
if (p_m_d_l3id)
add_trace("callref", "old", "0x%x", p_m_d_l3id);
dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, dinfo, sizeof(RELEASE_COMPLETE_t), p_m_d_ntmode);
release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 27); /* temporary unavailable */
+ enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 27); /* temporary unavailable */
add_trace("reason", NULL, "port blocked");
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, dinfo, sizeof(RELEASE_COMPLETE_t), p_m_d_ntmode);
release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
+ enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
new_state(PORT_STATE_RELEASE);
/* create endpoint */
if (p_epointlist)
- {
- PERROR("SOFTWARE ERROR: incoming call but already got an endpoint, exitting...\n");
- exit(-1);
- }
- if (!(epoint = new Endpoint(p_serial, 0)))
- {
- RELEASE_COMPLETE_t *release_complete;
-
- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, dinfo, sizeof(RELEASE_COMPLETE_t), p_m_d_ntmode);
- release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
- l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 41); /* temporary failure */
- end_trace();
- msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
- new_state(PORT_STATE_RELEASE);
- p_m_delete = 1;
- return;
- }
+ FATAL("Incoming call but already got an endpoint.\n");
+ if (!(epoint = new Endpoint(p_serial, 0, 0)))
+ FATAL("No memory for Endpoint instance\n");
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
- {
- PERROR("no memory for application\n");
- exit(-1);
- }
- if (!(epointlist_new(epoint->ep_serial)))
- {
- PERROR("no memory for epointlist\n");
- exit(-1);
- }
+ FATAL("No memory for Endpoint Application instance\n");
+ epointlist_new(epoint->ep_serial);
+
/* send setup message to endpoit */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
message->param.setup.isdn_port = p_m_portnum;
break;
}
p_connectinfo.isdn_port = p_m_portnum;
- SCPY(p_connectinfo.interfaces, p_m_mISDNport->ifport->interface->name);
+ SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
/* only in nt-mode we send connect ack. in te-mode it is done by stack itself or optional */
if (p_m_d_ntmode)
dec_ie_progress(disconnect->PROGRESS, (Q931_info_t *)((unsigned long)data+headerlen), &coding, &proglocation, &progress);
dec_ie_cause(disconnect->CAUSE, (Q931_info_t *)((unsigned long)data+headerlen), &location, &cause);
end_trace();
+ if (location == LOCATION_PRIVATE_LOCAL)
+ location = LOCATION_PRIVATE_REMOTE;
if (cause < 0)
cause = 16;
dmsg = create_l3msg(CC_RELEASE | REQUEST, MT_RELEASE, dinfo, sizeof(RELEASE_t), p_m_d_ntmode);
release = (RELEASE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&release->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 16); /* normal */
+ enc_ie_cause(&release->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 16); /* normal */
add_trace("reason", NULL, "no remote patterns");
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
}
dec_ie_cause(disconnect->CAUSE, (Q931_info_t *)((unsigned long)data+headerlen), &location, &cause);
end_trace();
+ if (location == LOCATION_PRIVATE_LOCAL)
+ location = LOCATION_PRIVATE_REMOTE;
/* collect cause */
- if (cause == CAUSE_REJECTED) /* call rejected */
- {
- p_m_d_collect_cause = CAUSE_REJECTED;
- p_m_d_collect_location = location;
- } else
- if (cause==CAUSE_NORMAL && p_m_d_collect_cause!=CAUSE_REJECTED) /* reject via hangup */
- {
- p_m_d_collect_cause = CAUSE_NORMAL;
- p_m_d_collect_location = location;
- } else
- if (cause==CAUSE_BUSY && p_m_d_collect_cause!=CAUSE_REJECTED && p_m_d_collect_cause!=CAUSE_NORMAL) /* busy */
- {
- p_m_d_collect_cause = CAUSE_BUSY;
- p_m_d_collect_location = location;
- } else
- if (cause==CAUSE_OUTOFORDER && p_m_d_collect_cause!=CAUSE_BUSY && p_m_d_collect_cause!=CAUSE_REJECTED && p_m_d_collect_cause!=CAUSE_NORMAL) /* no L1 */
- {
- p_m_d_collect_cause = CAUSE_OUTOFORDER;
- p_m_d_collect_location = location;
- } else
- if (cause!=0 && cause!=CAUSE_NOUSER && p_m_d_collect_cause!=CAUSE_OUTOFORDER && p_m_d_collect_cause!=CAUSE_BUSY && p_m_d_collect_cause!=CAUSE_REJECTED && p_m_d_collect_cause!=CAUSE_NORMAL) /* anything if cause exists and not 18 */
- {
- p_m_d_collect_cause = cause;
- p_m_d_collect_location = location;
- }
+ collect_cause(&p_m_d_collect_cause, &p_m_d_collect_location, cause, location);
add_trace("new-cause", "location", "%d", p_m_d_collect_location);
add_trace("new-cause", "value", "%d", p_m_d_collect_cause);
l1l2l3_trace_header(p_m_mISDNport, this, prim, DIRECTION_IN);
dec_ie_cause(release->CAUSE, (Q931_info_t *)((unsigned long)data+headerlen), &location, &cause);
end_trace();
+ if (location == LOCATION_PRIVATE_LOCAL)
+ location = LOCATION_PRIVATE_REMOTE;
if (cause < 0)
cause = 16;
dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, dinfo, sizeof(RELEASE_COMPLETE_t), p_m_d_ntmode);
release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 16);
+ enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 16);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
}
l1l2l3_trace_header(p_m_mISDNport, this, prim, DIRECTION_IN);
dec_ie_cause(release_complete->CAUSE, (Q931_info_t *)((unsigned long)data+headerlen), &location, &cause);
end_trace();
+ if (location == LOCATION_PRIVATE_LOCAL)
+ location = LOCATION_PRIVATE_REMOTE;
if (cause < 0)
cause = 16;
dmsg = create_l3msg(CC_HOLD_REJECT | REQUEST, MT_HOLD_REJECT, dinfo, sizeof(HOLD_REJECT_t), p_m_d_ntmode);
hold_reject = (HOLD_REJECT_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_HOLD_REJECT | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&hold_reject->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, p_m_hold?101:31); /* normal unspecified / incompatible state */
+ enc_ie_cause(&hold_reject->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, p_m_hold?101:31); /* normal unspecified / incompatible state */
add_trace("reason", NULL, "no endpoint");
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
dmsg = create_l3msg(CC_RETRIEVE_REJECT | REQUEST, MT_RETRIEVE_REJECT, dinfo, sizeof(RETRIEVE_REJECT_t), p_m_d_ntmode);
retrieve_reject = (RETRIEVE_REJECT_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RETRIEVE_REJECT | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&retrieve_reject->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, cause);
+ enc_ie_cause(&retrieve_reject->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, cause);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
dmsg = create_l3msg(CC_SUSPEND_REJECT | REQUEST, MT_SUSPEND_REJECT, dinfo, sizeof(SUSPEND_REJECT_t), p_m_d_ntmode);
suspend_reject = (SUSPEND_REJECT_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_SUSPEND_REJECT | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&suspend_reject->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
+ enc_ie_cause(&suspend_reject->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
{
/* nt-library now gives us the id via CC_RESUME */
if (dinfo&(~0xff) == 0xff00)
- {
- PERROR("fatal software error: l3-stack gives us a process id 0xff00-0xffff\n");
- exit(-1);
- }
+ FATAL("l3-stack gives us a process id 0xff00-0xffff\n");
l1l2l3_trace_header(p_m_mISDNport, this, CC_NEW_CR | INDICATION, DIRECTION_IN);
if (p_m_d_l3id)
add_trace("callref", "old", "0x%x", p_m_d_l3id);
dmsg = create_l3msg(CC_RESUME_REJECT | REQUEST, MT_RESUME_REJECT, dinfo, sizeof(RESUME_REJECT_t), p_m_d_ntmode);
resume_reject = (RESUME_REJECT_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RESUME_REJECT | REQUEST, DIRECTION_OUT);
- enc_ie_cause(&resume_reject->CAUSE, dmsg, (p_m_d_ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
+ enc_ie_cause(&resume_reject->CAUSE, dmsg, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, -ret);
if (ret == -27)
add_trace("reason", NULL, "port blocked");
end_trace();
/* create endpoint */
if (p_epointlist)
- {
- PERROR("SOFTWARE ERROR: incoming resume but already got an endpoint, exitting...\n");
- exit(-1);
- }
+ FATAL("Incoming resume but already got an endpoint.\n");
ret = -85; /* no call suspended */
epoint = epoint_first;
while(epoint)
if (!epoint)
goto reject;
- if (!(epointlist_new(epoint->ep_serial)))
- {
- PERROR("no memory for epointlist\n");
- exit(-1);
- }
+ epointlist_new(epoint->ep_serial);
if (!(epoint->portlist_new(p_serial, p_type, p_m_mISDNport->earlyb)))
- {
- PERROR("no memory for portlist\n");
- exit(-1);
- }
+ FATAL("No memory for portlist\n");
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RESUME);
message_put(message);
epointlist = epointlist->next;
}
if (!epointlist)
- {
- if (!(epointlist_new(epoint_id)))
- {
- PERROR("no memory for epointlist\n");
- exit(-1);
- }
- }
+ epointlist_new(epoint_id);
/* get channel */
exclusive = 0;
release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
/* send cause */
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
+ enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
new_state(PORT_STATE_RELEASE);
if (p_m_mISDNport->tones)
enc_ie_progress(&disconnect->PROGRESS, dmsg, 0, p_m_d_ntmode?1:5, 8);
/* send cause */
- enc_ie_cause(&disconnect->CAUSE, dmsg, (p_m_d_ntmode && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
+ enc_ie_cause(&disconnect->CAUSE, dmsg, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
/* send display */
if (param->disconnectinfo.display[0])
p = param->disconnectinfo.display;
release = (RELEASE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE | REQUEST, DIRECTION_OUT);
/* send cause */
- enc_ie_cause(&release->CAUSE, dmsg, (p_m_d_ntmode && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
+ enc_ie_cause(&release->CAUSE, dmsg, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
new_state(PORT_STATE_RELEASE);
release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + headerlen);
l1l2l3_trace_header(p_m_mISDNport, this, CC_RELEASE | REQUEST, DIRECTION_OUT);
/* send cause */
- enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_d_ntmode && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
+ enc_ie_cause(&release_complete->CAUSE, dmsg, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
end_trace();
msg_queue_tail(&p_m_mISDNport->downqueue, dmsg);
new_state(PORT_STATE_RELEASE);
if (p_m_mISDNport->tones)
enc_ie_progress(&disconnect->PROGRESS, dmsg, 0, p_m_d_ntmode?1:5, 8);
/* send cause */
- enc_ie_cause(&disconnect->CAUSE, dmsg, (p_m_d_ntmode && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
+ enc_ie_cause(&disconnect->CAUSE, dmsg, (p_m_mISDNport->locally && param->disconnectinfo.location==LOCATION_PRIVATE_LOCAL)?LOCATION_PRIVATE_LOCAL:param->disconnectinfo.location, param->disconnectinfo.cause);
/* send display */
epoint = find_epoint_id(epoint_id);
if (param->disconnectinfo.display[0])
break;
}
if (p_epointlist && p_state==PORT_STATE_IDLE)
- {
- PERROR("Pdss1(%s): software error: epoint pointer is set in idle state, how bad!! exitting.\n", p_name);
- exit(-1);
- }
+ FATAL("Pdss1(%s): epoint pointer is set in idle state, how bad!!\n", p_name);
/* note: pri is a special case, because links must be up for pri */
if (p_m_mISDNport->l1link || p_m_mISDNport->pri || !p_m_mISDNport->ntmode || p_state!=PORT_STATE_IDLE)
{
memcpy(&p_m_d_queue->param, param, sizeof(union parameter));
/* attach us */
if (!(epointlist_new(epoint_id)))
- {
- PERROR("no memory for epointlist\n");
- exit(-1);
- }
+ FATAL("No memory for epointlist\n");
/* activate link */
PDEBUG(DEBUG_ISDN, "the L1 is down, we try to establish the link NT portnum=%d (%s).\n", p_m_mISDNport->portnum, p_name);
act.prim = PH_ACTIVATE | REQUEST;
/* creating port object */
SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0)))
- {
- RELEASE_COMPLETE_t *release_complete;
- msg_t *dmsg;
- PERROR("FATAL ERROR: cannot create port object.\n");
- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, hh->dinfo, sizeof(RELEASE_COMPLETE_t), mISDNport->ntmode);
- release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + mISDN_HEADER_LEN);
- l1l2l3_trace_header(mISDNport, NULL, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause_standalone(mISDNport->ntmode?&release_complete->CAUSE:NULL, dmsg, (mISDNport->ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 47);
- end_trace();
- msg_queue_tail(&mISDNport->downqueue, dmsg);
- break;
- }
+ FATAL("Cannot create Port instance.\n");
pdss1->message_isdn(hh->prim, hh->dinfo, msg->data);
break;
/* creating port object */
SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_NT_IN, mISDNport, name, NULL, 0, 0)))
- {
- SUSPEND_REJECT_t *suspend_reject;
- msg_t *dmsg;
-
- PERROR("FATAL ERROR: cannot create port object.\n");
- dmsg = create_l3msg(CC_SUSPEND_REJECT | REQUEST, MT_SUSPEND_REJECT, hh->dinfo, sizeof(SUSPEND_REJECT_t), mISDNport->ntmode);
- suspend_reject = (SUSPEND_REJECT_t *)(dmsg->data + mISDN_HEADER_LEN);
- l1l2l3_trace_header(mISDNport, NULL, CC_SUSPEND_REJECT | REQUEST, DIRECTION_OUT);
- enc_ie_cause_standalone(mISDNport->ntmode?&suspend_reject->CAUSE:NULL, dmsg, (mISDNport->ntmode)?1:0, 47);
- end_trace();
- msg_queue_tail(&mISDNport->downqueue, dmsg);
- break;
- }
+ FATAL("Cannot create Port instance.\n");
pdss1->message_isdn(hh->prim, hh->dinfo, msg->data);
break;
/* creating port object */
SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
if (!(pdss1 = new Pdss1(PORT_TYPE_DSS1_TE_IN, mISDNport, name, NULL, 0, 0)))
- {
- RELEASE_COMPLETE_t *release_complete;
- msg_t *dmsg;
-
- PERROR("FATAL ERROR: cannot create port object.\n");
- dmsg = create_l3msg(CC_RELEASE_COMPLETE | REQUEST, MT_RELEASE_COMPLETE, frm->dinfo, sizeof(RELEASE_COMPLETE_t), mISDNport->ntmode);
- release_complete = (RELEASE_COMPLETE_t *)(dmsg->data + mISDN_HEADER_LEN);
- l1l2l3_trace_header(mISDNport, NULL, CC_RELEASE_COMPLETE | REQUEST, DIRECTION_OUT);
- enc_ie_cause_standalone(mISDNport->ntmode?&release_complete->CAUSE:NULL, dmsg, (mISDNport->ntmode)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 47);
- end_trace();
- msg_queue_tail(&mISDNport->downqueue, dmsg);
- free_msg(msg);
- return(0);
- }
+ FATAL("Cannot create Port instance.\n");
/* l3id will be set from dinfo at message_isdn */
pdss1->message_isdn(frm->prim, frm->dinfo, msg->data);
free_msg(msg);
/*
* endpoint constructor (link with either port or call id)
*/
-Endpoint::Endpoint(int port_id, int call_id)
+Endpoint::Endpoint(unsigned long port_id, unsigned long call_id, unsigned long use_epoint_id)
{
class Port *port;
class Endpoint **epointpointer;
*epointpointer = this;
/* serial */
- ep_serial = epoint_serial++;
+ if (use_epoint_id)
+ ep_serial = use_epoint_id;
+ else
+ ep_serial = epoint_serial++;
/* link to call or port */
if (port_id)
if ((port->p_type&PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1)
earlyb = ((class PmISDN *)port)->p_m_mISDNport->earlyb;
if (!portlist_new(port_id, port->p_type, earlyb))
- {
- PERROR("no mem for portlist, exitting...\n");
- exit(-1);
- }
+ FATAL("No memory for portlist.\n");
}
}
ep_call_id = call_id;
mtemp = portlist;
portlist = portlist->next;
memset(mtemp, 0, sizeof(struct port_list));
- free(mtemp);
+ FREE(mtemp, sizeof(struct port_list));
ememuse--;
}
temp = temp->next;
}
if (temp == 0)
- {
- PERROR("error: endpoint not in endpoint's list, exitting.\n");
- exit(-1);
- }
+ FATAL("Endpoint not in Endpoint's list.\n");
*tempp = next;
/* free */
struct port_list *portlist, **portlistpointer;
/* portlist structure */
- portlist = (struct port_list *)calloc(1, sizeof(struct port_list));
- if (!portlist)
- {
- PERROR("no mem for allocating port_list\n");
- return(0);
- }
+ portlist = (struct port_list *)MALLOC(sizeof(struct port_list));
ememuse++;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocating port_list.\n", ep_serial);
- memset(portlist, 0, sizeof(struct port_list));
/* add port_list to chain */
portlist->next = NULL;
tempp = &temp->next;
temp = temp->next;
}
- if (temp == 0)
- {
- PERROR("port_list not in endpoint's list, exitting.\n");
- exit(-1);
- }
+ if (!temp)
+ FATAL("port_list not in Endpoint's list.\n");
/* detach */
*tempp=portlist->next;
/* free */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removed port_list from endpoint\n", ep_serial);
- memset(portlist, 0, sizeof(struct port_list));
- free(portlist);
+ FREE(portlist, sizeof(struct port_list));
ememuse--;
}
class Endpoint
{
public:
- Endpoint(int port_id, int call_id);
+ Endpoint(unsigned long port_id, unsigned long call_id, unsigned long use_epoint_id);
~Endpoint();
class Endpoint *next; /* next in list */
unsigned long ep_serial; /* a unique serial to identify */
** **
\*****************************************************************************/
+/* maximum number of redial/powerdial and reply numbers to remember
+ */
+#define MAX_REMEMBER 99
+
/* display of callerid on internal numbers */
enum {
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
-#include "save.h"
+#include "macro.h"
char mode[256];
int type[256];
if (!(fp=fopen(name, "w")))
{
fprintf(stderr, "\nError: Failed to open '%s', try again.\n", name);
- exit(-1);
+ exit(EXIT_FAILURE);
}
fprintf(fp, "# rc script for mISDN driver\n\n");
fprintf(fp, "case \"$1\" in\n");
UPRINT(debug+(j*3), " %02x", centrex[i+1+j]);
i++;
}
- add_trace("facility", "CENTREX", "unknown=0x%2x len=%d%s\n", centrex[i], centrex[i+1], debug);
+ add_trace("facility", "CENTREX", "unknown=0x%02x len=%d%s\n", centrex[i], centrex[i+1], debug);
}
i += 1+centrex[i+1];
}
{
struct select_channel *selchannel, **selchannelp;
- selchannel = (struct select_channel *)malloc(sizeof(struct select_channel));
- if (!selchannel)
- {
- PERROR("No memory!");
- return;
- }
+ selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
memuse++;
- memset(selchannel, 0, sizeof(struct select_channel));
if (ifport->mISDNport->ntmode)
selchannel->channel = CHANNEL_FREE;
if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode)
{
selchannelp = &(selchannel->next);
- selchannel = (struct select_channel *)malloc(sizeof(struct select_channel));
- if (!selchannel)
- {
- PERROR("No memory!");
- return;
- }
+ selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
memuse++;
- memset(selchannel, 0, sizeof(struct select_channel));
selchannel->channel = CHANNEL_NO; // call waiting
*selchannelp = selchannel;
}
{
struct select_channel *selchannel;
- selchannel = (struct select_channel *)malloc(sizeof(struct select_channel));
- if (!selchannel)
- {
- PERROR("No memory!");
- return;
- }
+ selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
memuse++;
- memset(selchannel, 0, sizeof(struct select_channel));
selchannel->channel = CHANNEL_FREE;
searchif = searchif->next;
}
/* alloc port substructure */
- ifport = (struct interface_port *)malloc(sizeof(struct interface_port));
- if (!ifport)
- {
- SPRINT(interface_error, "No memory!");
- return(-1);
- }
+ ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
memuse++;
- memset(ifport, 0, sizeof(struct interface_port));
ifport->interface = interface;
/* set value */
ifport->portnum = val;
}
selchannel:
/* add to select-channel list */
- selchannel = (struct select_channel *)malloc(sizeof(struct select_channel));
- if (!selchannel)
- {
- SPRINT(interface_error, "No memory!");
- return(-1);
- }
+ selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
memuse++;
- memset(selchannel, 0, sizeof(struct select_channel));
/* set value */
selchannel->channel = val;
/* tail port */
}
selchannel:
/* add to select-channel list */
- selchannel = (struct select_channel *)malloc(sizeof(struct select_channel));
- if (!selchannel)
- {
- SPRINT(interface_error, "No memory!");
- return(-1);
- }
+ selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
memuse++;
- memset(selchannel, 0, sizeof(struct select_channel));
/* set value */
selchannel->channel = val;
/* tail port */
el = p;
p = get_seperated(p);
/* add MSN to list */
- ifmsn = (struct interface_msn *)malloc(sizeof(struct interface_msn));
- if (!ifmsn)
- {
- SPRINT(interface_error, "No memory!");
- return(-1);
- }
+ ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
memuse++;
- memset(ifmsn, 0, sizeof(struct interface_msn));
/* set value */
SCPY(ifmsn->msn, el);
/* tail port */
el = p;
p = get_seperated(p);
/* add screen entry to list*/
- ifscreen = (struct interface_screen *)malloc(sizeof(struct interface_screen));
- if (!ifscreen)
- {
- SPRINT(interface_error, "No memory!");
- return(-1);
- }
+ ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
memuse++;
- memset(ifscreen, 0, sizeof(struct interface_screen));
ifscreen->match_type = -1; /* unchecked */
ifscreen->match_present = -1; /* unchecked */
ifscreen->result_type = -1; /* unchanged */
struct interface_param *ifparam;
if (interface_newlist != NULL)
- {
- PERROR("software error, list is not empty.\n");
- exit(-1);
- }
+ FATAL("list is not empty.\n");
interface_error[0] = '\0';
SPRINT(filename, "%s/interface.conf", INSTALL_DATA);
}
/* append interface to new list */
- interface = (struct interface *)malloc(sizeof(struct interface));
- if (!interface)
- {
- SPRINT(interface_error, "No memory!");
- goto error;
- }
+ interface = (struct interface *)MALLOC(sizeof(struct interface));
memuse++;
- memset(interface, 0, sizeof(struct interface));
/* name interface */
SCPY(interface->name, parameter+1);
{
temp = selchannel;
selchannel = selchannel->next;
- memset(temp, 0, sizeof(struct select_channel));
- free(temp);
+ FREE(temp, sizeof(struct select_channel));
memuse--;
}
selchannel = ifport->out_channel;
{
temp = selchannel;
selchannel = selchannel->next;
- memset(temp, 0, sizeof(struct select_channel));
- free(temp);
+ FREE(temp, sizeof(struct select_channel));
memuse--;
}
temp = ifport;
ifport = ifport->next;
- memset(temp, 0, sizeof(struct interface_port));
- free(temp);
+ FREE(temp, sizeof(struct interface_port));
memuse--;
}
ifmsn = interface->ifmsn;
{
temp = ifmsn;
ifmsn = ifmsn->next;
- memset(temp, 0, sizeof(struct interface_msn));
- free(temp);
+ FREE(temp, sizeof(struct interface_msn));
memuse--;
}
ifscreen = interface->ifscreen_in;
{
temp = ifscreen;
ifscreen = ifscreen->next;
- memset(temp, 0, sizeof(struct interface_screen));
- free(temp);
+ FREE(temp, sizeof(struct interface_screen));
memuse--;
}
ifscreen = interface->ifscreen_out;
{
temp = ifscreen;
ifscreen = ifscreen->next;
- memset(temp, 0, sizeof(struct interface_screen));
- free(temp);
+ FREE(temp, sizeof(struct interface_screen));
memuse--;
}
iffilter = interface->iffilter;
{
temp = iffilter;
iffilter = iffilter->next;
- memset(temp, 0, sizeof(struct interface_filter));
- free(temp);
+ FREE(temp, sizeof(struct interface_filter));
memuse--;
}
temp = interface;
interface = interface->next;
- memset(temp, 0, sizeof(struct interface));
- free(temp);
+ FREE(temp, sizeof(struct interface));
memuse--;
}
}
+/*
+ * defaults of ports if not specified by config
+ */
+static void set_defaults(struct interface_port *ifport)
+{
+ /* default channel selection list */
+ if (!ifport->out_channel)
+ default_out_channel(ifport);
+ if (!ifport->in_channel)
+ default_in_channel(ifport);
+ /* default is_tones */
+ if (ifport->interface->is_tones)
+ ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
+ else
+ ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
+ /* default is_earlyb */
+ if (ifport->interface->is_earlyb)
+ ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
+ else
+ ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
+ /* set locally flag */
+ if (ifport->interface->extension)
+ ifport->mISDNport->locally = 1;
+ else
+ ifport->mISDNport->locally = 0;
+}
+
/*
* all links between mISDNport and interface are made
{
ifport->mISDNport = mISDNport;
mISDNport->ifport = ifport;
+ set_defaults(ifport);
}
mISDNport = mISDNport->next;
}
/* link port */
ifport->mISDNport = mISDNport;
mISDNport->ifport = ifport;
-
- /* default channel selection list */
- if (!ifport->out_channel)
- default_out_channel(ifport);
- if (!ifport->in_channel)
- default_in_channel(ifport);
- /* default is_tones */
- if (ifport->interface->is_tones)
- ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
- else
- ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
- /* default is_earlyb */
- if (ifport->interface->is_earlyb)
- ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
- else
- ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
+ set_defaults(ifport);
} else
{
ifport->block = 2; /* not available */
p_m_b_channel = 0;
p_m_b_exclusive = 0;
p_m_b_reserve = 0;
- p_m_jittercheck = 0;
p_m_delete = 0;
p_m_hold = 0;
p_m_txvol = p_m_rxvol = 0;
p_m_timeout = 0;
p_m_timer = 0;
- /* audio from up */
- p_m_fromup_buffer_readp = 0;
- p_m_fromup_buffer_writep = 0;
+ /* audio */
+ p_m_load = 0;
+ p_m_last_tv_sec = 0;
/* crypt */
p_m_crypt = 0;
*d++ = c2;
mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
chan_trace_header(mISDNport, isdnport, "BCHANNEL control", DIRECTION_OUT);
- add_trace(trace_name, NULL, "%d", trace_value);
+ if (c1 == CMX_CONF_JOIN)
+ add_trace(trace_name, NULL, "0x%08x", trace_value);
+ else
+ add_trace(trace_name, NULL, "%d", trace_value);
end_trace();
}
goto stack_error;
chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL create stack", DIRECTION_OUT);
add_trace("channel", NULL, "%d", i+1+(i>=15));
- add_trace("stack", "id", "0x%8x", mISDNport->b_stid[i]);
- add_trace("stack", "address", "0x%8x", mISDNport->b_addr[i]);
+ add_trace("stack", "id", "0x%08x", mISDNport->b_stid[i]);
+ add_trace("stack", "address", "0x%08x", mISDNport->b_addr[i]);
end_trace();
return(1);
chan_trace_header(mISDNport, mISDNport->b_port[i], "BCHANNEL remove stack", DIRECTION_OUT);
add_trace("channel", NULL, "%d", i+1+(i>=15));
- add_trace("stack", "id", "0x%8x", mISDNport->b_stid[i]);
- add_trace("stack", "address", "0x%8x", mISDNport->b_addr[i]);
+ add_trace("stack", "id", "0x%08x", mISDNport->b_stid[i]);
+ add_trace("stack", "address", "0x%08x", mISDNport->b_addr[i]);
end_trace();
/* remove our stack only if set */
PDEBUG(DEBUG_BCHANNEL, "free stack (b_addr=0x%x)\n", mISDNport->b_addr[i]);
case B_EVENT_ACTIVATE:
/* port must be linked in order to allow activation */
if (!mISDNport->b_port[i])
- {
- PERROR("SOFTWARE ERROR: bchannel must be linked to a Port class\n");
- exit(-1);
- }
+ FATAL("bchannel must be linked to a Port class\n");
switch(state)
{
case B_STATE_IDLE:
case B_EVENT_DEACTIVATE:
if (!mISDNport->b_port[i])
- {
- PERROR("SOFTWARE ERROR: bchannel must be linked to a Port class\n");
- exit(-1);
- }
+ FATAL("bchannel must be linked to a Port class\n");
switch(state)
{
case B_STATE_IDLE:
p_m_b_index = i;
p_m_b_channel = channel;
p_m_b_exclusive = exclusive;
- p_m_jittercheck = 0;
/* reserve channel */
if (!p_m_b_reserve)
/*
* handler
+
+audio transmission procedure:
+-----------------------------
+
+* priority
+three sources of audio transmission:
+- crypto-data high priority
+- tones high priority (also high)
+- remote-data low priority
+
+* elapsed
+a variable that temporarily shows the number of samples elapsed since last transmission process.
+p_m_last_tv_* is used to store that last timestamp. this is used to calculate the time elapsed.
+
+* load
+a variable that is increased whenever data is transmitted.
+it is decreased while time elapses. it stores the number of samples that
+are currently loaded to dsp module.
+since clock in dsp module is the same clock for user space process, these
+times have no skew.
+
+* levels
+there are two levels:
+ISDN_LOAD will give the load that have to be kept in dsp.
+ISDN_MAXLOAD will give the maximum load before dropping.
+
+* procedure for low priority data
+see txfromup() for procedure
+in short: remote data is ignored during high priority tones
+
+* procedure for high priority data
+whenever load is below ISDN_LOAD, load is filled up to ISDN_LOAD
+if no more data is available, load becomes empty again.
+
+'load' variable:
+0 ISDN_LOAD ISDN_MAXLOAD
++--------------------+----------------------+
+| | |
++--------------------+----------------------+
+
+on empty load or on load below ISDN_LOAD, the load is inceased to ISDN_LOAD:
+0 ISDN_LOAD ISDN_MAXLOAD
++--------------------+----------------------+
+|TTTTTTTTTTTTTTTTTTTT| |
++--------------------+----------------------+
+
+on empty load, remote-audio causes the load with the remote audio to be increased to ISDN_LOAD.
+0 ISDN_LOAD ISDN_MAXLOAD
++--------------------+----------------------+
+|TTTTTTTTTTTTTTTTTTTTRRRRR |
++--------------------+----------------------+
+
*/
int PmISDN::handler(void)
{
struct message *message;
- int elapsed, length;
+ int elapsed = 0;
int ret;
- int inbuffer;
if ((ret = Port::handler()))
return(ret);
- inbuffer = (p_m_fromup_buffer_writep - p_m_fromup_buffer_readp) & FROMUP_BUFFER_MASK;
- /* send tone data to isdn device only if we have data */
- if (p_tone_name[0] || p_m_crypt_msg_loops || inbuffer)
+ /* get elapsed */
+ if (p_m_last_tv_sec)
{
- /* calculate how much to transmit */
- if (!p_last_tv_sec)
- {
- elapsed = ISDN_PRELOAD; /* preload for the first time */
- } else
- {
- elapsed = 8000 * (now_tv.tv_sec - p_last_tv_sec)
- + 8 * (now_tv.tv_usec/1000 - p_last_tv_msec);
- /* gap was greater preload, so only fill up to preload level */
- if (elapsed > ISDN_PRELOAD)
- {
- elapsed = ISDN_PRELOAD;
- }
- }
-printf("p%d elapsed=%d\n", p_serial, elapsed);
- if (elapsed >= ISDN_TRANSMIT)
+ elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec)
+ + 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec);
+ } else
+ {
+ /* set clock of first process ever in this instance */
+ p_m_last_tv_sec = now_tv.tv_sec;
+ p_m_last_tv_msec = now_tv.tv_usec/1000;
+ }
+ /* process only if we have a minimum of samples, to make packets not too small */
+ if (elapsed >= ISDN_TRANSMIT)
+ {
+ /* set clock of last process! */
+ p_m_last_tv_sec = now_tv.tv_sec;
+ p_m_last_tv_msec = now_tv.tv_usec/1000;
+
+ /* update load */
+ if (elapsed < p_m_load)
+ p_m_load -= elapsed;
+ else
+ p_m_load = 0;
+
+ /* to send data, tone must be active OR crypt messages must be on */
+ if ((p_tone_name[0] || p_m_crypt_msg_loops) && p_m_load < ISDN_LOAD)
{
- unsigned char buf[mISDN_HEADER_LEN+ISDN_PRELOAD];
+ int tosend = ISDN_LOAD - p_m_load, length;
+ unsigned char buf[mISDN_HEADER_LEN+tosend];
iframe_t *frm = (iframe_t *)buf;
unsigned char *p = buf+mISDN_HEADER_LEN;
- p_last_tv_sec = now_tv.tv_sec;
- p_last_tv_msec = now_tv.tv_usec/1000;
-
- /* read tones or fill with silence */
- length = read_audio(p, elapsed);
-
- /*
- * get data from up
- * the fromup_buffer data is written to the beginning of the buffer
- * the part that is filles with tones (length) is skipped, so tones have priority
- * the length value is increased by the number of data copied from fromup_buffer
- */
-printf("p%d inbuffer=%d\n", p_serial, inbuffer);
- if (inbuffer)
- {
- /* inbuffer might be less than we skip due to audio */
- if (inbuffer <= length)
- {
- /* clear buffer */
- p_m_fromup_buffer_readp = p_m_fromup_buffer_writep;
- inbuffer = 0;
- } else
- {
- /* skip what we already have with tones */
- p_m_fromup_buffer_readp = (p_m_fromup_buffer_readp + length) & FROMUP_BUFFER_MASK;
- inbuffer -= length;
- p += length;
- }
- /* if we have more in buffer, than we send this time */
- if (inbuffer > (elapsed-length))
- inbuffer = elapsed - length;
- /* set length to what we actually have */
- length = length + inbuffer;
-printf("p%d inbuffer=%d\n", p_serial, inbuffer);
- /* now fill up with fromup_buffer */
- while (inbuffer)
- {
- *p++ = p_m_fromup_buffer[p_m_fromup_buffer_readp];
- p_m_fromup_buffer_readp = (p_m_fromup_buffer_readp + 1) & FROMUP_BUFFER_MASK;
- inbuffer--;
- }
- }
-printf("p%d length=%d\n", p_serial, length);
-
- /* overwrite buffer with crypto stuff */
- if (p_m_crypt_msg_loops)
+ /* copy crypto loops */
+ while (p_m_crypt_msg_loops && tosend)
{
- /* send pending message */
- int tosend;
-
/* how much do we have to send */
- tosend = p_m_crypt_msg_len - p_m_crypt_msg_current;
- if (tosend > elapsed)
- tosend = elapsed;
+ length = p_m_crypt_msg_len - p_m_crypt_msg_current;
- /* our length increases, if less */
- if (length < tosend)
+ /* clip tosend */
+ if (length > tosend)
length = tosend;
/* copy message (part) to buffer */
- memcpy(p, p_m_crypt_msg+p_m_crypt_msg_current, tosend);
- p_m_crypt_msg_current += tosend;
+ memcpy(p, p_m_crypt_msg+p_m_crypt_msg_current, length);
+
+ /* new position */
+ p_m_crypt_msg_current += length;
if (p_m_crypt_msg_current == p_m_crypt_msg_len)
{
+ /* next loop */
p_m_crypt_msg_current = 0;
p_m_crypt_msg_loops--;
}
+
+ /* new length */
+ tosend -= length;
+ }
+
+ /* copy tones */
+ if (p_tone_name[0] && tosend)
+ {
+ tosend -= read_audio(p, tosend);
}
+
+ /* send data */
frm->prim = DL_DATA | REQUEST;
frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
frm->dinfo = 0;
- frm->len = length;
- mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
-
- if (p_debug_nothingtosend)
- {
- p_debug_nothingtosend = 0;
- PDEBUG((DEBUG_PORT | DEBUG_BCHANNEL), "PmISDN(%s) start sending, because we have tones and/or remote audio.\n", p_name);
- }
- return(1);
+ frm->len = ISDN_LOAD - p_m_load - tosend;
+ if (frm->len)
+ mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+ p_m_load += frm->len;
}
- } else
- {
- if (!p_debug_nothingtosend)
- {
- p_debug_nothingtosend = 1;
- PDEBUG((DEBUG_PORT | DEBUG_BCHANNEL), "PmISDN(%s) stop sending, because we have only silence.\n", p_name);
- }
}
// NOTE: deletion is done by the child class
case CMX_TX_DATA:
if (!p_m_txdata)
{
- /* if rx is off, it may happen that fifos send us pending informations, we just ignore them */
- PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) ignoring rx data, because 'txdata' is turned off\n", p_name);
+ /* if tx is off, it may happen that fifos send us pending informations, we just ignore them */
+ PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) ignoring tx data, because 'txdata' is turned off\n", p_name);
return;
}
if (p_record)
* the call is connected OR interface features audio during call setup.
*/
//printf("%d -> %d prim=%x calldata=%d tones=%d\n", p_serial, ACTIVE_EPOINT(p_epointlist), frm->prim, p_m_calldata, p_m_mISDNport->earlyb);
-#warning "disabled for debug"
-#if 0
+#ifndef DEBUG_COREBRIDGE
if (p_state!=PORT_STATE_CONNECT
&& !p_m_mISDNport->earlyb)
return;
free_msg(msg);
if (errno == EAGAIN)
return(0);
- PERROR("FATAL ERROR: failed to do mISDN_read()\n");
- exit(-1);
+ FATAL("Failed to do mISDN_read()\n");
}
if (!ret)
{
if (ret < (int)mISDN_HEADER_LEN)
{
noentity:
- fprintf(stderr, "cannot request MGR_NEWENTITY from mISDN. Exitting due to software bug.");
- exit(-1);
+ FATAL("Cannot request MGR_NEWENTITY from mISDN. Exitting due to software bug.");
}
entity = frm->dinfo & 0xffff;
if (!entity)
mISDNportp = &mISDNport_first;
while(*mISDNportp)
mISDNportp = &((*mISDNportp)->next);
- mISDNport = (struct mISDNport *)calloc(1, sizeof(struct mISDNport));
- if (!mISDNport)
- {
- PERROR("Cannot alloc mISDNport structure\n");
- return(NULL);
- }
+ mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
pmemuse++;
- memset(mISDNport, 0, sizeof(mISDNport));
*mISDNportp = mISDNport;
/* allocate ressources of port */
/* phd */
msg_queue_purge(&nst->down_queue);
if (nst->phd_down_msg)
- free(nst->phd_down_msg);
+ FREE(nst->phd_down_msg, 0);
}
}
}
if (mISDNportp)
- {
- PERROR("software error, mISDNport not in list\n");
- exit(-1);
- }
+ FATAL("mISDNport not in list\n");
- memset(mISDNport, 0, sizeof(struct mISDNport));
- free(mISDNport);
+ FREE(mISDNport, sizeof(struct mISDNport));
pmemuse--;
/* close mISDNdevice, if no port */
if ((device = mISDN_open()) < 0)
{
fprintf(stderr, "cannot open mISDN device ret=%d errno=%d (%s) Check for mISDN modules!\nAlso did you create \"/dev/mISDN\"? Do: \"mknod /dev/mISDN c 46 0\"\n", device, errno, strerror(errno));
- exit(-1);
+ exit(EXIT_FAILURE);
}
/* get number of stacks */
/* close mISDN */
if ((err = mISDN_close(device)))
- {
- fprintf(stderr, "mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
- exit(-1);
- }
+ FATAL("mISDN_close() failed: err=%d '%s'\n", err, strerror(err));
}
*/
void PmISDN::txfromup(unsigned char *data, int length)
{
- int avail;
- /* no data */
- if (!length)
- return;
+ unsigned char buf[mISDN_HEADER_LEN+((length>ISDN_LOAD)?length:ISDN_LOAD)];
+ iframe_t *frm = (iframe_t *)buf;
- /* get free samples in buffer */
- avail = ((p_m_fromup_buffer_readp - p_m_fromup_buffer_writep - 1) & FROMUP_BUFFER_MASK);
- if (avail < length)
- {
- PDEBUG(DEBUG_PORT, "Port(%d): fromup_buffer overflows, this shall not happen under normal conditions\n", p_serial);
+ /* configure frame */
+ frm->prim = DL_DATA | REQUEST;
+ frm->addr = p_m_mISDNport->b_addr[p_m_b_index] | FLG_MSG_DOWN;
+ frm->dinfo = 0;
+
+ /* check if high priority tones exist
+ * ignore data in this case
+ */
+ if (p_tone_name[0] || p_m_crypt_msg_loops)
return;
- }
- /* write data to buffer and return */
- while(length)
+ /* preload procedure
+ * if transmit buffer in DSP module is empty,
+ * preload it to DSP_LOAD to prevent jitter gaps.
+ */
+ if (p_m_load==0 && ISDN_LOAD>0)
{
- p_m_fromup_buffer[p_m_fromup_buffer_writep] = *data++;
- p_m_fromup_buffer_writep = (p_m_fromup_buffer_writep + 1) & FROMUP_BUFFER_MASK;
- length--;
+
+ memcpy(buf+mISDN_HEADER_LEN, data, ISDN_LOAD);
+ frm->len = ISDN_LOAD;
+ mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+ p_m_load += frm->len;
}
- return; // must return, because length is 0
+
+ /* drop if load would exceed ISDN_MAXLOAD
+ * this keeps the delay not too high
+ */
+ if (p_m_load+length > ISDN_MAXLOAD)
+ return;
+
+ /* load data to buffer
+ */
+ memcpy(buf+mISDN_HEADER_LEN, data, length);
+ frm->len = length;
+ mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
+ p_m_load += frm->len;
}
int b_addr[128];
int b_state[128]; /* state 0 = IDLE */
int procids[128]; /* keep track of free ids */
+ int locally; /* local causes are sent as local causes not remote */
msg_queue_t downqueue; /* l4->l3 */
};
extern mISDNport *mISDNport_first;
int p_m_dtmf; /* dtmf decoding is enabled */
int p_m_calldata; /* the call requires data due to no briging capability */
- int p_m_fromup_buffer_readp; /* buffer for audio from remote endpoint */
- int p_m_fromup_buffer_writep;
- unsigned char p_m_fromup_buffer[FROMUP_BUFFER_SIZE];
+ int p_m_load; /* current data in dsp tx buffer */
+ unsigned long p_m_last_tv_sec; /* time stamp of last handler call, (to sync audio data */
+ unsigned long p_m_last_tv_msec;
+// int p_m_fromup_buffer_readp; /* buffer for audio from remote endpoint */
+// int p_m_fromup_buffer_writep;
+// unsigned char p_m_fromup_buffer[FROMUP_BUFFER_SIZE];
void txfromup(unsigned char *data, int length);
int p_m_crypt; /* encryption is enabled */
int p_m_b_channel; /* number 1,2 1..15,17... */
int p_m_b_exclusive; /* if bchannel is exclusive */
int p_m_b_reserve; /* set if channel is reserved */
- long long p_m_jittercheck; /* time of audio data */
- long long p_m_jitterdropped; /* number of bytes dropped */
+// long long p_m_jittercheck; /* time of audio data */
+// long long p_m_jitterdropped; /* number of bytes dropped */
int p_m_delete; /* true if obj. must del. */
int p_m_hold; /* if port is on hold */
unsigned long p_m_timeout; /* timeout of timers */
PDEBUG(DEBUG_EPOINT, "child process done for sending a mail\n");
/* exit process */
- memset(args, 0, sizeof(struct mail_args));
- free(args);
+ FREE(args, sizeof(struct mail_args));
amemuse--;
return(NULL);
}
struct mail_args *arg;
pthread_t tid;
- arg = (struct mail_args *)calloc(1, sizeof(struct mail_args));
- if (!arg)
- {
- PERROR("failed to alloc memory.\n");
- return;
- }
+ arg = (struct mail_args *)MALLOC(sizeof(struct mail_args));
amemuse++;
SCPY(arg->email, vbox_email);
printf("rules [action] = Get individual help for given action.\n");
// printf("route = Show current routing as it is parsed.\n");
printf("\n");
- ret = 0;
+ ret = 999;
goto free;
}
MEMCHECK("file handler(s) left",fhuse)
/* take me out */
+ if (ret == 999)
+ exit(0);
SPRINT(tracetext, "%s exit", NAME);
printf("%s\n", tracetext);
start_trace(0, NULL, NULL, NULL, 0, 0, 0, tracetext);
#define PERROR_RUNTIME(fmt, arg...) _printerror(NULL, 0, fmt, ## arg)
void _printdebug(const char *function, int line, unsigned long mask, const char *fmt, ...);
void _printerror(const char *function, int line, const char *fmt, ...);
+#define DEBUG_FUNC
void debug(const char *function, int line, char *prefix, char *buffer);
#define DEBUG_CONFIG 0x0001
#define DEBUG_LOG 0x7fff
/*
- * preload transmit buffer to avoid gaps at the beginning due to jitter
- * this is also the maximum load that will be kept in tx-buffer
- */
-#define ISDN_PRELOAD 1024 // samples
-
-/*
- * interval for refreshing transmit buffer
+ * load transmit buffer to avoid gaps at the beginning due to jitter
+ * also the maximum load that will be kept in tx-buffer
+ * also the (minimum) number of data to transmit in a frame
*/
+#define ISDN_LOAD 1024 // samples
+#define ISDN_MAXLOAD 2048 // samples
#define ISDN_TRANSMIT 256 // samples
/* give sendmail program. if not inside $PATH, give absolute path here (e.g. "/usr/sbin/sendmail")
*/
#define SENDMAIL "sendmail"
-/* maximum number of redial/powerdial and reply numbers to remember
- */
-#define MAX_REMEMBER 50
-
/* leave it above 1024, because lower values can be unsafe, higher valuse cause
* data larger than 512 bytes of hex strings.
*/
*/
#define RULE_NESTING 10
+/* to debug core bridging, rather than mISDN dsp bridging, enable.
+ * this is for debugging only, bridging conferences will not work
+ */
+//#define DEBUG_COREBRIDGE
+
/* special debugging for buffer overflow bugs
* note: whenever a buffer gets strange values, the budetect function must
* be modified to detect the change of these values. whenever it is detected,
#ifdef __cplusplus
}
#endif
-#include "save.h"
+#include "macro.h"
#include "options.h"
#include "interface.h"
#include "extension.h"
#include "vbox.h"
#include "call.h"
#include "callpbx.h"
-#include "callchan.h"
+#include "callasterisk.h"
#include "cause.h"
#include "alawulaw.h"
#include "tones.h"
struct message *message_create(int id_from, int id_to, int flow, int type)
{
struct message *message;
- int i = 0;
- while(i < 10)
- {
- message = (struct message *)calloc(1, sizeof(struct message));
- if (message)
- break;
-
- if (!i)
- PERROR("no mem for message, retrying...\n");
- i++;
- usleep(300000);
- }
+ message = (struct message *)MALLOC(sizeof(struct message));
if (!message)
- {
- PERROR("***Fatal error: no mem for message!!! exitting.\n");
- exit(-1);
- }
+ FATAL("No memory for message.\n");
mmemuse++;
- memset(message, 0, sizeof(struct message));
-
message->id_from = id_from;
message->id_to = id_to;
message->flow = flow;
messagepointer_end = &(message->next);
}
+void message_forward(int id_from, int id_to, int flow, union parameter *param)
+{
+ struct message *message;
+
+ /* get point to message */
+ message = (struct message *)((unsigned long)param - ((unsigned long)(&message->param) - (unsigned long)message));
+
+ /* protect, so forwarded messages are not freed after handling */
+ message->keep = 1;
+
+ message->id_from = id_from;
+ message->id_to = id_to;
+ message->flow = flow;
+ message_put(message);
+}
/* detaches the first messages from the message chain */
struct message *message_get(void)
if (!message_first)
messagepointer_end = &message_first;
+ message->keep = 0;
+
if ((options.deb&DEBUG_MSG) && message->type != MESSAGE_DATA)
+
PDEBUG(DEBUG_MSG, "message %s reading from %ld to %ld (memory %x)\n", messages_txt[message->type], message->id_from, message->id_to, message);
return(message);
/* free a message */
void message_free(struct message *message)
{
- memset(message, 0, sizeof(struct message));
- free(message);
+ if (message->keep)
+ return;
+ FREE(message, sizeof(struct message));
mmemuse--;
}
char extension[32]; /* internal id */
char name[16];
int isdn_port; /* internal/external port (if call is isdn) */
- char interfaces[128]; /* interfaces for extenal calls */
+ char interface[128]; /* interface for extenal calls */
int itype; /* type of interface */
int ntype; /* type of number */
int present; /* presentation */
int flow; /* from where to where */
unsigned long id_from; /* in case of flow==PORT_TO_EPOINT: id_from is the port's serial, id_to is the epoint's serial */
unsigned long id_to;
+ int keep;
union parameter param;
};
MESSAGE_VBOX_TONE, /* set answering VBOX tone */
MESSAGE_TONE_COUNTER, /* tone counter (for VBOX tone use) */
MESSAGE_TONE_EOF, /* tone is end of file */
+ MESSAGE_HELLO, /* hello message for asterisk */
};
#define MESSAGES static const char *messages_txt[] = { \
"MESSAGE_VBOX_TONE", \
"MESSAGE_TONE_COUNTER", \
"MESSAGE_TONE_EOF", \
+ "MESSAGE_HELLO", \
};
struct message *message_create(int id_from, int id_to, int flow, int type);
void message_put(struct message *message);
+void message_forward(int id_from, int id_to, int flow, union parameter *param);
struct message *message_get(void);
void message_free(struct message *message);
/* free */
PDEBUG(DEBUG_EPOINT, "PORT(%d) removed epoint from port\n", p_serial);
- memset(temp, 0, sizeof(struct epoint_list));
- free(temp);
+ FREE(temp, sizeof(struct epoint_list));
ememuse--;
}
}
if (temp == 0)
{
- PERROR("epoint_id not in port's list, exitting.\n");
+ PERROR("epoint_id not in port's list.\n");
return;
}
/* detach */
/* free */
PDEBUG(DEBUG_EPOINT, "PORT(%d) removed epoint from port\n", p_serial);
- memset(temp, 0, sizeof(struct epoint_list));
- free(temp);
+ FREE(temp, sizeof(struct epoint_list));
ememuse--;
}
struct epoint_list *epointlist, **epointlistpointer;
/* epointlist structure */
- epointlist = (struct epoint_list *)calloc(1, sizeof(struct epoint_list));
+ epointlist = (struct epoint_list *)MALLOC(sizeof(struct epoint_list));
if (!epointlist)
- {
- PERROR("no mem for allocating epoint_list\n");
- return(0);
- }
+ FATAL("No memory for epointlist\n");
ememuse++;
PDEBUG(DEBUG_EPOINT, "PORT(%d) allocating epoint_list.\n", p_serial);
- memset(epointlist, 0, sizeof(struct epoint_list));
/* add epoint_list to chain */
epointlist->next = NULL;
}
SCPY(p_name, portname);
SCPY(p_tone_dir, p_settings.tones_dir); // just to be sure
- p_last_tv_sec = 0;
- p_last_tv_msec = 0;
p_type = type;
p_serial = port_serial++;
- p_debug_nothingtosend = 0;
p_tone_fh = -1;
p_tone_fetched = NULL;
p_tone_name[0] = '\0';
temp = temp->next;
}
if (temp == NULL)
- {
- PERROR("PORT(%s) port not in port's list.\n", p_name);
- exit(-1);
- }
+ FATAL("PORT(%s) port not in port's list.\n", p_name);
/* detach */
*tempp=this->next;
/*
* read from the given file as specified in port_set_tone and return sample data
- * silence is appended if sample ends, but only the number of samples with tones are returned
+ * if the tone ends, the result may be less samples than requested
*/
int Port::read_audio(unsigned char *buffer, int length)
{
len = length;
/* if there is no tone set, use silence */
- if (p_tone_name[0] == 0)
- {
-rest_is_silence:
- memset(buffer, (options.law=='a')?0x2a:0xff, len); /* silence */
- goto done;
- }
+ if (!p_tone_name[0])
+ return(0);
/* if the file pointer is not open, we open it */
if (p_tone_fh<0 && p_tone_fetched==NULL)
}
if (len==0)
- goto done;
+ return(length-len);
if (p_tone_fh >= 0)
{
PDEBUG(DEBUG_PORT, "PORT(%s) 0-length loop: %s\n", p_name, filename);
p_tone_name[0]=0;
p_tone_dir[0]=0;
- goto rest_is_silence;
+ return(length-len);
}
/* if eof is reached, or if the normal file cannot be opened, continue with the loop file if possible */
PDEBUG(DEBUG_PORT, "PORT(%s) no tone loop: %s\n",p_name, filename);
p_tone_dir[0] = '\0';
p_tone_name[0] = '\0';
- goto rest_is_silence;
+ return(length-len);
}
fhuse++;
}
PDEBUG(DEBUG_PORT, "PORT(%s) no tone loop: %s\n",p_name, filename);
p_tone_dir[0] = '\0';
p_tone_name[0] = '\0';
- goto rest_is_silence;
+ return(length-len);
}
fhuse++;
}
/* now we have opened the loop */
goto read_more;
-
-done:
- return(length-len);
}
struct port_settings p_settings;
/* tone */
- unsigned long p_last_tv_sec; /* time stamp of last handler call, (to sync audio data */
- unsigned long p_last_tv_msec;
- int p_debug_nothingtosend; /* used for debugging the, if we have currently nothing to send (used for ISDN) */
char p_tone_dir[256]; /* name of current directory */
char p_tone_name[256]; /* name of current tone */
char p_tone_fh; /* file descriptor of current tone or -1 if not open */
{ "busy", MATCH_BUSY, COND_TYPE_STRING,
"busy=<extension>[,...]","Matches if any of the given extension is busy."},
{ "notbusy", MATCH_IDLE, COND_TYPE_STRING,
- "notbusy<extension>[,...]","Matches if any of the given extension is not busy."},
+ "notbusy=<extension>[,...]","Matches if any of the given extension is not busy."},
+ { "asterisk", MATCH_ASTERISK, COND_TYPE_NULL,
+ "asterisk","Matches if asterisk is not running with LCR channel driver."},
+ { "notasterisk",MATCH_NOTASTERISK,COND_TYPE_NULL,
+ "notasterisk","Matches if asterisk is not running with LCR channel driver."},
{ NULL, 0, 0, NULL}
};
cond = rule->cond_first;
if (cond->string_value)
{
- free(cond->string_value);
+ FREE(cond->string_value, 0);
rmemuse--;
}
if (cond->string_value_to)
{
- free(cond->string_value_to);
+ FREE(cond->string_value_to, 0);
rmemuse--;
}
rule->cond_first = cond->next;
- free(cond);
+ FREE(cond, sizeof(struct route_cond));
rmemuse--;
}
while(rule->action_first)
action->param_first = param->next;
if (param->string_value)
{
- free(param->string_value);
+ FREE(param->string_value, 0);
rmemuse--;
}
- free(param);
+ FREE(param, sizeof(struct route_param));
rmemuse--;
}
- free(action);
+ FREE(action, sizeof(struct route_action));
rmemuse--;
}
- free(rule);
+ FREE(rule, sizeof(struct route_rule));
rmemuse--;
}
- free(ruleset);
+ FREE(ruleset, sizeof(struct route_ruleset));
rmemuse--;
}
}
}
/* create ruleset */
- ruleset = (struct route_ruleset *)malloc(sizeof(struct route_ruleset));
- if (ruleset == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ ruleset = (struct route_ruleset *)MALLOC(sizeof(struct route_ruleset));
rmemuse++;
- memset(ruleset, 0, sizeof(struct route_ruleset));
*ruleset_pointer = ruleset;
ruleset_pointer = &(ruleset->next);
SCPY(ruleset->name, key);
goto new_ruleset;
}
- /* alloc memory for rule */
- rule = (struct route_rule *)malloc(sizeof(struct route_rule));
- if (rule == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ /* Alloc memory for rule */
+ rule = (struct route_rule *)MALLOC(sizeof(struct route_rule));
rmemuse++;
- memset(rule, 0, sizeof(struct route_rule));
*rule_pointer = rule;
rule_pointer = &(rule->next);
cond_pointer = &(rule->cond_first);
}
nextcondvalue:
- /* alloc memory for item */
- cond = (struct route_cond *)malloc(sizeof(struct route_cond));
- if (cond == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ /* Alloc memory for item */
+ cond = (struct route_cond *)MALLOC(sizeof(struct route_cond));
rmemuse++;
- memset(cond, 0, sizeof(struct route_cond));
*cond_pointer = cond;
cond_pointer = &(cond->next);
cond->index = index;
}
}
alloc_string:
- cond->string_value = (char *)malloc(strlen(key)+1);
- if (cond->string_value == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ cond->string_value = (char *)MALLOC(strlen(key)+1);
rmemuse++;
UCPY(cond->string_value, key);
if (value_type == VALUE_TYPE_STRING_RANGE)
{
- cond->string_value_to = (char *)malloc(strlen(key_to)+1);
- if (cond->string_value_to == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ cond->string_value_to = (char *)MALLOC(strlen(key_to)+1);
rmemuse++;
UCPY(cond->string_value_to, key_to);
cond->comp_string = strcmp(key, key_to);
}
/* alloc memory for action */
- action = (struct route_action *)malloc(sizeof(struct route_action));
- if (action == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ action = (struct route_action *)MALLOC(sizeof(struct route_action));
rmemuse++;
- memset(action, 0, sizeof(struct route_action));
*action_pointer = action;
action_pointer = &(action->next);
param_pointer = &(action->param_first);
}
nextparamvalue:
- /* alloc memory for param */
- param = (struct route_param *)malloc(sizeof(struct route_param));
- if (param == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ /* Alloc memory for param */
+ param = (struct route_param *)MALLOC(sizeof(struct route_param));
rmemuse++;
- memset(param, 0, sizeof(struct route_param));
*param_pointer = param;
param_pointer = &(param->next);
param->index = index;
SPRINT(failure, "Value '%s' unknown. ('yes' or 'no')", key);
goto parse_error;
}
- param->string_value = (char *)malloc(strlen(key)+1);
- if (param->string_value == NULL)
- {
- SPRINT(failure, "Out of memory.");
- goto parse_error;
- }
+ param->string_value = (char *)MALLOC(strlen(key)+1);
rmemuse++;
UCPY(param->string_value, key);
param->value_type = VALUE_TYPE_STRING;
FILE *tfp;
double timeout;
struct mISDNport *mISDNport;
+ struct admin_list *admin;
/* reset timeout action */
e_match_timeout = 0; /* no timeout */
break;
case MATCH_BUSY:
+ case MATCH_IDLE:
any = 0;
mISDNport = mISDNport_first;
while(mISDNport)
break;
mISDNport = mISDNport->next;
}
- if (mISDNport)
+ if (mISDNport && cond->match==MATCH_BUSY)
+ istrue = 1;
+ if (!mISDNport && cond->match==MATCH_IDLE)
istrue = 1;
break;
- case MATCH_IDLE:
- mISDNport = mISDNport_first;
- while(mISDNport)
+ case MATCH_ASTERISK:
+ case MATCH_NOTASTERISK:
+ admin = admin_list;
+ while(admin)
{
- if (mISDNport->ifport)
- if (!strcasecmp(mISDNport->ifport->interface->name, cond->string_value))
- if (mISDNport->use) /* break if in use */
+ if (admin->asterisk)
break;
- mISDNport = mISDNport->next;
+ admin = admin->next;
}
- if (!mISDNport)
+ if (admin && cond->match==MATCH_ASTERISK)
+ istrue = 1;
+ if (!admin && cond->match==MATCH_NOTASTERISK)
istrue = 1;
break;
MATCH_UP,
MATCH_BUSY,
MATCH_IDLE,
+ MATCH_ASTERISK,
+ MATCH_NOTASTERISK,
};
enum { /* how to parse text file during startup */
-BUG: no channels after reload interfaces
-BUG: audio is corrupted, shall we use fh or name for state of tones?
BUG: release to NT not always work
make asterisk call implementation
display message during nothing/play
-Port -> Channel
+Port -> Proc
Call -> Link
maybe:
facility: diversion, 3pty, ...
+VLAN-Kamera
+
+
break;
default:
- PERROR("codec %d is not supported, exitting...\n", codec);
- exit(-1);
+ FATAL("codec %d is not supported.\n", codec);
}
if (l>0 && left)
{
temp = tonesettone_temp;
tonesettone_temp = tonesettone_temp->next;
- free(temp);
+ FREE(temp, sizeof(struct tonesettone));
memuse--;
}
temp = toneset_temp;
toneset_temp = toneset_temp->next;
- free(temp);
+ FREE(temp, sizeof(struct toneset));
memuse--;
}
toneset_first = NULL;
printf("PBX: Fetching tones '%s'\n", p);
PDEBUG(DEBUG_PORT, "fetching tones directory '%s'\n", p);
- *toneset_nextpointer = (struct toneset *)calloc(1, sizeof(struct toneset));
- if (*toneset_nextpointer == NULL)
- {
- PERROR("No memory for tone set: '%s'\n",p);
- return(0);
- }
+ *toneset_nextpointer = (struct toneset *)MALLOC(sizeof(struct toneset));
memuse++;
memory += sizeof(struct toneset);
- memset(*toneset_nextpointer, 0 , sizeof(struct toneset));
SCPY((*toneset_nextpointer)->directory, p);
tonesettone_nextpointer = &(*toneset_nextpointer)->first;
continue;
}
- /* allocate tone */
- *tonesettone_nextpointer = (struct tonesettone *)calloc(1, sizeof(struct tonesettone)+tone_size);
- if (*toneset_nextpointer == NULL)
- {
- PERROR("No memory for tone set: '%s'\n",p);
- close(fh);
- fduse--;
- return(0);
- }
+ /* Allocate tone */
+ *tonesettone_nextpointer = (struct tonesettone *)MALLOC(sizeof(struct tonesettone)+tone_size);
memuse++;
//printf("tone:%s, %ld bytes\n", name, tone_size);
- memset(*tonesettone_nextpointer, 0 , sizeof(struct tonesettone)+tone_size);
memory += sizeof(struct tonesettone)+tone_size;
samples ++;
}
/* 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)+sizeof(admin_message));
response->num = 1;
/* message */
response->am[0].message = ADMIN_TRACE_RESPONSE;
-
memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
/* link relation */
if (p_epointlist)
- {
- PERROR("PORT(%s) software error: epoint pointer is set in idle state, how bad!! exitting.\n", p_name);
- exit(-1);
- }
- if (!(epointlist_new(epoint_id)))
- {
- PERROR("no memory for epointlist\n");
- exit(-1);
- }
+ FATAL("PORT(%s) Epoint pointer is set in idle state, how bad!!\n", p_name);
+ epointlist_new(epoint_id);
/* copy setup infos to port */
SCPY(p_vbox_extension, param->setup.dialinginfo.id);