From 98de5697e671d7ee05e8e847a5ea32e3bfa0c9e3 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 10 Dec 2018 03:41:22 -0500 Subject: [PATCH] TT#48650 use constant string hashing for string lookups To avoid repeated strcmp()s and make use of switch()'s optimised binary lookup, we employ a second build step that preprocesses certain .c files and uses gperf to substitute pseudomacros with their respective constant hash value. Change-Id: Id89c4728a0fc7aa911691d4dd1ba8e7b3916a983 --- .gitignore | 1 + daemon/Makefile | 4 +- daemon/call_interfaces.c | 265 +++++++++++++++++++++++---------------- daemon/control_ng.c | 126 ++++++++++--------- daemon/sdp.c | 135 ++++++++++---------- debian/control | 1 + lib/common.Makefile | 7 +- t/.gitignore | 1 + t/Makefile | 27 ++-- t/const_str_hash-test.c | 35 ++++++ utils/const_str_hash | 73 +++++++++++ 11 files changed, 425 insertions(+), 250 deletions(-) create mode 100644 t/const_str_hash-test.c create mode 100755 utils/const_str_hash diff --git a/.gitignore b/.gitignore index 326821191..1d012c677 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .*.sw? +*.strhash.c diff --git a/daemon/Makefile b/daemon/Makefile index 347e15724..d30a8caed 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -113,8 +113,8 @@ LDLIBS+= $(bcg729_lib) endif SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \ - bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c stun.c rtcp.c \ - crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c socket.c \ + bencode.c cookie_cache.c udp_listener.c control_ng.strhash.c sdp.strhash.c stun.c rtcp.c \ + crypto.c rtp.c call_interfaces.strhash.c dtls.c log.c cli.c graphite.c ice.c socket.c \ media_socket.c homer.c recording.c statistics.c cdr.c ssrc.c iptables.c tcp_listener.c \ codec.c load.c dtmf.c LIBSRCS= loglib.c auxlib.c rtplib.c str.c diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index c2d64799d..9d9910293 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -500,24 +500,41 @@ INLINE char *bencode_get_alt(bencode_item_t *i, const char *one, const char *two } INLINE void ng_sdes_option(struct sdp_ng_flags *out, str *s, void *dummy) { - if (!str_cmp(s, "no") || !str_cmp(s, "off") || !str_cmp(s, "disabled") - || !str_cmp(s, "disable")) - out->sdes_off = 1; - else if (!str_cmp(s, "unencrypted_srtp") || !str_cmp(s, "UNENCRYPTED_SRTP")) - out->sdes_unencrypted_srtp = 1; - else if (!str_cmp(s, "unencrypted_srtcp") || !str_cmp(s, "UNENCRYPTED_SRTCP")) - out->sdes_unencrypted_srtcp = 1; - else if (!str_cmp(s, "unauthenticated_srtp") || !str_cmp(s, "UNAUTHENTICATED_SRTP")) - out->sdes_unauthenticated_srtp = 1; - else if (!str_cmp(s, "encrypted_srtp") || !str_cmp(s, "ENCRYPTED_SRTP")) - out->sdes_encrypted_srtp = 1; - else if (!str_cmp(s, "encrypted_srtcp") || !str_cmp(s, "ENCRYPTED_SRTCP")) - out->sdes_encrypted_srtcp = 1; - else if (!str_cmp(s, "authenticated_srtp") || !str_cmp(s, "AUTHENTICATED_SRTP")) - out->sdes_authenticated_srtp = 1; - else - ilog(LOG_WARN, "Unknown 'SDES' flag encountered: '"STR_FORMAT"'", - STR_FMT(s)); + switch (__csh_lookup(s)) { + case CSH_LOOKUP("no"): + case CSH_LOOKUP("off"): + case CSH_LOOKUP("disabled"): + case CSH_LOOKUP("disable"): + out->sdes_off = 1; + break; + case CSH_LOOKUP("unencrypted_srtp"): + case CSH_LOOKUP("UNENCRYPTED_SRTP"): + out->sdes_unencrypted_srtp = 1; + break; + case CSH_LOOKUP("unencrypted_srtcp"): + case CSH_LOOKUP("UNENCRYPTED_SRTCP"): + out->sdes_unencrypted_srtcp = 1; + break; + case CSH_LOOKUP("unauthenticated_srtp"): + case CSH_LOOKUP("UNAUTHENTICATED_SRTP"): + out->sdes_unauthenticated_srtp = 1; + break; + case CSH_LOOKUP("encrypted_srtp"): + case CSH_LOOKUP("ENCRYPTED_SRTP"): + out->sdes_encrypted_srtp = 1; + break; + case CSH_LOOKUP("encrypted_srtcp"): + case CSH_LOOKUP("ENCRYPTED_SRTCP"): + out->sdes_encrypted_srtcp = 1; + break; + case CSH_LOOKUP("authenticated_srtp"): + case CSH_LOOKUP("AUTHENTICATED_SRTP"): + out->sdes_authenticated_srtp = 1; + break; + default: + ilog(LOG_WARN, "Unknown 'SDES' flag encountered: '"STR_FORMAT"'", + STR_FMT(s)); + } } @@ -535,19 +552,26 @@ static void call_ng_flags_list(struct sdp_ng_flags *out, bencode_item_t *input, } } static void call_ng_flags_rtcp_mux(struct sdp_ng_flags *out, str *s, void *dummy) { - if (!str_cmp(s, "offer")) - out->rtcp_mux_offer = 1; - else if (!str_cmp(s, "require")) - out->rtcp_mux_require = 1; - else if (!str_cmp(s, "demux")) - out->rtcp_mux_demux = 1; - else if (!str_cmp(s, "accept")) - out->rtcp_mux_accept = 1; - else if (!str_cmp(s, "reject")) - out->rtcp_mux_reject = 1; - else - ilog(LOG_WARN, "Unknown 'rtcp-mux' flag encountered: '" STR_FORMAT "'", - STR_FMT(s)); + switch (__csh_lookup(s)) { + case CSH_LOOKUP("offer"): + out->rtcp_mux_offer = 1; + break; + case CSH_LOOKUP("require"): + out->rtcp_mux_require = 1; + break; + case CSH_LOOKUP("demux"): + out->rtcp_mux_demux = 1; + break; + case CSH_LOOKUP("accept"): + out->rtcp_mux_accept = 1; + break; + case CSH_LOOKUP("reject"): + out->rtcp_mux_reject = 1; + break; + default: + ilog(LOG_WARN, "Unknown 'rtcp-mux' flag encountered: '" STR_FORMAT "'", + STR_FMT(s)); + } } static void call_ng_flags_replace(struct sdp_ng_flags *out, str *s, void *dummy) { str_hyphenate(s); @@ -590,65 +614,84 @@ INLINE int call_ng_flags_prefix(struct sdp_ng_flags *out, str *s_ori, const char static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { str_hyphenate(s); - // XXX use internal hash tables for these - if (!str_cmp(s, "trust-address")) - out->trust_address = 1; - else if (!str_cmp(s, "SIP-source-address")) - out->trust_address = 0; - else if (!str_cmp(s, "asymmetric")) - out->asymmetric = 1; - else if (!str_cmp(s, "no-redis-update")) - out->no_redis_update = 1; - else if (!str_cmp(s, "unidirectional")) - out->unidirectional = 1; - else if (!str_cmp(s, "strict-source")) - out->strict_source = 1; - else if (!str_cmp(s, "media-handover")) - out->media_handover = 1; - else if (!str_cmp(s, "reset")) - out->reset = 1; - else if (!str_cmp(s, "all")) - out->all = 1; - else if (!str_cmp(s, "fragment")) - out->fragment = 1; - else if (!str_cmp(s, "port-latching")) - out->port_latching = 1; - else if (!str_cmp(s, "generate-mid")) - out->generate_mid = 1; - else if (!str_cmp(s, "record-call")) - out->record_call = 1; - else if (!str_cmp(s, "no-rtcp-attribute")) - out->no_rtcp_attr = 1; - else if (!str_cmp(s, "full-rtcp-attribute")) - out->full_rtcp_attr = 1; - else if (!str_cmp(s, "loop-protect")) - out->loop_protect = 1; - else if (!str_cmp(s, "always-transcode")) - out->always_transcode = 1; - else if (!str_cmp(s, "asymmetric-codecs")) - out->asymmetric_codecs = 1; - else if (!str_cmp(s, "pad-crypto")) - out->pad_crypto = 1; - else { - // handle values aliases from other dictionaries - if (call_ng_flags_prefix(out, s, "SDES-", ng_sdes_option, NULL)) - return; - if (call_ng_flags_prefix(out, s, "codec-strip-", call_ng_flags_codec_ht, out->codec_strip)) - return; - if (call_ng_flags_prefix(out, s, "codec-offer-", call_ng_flags_codec_list, &out->codec_offer)) - return; + switch (__csh_lookup(s)) { + case CSH_LOOKUP("trust-address"): + out->trust_address = 1; + break; + case CSH_LOOKUP("SIP-source-address"): + out->trust_address = 0; + break; + case CSH_LOOKUP("asymmetric"): + out->asymmetric = 1; + break; + case CSH_LOOKUP("no-redis-update"): + out->no_redis_update = 1; + break; + case CSH_LOOKUP("unidirectional"): + out->unidirectional = 1; + break; + case CSH_LOOKUP("strict-source"): + out->strict_source = 1; + break; + case CSH_LOOKUP("media-handover"): + out->media_handover = 1; + break; + case CSH_LOOKUP("reset"): + out->reset = 1; + break; + case CSH_LOOKUP("all"): + out->all = 1; + break; + case CSH_LOOKUP("fragment"): + out->fragment = 1; + break; + case CSH_LOOKUP("port-latching"): + out->port_latching = 1; + break; + case CSH_LOOKUP("generate-mid"): + out->generate_mid = 1; + break; + case CSH_LOOKUP("record-call"): + out->record_call = 1; + break; + case CSH_LOOKUP("no-rtcp-attribute"): + out->no_rtcp_attr = 1; + break; + case CSH_LOOKUP("full-rtcp-attribute"): + out->full_rtcp_attr = 1; + break; + case CSH_LOOKUP("loop-protect"): + out->loop_protect = 1; + break; + case CSH_LOOKUP("always-transcode"): + out->always_transcode = 1; + break; + case CSH_LOOKUP("asymmetric-codecs"): + out->asymmetric_codecs = 1; + break; + case CSH_LOOKUP("pad-crypto"): + out->pad_crypto = 1; + break; + default: + // handle values aliases from other dictionaries + if (call_ng_flags_prefix(out, s, "SDES-", ng_sdes_option, NULL)) + return; + if (call_ng_flags_prefix(out, s, "codec-strip-", call_ng_flags_codec_ht, out->codec_strip)) + return; + if (call_ng_flags_prefix(out, s, "codec-offer-", call_ng_flags_codec_list, &out->codec_offer)) + return; #ifdef WITH_TRANSCODING - if (call_ng_flags_prefix(out, s, "transcode-", call_ng_flags_codec_list, &out->codec_transcode)) - return; - if (call_ng_flags_prefix(out, s, "codec-transcode-", call_ng_flags_codec_list, - &out->codec_transcode)) - return; - if (call_ng_flags_prefix(out, s, "codec-mask-", call_ng_flags_codec_ht, out->codec_mask)) - return; + if (call_ng_flags_prefix(out, s, "transcode-", call_ng_flags_codec_list, &out->codec_transcode)) + return; + if (call_ng_flags_prefix(out, s, "codec-transcode-", call_ng_flags_codec_list, + &out->codec_transcode)) + return; + if (call_ng_flags_prefix(out, s, "codec-mask-", call_ng_flags_codec_ht, out->codec_mask)) + return; #endif - ilog(LOG_WARN, "Unknown flag encountered: '" STR_FORMAT "'", - STR_FMT(s)); + ilog(LOG_WARN, "Unknown flag encountered: '" STR_FORMAT "'", + STR_FMT(s)); } } static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *input) { @@ -682,27 +725,39 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu } if (bencode_dictionary_get_str(input, "ICE", &s)) { - if (!str_cmp(&s, "remove")) - out->ice_remove = 1; - else if (!str_cmp(&s, "force")) - out->ice_force = 1; - else if (!str_cmp(&s, "force_relay") || !str_cmp(&s, "force-relay") - || !str_cmp(&s, "force relay")) - out->ice_force_relay = 1; - else - ilog(LOG_WARN, "Unknown 'ICE' flag encountered: '"STR_FORMAT"'", - STR_FMT(&s)); + switch (__csh_lookup(&s)) { + case CSH_LOOKUP("remove"): + out->ice_remove = 1; + break; + case CSH_LOOKUP("force"): + out->ice_force = 1; + break; + case CSH_LOOKUP("force_relay"): + case CSH_LOOKUP("force-relay"): + case CSH_LOOKUP("force relay"): + out->ice_force_relay = 1; + break; + default: + ilog(LOG_WARN, "Unknown 'ICE' flag encountered: '"STR_FORMAT"'", + STR_FMT(&s)); + } } if (bencode_dictionary_get_str(input, "DTLS", &s)) { - if (!str_cmp(&s, "passive")) - out->dtls_passive = 1; - else if (!str_cmp(&s, "no") || !str_cmp(&s, "off") || !str_cmp(&s, "disabled") - || !str_cmp(&s, "disable")) - out->dtls_off = 1; - else - ilog(LOG_WARN, "Unknown 'DTLS' flag encountered: '"STR_FORMAT"'", - STR_FMT(&s)); + switch (__csh_lookup(&s)) { + case CSH_LOOKUP("passive"): + out->dtls_passive = 1; + break; + case CSH_LOOKUP("no"): + case CSH_LOOKUP("off"): + case CSH_LOOKUP("disabled"): + case CSH_LOOKUP("disable"): + out->dtls_off = 1; + break; + default: + ilog(LOG_WARN, "Unknown 'DTLS' flag encountered: '"STR_FORMAT"'", + STR_FMT(&s)); + } } call_ng_flags_list(out, input, "rtcp-mux", call_ng_flags_rtcp_mux, NULL); diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 8a279afa8..59c4a0efa 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -184,57 +184,59 @@ static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin // start command timer gettimeofday(&cmd_start, NULL); - if (!str_cmp(&cmd, "ping")) { - resultstr = "pong"; - g_atomic_int_inc(&cur->ping); - } - else if (!str_cmp(&cmd, "offer")) { - errstr = call_offer_ng(dict, resp, addr, sin); - g_atomic_int_inc(&cur->offer); - } - else if (!str_cmp(&cmd, "answer")) { - errstr = call_answer_ng(dict, resp); - g_atomic_int_inc(&cur->answer); - } - else if (!str_cmp(&cmd, "delete")) { - errstr = call_delete_ng(dict, resp); - g_atomic_int_inc(&cur->delete); - } - else if (!str_cmp(&cmd, "query")) { - errstr = call_query_ng(dict, resp); - g_atomic_int_inc(&cur->query); - } - else if (!str_cmp(&cmd, "list")) { - errstr = call_list_ng(dict, resp); - g_atomic_int_inc(&cur->list); - } - else if (!str_cmp(&cmd, "start recording")) { - errstr = call_start_recording_ng(dict, resp); - g_atomic_int_inc(&cur->start_recording); - } - else if (!str_cmp(&cmd, "stop recording")) { - errstr = call_stop_recording_ng(dict, resp); - g_atomic_int_inc(&cur->stop_recording); - } - else if (!str_cmp(&cmd, "block DTMF")) { - errstr = call_block_dtmf_ng(dict, resp); - g_atomic_int_inc(&cur->block_dtmf); - } - else if (!str_cmp(&cmd, "unblock DTMF")) { - errstr = call_unblock_dtmf_ng(dict, resp); - g_atomic_int_inc(&cur->unblock_dtmf); - } - else if (!str_cmp(&cmd, "block media")) { - errstr = call_block_media_ng(dict, resp); - g_atomic_int_inc(&cur->block_media); - } - else if (!str_cmp(&cmd, "unblock media")) { - errstr = call_unblock_media_ng(dict, resp); - g_atomic_int_inc(&cur->unblock_media); - } - else - { - errstr = "Unrecognized command"; + int cmdcode = __csh_lookup(&cmd); + + switch (cmdcode) { + case CSH_LOOKUP("ping"): + resultstr = "pong"; + g_atomic_int_inc(&cur->ping); + break; + case CSH_LOOKUP("offer"): + errstr = call_offer_ng(dict, resp, addr, sin); + g_atomic_int_inc(&cur->offer); + break; + case CSH_LOOKUP("answer"): + errstr = call_answer_ng(dict, resp); + g_atomic_int_inc(&cur->answer); + break; + case CSH_LOOKUP("delete"): + errstr = call_delete_ng(dict, resp); + g_atomic_int_inc(&cur->delete); + break; + case CSH_LOOKUP("query"): + errstr = call_query_ng(dict, resp); + g_atomic_int_inc(&cur->query); + break; + case CSH_LOOKUP("list"): + errstr = call_list_ng(dict, resp); + g_atomic_int_inc(&cur->list); + break; + case CSH_LOOKUP("start recording"): + errstr = call_start_recording_ng(dict, resp); + g_atomic_int_inc(&cur->start_recording); + break; + case CSH_LOOKUP("stop recording"): + errstr = call_stop_recording_ng(dict, resp); + g_atomic_int_inc(&cur->stop_recording); + break; + case CSH_LOOKUP("block DTMF"): + errstr = call_block_dtmf_ng(dict, resp); + g_atomic_int_inc(&cur->block_dtmf); + break; + case CSH_LOOKUP("unblock DTMF"): + errstr = call_unblock_dtmf_ng(dict, resp); + g_atomic_int_inc(&cur->unblock_dtmf); + break; + case CSH_LOOKUP("block media"): + errstr = call_block_media_ng(dict, resp); + g_atomic_int_inc(&cur->block_media); + break; + case CSH_LOOKUP("unblock media"): + errstr = call_unblock_media_ng(dict, resp); + g_atomic_int_inc(&cur->unblock_media); + break; + default: + errstr = "Unrecognized command"; } // stop command timer @@ -248,15 +250,19 @@ static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin bencode_dictionary_add_string(resp, "result", resultstr); // update interval statistics - if (!str_cmp(&cmd, "offer")) { - atomic64_inc(&rtpe_statsps.offers); - timeval_update_request_time(&rtpe_totalstats_interval.offer, &cmd_process_time); - } else if (!str_cmp(&cmd, "answer")) { - atomic64_inc(&rtpe_statsps.answers); - timeval_update_request_time(&rtpe_totalstats_interval.answer, &cmd_process_time); - } else if (!str_cmp(&cmd, "delete")) { - atomic64_inc(&rtpe_statsps.deletes); - timeval_update_request_time(&rtpe_totalstats_interval.delete, &cmd_process_time); + switch (cmdcode) { + case CSH_LOOKUP("offer"): + atomic64_inc(&rtpe_statsps.offers); + timeval_update_request_time(&rtpe_totalstats_interval.offer, &cmd_process_time); + break; + case CSH_LOOKUP("answer"): + atomic64_inc(&rtpe_statsps.answers); + timeval_update_request_time(&rtpe_totalstats_interval.answer, &cmd_process_time); + break; + case CSH_LOOKUP("delete"): + atomic64_inc(&rtpe_statsps.deletes); + timeval_update_request_time(&rtpe_totalstats_interval.delete, &cmd_process_time); + break; } goto send_resp; diff --git a/daemon/sdp.c b/daemon/sdp.c index e0ab9e6b0..f0fb9e3ad 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -793,84 +793,81 @@ static int parse_attribute(struct sdp_attribute *a) { } ret = 0; - switch (a->name.len) { - case 3: - if (!str_cmp(&a->name, "mid")) - a->attr = ATTR_MID; + switch (__csh_lookup(&a->name)) { + case CSH_LOOKUP("mid"): + a->attr = ATTR_MID; break; - case 4: - if (!str_cmp(&a->name, "rtcp")) - ret = parse_attribute_rtcp(a); - else if (!str_cmp(&a->name, "ssrc")) - ret = parse_attribute_ssrc(a); - else if (!str_cmp(&a->name, "fmtp")) - ret = parse_attribute_fmtp(a); + case CSH_LOOKUP("rtcp"): + ret = parse_attribute_rtcp(a); break; - case 5: - if (!str_cmp(&a->name, "group")) - ret = parse_attribute_group(a); - else if (!str_cmp(&a->name, "setup")) - ret = parse_attribute_setup(a); - else if (!str_cmp(&a->name, "ptime")) - a->attr = ATTR_PTIME; + case CSH_LOOKUP("ssrc"): + ret = parse_attribute_ssrc(a); break; - case 6: - if (!str_cmp(&a->name, "crypto")) - ret = parse_attribute_crypto(a); - else if (!str_cmp(&a->name, "extmap")) - a->attr = ATTR_EXTMAP; - else if (!str_cmp(&a->name, "rtpmap")) - ret = parse_attribute_rtpmap(a); + case CSH_LOOKUP("fmtp"): + ret = parse_attribute_fmtp(a); break; - case 7: - if (!str_cmp(&a->name, "ice-pwd")) - a->attr = ATTR_ICE_PWD; + case CSH_LOOKUP("group"): + ret = parse_attribute_group(a); break; - case 8: - switch (a->name.s[0]) { - case 'i': - if (!str_cmp(&a->name, "ice-lite")) - a->attr = ATTR_ICE_LITE; - else if (!str_cmp(&a->name, "inactive")) - a->attr = ATTR_INACTIVE; - break; - case 's': - if (!str_cmp(&a->name, "sendrecv")) - a->attr = ATTR_SENDRECV; - else if (!str_cmp(&a->name, "sendonly")) - a->attr = ATTR_SENDONLY; - break; - case 'r': - if (!str_cmp(&a->name, "recvonly")) - a->attr = ATTR_RECVONLY; - if (!str_cmp(&a->name, "rtcp-mux")) - a->attr = ATTR_RTCP_MUX; - break; - } + case CSH_LOOKUP("setup"): + ret = parse_attribute_setup(a); + break; + case CSH_LOOKUP("ptime"): + a->attr = ATTR_PTIME; + break; + case CSH_LOOKUP("crypto"): + ret = parse_attribute_crypto(a); + break; + case CSH_LOOKUP("extmap"): + a->attr = ATTR_EXTMAP; + break; + case CSH_LOOKUP("rtpmap"): + ret = parse_attribute_rtpmap(a); + break; + case CSH_LOOKUP("ice-pwd"): + a->attr = ATTR_ICE_PWD; + break; + case CSH_LOOKUP("ice-lite"): + a->attr = ATTR_ICE_LITE; + break; + case CSH_LOOKUP("inactive"): + a->attr = ATTR_INACTIVE; + break; + case CSH_LOOKUP("sendrecv"): + a->attr = ATTR_SENDRECV; + break; + case CSH_LOOKUP("sendonly"): + a->attr = ATTR_SENDONLY; + break; + case CSH_LOOKUP("recvonly"): + a->attr = ATTR_RECVONLY; + break; + case CSH_LOOKUP("rtcp-mux"): + a->attr = ATTR_RTCP_MUX; + break; + case CSH_LOOKUP("candidate"): + ret = parse_attribute_candidate(a); + break; + case CSH_LOOKUP("ice-ufrag"): + a->attr = ATTR_ICE_UFRAG; + break; + case CSH_LOOKUP("rtpengine"): + a->attr = ATTR_RTPENGINE; + break; + case CSH_LOOKUP("ice-options"): + a->attr = ATTR_ICE_OPTIONS; break; - case 9: - if (!str_cmp(&a->name, "candidate")) - ret = parse_attribute_candidate(a); - else if (!str_cmp(&a->name, "ice-ufrag")) - a->attr = ATTR_ICE_UFRAG; - else if (!str_cmp(&a->name, "rtpengine")) - a->attr = ATTR_RTPENGINE; + case CSH_LOOKUP("fingerprint"): + ret = parse_attribute_fingerprint(a); break; - case 11: - if (!str_cmp(&a->name, "ice-options")) - a->attr = ATTR_ICE_OPTIONS; - else if (!str_cmp(&a->name, "fingerprint")) - ret = parse_attribute_fingerprint(a); + case CSH_LOOKUP("ice-mismatch"): + a->attr = ATTR_ICE; break; - case 12: - if (!str_cmp(&a->name, "ice-mismatch")) - a->attr = ATTR_ICE; + case CSH_LOOKUP("remote-candidates"): + a->attr = ATTR_ICE; break; - case 17: - if (!str_cmp(&a->name, "remote-candidates")) - a->attr = ATTR_ICE; - else if (!str_cmp(&a->name, "end-of-candidates")) - a->attr = ATTR_END_OF_CANDIDATES; + case CSH_LOOKUP("end-of-candidates"): + a->attr = ATTR_END_OF_CANDIDATES; break; } diff --git a/debian/control b/debian/control index 230e1e4cb..853005e12 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,7 @@ Standards-Version: 3.9.8 Build-Depends: debhelper (>= 10~), default-libmysqlclient-dev | libmysqlclient-dev, + gperf, iptables-dev (>= 1.4), libavcodec-dev (>= 6:10), libavfilter-dev (>= 6:10), diff --git a/lib/common.Makefile b/lib/common.Makefile index ae63d69a6..d0e925fec 100644 --- a/lib/common.Makefile +++ b/lib/common.Makefile @@ -13,7 +13,7 @@ dep: .depend clean: rm -f $(OBJS) $(TARGET) $(LIBSRCS) $(DAEMONSRCS) $(ADD_CLEAN) .depend core core.* - rm -f fix_frame_channel_layout.h fix_frame_channel_layout-test.[co] + rm -f fix_frame_channel_layout.h fix_frame_channel_layout-test.[co] *.strhash.c $(HASHSRCS) .depend: $(SRCS) $(LIBSRCS) $(DAEMONSRCS) Makefile $(CC) $(CFLAGS) -M $(SRCS) $(LIBSRCS) $(DAEMONSRCS) | sed -e 's/:/ .depend:/' > .depend @@ -27,13 +27,16 @@ $(LIBSRCS): $(patsubst %,../lib/%,$(LIBSRCS)) echo '/******** GENERATED FILE ********/' > "$@" cat ../lib/"$@" >> "$@" -$(DAEMONSRCS): $(patsubst %,../daemon/%,$(DAEMONSRCS)) +$(DAEMONSRCS) $(HASHSRCS): $(patsubst %,../daemon/%,$(DAEMONSRCS)) $(patsubst %,../daemon/%,$(HASHSRCS)) rm -f "$@" echo '/******** GENERATED FILE ********/' > "$@" cat ../daemon/"$@" >> "$@" resample.c: fix_frame_channel_layout.h +%.strhash.c: %.c ../utils/const_str_hash + ../utils/const_str_hash < $< > $@ + fix_frame_channel_layout.h: ../lib/fix_frame_channel_layout-* echo "Looking for usable alternative for $@"; \ rm -f fix_frame_channel_layout-test.[co]; \ diff --git a/t/.gitignore b/t/.gitignore index 0b00585b5..003bc046d 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -44,3 +44,4 @@ transcode-test udp_listener.c payload-tracker-test dtmf.c +const_str_hash-test.strhash diff --git a/t/Makefile b/t/Makefile index 9d53e4775..6b086d953 100644 --- a/t/Makefile +++ b/t/Makefile @@ -49,21 +49,21 @@ LDLIBS+= $(shell pkg-config xmlrpc_util --libs 2> /dev/null) LDLIBS+= -lhiredis endif -SRCS= bitstr-test.c aes-crypt.c payload-tracker-test.c -ifeq ($(with_transcoding),yes) -SRCS+= amr-decode-test.c amr-encode-test.c transcode-test.c -endif +SRCS= bitstr-test.c aes-crypt.c payload-tracker-test.c const_str_hash-test.strhash.c LIBSRCS= loglib.c auxlib.c str.c rtplib.c -ifeq ($(with_transcoding),yes) -LIBSRCS+= codeclib.c resample.c -endif DAEMONSRCS= crypto.c +HASHSRCS= + ifeq ($(with_transcoding),yes) +SRCS+= amr-decode-test.c amr-encode-test.c transcode-test.c +LIBSRCS+= codeclib.c resample.c DAEMONSRCS+= codec.c ssrc.c call.c ice.c aux.c kernel.c media_socket.c stun.c bencode.c socket.c poller.c \ - dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c call_interfaces.c sdp.c \ - rtp.c control_ng.c streambuf.c cookie_cache.c udp_listener.c homer.c load.c cdr.c dtmf.c + dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c \ + rtp.c streambuf.c cookie_cache.c udp_listener.c homer.c load.c cdr.c dtmf.c +HASHSRCS+= call_interfaces.c control_ng.c sdp.c endif -OBJS= $(SRCS:.c=.o) $(LIBSRCS:.c=.o) $(DAEMONSRCS:.c=.o) + +OBJS= $(SRCS:.c=.o) $(LIBSRCS:.c=.o) $(DAEMONSRCS:.c=.o) $(HASHSRCS:.c=.strhash.o) COMMONOBJS= str.o auxlib.o rtplib.o loglib.o @@ -73,7 +73,7 @@ include .depend .PHONY: unit-tests -TESTS= bitstr-test aes-crypt payload-tracker-test +TESTS= bitstr-test aes-crypt payload-tracker-test const_str_hash-test.strhash ifeq ($(with_transcoding),yes) TESTS+= amr-decode-test amr-encode-test transcode-test endif @@ -93,7 +93,10 @@ aes-crypt: aes-crypt.o $(COMMONOBJS) crypto.o transcode-test: transcode-test.o $(COMMONOBJS) codeclib.o resample.o codec.o ssrc.o call.o ice.o aux.o \ kernel.o media_socket.o stun.o bencode.o socket.o poller.o dtls.o recording.o statistics.o \ - rtcp.o redis.o iptables.o graphite.o call_interfaces.o sdp.o rtp.o crypto.o control_ng.o \ + rtcp.o redis.o iptables.o graphite.o call_interfaces.strhash.o sdp.strhash.o rtp.o crypto.o \ + control_ng.strhash.o \ streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o dtmf.o payload-tracker-test: payload-tracker-test.o $(COMMONOBJS) ssrc.o aux.o auxlib.o rtp.o crypto.o + +const_str_hash-test.strhash: const_str_hash-test.strhash.o $(COMMONOBJS) diff --git a/t/const_str_hash-test.c b/t/const_str_hash-test.c new file mode 100644 index 000000000..a028a3402 --- /dev/null +++ b/t/const_str_hash-test.c @@ -0,0 +1,35 @@ +#include +#include +#include "str.h" + +static int test_hash(char *p) { + str s; + str_init(&s, p); + switch (__csh_lookup(&s)) { + case CSH_LOOKUP("one"): + return 1; + case CSH_LOOKUP("two"): + return 2; + case CSH_LOOKUP("dashed-string"): + return 3; + default: + return 0; + } + // STR_LOOKUP("one") // catch duplicate +} + +static void test(char *p, int exp) { + int h = test_hash(p); + if (h != exp) { + printf("%s:%i test failed: %u != %u (string '%s')\n", __FILE__, __LINE__, h, exp, p); + abort(); + } +} + +int main() { + test("one", 1); + test("two", 2); + test("dashed-string", 3); + test("doesn't exist", 0); + return 0; +} diff --git a/utils/const_str_hash b/utils/const_str_hash new file mode 100755 index 000000000..e17d3c177 --- /dev/null +++ b/utils/const_str_hash @@ -0,0 +1,73 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +print("/******** GENERATED FILE ********/\n"); + +my $rewritten_input = ''; +my $iter = 0; +my $keys = ''; +my %key_vals; + +# collect keywords and rewrite input file with in lookup keys + +while (my $line = <>) { + if (!($line =~ s/CSH_LOOKUP\("(.*?)"\)/{}/)) { + $rewritten_input .= $line; + next; + } + my $key = $1; + if (exists($key_vals{$key})) { + $line =~ s/{}/$key_vals{$key}/; + } + else { + $line =~ s/{}/$iter/; + $keys .= "$key,$iter\n"; + $key_vals{$key} = $iter; + $iter++; + } + $rewritten_input .= $line; +} + +# pass collected output to gperf + +my ($rd, $wr); +my $pid = open2($rd, $wr, qw(gperf -t -E -l -c -t -I -H __csh_hash -N __csh_lookup_raw)); + +# gperf header and keys + +print { $wr } "struct __csh_hash_lookup { char *name; int num; };\n%%\n"; +print { $wr } $keys; + +# read gperf output + +close($wr); +my $hash_func_code; +{ + local $/ = undef; + $hash_func_code = <$rd>; +} +close($rd); +waitpid($pid, 0); +exit(1) if $?; + +# convert lookup function to static + +$hash_func_code =~ s/(^|\s)struct\s+__csh_hash_lookup\s*\*/\nstatic$&/s; + +# print combined output + +print $hash_func_code; +# add convenience function +print <s, s->len); + if (!h) + return -1; + return h->num; +} +END +print $rewritten_input;