diff --git a/src/isdn/main.c b/src/isdn/main.c index bf86c5a..e49a287 100644 --- a/src/isdn/main.c +++ b/src/isdn/main.c @@ -193,7 +193,7 @@ static int handle_options(int short_option, int argi, char **argv) law = 'u'; break; case 'p': - portname = strdup(argv[argi]); + portname = options_strdup(argv[argi]); break; case 'n': ntmode = 1; @@ -211,13 +211,13 @@ static int handle_options(int short_option, int argi, char **argv) layer2hold = atoi(argv[argi]); break; case OPT_CHANNEL_OUT: - channel_out = strdup(argv[argi]); + channel_out = options_strdup(argv[argi]); break; case OPT_CHANNEL_IN: - channel_in = strdup(argv[argi]); + channel_in = options_strdup(argv[argi]); break; case OPT_TIMEOUTS: - timeouts = strdup(argv[argi]); + timeouts = options_strdup(argv[argi]); break; case OPT_TX_DELAY: tx_delay = atoi(argv[argi]); @@ -229,7 +229,7 @@ static int handle_options(int short_option, int argi, char **argv) rx_gain = atoi(argv[argi]) / 6; break; case OPT_PIPELINE: - pipeline = strdup(argv[argi]); + pipeline = options_strdup(argv[argi]); break; case OPT_DTMF: dtmf = atoi(argv[argi]); @@ -261,7 +261,7 @@ static int handle_options(int short_option, int argi, char **argv) fprintf(stderr, "Too many osmo-cc args!\n"); break; } - cc_argv[cc_argc++] = strdup(argv[argi]); + cc_argv[cc_argc++] = options_strdup(argv[argi]); break; default: return -EINVAL; @@ -304,7 +304,7 @@ int main(int argc, char *argv[]) if (!isdn_ep) goto error; - cc_argv[cc_argc++] = strdup("remote auto"); + cc_argv[cc_argc++] = options_strdup("remote auto"); /* handle options / config file */ add_options(); @@ -373,6 +373,8 @@ error: if (layer3_initialized) cleanup_layer3(); + options_free(); + return 0; } diff --git a/src/libdebug/debug.c b/src/libdebug/debug.c index 946963d..44902ea 100644 --- a/src/libdebug/debug.c +++ b/src/libdebug/debug.c @@ -40,11 +40,51 @@ struct debug_cat { const char *color; } debug_cat[] = { { "options", "\033[0;33m" }, + { "sender", "\033[1;33m" }, + { "sound", "\033[0;35m" }, { "dsp", "\033[0;31m" }, + { "anetz", "\033[1;34m" }, + { "bnetz", "\033[1;34m" }, + { "cnetz", "\033[1;34m" }, + { "nmt", "\033[1;34m" }, + { "amps", "\033[1;34m" }, + { "r2000", "\033[1;34m" }, + { "imts", "\033[1;34m" }, + { "mpt1327", "\033[1;34m" }, + { "jollycom", "\033[1;34m" }, + { "eurosignal", "\033[1;34m" }, + { "frame", "\033[0;36m" }, + { "call", "\033[0;37m" }, + { "cc", "\033[1;32m" }, + { "database", "\033[0;33m" }, + { "transaction", "\033[0;32m" }, + { "dms", "\033[0;33m" }, + { "sms", "\033[1;37m" }, + { "sdr", "\033[1;31m" }, + { "uhd", "\033[1;35m" }, + { "soapy", "\033[1;35m" }, + { "wave", "\033[1;33m" }, + { "radio", "\033[1;34m" }, + { "am791x", "\033[0;31m" }, + { "uart", "\033[0;32m" }, + { "device", "\033[0;33m" }, + { "datenklo", "\033[1;34m" }, + { "zeit", "\033[1;34m" }, + { "sim layer 1", "\033[0;31m" }, + { "sim layer 2", "\033[0;33m" }, + { "sim ICL layer", "\033[0;36m" }, + { "sim layer 7", "\033[0;37m" }, + { "mtp layer 2", "\033[1;33m" }, + { "mtp layer 3", "\033[1;36m" }, + { "MuP", "\033[1;37m" }, + { "router", "\033[1;35m" }, + { "stderr", "\033[1;37m" }, + { "ss5", "\033[1;34m" }, { "isdn", "\033[1;35m" }, { "misdn", "\033[0;34m" }, { "dss1", "\033[1;34m" }, - { "cc", "\033[1;32m" }, + { "sip", "\033[1;35m" }, + { "telephone", "\033[1;34m" }, { NULL, NULL } }; @@ -52,12 +92,34 @@ int debuglevel = DEBUG_INFO; uint64_t debug_mask = ~0; extern int num_kanal; +void (*clear_console_text)(void) = NULL; +void (*print_console_text)(void) = NULL; + +int debug_limit_scroll = 0; + +void get_win_size(int *w, int *h) +{ + struct winsize win; + int rc; + + rc = ioctl(0, TIOCGWINSZ, &win); + if (rc) { + *w = 80; + *h = 25; + return; + } + + *h = win.ws_row; + *w = win.ws_col; +} + void _printdebug(const char *file, const char __attribute__((unused)) *function, int line, int cat, int level, const char *kanal, const char *fmt, ...) { char buffer[4096], *b = buffer; int s = sizeof(buffer) - 1; const char *p; va_list args; + int w, h; if (debuglevel > level) return; @@ -80,7 +142,17 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function, while ((p = strchr(file, '/'))) file = p + 1; + if (clear_console_text) + clear_console_text(); + if (debug_limit_scroll) { + get_win_size(&w, &h); + printf("\0337\033[%d;%dr\0338", debug_limit_scroll + 1, h); + } printf("%s%s:%4d %s: %s\033[0;39m", debug_cat[cat].color, file, line, debug_level[level], buffer); + if (debug_limit_scroll) + printf("\0337\033[%d;%dr\0338", 1, h); + if (print_console_text) + print_console_text(); fflush(stdout); } @@ -136,22 +208,24 @@ void debug_list_cat(void) int parse_debug_opt(const char *optarg) { int i, max_level = 0; - char *dstring, *p; + char *dup, *dstring, *p; for (i = 0; debug_level[i]; i++) max_level = i; - dstring = strdup(optarg); + dup = dstring = strdup(optarg); p = strsep(&dstring, ","); for (i = 0; i < p[i]; i++) { if (p[i] < '0' || p[i] > '9') { fprintf(stderr, "Only digits are allowed for debug level!\n"); + free(dup); return -EINVAL; } } debuglevel = atoi(p); if (debuglevel > max_level) { fprintf(stderr, "Debug level too high, use 'list' to show available levels!\n"); + free(dup); return -EINVAL; } if (dstring) @@ -163,11 +237,13 @@ int parse_debug_opt(const char *optarg) } if (!debug_cat[i].name) { fprintf(stderr, "Given debug category '%s' unknown, use 'list' to show available categories!\n", p); + free(dup); return -EINVAL; } debug_mask |= ((uint64_t)1 << i); } + free(dup); return 0; } diff --git a/src/libdebug/debug.h b/src/libdebug/debug.h index 63cd23c..64cc155 100644 --- a/src/libdebug/debug.h +++ b/src/libdebug/debug.h @@ -5,11 +5,51 @@ #define DEBUG_ERROR 3 /* there is an error with this software */ #define DOPTIONS 0 -#define DDSP 1 -#define DISDN 2 -#define DMISDN 3 -#define DDSS1 4 -#define DCC 5 +#define DSENDER 1 +#define DSOUND 2 +#define DDSP 3 +#define DANETZ 4 +#define DBNETZ 5 +#define DCNETZ 6 +#define DNMT 7 +#define DAMPS 8 +#define DR2000 9 +#define DIMTS 10 +#define DMPT1327 11 +#define DJOLLY 12 +#define DEURO 13 +#define DFRAME 14 +#define DCALL 15 +#define DCC 16 +#define DDB 17 +#define DTRANS 18 +#define DDMS 19 +#define DSMS 20 +#define DSDR 21 +#define DUHD 22 +#define DSOAPY 23 +#define DWAVE 24 +#define DRADIO 25 +#define DAM791X 26 +#define DUART 27 +#define DDEVICE 28 +#define DDATENKLO 29 +#define DZEIT 30 +#define DSIM1 31 +#define DSIM2 32 +#define DSIMI 33 +#define DSIM7 34 +#define DMTP2 35 +#define DMTP3 36 +#define DMUP 37 +#define DROUTER 38 +#define DSTDERR 39 +#define DSS5 40 +#define DISDN 41 +#define DMISDN 42 +#define DDSS1 43 +#define DSIP 44 +#define DTEL 45 void get_win_size(int *w, int *h); diff --git a/src/liboptions/options.c b/src/liboptions/options.c index 4b8f062..d49e698 100644 --- a/src/liboptions/options.c +++ b/src/liboptions/options.c @@ -36,12 +36,37 @@ static option_t *option_head = NULL; static option_t **option_tailp = &option_head; static int first_option = 1; +static struct options_strdup_entry { + struct options_strdup_entry *next; + char s[1]; +} *options_strdup_list = NULL; + +char *options_strdup(const char *s) +{ + struct options_strdup_entry *o; + + o = malloc(sizeof(struct options_strdup_entry) + strlen(s)); + if (!o) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "No mem!\n"); + abort(); + } + o->next = options_strdup_list; + options_strdup_list = o; + strcpy(o->s, s); + + return o->s; +} + void option_add(int short_option, const char *long_option, int parameter_count) { option_t *option; - /* check if option already exists */ + /* check if option already exists or is not allowed */ for (option = option_head; option; option = option->next) { + if (!strcmp(option->long_option, "config")) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Option '%s' is not allowed to add, please fix!\n", option->long_option); + abort(); + } if (option->short_option == short_option || !strcmp(option->long_option, long_option)) { PDEBUG(DOPTIONS, DEBUG_ERROR, "Option '%s' added twice, please fix!\n", option->long_option); @@ -62,24 +87,32 @@ void option_add(int short_option, const char *long_option, int parameter_count) option_tailp = &(option->next); } -int options_config_file(const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[])) +int options_config_file(int argc, char *argv[], const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[])) { static const char *home; char config[256]; FILE *fp; - char buffer[256], opt[256], param[256], *p, *argv[16]; + char buffer[256], opt[256], param[256], *p, *args[16]; char params[1024]; int line; int rc = 1; int i, j, quote; option_t *option; - /* open config file */ - home = getenv("HOME"); - if (home == NULL) - return 1; - sprintf(config, "%s/%s", home, config_file + 2); + /* select for alternative config file */ + if (argc > 2 && !strcmp(argv[1], "--config")) + config_file = argv[2]; + + /* add home directory */ + if (config_file[0] == '~' && config_file[1] == '/') { + home = getenv("HOME"); + if (home == NULL) + return 1; + sprintf(config, "%s/%s", home, config_file + 2); + } else + strcpy(config, config_file); + /* open config file */ fp = fopen(config, "r"); if (!fp) { PDEBUG(DOPTIONS, DEBUG_INFO, "Config file '%s' seems not to exist, using command line options only.\n", config); @@ -158,7 +191,7 @@ int options_config_file(const char *config_file, int (*handle_options)(int short param[j++] = *p++; } param[j] = '\0'; - argv[i] = strdup(param); + args[i] = options_strdup(param); sprintf(strchr(params, '\0'), " '%s'", param); /* skip white spaces behind option */ while (*p > '\0' && *p <= ' ') @@ -185,7 +218,7 @@ int options_config_file(const char *config_file, int (*handle_options)(int short PDEBUG(DOPTIONS, DEBUG_ERROR, "Given option '%s' in config file '%s' at line %d requires %d parameter(s), use '-h' for help!\n", opt, config_file, line, option->parameter_count); return -EINVAL; } - rc = handle_options(option->short_option, 0, argv); + rc = handle_options(option->short_option, 0, args); if (rc <= 0) goto done; first_option = 0; @@ -206,6 +239,19 @@ int options_command_line(int argc, char *argv[], int (*handle_options)(int short int rc; for (argi = 1; argi < argc; argi++) { + /* --config */ + if (!strcmp(argv[argi], "--config")) { + if (argi > 1) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' must be the first option specified, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + if (argc <= 2) { + PDEBUG(DOPTIONS, DEBUG_ERROR, "Given command line option '%s' requires 1 parameter, use '-h' for help!\n", argv[argi]); + return -EINVAL; + } + argi += 1; + continue; + } if (argv[argi][0] == '-') { if (argv[argi][1] != '-') { if (strlen(argv[argi]) != 2) { @@ -273,3 +319,21 @@ int option_is_first(void) return first_option; } +void options_free(void) +{ + while (options_strdup_list) { + struct options_strdup_entry *o; + o = options_strdup_list; + options_strdup_list = o->next; + free(o); + } + + while (option_head) { + option_t *o; + o = option_head; + option_head = o->next; + free(o); + } + option_tailp = &option_head; +} + diff --git a/src/liboptions/options.h b/src/liboptions/options.h index 6f7e41a..5f494e0 100644 --- a/src/liboptions/options.h +++ b/src/liboptions/options.h @@ -1,6 +1,8 @@ +char *options_strdup(const char *s); void option_add(int short_option, const char *long_option, int parameter_count); -int options_config_file(const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[])); +int options_config_file(int argc, char *argv[], const char *config_file, int (*handle_options)(int short_option, int argi, char *argv[])); int options_command_line(int argc, char *argv[], int (*handle_options)(int short_option, int argi, char *argv[])); int option_is_first(void); +void options_free(void); diff --git a/src/libosmocc/helper.c b/src/libosmocc/helper.c index cde8b27..6317ed3 100644 --- a/src/libosmocc/helper.c +++ b/src/libosmocc/helper.c @@ -56,10 +56,10 @@ const char *osmo_cc_helper_audio_accept(void *priv, struct osmo_cc_helper_audio_ { char offer_sdp[65536]; const char *accept_sdp; - osmo_cc_session_media_t *media, *selected_media = NULL; - osmo_cc_session_codec_t *codec, *selected_codec = NULL; + osmo_cc_session_media_t *media, *selected_media; + osmo_cc_session_codec_t *codec, *selected_codec, *telephone_event; int rc; - int i, selected_i; + int i, selected_codec_i, telephone_event_i; if (*session_p) { PDEBUG(DCC, DEBUG_ERROR, "Session already set, please fix!\n"); @@ -83,33 +83,53 @@ const char *osmo_cc_helper_audio_accept(void *priv, struct osmo_cc_helper_audio_ return NULL; } - selected_i = -1; + selected_media = NULL; osmo_cc_session_for_each_media((*session_p)->media_list, media) { /* only audio */ if (media->description.type != osmo_cc_session_media_type_audio) continue; + selected_codec_i = -1; + selected_codec = NULL; + telephone_event_i = -1; + telephone_event = NULL; osmo_cc_session_for_each_codec(media->codec_list, codec) { - for (i = 0; codecs[i].payload_name; i++) { - if (osmo_cc_session_if_codec(codec, codecs[i].payload_name, codecs[i].payload_rate, codecs[i].payload_channels)) { - /* select the first matchting codec or the one we prefer */ - if (selected_i < 0 || i < selected_i) { - selected_codec = codec; - selected_media = media; - selected_i = i; + if (!!strcasecmp(codec->payload_name, "telephone-event")) { + for (i = 0; codecs[i].payload_name; i++) { + if (osmo_cc_session_if_codec(codec, codecs[i].payload_name, codecs[i].payload_rate, codecs[i].payload_channels)) { + /* select the first matchting codec or the one we prefer */ + if (selected_codec_i < 0 || i < selected_codec_i) { + selected_codec = codec; + selected_codec_i = i; + selected_media = media; + } + /* if we don't force our preferred codec, use the preferred one from the remote */ + if (!force_our_codec) + break; } - /* if we don't force our preferred codec, use the preferred one from the remote */ - if (!force_our_codec) - break; + } + } else { + /* special case: add telephone-event, if supported */ + for (i = 0; codecs[i].payload_name; i++) { + if (!!strcasecmp(codecs[i].payload_name, "telephone-event")) + continue; + telephone_event = codec; + telephone_event_i = i; + break; } } } + /* codec is selected within this media, we are done */ + if (selected_codec) + break; } if (!selected_codec) { PDEBUG(DCC, DEBUG_ERROR, "No codec found in setup message that we support.\n"); osmo_cc_free_session(*session_p); return NULL; } - osmo_cc_session_accept_codec(selected_codec, codecs[selected_i].encoder, codecs[selected_i].decoder); + osmo_cc_session_accept_codec(selected_codec, codecs[selected_codec_i].encoder, codecs[selected_codec_i].decoder); + if (telephone_event) + osmo_cc_session_accept_codec(telephone_event, codecs[telephone_event_i].encoder, codecs[telephone_event_i].decoder); osmo_cc_session_accept_media(selected_media, 0, 0, NULL, 1, 1, receiver); osmo_cc_rtp_open(selected_media); osmo_cc_rtp_connect(selected_media); diff --git a/src/libosmocc/message.c b/src/libosmocc/message.c index 0eb25ac..afee718 100644 --- a/src/libosmocc/message.c +++ b/src/libosmocc/message.c @@ -98,6 +98,60 @@ const char *osmo_cc_msg_name(uint8_t msg_type) } } +const char *osmo_cc_network_type_name(uint8_t type) +{ + switch (type) { + case OSMO_CC_NETWORK_UNDEFINED: + return ""; + case OSMO_CC_NETWORK_ALSA_NONE: + return "alsa"; + case OSMO_CC_NETWORK_POTS_NONE: + return "pots"; + case OSMO_CC_NETWORK_ISDN_NONE: + return "isdn"; + case OSMO_CC_NETWORK_SIP_NONE: + return "sip"; + case OSMO_CC_NETWORK_GSM_IMSI: + return "gsm-imsi"; + case OSMO_CC_NETWORK_GSM_IMEI: + return "gsm-imei"; + case OSMO_CC_NETWORK_WEB_NONE: + return "web"; + case OSMO_CC_NETWORK_DECT_NONE: + return "decs"; + case OSMO_CC_NETWORK_BLUETOOTH_NONE: + return "bluetooth"; + case OSMO_CC_NETWORK_SS5_NONE: + return "ss5"; + case OSMO_CC_NETWORK_ANETZ_NONE: + return "anetz"; + case OSMO_CC_NETWORK_BNETZ_MUENZ: + return "bnetz"; + case OSMO_CC_NETWORK_CNETZ_NONE: + return "cnetz"; + case OSMO_CC_NETWORK_NMT_NONE: + return "nmt"; + case OSMO_CC_NETWORK_R2000_NONE: + return "radiocom2000"; + case OSMO_CC_NETWORK_AMPS_ESN: + return "amps"; + case OSMO_CC_NETWORK_MTS_NONE: + return "mts"; + case OSMO_CC_NETWORK_IMTS_NONE: + return "imts"; + case OSMO_CC_NETWORK_EUROSIGNAL_NONE: + return "eurosignal"; + case OSMO_CC_NETWORK_JOLLYCOM_NONE: + return "jollycom"; + case OSMO_CC_NETWORK_MPT1327_PSTN: + return "mpt1327-pstn"; + case OSMO_CC_NETWORK_MPT1327_PBX: + return "mpt1327-pbx"; + default: + return ""; + } +} + /* create message with maximum size */ osmo_cc_msg_t *osmo_cc_new_msg(uint8_t msg_type) { diff --git a/src/libosmocc/message.h b/src/libosmocc/message.h index 7821988..7f0b228 100644 --- a/src/libosmocc/message.h +++ b/src/libosmocc/message.h @@ -251,6 +251,8 @@ enum osmo_cc_ie_type { #define OSMO_CC_NETWORK_IMTS_NONE 0x87 #define OSMO_CC_NETWORK_EUROSIGNAL_NONE 0x88 #define OSMO_CC_NETWORK_JOLLYCOM_NONE 0x89 /* call from JollyCom... */ +#define OSMO_CC_NETWORK_MPT1327_PSTN 0x8a /* call from MPT1327 */ +#define OSMO_CC_NETWORK_MPT1327_PBX 0x8b /* id is selected PBX number */ typedef struct osmo_cc_msg { uint8_t type; @@ -379,6 +381,7 @@ struct osmo_cc_ie_private { uint32_t osmo_cc_new_callref(void); const char *osmo_cc_msg_name(uint8_t msg_type); +const char *osmo_cc_network_type_name(uint8_t type); osmo_cc_msg_t *osmo_cc_new_msg(uint8_t msg_type); osmo_cc_msg_t *osmo_cc_clone_msg(osmo_cc_msg_t *msg); osmo_cc_msg_t *osmo_cc_msg_list_dequeue(osmo_cc_msg_list_t **mlp, uint32_t *callref_p); diff --git a/src/libosmocc/session.c b/src/libosmocc/session.c index 9751845..1438ae2 100644 --- a/src/libosmocc/session.c +++ b/src/libosmocc/session.c @@ -26,6 +26,7 @@ #include #include "../libtimer/timer.h" #include "../libdebug/debug.h" +#include "../liboptions/options.h" #include "endpoint.h" #define NTP_OFFSET 2208988800 @@ -38,7 +39,7 @@ void osmo_cc_set_local_peer(enum osmo_cc_session_nettype nettype, enum osmo_cc_s { default_nettype = nettype; default_addrtype = addrtype; - default_unicast_address = strdup(address); + default_unicast_address = options_strdup(address); } osmo_cc_session_t *osmo_cc_new_session(void *priv, const char *username, const char *sess_id, const char *sess_version, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *unicast_address, const char *session_name, int debug)