mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-10-31 03:53:54 +00:00 
			
		
		
		
	Compare commits
	
		
			42 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 2eacae8f2e | ||
|  | 403d5f1489 | ||
|  | f227633959 | ||
|  | 83c8846728 | ||
|  | 78ee99adcf | ||
|  | de4090d920 | ||
|  | 732cadd2c8 | ||
|  | 6747b60a95 | ||
|  | 90ae9ed0a2 | ||
|  | 206be49c69 | ||
|  | 45559e9230 | ||
|  | f94b846224 | ||
|  | 3ea3a69821 | ||
|  | 46ddc65626 | ||
|  | 71f313749e | ||
|  | 80a5abbbe3 | ||
|  | ba812f7e86 | ||
|  | 345c37a543 | ||
|  | b3457cd250 | ||
|  | fcf1864db3 | ||
|  | 9221b67f3b | ||
|  | 732d595a26 | ||
|  | 3bc9d53628 | ||
|  | b5a4f45dbf | ||
|  | e6bafbf3e3 | ||
|  | 5c7b128166 | ||
|  | 5469edc278 | ||
|  | 66952183a9 | ||
|  | cc97f58d96 | ||
|  | 5d6931881a | ||
|  | 0f4be7699b | ||
|  | 546983cdbc | ||
|  | c04de4e7bb | ||
|  | d46cdd80de | ||
|  | 6676e63c89 | ||
|  | 1f99c3aaae | ||
|  | e6ef4e7484 | ||
|  | b0fa041a28 | ||
|  | e17bf77bdd | ||
|  | 802b1fad61 | ||
|  | 8a8973eec2 | ||
|  | 17e7ea66e4 | 
							
								
								
									
										14
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								configure.ac
									
									
									
									
									
								
							| @@ -44,13 +44,13 @@ AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""]) | |||||||
| AC_SUBST(LIBRARY_DLSYM) | AC_SUBST(LIBRARY_DLSYM) | ||||||
|  |  | ||||||
|  |  | ||||||
| PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.10.0) | PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.11.0) | ||||||
| PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.10.0) | PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0) | ||||||
| PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.10.0) | PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0) | ||||||
| PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.10.0) | PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0) | ||||||
| PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.5.0) | PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.6.0) | ||||||
| PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.6.0) | PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0) | ||||||
| PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 1.6.0) | PKG_CHECK_MODULES(LIBOSMOTRAU, libosmotrau >= 2.0.0) | ||||||
|  |  | ||||||
| CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread" | CFLAGS="$CFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread" | ||||||
| CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread" | CPPFLAGS="$CPPFLAGS -DBUILDING_LIBOSMOMGCPCLIENT -pthread" | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ export deps inst | |||||||
| osmo-clean-workspace.sh | osmo-clean-workspace.sh | ||||||
|  |  | ||||||
| mkdir "$deps" || true | mkdir "$deps" || true | ||||||
| osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false | osmo-build-dep.sh libosmocore "" --disable-doxygen | ||||||
|  |  | ||||||
| verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]") | verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]") | ||||||
|  |  | ||||||
| @@ -30,8 +30,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" | |||||||
| export LD_LIBRARY_PATH="$inst/lib" | export LD_LIBRARY_PATH="$inst/lib" | ||||||
| export PATH="$inst/bin:$PATH" | export PATH="$inst/bin:$PATH" | ||||||
|  |  | ||||||
|  | osmo-build-dep.sh libosmo-netif "" --disable-doxygen | ||||||
| osmo-build-dep.sh libosmo-abis | osmo-build-dep.sh libosmo-abis | ||||||
| osmo-build-dep.sh libosmo-netif |  | ||||||
|  |  | ||||||
| # Additional configure options and depends | # Additional configure options and depends | ||||||
| CONFIG="" | CONFIG="" | ||||||
|   | |||||||
							
								
								
									
										49
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,52 @@ | |||||||
|  | osmo-mgw (1.14.0) unstable; urgency=medium | ||||||
|  |  | ||||||
|  |   [ Pau Espin Pedrol ] | ||||||
|  |   * jenkins.sh: libosmo-netif no longer depends on libosmo-abis | ||||||
|  |   * jenkins.sh: Use --disable-doxygen configure param | ||||||
|  |   * mgcp-client: Fix wrong value passed to strerror() | ||||||
|  |   * mgcp_client_internal.h: Add missing header dependency | ||||||
|  |   * mgcp-cli: Mark iofd ptr as NULL when freed | ||||||
|  |   * mgcp-cli: Improve error handling around mgcp_msg_gen() return | ||||||
|  |   * mgcp-cli: Fix filling in wrong local IP address of SDP Origin o= | ||||||
|  |   * mgw: Drop own MGCP extension 'noanswer' | ||||||
|  |   * cosmetic: mgw: Fix indentation whitespace | ||||||
|  |   * mgcp-client: Fix regression checking null ptr | ||||||
|  |   * mgw: Rename and move code freeing endp connection | ||||||
|  |   * mgw: Rename and move several get_conn funcs acting on endp object | ||||||
|  |   * mgw: mgcp_network.c: Simplify use of conn_rtp ptr | ||||||
|  |   * mgw: Clean up access to conn_rtp from conn | ||||||
|  |   * mgw: Avoid 2nd lookup of conn in endp during CRCX | ||||||
|  |   * cosmetic: mgw: iuup: Update comment | ||||||
|  |   * mgw: constify mgcp_endp_avail() param | ||||||
|  |   * mgcp_endp: Add helpers accessing endp connections | ||||||
|  |   * mgw: mgcp_protocol: assert freeing last conn allows creating new conn | ||||||
|  |   * mgw: Split conn mode parsing and applying into conn | ||||||
|  |   * mgw: CRCXMDCX/DLCX: rename conn and conn_rtp variables | ||||||
|  |   * mgw: Use bool instead of int in local var | ||||||
|  |   * Rename mgcp_free_rtp_port() to mgcp_rtp_end_free_port() | ||||||
|  |   * mgw: Split mgcp_rtp_end to its own file | ||||||
|  |   * mgw: Introduce mgcp_rtp_end_init() | ||||||
|  |   * mgw: Introduce struct mgcp_codecset struct | ||||||
|  |   * mgw: Cleanup rtp_endp fields in its own function | ||||||
|  |   * mgw: Move force_ptime logic outside of main CRCX func handler | ||||||
|  |   * mgw: Move several params setting to mgcp_rtp_end_init() | ||||||
|  |   * mgw: Simplify and redo code around ssrc patch feature | ||||||
|  |   * mgw: Clean up code allocating conn_rtp rtp/rtcp sockets | ||||||
|  |   * mgw: Rename and cleanup code allocating rtp/rtcp ports in trunk | ||||||
|  |   * mgw: CRCX: Split mgcp header pars parsing into a previous step | ||||||
|  |   * mgw: MDCX: Split mgcp header pars parsing into a previous step | ||||||
|  |   * mgw: DLCX: Split mgcp header pars parsing into a previous step | ||||||
|  |   * mgw: Decouple SDP parsing step from conn obj update | ||||||
|  |   * mgw: Remove wrong TODO comment | ||||||
|  |   * mgw: MDCX: Simplify early return code paths | ||||||
|  |  | ||||||
|  |   [ Mychaela N. Falconia ] | ||||||
|  |   * E1 cosmetic: reduce white space in hard-coded TRAU-DL frames | ||||||
|  |   * E1: replace idle_tf_efr[] with a better version | ||||||
|  |   * E1: replace idle_tf_fr[] with a better version | ||||||
|  |  | ||||||
|  |  -- Oliver Smith <osmith@sysmocom.de>  Wed, 12 Feb 2025 12:30:33 +0100 | ||||||
|  |  | ||||||
| osmo-mgw (1.13.1) unstable; urgency=medium | osmo-mgw (1.13.1) unstable; urgency=medium | ||||||
|  |  | ||||||
|   [ Philipp Maier ] |   [ Philipp Maier ] | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							| @@ -6,9 +6,9 @@ Build-Depends: debhelper (>= 10), | |||||||
|                dh-autoreconf, |                dh-autoreconf, | ||||||
|                pkg-config, |                pkg-config, | ||||||
|                autotools-dev, |                autotools-dev, | ||||||
|                libosmocore-dev (>= 1.10.0), |                libosmocore-dev (>= 1.11.0), | ||||||
|                libosmo-netif-dev (>= 1.5.0), |                libosmo-netif-dev (>= 1.6.0), | ||||||
|                libosmo-abis-dev (>= 1.6.0), |                libosmo-abis-dev (>= 2.0.0), | ||||||
|                osmo-gsm-manuals-dev (>= 1.6.0) |                osmo-gsm-manuals-dev (>= 1.6.0) | ||||||
| Standards-Version: 3.9.8 | Standards-Version: 3.9.8 | ||||||
| Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw | Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| noinst_HEADERS = \ | noinst_HEADERS = \ | ||||||
| 	vty.h \ | 	vty.h \ | ||||||
| 	mgcp_msg.h \ | 	mgcp_msg.h \ | ||||||
|  | 	mgcp_codec.h \ | ||||||
| 	mgcp_conn.h \ | 	mgcp_conn.h \ | ||||||
| 	mgcp_stat.h \ | 	mgcp_stat.h \ | ||||||
| 	mgcp_endp.h \ | 	mgcp_endp.h \ | ||||||
| @@ -13,4 +14,5 @@ noinst_HEADERS = \ | |||||||
| 	mgcp_network.h \ | 	mgcp_network.h \ | ||||||
| 	mgcp_protocol.h \ | 	mgcp_protocol.h \ | ||||||
| 	mgcp_iuup.h \ | 	mgcp_iuup.h \ | ||||||
|  | 	mgcp_rtp_end.h \ | ||||||
| 	$(NULL) | 	$(NULL) | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_common.h> | ||||||
|  |  | ||||||
| #define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20 | #define DEFAULT_RTP_AUDIO_FRAME_DUR_NUM 20 | ||||||
| #define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000 | #define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000 | ||||||
| #define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20 | #define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20 | ||||||
| @@ -8,14 +12,37 @@ | |||||||
|  |  | ||||||
| #define PTYPE_UNDEFINED (-1) | #define PTYPE_UNDEFINED (-1) | ||||||
|  |  | ||||||
| struct mgcp_conn_rtp; | struct mgcp_rtp_codec { | ||||||
|  | 	uint32_t rate; | ||||||
|  | 	int channels; | ||||||
|  | 	uint32_t frame_duration_num; | ||||||
|  | 	uint32_t frame_duration_den; | ||||||
|  |  | ||||||
|  | 	int payload_type; | ||||||
|  | 	char audio_name[64]; | ||||||
|  | 	char subtype_name[64]; | ||||||
|  |  | ||||||
|  | 	bool param_present; | ||||||
|  | 	struct mgcp_codec_param param; | ||||||
|  | }; | ||||||
|  |  | ||||||
| void mgcp_codec_summary(struct mgcp_conn_rtp *conn); |  | ||||||
| void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn); |  | ||||||
| int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param); |  | ||||||
| int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst); |  | ||||||
| const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn, |  | ||||||
| 								const char *subtype_name, unsigned int match_nr); |  | ||||||
| bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec); | bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec); | ||||||
| bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec); | bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec); | ||||||
| struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type); |  | ||||||
|  | struct mgcp_rtp_codecset { | ||||||
|  | 	/* currently selected audio codec */ | ||||||
|  | 	struct mgcp_rtp_codec *codec; | ||||||
|  | 	/* array with assigned audio codecs to choose from (SDP) */ | ||||||
|  | 	struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS]; | ||||||
|  | 	/* number of assigned audio codecs (SDP) */ | ||||||
|  | 	unsigned int codecs_assigned; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset); | ||||||
|  | void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str); | ||||||
|  | int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, | ||||||
|  | 			    const char *audio_name, const struct mgcp_codec_param *param); | ||||||
|  | int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst); | ||||||
|  | const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset, | ||||||
|  | 								const char *subtype_name, unsigned int match_nr); | ||||||
|  | struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type); | ||||||
|   | |||||||
| @@ -24,11 +24,14 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <osmocom/mgcp/mgcp.h> | #include <osmocom/mgcp/mgcp.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_common.h> | ||||||
| #include <osmocom/mgcp/mgcp_network.h> | #include <osmocom/mgcp/mgcp_network.h> | ||||||
| #include <osmocom/mgcp/osmux.h> | #include <osmocom/mgcp/osmux.h> | ||||||
| #include <osmocom/core/linuxlist.h> | #include <osmocom/core/linuxlist.h> | ||||||
| #include <osmocom/core/rate_ctr.h> | #include <osmocom/core/rate_ctr.h> | ||||||
|  | #include <osmocom/core/utils.h> | ||||||
| #include <osmocom/gsm/iuup.h> | #include <osmocom/gsm/iuup.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_rtp_end.h> | ||||||
| #include <inttypes.h> | #include <inttypes.h> | ||||||
|  |  | ||||||
| #define LOGPCONN(conn, cat, level, fmt, args...) \ | #define LOGPCONN(conn, cat, level, fmt, args...) \ | ||||||
| @@ -237,15 +240,16 @@ static inline bool mgcp_conn_rtp_is_iuup(const struct mgcp_conn_rtp *conn) | |||||||
| 	return conn->type == MGCP_RTP_IUUP; | 	return conn->type == MGCP_RTP_IUUP; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static inline struct mgcp_conn_rtp *mgcp_conn_get_conn_rtp(struct mgcp_conn *conn) | ||||||
|  | { | ||||||
|  | 	OSMO_ASSERT(conn->type == MGCP_CONN_TYPE_RTP); | ||||||
|  | 	return &conn->u.rtp; | ||||||
|  | } | ||||||
|  |  | ||||||
| struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp, | struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp, | ||||||
| 				  enum mgcp_conn_type type, char *name); | 				  enum mgcp_conn_type type, char *name); | ||||||
| struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id); | void mgcp_conn_free(struct mgcp_conn *conn); | ||||||
| struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, | int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode); | ||||||
| 					const char *id); |  | ||||||
| void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id); |  | ||||||
| void mgcp_conn_free_oldest(struct mgcp_endpoint *endp); |  | ||||||
| void mgcp_conn_free_all(struct mgcp_endpoint *endp); |  | ||||||
| char *mgcp_conn_dump(struct mgcp_conn *conn); | char *mgcp_conn_dump(struct mgcp_conn *conn); | ||||||
| struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn); | struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn); | ||||||
| struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp); |  | ||||||
| void mgcp_conn_watchdog_kick(struct mgcp_conn *conn); | void mgcp_conn_watchdog_kick(struct mgcp_conn *conn); | ||||||
|   | |||||||
| @@ -138,11 +138,20 @@ struct mgcp_endpoint *mgcp_endp_by_name_trunk(int *cause, const char *epname, | |||||||
| 					      const struct mgcp_trunk *trunk); | 					      const struct mgcp_trunk *trunk); | ||||||
| struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname, | struct mgcp_endpoint *mgcp_endp_by_name(int *cause, const char *epname, | ||||||
| 					struct mgcp_config *cfg); | 					struct mgcp_config *cfg); | ||||||
| bool mgcp_endp_avail(struct mgcp_endpoint *endp); | bool mgcp_endp_avail(const struct mgcp_endpoint *endp); | ||||||
|  | unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp); | ||||||
|  | bool mgcp_endp_is_full(const struct mgcp_endpoint *endp); | ||||||
| void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | void mgcp_endp_add_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | ||||||
| void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | ||||||
|  | void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp); | ||||||
|  | void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp); | ||||||
| void mgcp_endp_strip_name(char *epname_stripped, const char *epname, | void mgcp_endp_strip_name(char *epname_stripped, const char *epname, | ||||||
| 			 const struct mgcp_trunk *trunk); | 			 const struct mgcp_trunk *trunk); | ||||||
| struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname, | struct mgcp_endpoint *mgcp_endp_find_specific(const char *epname, | ||||||
| 			const struct mgcp_trunk *trunk); | 			const struct mgcp_trunk *trunk); | ||||||
| void mgcp_endp_release(struct mgcp_endpoint *endp); | void mgcp_endp_release(struct mgcp_endpoint *endp); | ||||||
|  |  | ||||||
|  | struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id); | ||||||
|  | struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp); | ||||||
|  | struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp, | ||||||
|  | 					const char *id); | ||||||
|   | |||||||
| @@ -27,6 +27,8 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #include <osmocom/mgcp/mgcp_common.h> | ||||||
|  |  | ||||||
| struct mgcp_conn; | struct mgcp_conn; | ||||||
| struct mgcp_parse_data; | struct mgcp_parse_data; | ||||||
| struct mgcp_endpoint; | struct mgcp_endpoint; | ||||||
| @@ -34,14 +36,14 @@ struct mgcp_trunk; | |||||||
|  |  | ||||||
| void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble); | void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble); | ||||||
|  |  | ||||||
| int mgcp_parse_conn_mode(const char *msg, struct mgcp_endpoint *endp, | enum mgcp_connection_mode mgcp_parse_conn_mode(const char *msg); | ||||||
| 			 struct mgcp_conn *conn); |  | ||||||
|  |  | ||||||
| int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data); | int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data); | ||||||
|  | int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata); | ||||||
|  |  | ||||||
| int mgcp_parse_osmux_cid(const char *line); | int mgcp_parse_osmux_cid(const char *line); | ||||||
|  |  | ||||||
| bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line); | bool mgcp_check_param(const char *line); | ||||||
|  |  | ||||||
| int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid); | int mgcp_verify_call_id(struct mgcp_endpoint *endp, const char *callid); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -74,65 +74,6 @@ struct mgcp_rtp_state { | |||||||
| 	uint32_t alt_rtp_tx_ssrc; | 	uint32_t alt_rtp_tx_ssrc; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct mgcp_rtp_codec { |  | ||||||
| 	uint32_t rate; |  | ||||||
| 	int channels; |  | ||||||
| 	uint32_t frame_duration_num; |  | ||||||
| 	uint32_t frame_duration_den; |  | ||||||
|  |  | ||||||
| 	int payload_type; |  | ||||||
| 	char audio_name[64]; |  | ||||||
| 	char subtype_name[64]; |  | ||||||
|  |  | ||||||
| 	bool param_present; |  | ||||||
| 	struct mgcp_codec_param param; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */ |  | ||||||
| struct mgcp_rtp_end { |  | ||||||
| 	/* remote IP address of the RTP socket */ |  | ||||||
| 	struct osmo_sockaddr addr; |  | ||||||
|  |  | ||||||
| 	/* in network byte order */ |  | ||||||
| 	uint16_t rtcp_port; |  | ||||||
|  |  | ||||||
| 	/* currently selected audio codec */ |  | ||||||
| 	struct mgcp_rtp_codec *codec; |  | ||||||
|  |  | ||||||
| 	/* array with assigned audio codecs to choose from (SDP) */ |  | ||||||
| 	struct mgcp_rtp_codec codecs[MGCP_MAX_CODECS]; |  | ||||||
|  |  | ||||||
| 	/* number of assigned audio codecs (SDP) */ |  | ||||||
| 	unsigned int codecs_assigned; |  | ||||||
|  |  | ||||||
| 	/* per endpoint data */ |  | ||||||
| 	int  frames_per_packet; |  | ||||||
| 	uint32_t packet_duration_ms; |  | ||||||
| 	int maximum_packet_time; /* -1: not set */ |  | ||||||
| 	/* are we transmitting packets (true) or dropping (false) outbound packets */ |  | ||||||
| 	bool output_enabled; |  | ||||||
| 	/* FIXME: This parameter can be set + printed, but is nowhere used! */ |  | ||||||
| 	int force_output_ptime; |  | ||||||
|  |  | ||||||
| 	/* RTP patching */ |  | ||||||
| 	int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ |  | ||||||
| 	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */ |  | ||||||
| 	int force_aligned_timing; |  | ||||||
| 	bool rfc5993_hr_convert; |  | ||||||
|  |  | ||||||
| 	/* Each end has a separate socket for RTP and RTCP */ |  | ||||||
| 	struct osmo_io_fd *rtp; |  | ||||||
| 	struct osmo_io_fd *rtcp; |  | ||||||
|  |  | ||||||
| 	/* local UDP port number of the RTP socket; RTCP is +1 */ |  | ||||||
| 	int local_port; |  | ||||||
| 	/* where the endpoint RTP connection binds to, set during CRCX and |  | ||||||
| 	 * possibly updated during MDCX */ |  | ||||||
| 	char local_addr[INET6_ADDRSTRLEN]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end); |  | ||||||
|  |  | ||||||
| struct mgcp_rtp_tap { | struct mgcp_rtp_tap { | ||||||
| 	/* is this tap active (1) or not (0) */ | 	/* is this tap active (1) or not (0) */ | ||||||
| 	int enabled; | 	int enabled; | ||||||
| @@ -150,9 +91,7 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg); | |||||||
| void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | ||||||
| int mgcp_dispatch_e1_bridge_cb(struct msgb *msg); | int mgcp_dispatch_e1_bridge_cb(struct msgb *msg); | ||||||
| void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn); | ||||||
| int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port, | int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn, int rtp_port); | ||||||
| 			   struct mgcp_conn_rtp *conn); |  | ||||||
| void mgcp_free_rtp_port(struct mgcp_rtp_end *end); |  | ||||||
| void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | ||||||
| 			  struct mgcp_rtp_state *state, | 			  struct mgcp_rtp_state *state, | ||||||
| 			  struct mgcp_rtp_end *rtp_end, | 			  struct mgcp_rtp_end *rtp_end, | ||||||
|   | |||||||
| @@ -1,11 +1,73 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  |  | ||||||
|  | #include <osmocom/core/utils.h> | ||||||
|  | #include <osmocom/core/socket.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_common.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_codec.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define MGCP_PARSE_SDP_PTIME_UNSET (-1) | ||||||
|  | #define MGCP_PARSE_SDP_MAXPTIME_UNSET (-1) | ||||||
|  | #define MGCP_PARSE_SDP_RTP_PORT_UNSET (0) | ||||||
|  |  | ||||||
|  | struct mgcp_parse_sdp { | ||||||
|  | 	int ptime; | ||||||
|  | 	int maxptime; | ||||||
|  | 	int rtp_port; | ||||||
|  | 	struct osmo_sockaddr rem_addr; /* Only IP address, port is in rtp_port above */ | ||||||
|  | 	struct mgcp_rtp_codecset cset; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static inline void mgcp_parse_sdp_init(struct mgcp_parse_sdp *sdp) | ||||||
|  | { | ||||||
|  | 	sdp->ptime = MGCP_PARSE_SDP_PTIME_UNSET; | ||||||
|  | 	sdp->maxptime = MGCP_PARSE_SDP_MAXPTIME_UNSET; | ||||||
|  | 	sdp->rtp_port = MGCP_PARSE_SDP_RTP_PORT_UNSET; | ||||||
|  | 	sdp->rem_addr = (struct osmo_sockaddr){ .u.sa.sa_family = AF_UNSPEC }; | ||||||
|  | 	mgcp_codecset_reset(&sdp->cset); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET (-2) | ||||||
|  | #define MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD (-1) | ||||||
|  |  | ||||||
|  | struct mgcp_parse_hdr_pars { | ||||||
|  | 	const char *local_options; | ||||||
|  | 	const char *callid; | ||||||
|  | 	const char *connid; | ||||||
|  | 	enum mgcp_connection_mode mode; | ||||||
|  | 	int remote_osmux_cid; | ||||||
|  | 	bool have_sdp; | ||||||
|  | 	/*! MGCP_X_OSMO_IGN_* flags from 'X-Osmo-IGN:' header */ | ||||||
|  | 	uint32_t x_osmo_ign; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static inline void mgcp_parse_hdr_pars_init(struct mgcp_parse_hdr_pars *hpars) | ||||||
|  | { | ||||||
|  | 	*hpars = (struct mgcp_parse_hdr_pars){ | ||||||
|  | 		.local_options = NULL, | ||||||
|  | 		.callid = NULL, | ||||||
|  | 		.connid = NULL, | ||||||
|  | 		.mode = MGCP_CONN_NONE, | ||||||
|  | 		.remote_osmux_cid = MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET, | ||||||
|  | 		.have_sdp = false, | ||||||
|  | 		.x_osmo_ign = 0, | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Internal structure while parsing a request */ | /* Internal structure while parsing a request */ | ||||||
| struct mgcp_parse_data { | struct mgcp_parse_data { | ||||||
| 	struct mgcp_config *cfg; | 	struct mgcp_config *cfg; | ||||||
|  | 	char *save; | ||||||
|  | 	/* MGCP Header: */ | ||||||
| 	char *epname; | 	char *epname; | ||||||
| 	char *trans; | 	char *trans; | ||||||
| 	char *save; | 	struct mgcp_parse_hdr_pars hpars; | ||||||
|  | 	/* MGCP Body: */ | ||||||
|  | 	struct mgcp_parse_sdp sdp; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Local connection options */ | /* Local connection options */ | ||||||
| @@ -23,8 +85,12 @@ int check_local_cx_options(void *ctx, const char *options); | |||||||
|  |  | ||||||
| struct mgcp_rtp_end; | struct mgcp_rtp_end; | ||||||
| struct mgcp_endpoint; | struct mgcp_endpoint; | ||||||
| void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, |  | ||||||
| 			 struct mgcp_rtp_end *rtp); |  | ||||||
|  |  | ||||||
| uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp, | uint32_t mgcp_rtp_packet_duration(const struct mgcp_endpoint *endp, | ||||||
| 				  const struct mgcp_rtp_end *rtp); | 				  const struct mgcp_rtp_end *rtp); | ||||||
|  |  | ||||||
|  | extern const struct value_string mgcp_connection_mode_strs[]; | ||||||
|  | static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode) | ||||||
|  | { | ||||||
|  | 	return get_value_string(mgcp_connection_mode_strs, mode); | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								include/osmocom/mgcp/mgcp_rtp_end.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <inttypes.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  |  | ||||||
|  | #include <osmocom/core/socket.h> | ||||||
|  | #include <osmocom/core/osmo_io.h> | ||||||
|  |  | ||||||
|  | #include <osmocom/mgcp/mgcp.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_codec.h> | ||||||
|  |  | ||||||
|  | /* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */ | ||||||
|  | struct mgcp_rtp_end { | ||||||
|  | 	struct mgcp_conn_rtp *conn_rtp; /* backpointer */ | ||||||
|  | 	/* remote IP address of the RTP socket */ | ||||||
|  | 	struct osmo_sockaddr addr; | ||||||
|  |  | ||||||
|  | 	/* in network byte order */ | ||||||
|  | 	uint16_t rtcp_port; | ||||||
|  |  | ||||||
|  | 	struct mgcp_rtp_codecset cset; | ||||||
|  |  | ||||||
|  | 	/* per endpoint data */ | ||||||
|  | 	int  frames_per_packet; | ||||||
|  | 	uint32_t packet_duration_ms; | ||||||
|  | 	int maximum_packet_time; /* -1: not set */ | ||||||
|  | 	/* are we transmitting packets (true) or dropping (false) outbound packets */ | ||||||
|  | 	bool output_enabled; | ||||||
|  | 	/* FIXME: This parameter can be set + printed, but is nowhere used! */ | ||||||
|  | 	int force_output_ptime; | ||||||
|  |  | ||||||
|  | 	/* RTP patching */ | ||||||
|  | 	bool force_constant_ssrc; | ||||||
|  | 	/* should we perform align_rtp_timestamp_offset() (1) or not (0) */ | ||||||
|  | 	int force_aligned_timing; | ||||||
|  | 	bool rfc5993_hr_convert; | ||||||
|  |  | ||||||
|  | 	/* Each end has a separate socket for RTP and RTCP */ | ||||||
|  | 	struct osmo_io_fd *rtp; | ||||||
|  | 	struct osmo_io_fd *rtcp; | ||||||
|  |  | ||||||
|  | 	/* local UDP port number of the RTP socket; RTCP is +1 */ | ||||||
|  | 	int local_port; | ||||||
|  | 	/* where the endpoint RTP connection binds to, set during CRCX and | ||||||
|  | 	 * possibly updated during MDCX */ | ||||||
|  | 	char local_addr[INET6_ADDRSTRLEN]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp); | ||||||
|  | void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end); | ||||||
|  | void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms); | ||||||
|  | bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end); | ||||||
|  | void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end); | ||||||
| @@ -22,9 +22,9 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, | struct mgcp_parse_data; | ||||||
| 			struct mgcp_conn_rtp *conn, |  | ||||||
| 			struct mgcp_parse_data *p); | int mgcp_parse_sdp_data(struct mgcp_parse_data *p); | ||||||
|  |  | ||||||
| int mgcp_write_response_sdp(const struct mgcp_endpoint *endp, | int mgcp_write_response_sdp(const struct mgcp_endpoint *endp, | ||||||
| 			    const struct mgcp_conn_rtp *conn, struct msgb *sdp, | 			    const struct mgcp_conn_rtp *conn, struct msgb *sdp, | ||||||
|   | |||||||
| @@ -2,9 +2,10 @@ | |||||||
|  |  | ||||||
| #include <osmocom/gsm/i460_mux.h> | #include <osmocom/gsm/i460_mux.h> | ||||||
| #include <osmocom/abis/e1_input.h> | #include <osmocom/abis/e1_input.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_conn.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_network.h> | ||||||
| #include <osmocom/mgcp/mgcp_ratectr.h> | #include <osmocom/mgcp/mgcp_ratectr.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| #define LOGPTRUNK(trunk, cat, level, fmt, args...) \ | #define LOGPTRUNK(trunk, cat, level, fmt, args...) \ | ||||||
| LOGP(cat, level, "trunk:%u " fmt, \ | LOGP(cat, level, "trunk:%u " fmt, \ | ||||||
|      trunk ? trunk->trunk_nr : 0, \ |      trunk ? trunk->trunk_nr : 0, \ | ||||||
| @@ -34,7 +35,7 @@ struct mgcp_trunk { | |||||||
| 	int keepalive_interval; | 	int keepalive_interval; | ||||||
|  |  | ||||||
| 	/* RTP patching */ | 	/* RTP patching */ | ||||||
| 	int force_constant_ssrc; /* 0: don't, 1: once */ | 	bool force_constant_ssrc; | ||||||
| 	int force_aligned_timing; | 	int force_aligned_timing; | ||||||
| 	bool rfc5993_hr_convert; | 	bool rfc5993_hr_convert; | ||||||
|  |  | ||||||
| @@ -78,6 +79,7 @@ struct mgcp_trunk *mgcp_trunk_by_num(const struct mgcp_config *cfg, enum mgcp_tr | |||||||
| struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname); | struct mgcp_trunk *mgcp_trunk_by_name(const struct mgcp_config *cfg, const char *epname); | ||||||
| int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname); | int e1_trunk_nr_from_epname(unsigned int *trunk_nr, const char *epname); | ||||||
| struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num); | struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigned int num); | ||||||
|  | int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp); | ||||||
|  |  | ||||||
| /* The virtual trunk is always created on trunk id 0 for historical reasons, | /* The virtual trunk is always created on trunk id 0 for historical reasons, | ||||||
|  * use this define constant as ID when allocating a virtual trunk. Other |  * use this define constant as ID when allocating a virtual trunk. Other | ||||||
|   | |||||||
| @@ -3,6 +3,8 @@ | |||||||
| #include <osmocom/core/osmo_io.h> | #include <osmocom/core/osmo_io.h> | ||||||
| #include <osmocom/core/timer.h> | #include <osmocom/core/timer.h> | ||||||
|  |  | ||||||
|  | #include <osmocom/mgcp_client/mgcp_client.h> | ||||||
|  |  | ||||||
| #define MSGB_CB_MGCP_TRANS_ID 0 | #define MSGB_CB_MGCP_TRANS_ID 0 | ||||||
|  |  | ||||||
| /* Struct that holds one endpoint name */ | /* Struct that holds one endpoint name */ | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ AM_LDFLAGS = \ | |||||||
|  |  | ||||||
| # This is not at all related to the release version, but a range of supported | # This is not at all related to the release version, but a range of supported | ||||||
| # API versions. Read TODO_RELEASE in the source tree's root! | # API versions. Read TODO_RELEASE in the source tree's root! | ||||||
| MGCP_CLIENT_LIBVERSION=14:0:0 | MGCP_CLIENT_LIBVERSION=14:1:0 | ||||||
|  |  | ||||||
| lib_LTLIBRARIES = \ | lib_LTLIBRARIES = \ | ||||||
| 	libosmo-mgcp-client.la \ | 	libosmo-mgcp-client.la \ | ||||||
|   | |||||||
| @@ -786,8 +786,10 @@ static void mgcp_read_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg) | |||||||
| 	struct mgcp_client *mgcp = osmo_iofd_get_data(iofd); | 	struct mgcp_client *mgcp = osmo_iofd_get_data(iofd); | ||||||
|  |  | ||||||
| 	if (res <= 0) { | 	if (res <= 0) { | ||||||
|  | 		char errbuf[128] = ""; | ||||||
|  | 		strerror_r(-res, errbuf, sizeof(errbuf)); | ||||||
| 		LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n", | 		LOGPMGW(mgcp, LOGL_ERROR, "Failed to read: %s: %d='%s'\n", | ||||||
| 			osmo_iofd_get_name(iofd), res, strerror(res)); | 			osmo_iofd_get_name(iofd), res, errbuf); | ||||||
|  |  | ||||||
| 		msgb_free(msg); | 		msgb_free(msg); | ||||||
| 		return; | 		return; | ||||||
| @@ -822,8 +824,10 @@ static void mgcp_write_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg) | |||||||
| 	struct mgcp_client *mgcp = osmo_iofd_get_data(iofd); | 	struct mgcp_client *mgcp = osmo_iofd_get_data(iofd); | ||||||
|  |  | ||||||
| 	if (OSMO_UNLIKELY(res != msg->len)) { | 	if (OSMO_UNLIKELY(res != msg->len)) { | ||||||
|  | 		char errbuf[128] = ""; | ||||||
|  | 		strerror_r(-res, errbuf, sizeof(errbuf)); | ||||||
| 		LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n", | 		LOGPMGW(mgcp, LOGL_ERROR, "Failed to Tx MGCP: %s: %d='%s'; msg: len=%u '%s'...\n", | ||||||
| 			osmo_iofd_get_name(mgcp->iofd), res, strerror(res), | 			osmo_iofd_get_name(mgcp->iofd), res, errbuf, | ||||||
| 			msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len))); | 			msg->len, osmo_escape_str((const char *)msg->data, OSMO_MIN(42, msg->len))); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -860,6 +864,10 @@ static void _mgcp_client_send_dlcx(struct mgcp_client *mgcp, const char *epname) | |||||||
| 	}; | 	}; | ||||||
| 	osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint)); | 	osmo_strlcpy(mgcp_msg_dlcx.endpoint, epname, sizeof(mgcp_msg_dlcx.endpoint)); | ||||||
| 	msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx); | 	msgb_dlcx = mgcp_msg_gen(mgcp, &mgcp_msg_dlcx); | ||||||
|  | 	if (!msgb_dlcx) { | ||||||
|  | 		LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP DLCX %s\n", epname); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL); | 	mgcp_client_tx(mgcp, msgb_dlcx, &_ignore_mgcp_response, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -873,6 +881,10 @@ static void _mgcp_client_send_auep(struct mgcp_client *mgcp, const char *epname) | |||||||
| 	}; | 	}; | ||||||
| 	OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname); | 	OSMO_STRLCPY_ARRAY(mgcp_msg_auep.endpoint, epname); | ||||||
| 	msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep); | 	msgb_auep = mgcp_msg_gen(mgcp, &mgcp_msg_auep); | ||||||
|  | 	if (!msgb_auep) { | ||||||
|  | 		LOGPMGW(mgcp, LOGL_ERROR, "Failed generating MGCP AUEP %s\n", epname); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 	mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL); | 	mgcp_client_tx(mgcp, msgb_auep, &_ignore_mgcp_response, NULL); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1047,6 +1059,7 @@ void mgcp_client_disconnect(struct mgcp_client *mgcp) | |||||||
| 	osmo_iofd_txqueue_clear(mgcp->iofd); | 	osmo_iofd_txqueue_clear(mgcp->iofd); | ||||||
| 	LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd)); | 	LOGPMGW(mgcp, LOGL_INFO, "MGCP association: %s -- closed!\n", osmo_iofd_get_name(mgcp->iofd)); | ||||||
| 	osmo_iofd_free(mgcp->iofd); | 	osmo_iofd_free(mgcp->iofd); | ||||||
|  | 	mgcp->iofd = NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! Get the IP-Aaddress of the associated MGW as string. | /*! Get the IP-Aaddress of the associated MGW as string. | ||||||
| @@ -1307,6 +1320,36 @@ static int add_lco(struct msgb *msg, struct mgcp_msg *mgcp_msg) | |||||||
| #undef MSGB_PRINTF_OR_RET | #undef MSGB_PRINTF_OR_RET | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Helper function to obtain local IP address used in MGCP towards MGW, | ||||||
|  |  * in string format, to fill the SDP "Origin" ("o=") field. | ||||||
|  |  * return 0 on success, negative on error. | ||||||
|  |  */ | ||||||
|  | static int get_mgcp_local_addr(const struct mgcp_client *mgcp, char *local_ip, size_t local_ip_len) | ||||||
|  | { | ||||||
|  | 	int fd; | ||||||
|  |  | ||||||
|  | 	/* Try to get the socket local IP address if available: */ | ||||||
|  | 	if (mgcp->iofd && ((fd = osmo_iofd_get_fd(mgcp->iofd)) >= 0)) { | ||||||
|  | 		if (osmo_sock_get_local_ip(fd, local_ip, local_ip_len) == 0) | ||||||
|  | 			return 0; | ||||||
|  | 		/* else: continue below */ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* If MGCP local address was explicitly specified in config, use it: */ | ||||||
|  | 	if (mgcp->actual.local_addr) { | ||||||
|  | 		osmo_strlcpy(local_ip, mgcp->actual.local_addr, local_ip_len); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Guess our local address based on system routing towards MGW: */ | ||||||
|  | 	OSMO_ASSERT(local_ip_len >= INET6_ADDRSTRLEN); | ||||||
|  | 	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) == 0) | ||||||
|  | 		return 0; | ||||||
|  |  | ||||||
|  | 	LOGPMGW(mgcp, LOGL_ERROR, "Could not determine local IP-Address!\n"); | ||||||
|  | 	return -EINVAL; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */ | /* Helper function for mgcp_msg_gen(): Add SDP information to MGCP message */ | ||||||
| static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp) | static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_client *mgcp) | ||||||
| { | { | ||||||
| @@ -1316,6 +1359,7 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie | |||||||
| 	const char *codec; | 	const char *codec; | ||||||
| 	unsigned int pt; | 	unsigned int pt; | ||||||
| 	uint16_t audio_port; | 	uint16_t audio_port; | ||||||
|  | 	int rc; | ||||||
|  |  | ||||||
| #define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \ | #define MSGB_PRINTF_OR_RET(FMT, ARGS...) do { \ | ||||||
| 		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \ | 		if (msgb_printf(msg, FMT, ##ARGS) != 0) { \ | ||||||
| @@ -1331,11 +1375,9 @@ static int add_sdp(struct msgb *msg, struct mgcp_msg *mgcp_msg, struct mgcp_clie | |||||||
| 	MSGB_PRINTF_OR_RET("v=0\r\n"); | 	MSGB_PRINTF_OR_RET("v=0\r\n"); | ||||||
|  |  | ||||||
| 	/* Determine local IP-Address */ | 	/* Determine local IP-Address */ | ||||||
| 	if (osmo_sock_local_ip(local_ip, mgcp->actual.remote_addr) < 0) { | 	rc = get_mgcp_local_addr(mgcp, local_ip, sizeof(local_ip)); | ||||||
| 		LOGPMGW(mgcp, LOGL_ERROR, | 	if (rc < 0) | ||||||
| 			"Could not determine local IP-Address!\n"); | 		return rc; | ||||||
| 		return -EINVAL; |  | ||||||
| 	} |  | ||||||
| 	local_ip_family = osmo_ip_str_type(local_ip); | 	local_ip_family = osmo_ip_str_type(local_ip); | ||||||
| 	if (local_ip_family == AF_UNSPEC) | 	if (local_ip_family == AF_UNSPEC) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|   | |||||||
| @@ -157,6 +157,7 @@ static void set_conn_mode(struct mgcp_msg *mgcp_msg, struct mgcp_conn_peer *peer | |||||||
| 		mgcp_msg->conn_mode = conn_mode; | 		mgcp_msg->conn_mode = conn_mode; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* returns message buffer containing MGXP MDCX on success, NULL on error. */ | ||||||
| static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx) | static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx) | ||||||
| { | { | ||||||
| 	struct mgcp_msg mgcp_msg; | 	struct mgcp_msg mgcp_msg; | ||||||
| @@ -192,6 +193,7 @@ static struct msgb *make_mdcx_msg(struct mgcp_ctx *mgcp_ctx) | |||||||
| 	return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg); | 	return mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* returns message buffer containing MGXP DLCX on success, NULL on error. */ | ||||||
| struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx) | struct msgb *make_dlcx_msg(struct mgcp_ctx *mgcp_ctx) | ||||||
| { | { | ||||||
| 	struct mgcp_msg mgcp_msg; | 	struct mgcp_msg mgcp_msg; | ||||||
| @@ -231,8 +233,10 @@ static void fsm_crcx_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) | |||||||
| 		set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local); | 		set_conn_mode(&mgcp_msg, &mgcp_ctx->conn_peer_local); | ||||||
|  |  | ||||||
| 		msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg); | 		msg = mgcp_msg_gen(mgcp_ctx->mgcp, &mgcp_msg); | ||||||
| 		OSMO_ASSERT(msg); | 		if (!msg) { | ||||||
|  | 			osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg); | 		mgcp_ctx->mgw_pending_trans = mgcp_msg_trans_id(msg); | ||||||
| 		mgcp_ctx->mgw_trans_pending = true; | 		mgcp_ctx->mgw_trans_pending = true; | ||||||
| 		rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi); | 		rc = mgcp_client_tx(mgcp, msg, mgw_crcx_resp_cb, fi); | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ libosmo_mgcp_a_SOURCES = \ | |||||||
| 	mgcp_endp.c \ | 	mgcp_endp.c \ | ||||||
| 	mgcp_trunk.c \ | 	mgcp_trunk.c \ | ||||||
| 	mgcp_ratectr.c \ | 	mgcp_ratectr.c \ | ||||||
|  | 	mgcp_rtp_end.c \ | ||||||
| 	mgcp_e1.c \ | 	mgcp_e1.c \ | ||||||
| 	mgcp_iuup.c \ | 	mgcp_iuup.c \ | ||||||
| 	$(NULL) | 	$(NULL) | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ | |||||||
|  |  | ||||||
| /* Helper function to dump codec information of a specified codec to a printable | /* Helper function to dump codec information of a specified codec to a printable | ||||||
|  * string, used by dump_codec_summary() */ |  * string, used by dump_codec_summary() */ | ||||||
| static char *dump_codec(struct mgcp_rtp_codec *codec) | static char *mgcp_codec_dump(struct mgcp_rtp_codec *codec) | ||||||
| { | { | ||||||
| 	static char str[256]; | 	static char str[256]; | ||||||
| 	char *pt_str; | 	char *pt_str; | ||||||
| @@ -49,31 +49,25 @@ static char *dump_codec(struct mgcp_rtp_codec *codec) | |||||||
| } | } | ||||||
|  |  | ||||||
| /*! Dump a summary of all negotiated codecs to debug log | /*! Dump a summary of all negotiated codecs to debug log | ||||||
|  *  \param[in] conn related rtp-connection. */ |  *  \param[in] cset related codecset. | ||||||
| void mgcp_codec_summary(struct mgcp_conn_rtp *conn) |  *  \param[in] prefix_str Prefix string to print during logging. | ||||||
|  |  * */ | ||||||
|  | void mgcp_codecset_summary(struct mgcp_rtp_codecset *cset, const char *prefix_str) | ||||||
| { | { | ||||||
| 	struct mgcp_rtp_end *rtp; |  | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	struct mgcp_rtp_codec *codec; |  | ||||||
| 	struct mgcp_endpoint *endp; |  | ||||||
|  |  | ||||||
| 	rtp = &conn->end; | 	if (cset->codecs_assigned == 0) { | ||||||
| 	endp = conn->conn->endp; | 		LOGP(DLMGCP, LOGL_ERROR, "%s no codecs available\n", prefix_str); | ||||||
|  |  | ||||||
| 	if (rtp->codecs_assigned == 0) { |  | ||||||
| 		LOGPENDP(endp, DLMGCP, LOGL_ERROR, "conn:%s no codecs available\n", |  | ||||||
| 			 mgcp_conn_dump(conn->conn)); |  | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Store parsed codec information */ | 	/* Store parsed codec information */ | ||||||
| 	for (i = 0; i < rtp->codecs_assigned; i++) { | 	for (i = 0; i < cset->codecs_assigned; i++) { | ||||||
| 		codec = &rtp->codecs[i]; | 		struct mgcp_rtp_codec *codec = &cset->codecs[i]; | ||||||
|  |  | ||||||
| 		LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s codecs[%u]:%s", | 		LOGP(DLMGCP, LOGL_DEBUG, "%s codecs[%u]:%s", prefix_str, i, mgcp_codec_dump(codec)); | ||||||
| 			 mgcp_conn_dump(conn->conn), i, dump_codec(codec)); |  | ||||||
|  |  | ||||||
| 		if (codec == rtp->codec) | 		if (codec == cset->codec) | ||||||
| 			LOGPC(DLMGCP, LOGL_DEBUG, " [selected]"); | 			LOGPC(DLMGCP, LOGL_DEBUG, " [selected]"); | ||||||
|  |  | ||||||
| 		LOGPC(DLMGCP, LOGL_DEBUG, "\n"); | 		LOGPC(DLMGCP, LOGL_DEBUG, "\n"); | ||||||
| @@ -81,7 +75,7 @@ void mgcp_codec_summary(struct mgcp_conn_rtp *conn) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Initalize or reset codec information with default data. */ | /* Initalize or reset codec information with default data. */ | ||||||
| static void codec_init(struct mgcp_rtp_codec *codec) | static void mgcp_codec_init(struct mgcp_rtp_codec *codec) | ||||||
| { | { | ||||||
| 	*codec = (struct mgcp_rtp_codec){ | 	*codec = (struct mgcp_rtp_codec){ | ||||||
| 		.payload_type = -1, | 		.payload_type = -1, | ||||||
| @@ -94,20 +88,20 @@ static void codec_init(struct mgcp_rtp_codec *codec) | |||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void codec_free(struct mgcp_rtp_codec *codec) | static void mgcp_codec_free(struct mgcp_rtp_codec *codec) | ||||||
| { | { | ||||||
| 	*codec = (struct mgcp_rtp_codec){}; | 	*codec = (struct mgcp_rtp_codec){}; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! Initalize or reset codec information with default data. | /*! Initalize or reset codec information with default data. | ||||||
|  *  \param[out] conn related rtp-connection. */ |  *  \param[out] conn related rtp-connection. */ | ||||||
| void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn) | void mgcp_codecset_reset(struct mgcp_rtp_codecset *cset) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	for (i = 0; i < conn->end.codecs_assigned; i++) | 	for (i = 0; i < cset->codecs_assigned; i++) | ||||||
| 		codec_free(&conn->end.codecs[i]); | 		mgcp_codec_free(&cset->codecs[i]); | ||||||
| 	conn->end.codecs_assigned = 0; | 	cset->codecs_assigned = 0; | ||||||
| 	conn->end.codec = NULL; | 	cset->codec = NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! Add codec configuration depending on payload type and/or codec name. This | /*! Add codec configuration depending on payload type and/or codec name. This | ||||||
| @@ -118,23 +112,23 @@ void mgcp_codec_reset_all(struct mgcp_conn_rtp *conn) | |||||||
|  *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1"). |  *  \param[in] audio_name audio codec name, in uppercase (e.g. "GSM/8000/1"). | ||||||
|  *  \param[in] param optional codec parameters (set to NULL when unused). |  *  \param[in] param optional codec parameters (set to NULL when unused). | ||||||
|  *  \returns 0 on success, -EINVAL on failure. */ |  *  \returns 0 on success, -EINVAL on failure. */ | ||||||
| int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *audio_name, const struct mgcp_codec_param *param) | int mgcp_codecset_add_codec(struct mgcp_rtp_codecset *cset, int payload_type, const char *audio_name, const struct mgcp_codec_param *param) | ||||||
| { | { | ||||||
| 	int rate; | 	int rate; | ||||||
| 	int channels; | 	int channels; | ||||||
| 	struct mgcp_rtp_codec *codec; | 	struct mgcp_rtp_codec *codec; | ||||||
| 	unsigned int pt_offset = conn->end.codecs_assigned; | 	unsigned int pt_offset = cset->codecs_assigned; | ||||||
|  |  | ||||||
| 	/* The amount of codecs we can store is limited, make sure we do not | 	/* The amount of codecs we can store is limited, make sure we do not | ||||||
| 	 * overrun this limit. */ | 	 * overrun this limit. */ | ||||||
| 	if (conn->end.codecs_assigned >= MGCP_MAX_CODECS) | 	if (cset->codecs_assigned >= MGCP_MAX_CODECS) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  |  | ||||||
| 	/* First unused entry */ | 	/* First unused entry */ | ||||||
| 	codec = &conn->end.codecs[conn->end.codecs_assigned]; | 	codec = &cset->codecs[cset->codecs_assigned]; | ||||||
|  |  | ||||||
| 	/* Initalize the codec struct with some default data to begin with */ | 	/* Initalize the codec struct with some default data to begin with */ | ||||||
| 	codec_init(codec); | 	mgcp_codec_init(codec); | ||||||
|  |  | ||||||
| 	if (payload_type != PTYPE_UNDEFINED) { | 	if (payload_type != PTYPE_UNDEFINED) { | ||||||
| 		/* Make sure we do not get any reserved or undefined type numbers */ | 		/* Make sure we do not get any reserved or undefined type numbers */ | ||||||
| @@ -268,11 +262,11 @@ int mgcp_codec_add(struct mgcp_conn_rtp *conn, int payload_type, const char *aud | |||||||
| 	} else | 	} else | ||||||
| 		codec->param_present = false; | 		codec->param_present = false; | ||||||
|  |  | ||||||
| 	conn->end.codecs_assigned++; | 	cset->codecs_assigned++; | ||||||
| 	return 0; | 	return 0; | ||||||
| error: | error: | ||||||
| 	/* Make sure we leave a clean codec entry on error. */ | 	/* Make sure we leave a clean codec entry on error. */ | ||||||
| 	codec_free(codec); | 	mgcp_codec_free(codec); | ||||||
| 	return -EINVAL; | 	return -EINVAL; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -296,7 +290,7 @@ bool mgcp_codec_amr_is_octet_aligned(const struct mgcp_rtp_codec *codec) | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Compare two codecs, all parameters must match up */ | /* Compare two codecs, all parameters must match up */ | ||||||
| static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b) | static bool codecs_same(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b) | ||||||
| { | { | ||||||
| 	/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers | 	/* All codec properties must match up, except the payload type number. Even though standardisd payload numbers | ||||||
| 	 * exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal | 	 * exist for certain situations, the call agent may still assign them freely. Hence we must not insist on equal | ||||||
| @@ -325,7 +319,7 @@ static bool codecs_same(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *c | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */ | /* Compare two codecs, all parameters must match up, except parameters related to payload formatting (not checked). */ | ||||||
| static bool codecs_convertible(struct mgcp_rtp_codec *codec_a, struct mgcp_rtp_codec *codec_b) | static bool codecs_convertible(const struct mgcp_rtp_codec *codec_a, const struct mgcp_rtp_codec *codec_b) | ||||||
| { | { | ||||||
| 	/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to | 	/* OsmoMGW currently has no ability to transcode from one codec to another. However OsmoMGW is still able to | ||||||
| 	 * translate between different payload formats as long as the encoded voice data itself does not change. | 	 * translate between different payload formats as long as the encoded voice data itself does not change. | ||||||
| @@ -354,21 +348,18 @@ iufp: | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec) | struct mgcp_rtp_codec *mgcp_codecset_find_same(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec) | ||||||
| { | { | ||||||
| 	struct mgcp_rtp_end *rtp_end; |  | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	unsigned int codecs_assigned; | 	unsigned int codecs_assigned; | ||||||
|  |  | ||||||
| 	rtp_end = &conn->end; |  | ||||||
|  |  | ||||||
| 	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In | 	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In | ||||||
| 	 * the first run we will look for an exact match. */ | 	 * the first run we will look for an exact match. */ | ||||||
| 	codecs_assigned = rtp_end->codecs_assigned; | 	codecs_assigned = cset->codecs_assigned; | ||||||
| 	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS); | 	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS); | ||||||
| 	for (i = 0; i < codecs_assigned; i++) { | 	for (i = 0; i < codecs_assigned; i++) { | ||||||
| 		if (codecs_same(codec, &rtp_end->codecs[i])) { | 		if (codecs_same(codec, &cset->codecs[i])) { | ||||||
| 			return &rtp_end->codecs[i]; | 			return &cset->codecs[i]; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -377,28 +368,26 @@ struct mgcp_rtp_codec *mgcp_codec_find_same(struct mgcp_conn_rtp *conn, struct m | |||||||
| } | } | ||||||
|  |  | ||||||
| /* For a given codec, find a convertible codec in the given connection. */ | /* For a given codec, find a convertible codec in the given connection. */ | ||||||
| static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, struct mgcp_rtp_codec *codec) | static struct mgcp_rtp_codec *codecset_find_convertible(struct mgcp_rtp_codecset *cset, const struct mgcp_rtp_codec *codec) | ||||||
| { | { | ||||||
| 	struct mgcp_rtp_end *rtp_end; |  | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	unsigned int codecs_assigned; | 	unsigned int codecs_assigned; | ||||||
| 	struct mgcp_rtp_codec *codec_convertible = NULL; | 	struct mgcp_rtp_codec *codec_convertible = NULL; | ||||||
|  |  | ||||||
| 	rtp_end = &conn->end; |  | ||||||
|  |  | ||||||
| 	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In | 	/* Use the codec information from the source and try to find the equivalent of it on the destination side. In | ||||||
| 	 * the first run we will look for an exact match. */ | 	 * the first run we will look for an exact match. */ | ||||||
| 	codec_convertible = mgcp_codec_find_same(conn, codec); | 	codec_convertible = mgcp_codecset_find_same(cset, codec); | ||||||
| 	if (codec_convertible) | 	if (codec_convertible) | ||||||
| 		return codec_convertible; | 		return codec_convertible; | ||||||
|  |  | ||||||
| 	/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the | 	/* In case we weren't able to find an exact match, we will try to find a match that is the same codec, but the | ||||||
| 	 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */ | 	 * payload format may be different. This alternative will require a frame format conversion (i.e. AMR bwe->oe) */ | ||||||
| 	codecs_assigned = rtp_end->codecs_assigned; | 	codecs_assigned = cset->codecs_assigned; | ||||||
| 	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS); | 	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS); | ||||||
| 	for (i = 0; i < codecs_assigned; i++) { | 	for (i = 0; i < codecs_assigned; i++) { | ||||||
| 		if (codecs_convertible(codec, &rtp_end->codecs[i])) { | 		if (codecs_convertible(codec, &cset->codecs[i])) { | ||||||
| 			codec_convertible = &rtp_end->codecs[i]; | 			codec_convertible = &cset->codecs[i]; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -408,20 +397,20 @@ static struct mgcp_rtp_codec *codec_find_convertible(struct mgcp_conn_rtp *conn, | |||||||
|  |  | ||||||
| /*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available, | /*! Decide for one suitable codec on both of the given connections. In case a destination connection is not available, | ||||||
|  *  a tentative decision is made. |  *  a tentative decision is made. | ||||||
|  *  \param[inout] conn_src related rtp-connection. |  *  \param[in] cset_src related codec set. | ||||||
|  *  \param[inout] conn_dst related destination rtp-connection (NULL if not present). |  *  \param[inout] cset_dst related destination codec set (NULL if not present). | ||||||
|  *  \returns 0 on success, -EINVAL on failure. */ |  *  \returns 0 on success, -EINVAL on failure. */ | ||||||
| int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn_dst) | int mgcp_codecset_decide(struct mgcp_rtp_codecset *cset_src, struct mgcp_rtp_codecset *cset_dst) | ||||||
| { | { | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
|  |  | ||||||
| 	/* In case no destination connection is available (yet), or in case the destination connection exists but has | 	/* In case no destination connection is available (yet), or in case the destination connection exists but has | ||||||
| 	 * no codecs assigned, we are forced to make a simple tentative decision: | 	 * no codecs assigned, we are forced to make a simple tentative decision: | ||||||
| 	 * We just use the first codec of the source connection (conn_src) */ | 	 * We just use the first codec of the source connection (conn_src) */ | ||||||
| 	OSMO_ASSERT(conn_src->end.codecs_assigned <= MGCP_MAX_CODECS); | 	OSMO_ASSERT(cset_src->codecs_assigned <= MGCP_MAX_CODECS); | ||||||
| 	if (!conn_dst || conn_dst->end.codecs_assigned == 0) { | 	if (!cset_dst || cset_dst->codecs_assigned == 0) { | ||||||
| 		if (conn_src->end.codecs_assigned >= 1) { | 		if (cset_src->codecs_assigned >= 1) { | ||||||
| 			conn_src->end.codec = &conn_src->end.codecs[0]; | 			cset_src->codec = &cset_src->codecs[0]; | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} else | 		} else | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| @@ -430,38 +419,38 @@ int mgcp_codec_decide(struct mgcp_conn_rtp *conn_src, struct mgcp_conn_rtp *conn | |||||||
| 	/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case | 	/* Compare all codecs of the source connection (conn_src) to the codecs of the destination connection (conn_dst). In case | ||||||
| 	 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be | 	 * of a match set this codec on both connections. This would be an ideal selection since no codec conversion would be | ||||||
| 	 * required. */ | 	 * required. */ | ||||||
| 	for (i = 0; i < conn_src->end.codecs_assigned; i++) { | 	for (i = 0; i < cset_src->codecs_assigned; i++) { | ||||||
| 		struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i]; | 		struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i]; | ||||||
| 		struct mgcp_rtp_codec *codec_conn_dst = mgcp_codec_find_same(conn_dst, codec_conn_src); | 		struct mgcp_rtp_codec *codec_cset_dst = mgcp_codecset_find_same(cset_dst, codec_cset_src); | ||||||
| 		if (codec_conn_dst) { | 		if (codec_cset_dst) { | ||||||
| 			/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both | 			/* We found the a codec that is exactly the same (same codec, same payload format etc.) on both | ||||||
| 			 * sides. We now set this codec on both connections. */ | 			 * sides. We now set this codec on both connections. */ | ||||||
| 			conn_dst->end.codec = codec_conn_dst; | 			cset_dst->codec = codec_cset_dst; | ||||||
| 			conn_src->end.codec = codec_conn_src; | 			cset_src->codec = codec_cset_src; | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able | 	/* In case we could not find a codec that is exactly the same, let's at least try to find a codec that we are able | ||||||
| 	 * to convert. */ | 	 * to convert. */ | ||||||
| 	for (i = 0; i < conn_src->end.codecs_assigned; i++) { | 	for (i = 0; i < cset_src->codecs_assigned; i++) { | ||||||
| 		struct mgcp_rtp_codec *codec_conn_src = &conn_src->end.codecs[i]; | 		struct mgcp_rtp_codec *codec_cset_src = &cset_src->codecs[i]; | ||||||
| 		struct mgcp_rtp_codec *codec_conn_dst = codec_find_convertible(conn_dst, codec_conn_src); | 		struct mgcp_rtp_codec *codec_cset_dst = codecset_find_convertible(cset_dst, codec_cset_src); | ||||||
| 		if (codec_conn_dst) { | 		if (codec_cset_dst) { | ||||||
| 			/* We found the a codec that we can convert to. Set each side to its codec. */ | 			/* We found the a codec that we can convert to. Set each side to its codec. */ | ||||||
| 			conn_dst->end.codec = codec_conn_dst; | 			cset_dst->codec = codec_cset_dst; | ||||||
| 			conn_src->end.codec = codec_conn_src; | 			cset_src->codec = codec_cset_src; | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (conn_dst->end.codecs_assigned) | 	if (cset_dst->codecs_assigned) | ||||||
| 		conn_dst->end.codec = &conn_dst->end.codecs[0]; | 		cset_dst->codec = &cset_dst->codecs[0]; | ||||||
| 	else | 	else | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  |  | ||||||
| 	if (conn_src->end.codecs_assigned) | 	if (cset_src->codecs_assigned) | ||||||
| 		conn_src->end.codec = &conn_src->end.codecs[0]; | 		cset_src->codec = &cset_src->codecs[0]; | ||||||
| 	else | 	else | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  |  | ||||||
| @@ -488,38 +477,36 @@ bool mgcp_codec_amr_align_mode_is_indicated(const struct mgcp_rtp_codec *codec) | |||||||
|  * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times |  * \param match_nr  Index for the match found, first being match_nr == 0. Iterate all matches by calling multiple times | ||||||
|  *                  with incrementing match_nr. |  *                  with incrementing match_nr. | ||||||
|  * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */ |  * \return codec definition for that conn matching the subtype_name, or NULL if no such match_nr is found. */ | ||||||
| const struct mgcp_rtp_codec *mgcp_codec_pt_find_by_subtype_name(struct mgcp_conn_rtp *conn, | const struct mgcp_rtp_codec *mgcp_codecset_pt_find_by_subtype_name(const struct mgcp_rtp_codecset *cset, | ||||||
| 								const char *subtype_name, unsigned int match_nr) | 								const char *subtype_name, unsigned int match_nr) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
| 	for (i = 0; i < conn->end.codecs_assigned; i++) { | 	for (i = 0; i < cset->codecs_assigned; i++) { | ||||||
| 		if (!strcmp(conn->end.codecs[i].subtype_name, subtype_name)) { | 		if (!strcmp(cset->codecs[i].subtype_name, subtype_name)) { | ||||||
| 			if (match_nr) { | 			if (match_nr) { | ||||||
| 				match_nr--; | 				match_nr--; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			return &conn->end.codecs[i]; | 			return &cset->codecs[i]; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! Lookup a codec that is assigned to a connection by its payload type number. | /*! Lookup a codec that is assigned to a connection by its payload type number. | ||||||
|  *  \param[in] conn related rtp-connection. |  *  \param[in] cset related codec set. | ||||||
|  *  \param[in] payload_type number of the codec to look up. |  *  \param[in] payload_type number of the codec to look up. | ||||||
|  *  \returns pointer to codec struct on success, NULL on failure. */ |  *  \returns pointer to codec struct on success, NULL on failure. */ | ||||||
| struct mgcp_rtp_codec *mgcp_codec_from_pt(struct mgcp_conn_rtp *conn, int payload_type) | struct mgcp_rtp_codec *mgcp_codecset_find_codec_from_pt(struct mgcp_rtp_codecset *cset, int payload_type) | ||||||
| { | { | ||||||
| 	struct mgcp_rtp_end *rtp_end = &conn->end; |  | ||||||
| 	unsigned int codecs_assigned = rtp_end->codecs_assigned; |  | ||||||
| 	struct mgcp_rtp_codec *codec = NULL; | 	struct mgcp_rtp_codec *codec = NULL; | ||||||
| 	size_t i; | 	size_t i; | ||||||
|  |  | ||||||
| 	OSMO_ASSERT(codecs_assigned <= MGCP_MAX_CODECS); | 	OSMO_ASSERT(cset->codecs_assigned <= MGCP_MAX_CODECS); | ||||||
|  |  | ||||||
| 	for (i = 0; i < codecs_assigned; i++) { | 	for (i = 0; i < cset->codecs_assigned; i++) { | ||||||
| 		if (payload_type == rtp_end->codecs[i].payload_type) { | 		if (payload_type == cset->codecs[i].payload_type) { | ||||||
| 			codec = &rtp_end->codecs[i]; | 			codec = &cset->codecs[i]; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -74,7 +74,7 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id) | |||||||
|  |  | ||||||
| 		/* ensure that the generated conn_id is unique | 		/* ensure that the generated conn_id is unique | ||||||
| 		 * for this endpoint */ | 		 * for this endpoint */ | ||||||
| 		if (!mgcp_conn_get_rtp(endp, id_hex)) { | 		if (!mgcp_endp_get_conn_rtp(endp, id_hex)) { | ||||||
| 			osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN); | 			osmo_strlcpy(id, id_hex, MGCP_CONN_ID_MAXLEN); | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		} | ||||||
| @@ -88,7 +88,6 @@ static int mgcp_alloc_id(struct mgcp_endpoint *endp, char *id) | |||||||
| /* Initialize rtp connection struct with default values */ | /* Initialize rtp connection struct with default values */ | ||||||
| static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn) | static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn *conn) | ||||||
| { | { | ||||||
| 	struct mgcp_rtp_end *end = &conn_rtp->end; |  | ||||||
| 	/* FIXME: Each new rate counter group requires an unique index. At the | 	/* FIXME: Each new rate counter group requires an unique index. At the | ||||||
| 	 * moment we generate this index using this counter, but perhaps there | 	 * moment we generate this index using this counter, but perhaps there | ||||||
| 	 * is a more concious way to assign the indexes. */ | 	 * is a more concious way to assign the indexes. */ | ||||||
| @@ -106,17 +105,6 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn * | |||||||
| 	/* backpointer to the generic part of the connection */ | 	/* backpointer to the generic part of the connection */ | ||||||
| 	conn->u.rtp.conn = conn; | 	conn->u.rtp.conn = conn; | ||||||
|  |  | ||||||
| 	end->rtp = NULL; |  | ||||||
| 	end->rtcp = NULL; |  | ||||||
| 	memset(&end->addr, 0, sizeof(end->addr)); |  | ||||||
| 	end->rtcp_port = 0; |  | ||||||
|  |  | ||||||
| 	/* Set default values */ |  | ||||||
| 	end->frames_per_packet = 0;	/* unknown */ |  | ||||||
| 	end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; |  | ||||||
| 	end->output_enabled = false; |  | ||||||
| 	end->maximum_packet_time = -1; |  | ||||||
|  |  | ||||||
| 	conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++); | 	conn_rtp->ctrg = rate_ctr_group_alloc(conn, &rate_ctr_group_desc, rate_ctr_index++); | ||||||
| 	if (!conn_rtp->ctrg) | 	if (!conn_rtp->ctrg) | ||||||
| 		return -1; | 		return -1; | ||||||
| @@ -124,9 +112,7 @@ static int mgcp_rtp_conn_init(struct mgcp_conn_rtp *conn_rtp, struct mgcp_conn * | |||||||
| 	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR); | 	conn_rtp->state.in_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, IN_STREAM_ERR_TSTMP_CTR); | ||||||
| 	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR); | 	conn_rtp->state.out_stream.err_ts_ctr = rate_ctr_group_get_ctr(conn_rtp->ctrg, OUT_STREAM_ERR_TSTMP_CTR); | ||||||
|  |  | ||||||
| 	/* Make sure codec table is reset */ | 	mgcp_rtp_end_init(&conn_rtp->end, conn_rtp); | ||||||
| 	mgcp_codec_reset_all(conn_rtp); |  | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -137,16 +123,15 @@ static void mgcp_rtp_conn_cleanup(struct mgcp_conn_rtp *conn_rtp) | |||||||
| 		conn_osmux_disable(conn_rtp); | 		conn_osmux_disable(conn_rtp); | ||||||
| 	if (mgcp_conn_rtp_is_iuup(conn_rtp)) | 	if (mgcp_conn_rtp_is_iuup(conn_rtp)) | ||||||
| 		mgcp_conn_iuup_cleanup(conn_rtp); | 		mgcp_conn_iuup_cleanup(conn_rtp); | ||||||
| 	mgcp_free_rtp_port(&conn_rtp->end); | 	mgcp_rtp_end_cleanup(&conn_rtp->end); | ||||||
| 	rate_ctr_group_free(conn_rtp->ctrg); | 	rate_ctr_group_free(conn_rtp->ctrg); | ||||||
| 	mgcp_codec_reset_all(conn_rtp); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void mgcp_conn_watchdog_cb(void *data) | void mgcp_conn_watchdog_cb(void *data) | ||||||
| { | { | ||||||
| 	struct mgcp_conn *conn = data; | 	struct mgcp_conn *conn = data; | ||||||
| 	LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n"); | 	LOGPCONN(conn, DLMGCP, LOGL_ERROR, "connection timed out!\n"); | ||||||
| 	mgcp_conn_free(conn->endp, conn->id); | 	mgcp_conn_free(conn); | ||||||
| } | } | ||||||
|  |  | ||||||
| void mgcp_conn_watchdog_kick(struct mgcp_conn *conn) | void mgcp_conn_watchdog_kick(struct mgcp_conn *conn) | ||||||
| @@ -212,58 +197,6 @@ struct mgcp_conn *mgcp_conn_alloc(void *ctx, struct mgcp_endpoint *endp, | |||||||
| 	return conn; | 	return conn; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! find a connection by its ID. |  | ||||||
|  *  \param[in] endp associated endpoint |  | ||||||
|  *  \param[in] id identification number of the connection |  | ||||||
|  *  \returns pointer to allocated connection, NULL if not found */ |  | ||||||
| struct mgcp_conn *mgcp_conn_get(struct mgcp_endpoint *endp, const char *id) |  | ||||||
| { |  | ||||||
| 	struct mgcp_conn *conn; |  | ||||||
| 	const char *id_upper; |  | ||||||
| 	const char *conn_id; |  | ||||||
|  |  | ||||||
| 	if (!id || !*id) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	/* Ignore leading zeros in needle */ |  | ||||||
| 	while (*id == '0') |  | ||||||
| 		id++; |  | ||||||
|  |  | ||||||
| 	/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of |  | ||||||
| 	 * Connections" defines the id as a hex string, so clients may return lower case hex even though |  | ||||||
| 	 * we sent upper case hex in the CRCX response. */ |  | ||||||
| 	id_upper = osmo_str_toupper(id); |  | ||||||
|  |  | ||||||
| 	llist_for_each_entry(conn, &endp->conns, entry) { |  | ||||||
| 		/* Ignore leading zeros in haystack */ |  | ||||||
| 		for (conn_id=conn->id; *conn_id == '0'; conn_id++); |  | ||||||
|  |  | ||||||
| 		if (strcmp(conn_id, id_upper) == 0) |  | ||||||
| 			return conn; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*! find an RTP connection by its ID. |  | ||||||
|  *  \param[in] endp associated endpoint |  | ||||||
|  *  \param[in] id identification number of the connection |  | ||||||
|  *  \returns pointer to allocated connection, NULL if not found */ |  | ||||||
| struct mgcp_conn_rtp *mgcp_conn_get_rtp(struct mgcp_endpoint *endp, |  | ||||||
| 					const char *id) |  | ||||||
| { |  | ||||||
| 	struct mgcp_conn *conn; |  | ||||||
|  |  | ||||||
| 	conn = mgcp_conn_get(endp, id); |  | ||||||
| 	if (!conn) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	if (conn->type == MGCP_CONN_TYPE_RTP) |  | ||||||
| 		return &conn->u.rtp; |  | ||||||
|  |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp) | static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn_rtp) | ||||||
| { | { | ||||||
| 	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats; | 	struct rate_ctr_group *all_stats = endp->trunk->ratectr.all_rtp_conn_stats; | ||||||
| @@ -286,21 +219,21 @@ static void aggregate_rtp_conn_stats(struct mgcp_endpoint *endp, struct mgcp_con | |||||||
| 	rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS)); | 	rate_ctr_inc(rate_ctr_group_get_ctr(all_stats, RTP_NUM_CONNECTIONS)); | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! free a connection by its ID. | /*! free a connection | ||||||
|  *  \param[in] endp associated endpoint |  *  \param[in] conn the conn to free. May be NULL. | ||||||
|  *  \param[in] id identification number of the connection */ | */ | ||||||
| void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id) | void mgcp_conn_free(struct mgcp_conn *conn) | ||||||
| { | { | ||||||
| 	struct mgcp_conn *conn; | 	struct mgcp_conn_rtp *conn_rtp; | ||||||
|  |  | ||||||
| 	conn = mgcp_conn_get(endp, id); |  | ||||||
| 	if (!conn) | 	if (!conn) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	switch (conn->type) { | 	switch (conn->type) { | ||||||
| 	case MGCP_CONN_TYPE_RTP: | 	case MGCP_CONN_TYPE_RTP: | ||||||
| 		aggregate_rtp_conn_stats(endp, &conn->u.rtp); | 		conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
| 		mgcp_rtp_conn_cleanup(&conn->u.rtp); | 		aggregate_rtp_conn_stats(conn->endp, conn_rtp); | ||||||
|  | 		mgcp_rtp_conn_cleanup(conn_rtp); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		/* NOTE: This should never be called with an | 		/* NOTE: This should never be called with an | ||||||
| @@ -310,43 +243,40 @@ void mgcp_conn_free(struct mgcp_endpoint *endp, const char *id) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	osmo_timer_del(&conn->watchdog); | 	osmo_timer_del(&conn->watchdog); | ||||||
| 	mgcp_endp_remove_conn(endp, conn); | 	mgcp_endp_remove_conn(conn->endp, conn); | ||||||
| 	/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */ | 	/* WARN: endp may have be freed after call to mgcp_endp_remove_conn */ | ||||||
| 	talloc_free(conn); | 	talloc_free(conn); | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! free oldest connection in the list. | /*! Parse connection mode. | ||||||
|  *  \param[in] endp associated endpoint */ |  *  \param[in] conn Connection whose mode is being set | ||||||
| void mgcp_conn_free_oldest(struct mgcp_endpoint *endp) |  *  \param[in] mode Mode to set | ||||||
|  |  *  \returns 0 on success, -1 on error */ | ||||||
|  | int mgcp_conn_set_mode(struct mgcp_conn *conn, enum mgcp_connection_mode mode) | ||||||
| { | { | ||||||
| 	struct mgcp_conn *conn; | 	OSMO_ASSERT(conn); | ||||||
|  | 	if (mode == MGCP_CONN_NONE) { | ||||||
|  | 		LOGPCONN(conn, DLMGCP, LOGL_ERROR, | ||||||
|  | 			 "missing connection mode\n"); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 	conn->mode = mode; | ||||||
|  | 	LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n", | ||||||
|  | 		 mgcp_cmode_name(mode), conn->mode); | ||||||
|  |  | ||||||
| 	if (llist_empty(&endp->conns)) | 	/* Special handling for RTP connections */ | ||||||
| 		return; | 	if (conn->type == MGCP_CONN_TYPE_RTP) { | ||||||
|  | 		struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
|  | 		conn_rtp->end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY); | ||||||
|  | 		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n", | ||||||
|  | 			 conn_rtp->end.output_enabled); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry); | 	/* The VTY might change the connection mode at any time, so we have | ||||||
| 	if (!conn) | 	 * to hold a copy of the original connection mode */ | ||||||
| 		return; | 	conn->mode_orig = conn->mode; | ||||||
|  |  | ||||||
| 	mgcp_conn_free(endp, conn->id); | 	return 0; | ||||||
| } |  | ||||||
|  |  | ||||||
| /*! free all connections at once. |  | ||||||
|  *  \param[in] endp associated endpoint */ |  | ||||||
| #if defined(__has_attribute) |  | ||||||
| #if __has_attribute(no_sanitize) |  | ||||||
| __attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */ |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
| void mgcp_conn_free_all(struct mgcp_endpoint *endp) |  | ||||||
| { |  | ||||||
| 	struct mgcp_conn *conn; |  | ||||||
|  |  | ||||||
| 	/* Drop all items in the list, might be consecutive! */ |  | ||||||
| 	while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry))) |  | ||||||
| 		mgcp_conn_free(endp, conn->id); |  | ||||||
|  |  | ||||||
| 	return; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! dump basic connection information to human readable string. | /*! dump basic connection information to human readable string. | ||||||
| @@ -357,24 +287,26 @@ char *mgcp_conn_dump(struct mgcp_conn *conn) | |||||||
| 	static char str[sizeof(conn->name)+sizeof(conn->id)+256]; | 	static char str[sizeof(conn->name)+sizeof(conn->id)+256]; | ||||||
| 	char ipbuf[INET6_ADDRSTRLEN]; | 	char ipbuf[INET6_ADDRSTRLEN]; | ||||||
| 	struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) }; | 	struct osmo_strbuf sb = { .buf = str, .len = sizeof(str) }; | ||||||
|  | 	struct mgcp_conn_rtp *conn_rtp; | ||||||
|  |  | ||||||
| 	if (!conn) | 	if (!conn) | ||||||
| 		return "NULL"; | 		return "NULL"; | ||||||
|  |  | ||||||
| 	switch (conn->type) { | 	switch (conn->type) { | ||||||
| 	case MGCP_CONN_TYPE_RTP: | 	case MGCP_CONN_TYPE_RTP: | ||||||
|  | 		conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
| 		OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u", | 		OSMO_STRBUF_PRINTF(sb, "(%s/%s C:%s r=%s:%u<->l=%s:%u", | ||||||
| 				   conn->name, | 				   conn->name, | ||||||
| 				   mgcp_conn_rtp_type_name(conn->type), | 				   mgcp_conn_rtp_type_name(conn->type), | ||||||
| 				   conn->id, | 				   conn->id, | ||||||
| 				   osmo_sockaddr_ntop(&conn->u.rtp.end.addr.u.sa, ipbuf) ? : "NULL", | 				   osmo_sockaddr_ntop(&conn_rtp->end.addr.u.sa, ipbuf) ? : "NULL", | ||||||
| 				   osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa), | 				   osmo_sockaddr_port(&conn_rtp->end.addr.u.sa), | ||||||
| 				   conn->u.rtp.end.local_addr ? : "NULL", | 				   conn_rtp->end.local_addr ? : "NULL", | ||||||
| 				   conn->u.rtp.end.local_port); | 				   conn_rtp->end.local_port); | ||||||
|  |  | ||||||
| 		switch (conn->u.rtp.type) { | 		switch (conn_rtp->type) { | ||||||
| 		case MGCP_RTP_OSMUX: | 		case MGCP_RTP_OSMUX: | ||||||
| 			OSMO_STRBUF_PRINTF(sb, " CID=%u", conn->u.rtp.osmux.local_cid); | 			OSMO_STRBUF_PRINTF(sb, " CID=%u", conn_rtp->osmux.local_cid); | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			break; | 			break; | ||||||
| @@ -414,16 +346,6 @@ struct mgcp_conn *mgcp_find_dst_conn(struct mgcp_conn *conn) | |||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! get oldest connection in the list. |  | ||||||
|  *  \param[in] endp associated endpoint */ |  | ||||||
| struct mgcp_conn *mgcp_conn_get_oldest(struct mgcp_endpoint *endp) |  | ||||||
| { |  | ||||||
| 	if (llist_empty(&endp->conns)) |  | ||||||
| 		return NULL; |  | ||||||
|  |  | ||||||
| 	return llist_last_entry(&endp->conns, struct mgcp_conn, entry); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const struct value_string mgcp_conn_rtp_type_names[] = { | const struct value_string mgcp_conn_rtp_type_names[] = { | ||||||
| 	{ MGCP_RTP_DEFAULT, "rtp" }, | 	{ MGCP_RTP_DEFAULT, "rtp" }, | ||||||
| 	{ MGCP_RTP_OSMUX, "osmux" }, | 	{ MGCP_RTP_OSMUX, "osmux" }, | ||||||
|   | |||||||
| @@ -56,133 +56,147 @@ static const struct e1inp_line_ops dummy_e1_line_ops = { | |||||||
| 	.sign_link = NULL, | 	.sign_link = NULL, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* EFR idle frame */ | /* The following EFR TRAU-DL frame is a dummy to be transmitted in the absence | ||||||
| static const ubit_t idle_tf_efr[] = { 0, 0, 0, 0, 0, 0, 0, 0, |  * of RTP-derived TRAU-DL frames.  The payload bit content here is the decoder | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, |  * homing frame (DHF) of TS 46.060 section 8.2 Table 7 - the best we can do | ||||||
| 				      1, 1, 1, 0, 1, 0, 0, 0, |  * in the absence of a proper TFO transform for EFR - while the full TRAU-DL | ||||||
| 				      0, 0, 0, 0, 1, 0, 0, 0, |  * frame was generated by passing said EFR DHF through osmo_rtp2trau(). | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, |  */ | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | static const ubit_t idle_tf_efr[] = { | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 1, 0, 1, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 1, 1, 1, 1, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 0, 0, 1, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 1, 0, 1, 1, 1, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 1, 0, 1, 1, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 0, 0, 1, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 1, 1, 1, 1, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 0, 1, 0, 1, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 0, 1, 1, 0, 1, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 1, 1, 0, 0, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 1, 1, 1, 1, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 1, 1, 1, 0, 1, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 1, 1, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 1, 1, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 1, 1, 1, 1, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 1, 1, 0, 1, 1, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 1, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 1, 0, 1, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 0, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 0, 0, 1, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 1, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 0, 1, 0, 1, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 0, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				      0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 1, 1, 1, 0, | ||||||
| 				      1, 0, 0, 0, 0, 0, 1, 0, | 	1, 1, 1, 0, 1, 0, 1, 1, | ||||||
| 				      1, 1, 1, 1, 1, 1, 1, 1, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
|  | 	1, 0, 0, 0, 1, 1, 1, 1, | ||||||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* FR idle frame */ | /* The following FRv1 TRAU-DL frame is a dummy to be transmitted in the absence | ||||||
| static const ubit_t idle_tf_fr[] = { 0, 0, 0, 0, 0, 0, 0, 0, |  * of RTP-derived TRAU-DL frames.  The payload bit content here is the silence | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, |  * frame of TS 46.011 Table 1 - the best we can do without integrating the | ||||||
| 				     1, 1, 1, 1, 0, 0, 0, 0, |  * TFO transform for FRv1 from Themyscira libgsmfr2 - while the full TRAU-DL | ||||||
| 				     0, 0, 0, 0, 1, 0, 0, 0, |  * frame was generated by passing said FRv1 silence frame through | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, |  * osmo_rtp2trau(). | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, |  */ | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | static const ubit_t idle_tf_fr[] = { | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 1, 1, 0, 0, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 1, 1, 1, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 0, 1, 0, 1, 1, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 1, 1, 0, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 0, 1, 0, 1, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 0, 0, 1, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 1, 0, 0, 1, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 1, 0, 1, 0, 0, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 0, 0, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	0, 1, 1, 0, 0, 0, 1, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 0, 1, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 1, 0, 1, 1, 0, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 1, 1, 0, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 1, 1, 0, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 0, 0, 1, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 1, 0, 0, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 1, 1, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 1, 1, 1, 0, 0, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 0, 1, 1, 1, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 1, 1, 0, 1, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 1, 0, 0, 1, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 0, 1, 1, 0, 0, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 0, 1, 0, 0, 0, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 1, 0, 0, 0, 1, 1, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 0, 1, 0, 0, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 1, 1, 0, 1, 1, 0, 1, | ||||||
| 				     1, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 1, 1, 0, 0, 0, 1, | ||||||
| 				     0, 0, 0, 0, 0, 0, 0, 0, | 	1, 0, 0, 1, 1, 1, 0, 1, | ||||||
| 				     1, 0, 0, 0, 0, 0, 1, 0, | 	1, 0, 0, 0, 0, 1, 0, 1, | ||||||
| 				     1, 1, 1, 1, 1, 1, 1, 1, | 	1, 0, 0, 0, 1, 0, 0, 0, | ||||||
|  | 	0, 0, 0, 0, 1, 1, 0, 0, | ||||||
|  | 	1, 0, 1, 1, 1, 0, 0, 0, | ||||||
|  | 	1, 0, 0, 1, 1, 1, 0, 1, | ||||||
|  | 	1, 1, 0, 1, 1, 0, 1, 1, | ||||||
|  | 	0, 0, 0, 1, 0, 0, 1, 1, | ||||||
|  | 	1, 1, 0, 1, 1, 0, 1, 1, | ||||||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Idle speech frame, see also GSM 08.60, chapter 3.4 */ | /* Idle speech frame, see also GSM 08.60, chapter 3.4 */ | ||||||
| static const ubit_t idle_tf_spch[] = { 0, 0, 0, 0, 0, 0, 0, 0, | static const ubit_t idle_tf_spch[] = { | ||||||
| 				       0, 0, 0, 0, 0, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				       1, 0, 1, 1, 1, 0, 0, 0, | 	0, 0, 0, 0, 0, 0, 0, 0, | ||||||
| 				       0, 0, 0, 0, 1, 0, 0, 0, | 	1, 0, 1, 1, 1, 0, 0, 0, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	0, 0, 0, 0, 1, 0, 0, 0, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 0, | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| 				       1, 1, 1, 1, 1, 1, 1, 1, | 	1, 1, 1, 1, 1, 1, 1, 0, | ||||||
|  | 	1, 1, 1, 1, 1, 1, 1, 1, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may | /* If the RTP transmission has dropouts for some reason the I.460 TX-Queue may | ||||||
| @@ -650,15 +664,17 @@ int mgcp_e1_endp_equip(struct mgcp_endpoint *endp, uint8_t ts, uint8_t ss, uint8 | |||||||
| void mgcp_e1_endp_update(struct mgcp_endpoint *endp) | void mgcp_e1_endp_update(struct mgcp_endpoint *endp) | ||||||
| { | { | ||||||
| 	struct mgcp_conn *conn; | 	struct mgcp_conn *conn; | ||||||
|  | 	struct mgcp_conn_rtp *conn_rtp; | ||||||
| 	struct mgcp_rtp_codec *codec; | 	struct mgcp_rtp_codec *codec; | ||||||
| 	enum osmo_tray_sync_pat_id sync_pat_id; | 	enum osmo_tray_sync_pat_id sync_pat_id; | ||||||
|  |  | ||||||
| 	/* In order to determine the codec, find the oldest connection on | 	/* In order to determine the codec, find the oldest connection on | ||||||
| 	 * the endpoint and use its codec information. Normally on an E1 | 	 * the endpoint and use its codec information. Normally on an E1 | ||||||
| 	 * endpoint no more than one connection should exist. */ | 	 * endpoint no more than one connection should exist. */ | ||||||
| 	conn = mgcp_conn_get_oldest(endp); | 	conn = mgcp_endp_get_conn_oldest(endp); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	codec = conn->u.rtp.end.codec; | 	conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
|  | 	codec = conn_rtp->end.cset.codec; | ||||||
| 	OSMO_ASSERT(codec); | 	OSMO_ASSERT(codec); | ||||||
|  |  | ||||||
| 	/* Update codec information */ | 	/* Update codec information */ | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ static char *gen_virtual_epname(void *ctx, const char *domain, | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Generate E1 endpoint name from given numeric parameters */ | /* Generate E1 endpoint name from given numeric parameters */ | ||||||
| static char *gen_e1_epname(void *ctx, const char *domain, unsigned int trunk_nr, | static char *gen_e1_epname(const void *ctx, const char *domain, unsigned int trunk_nr, | ||||||
| 			   uint8_t ts_nr, uint8_t ss_nr) | 			   uint8_t ts_nr, uint8_t ss_nr) | ||||||
| { | { | ||||||
| 	unsigned int rate; | 	unsigned int rate; | ||||||
| @@ -446,7 +446,7 @@ static uint8_t e1_ss_nr_from_epname(const char *epname) | |||||||
| /* Check if the selected E1 endpoint is avalable, which means that none of | /* Check if the selected E1 endpoint is avalable, which means that none of | ||||||
|  * the overlapping endpoints are currently serving a call. (if the system |  * the overlapping endpoints are currently serving a call. (if the system | ||||||
|  * is properly configured such a situation should never ocurr!) */ |  * is properly configured such a situation should never ocurr!) */ | ||||||
| static bool endp_avail_e1(struct mgcp_endpoint *endp) | static bool endp_avail_e1(const struct mgcp_endpoint *endp) | ||||||
| { | { | ||||||
| 	/* The following map shows the overlapping of the subslots and their | 	/* The following map shows the overlapping of the subslots and their | ||||||
| 	 * respective rates. The numbers on the right running from top to bottom | 	 * respective rates. The numbers on the right running from top to bottom | ||||||
| @@ -552,7 +552,7 @@ static bool endp_avail_e1(struct mgcp_endpoint *endp) | |||||||
| /*! check if an endpoint is available for any kind of operation. | /*! check if an endpoint is available for any kind of operation. | ||||||
|  *  \param[in] endp endpoint to check. |  *  \param[in] endp endpoint to check. | ||||||
|  *  \returns true if endpoint is avalable, false it is blocked for any reason. */ |  *  \returns true if endpoint is avalable, false it is blocked for any reason. */ | ||||||
| bool mgcp_endp_avail(struct mgcp_endpoint *endp) | bool mgcp_endp_avail(const struct mgcp_endpoint *endp) | ||||||
| { | { | ||||||
| 	switch (endp->trunk->trunk_type) { | 	switch (endp->trunk->trunk_type) { | ||||||
| 	case MGCP_TRUNK_VIRTUAL: | 	case MGCP_TRUNK_VIRTUAL: | ||||||
| @@ -569,6 +569,24 @@ bool mgcp_endp_avail(struct mgcp_endpoint *endp) | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /*! Get number of conns in an endpoint. | ||||||
|  |  *  \param[in] endp endpoint to check. | ||||||
|  |  *  \returns Number of connections present in the endpoint. */ | ||||||
|  | unsigned int mgcp_endp_num_conns(const struct mgcp_endpoint *endp) | ||||||
|  | { | ||||||
|  | 	return llist_count(&endp->conns); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! check if an endpoint can in current state allocate new conns. | ||||||
|  |  *  \param[in] endp endpoint to check. | ||||||
|  |  *  \returns true if more connections can be allowed on endpoint, false if it is already busy. */ | ||||||
|  | bool mgcp_endp_is_full(const struct mgcp_endpoint *endp) | ||||||
|  | { | ||||||
|  | 	if (endp->type->max_conns == 0) | ||||||
|  | 		return false; | ||||||
|  | 	return mgcp_endp_num_conns(endp) >= endp->type->max_conns; | ||||||
|  | } | ||||||
|  |  | ||||||
| /*! claim endpoint, sets callid and activates endpoint, should be called at the | /*! claim endpoint, sets callid and activates endpoint, should be called at the | ||||||
|  *  beginning of the CRCX procedure when it is clear that a new call should be |  *  beginning of the CRCX procedure when it is clear that a new call should be | ||||||
|  *  created. |  *  created. | ||||||
| @@ -655,6 +673,97 @@ void mgcp_endp_remove_conn(struct mgcp_endpoint *endp, struct mgcp_conn *conn) | |||||||
| 		mgcp_endp_release(endp); | 		mgcp_endp_release(endp); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /*! free oldest connection in the list. | ||||||
|  |  *  \param[in] endp associated endpoint */ | ||||||
|  | void mgcp_endp_free_conn_oldest(struct mgcp_endpoint *endp) | ||||||
|  | { | ||||||
|  | 	struct mgcp_conn *conn; | ||||||
|  |  | ||||||
|  | 	if (llist_empty(&endp->conns)) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	conn = llist_last_entry(&endp->conns, struct mgcp_conn, entry); | ||||||
|  | 	mgcp_conn_free(conn); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! free all connections at once. | ||||||
|  |  *  \param[in] endp associated endpoint */ | ||||||
|  | #if defined(__has_attribute) | ||||||
|  | #if __has_attribute(no_sanitize) | ||||||
|  | __attribute__((no_sanitize("undefined"))) /* ubsan detects a misaligned load */ | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  | void mgcp_endp_free_conn_all(struct mgcp_endpoint *endp) | ||||||
|  | { | ||||||
|  | 	struct mgcp_conn *conn; | ||||||
|  |  | ||||||
|  | 	/* Drop all items in the list, might be consecutive! */ | ||||||
|  | 	while ((conn = llist_first_entry_or_null(&endp->conns, struct mgcp_conn, entry))) | ||||||
|  | 		mgcp_conn_free(conn); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! find a connection by its ID. | ||||||
|  |  *  \param[in] endp associated endpoint | ||||||
|  |  *  \param[in] id identification number of the connection | ||||||
|  |  *  \returns pointer to allocated connection, NULL if not found */ | ||||||
|  | struct mgcp_conn *mgcp_endp_get_conn(struct mgcp_endpoint *endp, const char *id) | ||||||
|  | { | ||||||
|  | 	struct mgcp_conn *conn; | ||||||
|  | 	const char *id_upper; | ||||||
|  | 	const char *conn_id; | ||||||
|  |  | ||||||
|  | 	if (!id || !*id) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	/* Ignore leading zeros in needle */ | ||||||
|  | 	while (*id == '0') | ||||||
|  | 		id++; | ||||||
|  |  | ||||||
|  | 	/* Use uppercase to compare identifiers, to avoid mismatches: RFC3435 2.1.3.2 "Names of | ||||||
|  | 	 * Connections" defines the id as a hex string, so clients may return lower case hex even though | ||||||
|  | 	 * we sent upper case hex in the CRCX response. */ | ||||||
|  | 	id_upper = osmo_str_toupper(id); | ||||||
|  |  | ||||||
|  | 	llist_for_each_entry(conn, &endp->conns, entry) { | ||||||
|  | 		/* Ignore leading zeros in haystack */ | ||||||
|  | 		for (conn_id = conn->id; *conn_id == '0'; conn_id++); | ||||||
|  |  | ||||||
|  | 		if (strcmp(conn_id, id_upper) == 0) | ||||||
|  | 			return conn; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! get oldest connection in the list. | ||||||
|  |  *  \param[in] endp associated endpoint */ | ||||||
|  | struct mgcp_conn *mgcp_endp_get_conn_oldest(struct mgcp_endpoint *endp) | ||||||
|  | { | ||||||
|  | 	if (llist_empty(&endp->conns)) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	return llist_last_entry(&endp->conns, struct mgcp_conn, entry); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! find an RTP connection by its ID. | ||||||
|  |  *  \param[in] endp associated endpoint | ||||||
|  |  *  \param[in] id identification number of the connection | ||||||
|  |  *  \returns pointer to allocated connection, NULL if not found */ | ||||||
|  | struct mgcp_conn_rtp *mgcp_endp_get_conn_rtp(struct mgcp_endpoint *endp, | ||||||
|  | 					const char *id) | ||||||
|  | { | ||||||
|  | 	struct mgcp_conn *conn; | ||||||
|  |  | ||||||
|  | 	conn = mgcp_endp_get_conn(endp, id); | ||||||
|  | 	if (!conn) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	if (conn->type == MGCP_CONN_TYPE_RTP) | ||||||
|  | 		return mgcp_conn_get_conn_rtp(conn); | ||||||
|  |  | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
| /*! release endpoint, all open connections are closed. | /*! release endpoint, all open connections are closed. | ||||||
|  *  \param[in] endp endpoint to release */ |  *  \param[in] endp endpoint to release */ | ||||||
| void mgcp_endp_release(struct mgcp_endpoint *endp) | void mgcp_endp_release(struct mgcp_endpoint *endp) | ||||||
| @@ -665,7 +774,7 @@ void mgcp_endp_release(struct mgcp_endpoint *endp) | |||||||
| 	 * all connections have been removed already. In case | 	 * all connections have been removed already. In case | ||||||
| 	 * that there are still connections open (e.g. when | 	 * that there are still connections open (e.g. when | ||||||
| 	 * RSIP is executed), free them all at once. */ | 	 * RSIP is executed), free them all at once. */ | ||||||
| 	mgcp_conn_free_all(endp); | 	mgcp_endp_free_conn_all(endp); | ||||||
|  |  | ||||||
| 	/* We must only decrement the stat item when the endpoint as actually | 	/* We must only decrement the stat item when the endpoint as actually | ||||||
| 	 * claimed. An endpoint is claimed when a call-id is set */ | 	 * claimed. An endpoint is claimed when a call-id is set */ | ||||||
|   | |||||||
| @@ -264,6 +264,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg | |||||||
| 	uint8_t *amr_data; | 	uint8_t *amr_data; | ||||||
| 	struct rtp_hdr *rtp_hdr; | 	struct rtp_hdr *rtp_hdr; | ||||||
| 	struct amr_hdr *amr_hdr; | 	struct amr_hdr *amr_hdr; | ||||||
|  | 	struct mgcp_rtp_codec *dst_codec; | ||||||
| 	int rc; | 	int rc; | ||||||
|  |  | ||||||
| 	ft = osmo_amr_bytes_to_ft(msgb_l3len(msg)); | 	ft = osmo_amr_bytes_to_ft(msgb_l3len(msg)); | ||||||
| @@ -275,7 +276,8 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg | |||||||
| 	} | 	} | ||||||
| 	msgb_pull_to_l3(msg); | 	msgb_pull_to_l3(msg); | ||||||
|  |  | ||||||
| 	if (mgcp_codec_amr_is_octet_aligned(conn_rtp_dst->end.codec)) { | 	dst_codec = conn_rtp_dst->end.cset.codec; | ||||||
|  | 	if (mgcp_codec_amr_is_octet_aligned(dst_codec)) { | ||||||
| 		LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg)); | 		LOGP(DLMGCP, LOGL_DEBUG, "Convert IuUP -> AMR OA: ft %d, len %d\n", ft, msgb_length(msg)); | ||||||
| 		amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr)); | 		amr_hdr = (struct amr_hdr *) msgb_push(msg, sizeof(struct amr_hdr)); | ||||||
| 		amr_hdr->cmr = 15; /* no change */ | 		amr_hdr->cmr = 15; /* no change */ | ||||||
| @@ -303,7 +305,7 @@ static int bridge_iuup_to_rtp_peer(struct mgcp_conn_rtp *conn_rtp_src, struct mg | |||||||
| 		.extension = 0, | 		.extension = 0, | ||||||
| 		.padding = 0, | 		.padding = 0, | ||||||
| 		.version = 0, | 		.version = 0, | ||||||
| 		.payload_type = conn_rtp_dst->end.codec->payload_type, | 		.payload_type = dst_codec->payload_type, | ||||||
| 		.marker = 0, | 		.marker = 0, | ||||||
| 		.sequence = frame_nr, | 		.sequence = frame_nr, | ||||||
| 		.timestamp = 0, | 		.timestamp = 0, | ||||||
| @@ -502,7 +504,7 @@ static int mgcp_send_iuup(struct mgcp_endpoint *endp, struct msgb *msg, | |||||||
| 	 * ignored by the receiver, but still it's useful for debug purposes | 	 * ignored by the receiver, but still it's useful for debug purposes | ||||||
| 	 * to set it. Moreover, it seems ip.access nano3g produces much worse | 	 * to set it. Moreover, it seems ip.access nano3g produces much worse | ||||||
| 	 * audio output on the air side if timestamp is not set properly. */ | 	 * audio output on the air side if timestamp is not set properly. */ | ||||||
| 	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate)); | 	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate)); | ||||||
| 	hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence); | 	hdr->sequence = osmo_htons(rtp_state->alt_rtp_tx_sequence); | ||||||
| 	hdr->ssrc = rtp_state->alt_rtp_tx_ssrc; | 	hdr->ssrc = rtp_state->alt_rtp_tx_ssrc; | ||||||
| 	rtp_state->alt_rtp_tx_sequence++; | 	rtp_state->alt_rtp_tx_sequence++; | ||||||
| @@ -544,13 +546,13 @@ static int _conn_iuup_transport_prim_cb(struct osmo_prim_hdr *oph, void *ctx) | |||||||
|  |  | ||||||
| 	msgb_pull_to_l2(msg); | 	msgb_pull_to_l2(msg); | ||||||
| 	rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph)); | 	rtph = (struct rtp_hdr *)msgb_push(msg, sizeof(*rtph)); | ||||||
| 	/* TODO: fill rtph properly: */ | 	/* rtph is further filled in mgcp_send_iuup() below. */ | ||||||
| 	*rtph = (struct rtp_hdr){ | 	*rtph = (struct rtp_hdr){ | ||||||
| 		.csrc_count = 0, | 		.csrc_count = 0, | ||||||
| 		.extension = 0, | 		.extension = 0, | ||||||
| 		.padding = 0, | 		.padding = 0, | ||||||
| 		.version = 2, | 		.version = 2, | ||||||
| 		.payload_type = conn_rtp_dst->end.codec->payload_type, | 		.payload_type = conn_rtp_dst->end.cset.codec->payload_type, | ||||||
| 		.marker = 0, | 		.marker = 0, | ||||||
| 		.sequence = 0, | 		.sequence = 0, | ||||||
| 		.timestamp = 0, | 		.timestamp = 0, | ||||||
| @@ -645,6 +647,7 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn | |||||||
| 	struct rtp_hdr *rtph; | 	struct rtp_hdr *rtph; | ||||||
| 	int rc = -1; | 	int rc = -1; | ||||||
| 	int iuup_length = 0; | 	int iuup_length = 0; | ||||||
|  | 	struct mgcp_rtp_codec *src_codec; | ||||||
| 	int8_t rfci; | 	int8_t rfci; | ||||||
|  |  | ||||||
| 	/* Tx RNL-DATA.req */ | 	/* Tx RNL-DATA.req */ | ||||||
| @@ -657,13 +660,14 @@ int mgcp_conn_iuup_send_rtp(struct mgcp_conn_rtp *conn_src_rtp, struct mgcp_conn | |||||||
|  |  | ||||||
| 	/* TODO: CMR handling & multiple frames handling */ | 	/* TODO: CMR handling & multiple frames handling */ | ||||||
|  |  | ||||||
| 	if (strcmp(conn_src_rtp->end.codec->subtype_name, "AMR") != 0) { | 	src_codec = conn_src_rtp->end.cset.codec; | ||||||
|  | 	if (strcmp(src_codec->subtype_name, "AMR") != 0) { | ||||||
| 		LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR, | 		LOG_CONN_RTP(conn_src_rtp, LOGL_ERROR, | ||||||
| 			     "Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n", | 			     "Bridge RTP=>IuUP: Bridging src codec %s to IuUP AMR not supported\n", | ||||||
| 			     conn_src_rtp->end.codec->subtype_name); | 			     src_codec->subtype_name); | ||||||
| 		goto free_ret; | 		goto free_ret; | ||||||
| 	} | 	} | ||||||
| 	if (mgcp_codec_amr_is_octet_aligned(conn_src_rtp->end.codec)) { | 	if (mgcp_codec_amr_is_octet_aligned(src_codec)) { | ||||||
| 		struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg); | 		struct amr_hdr *amr_hdr = (struct amr_hdr *) msgb_data(msg); | ||||||
| 		if (msgb_length(msg) < (sizeof(*amr_hdr))) { | 		if (msgb_length(msg) < (sizeof(*amr_hdr))) { | ||||||
| 			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, | 			LOG_CONN_RTP(conn_src_rtp, LOGL_NOTICE, | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
|  | #include <ctype.h> | ||||||
|  |  | ||||||
| #include <osmocom/mgcp/mgcp.h> | #include <osmocom/mgcp/mgcp.h> | ||||||
| #include <osmocom/mgcp/osmux.h> | #include <osmocom/mgcp/osmux.h> | ||||||
| @@ -33,6 +34,10 @@ | |||||||
| #include <osmocom/mgcp/mgcp_endp.h> | #include <osmocom/mgcp/mgcp_endp.h> | ||||||
| #include <osmocom/mgcp/mgcp_trunk.h> | #include <osmocom/mgcp/mgcp_trunk.h> | ||||||
|  |  | ||||||
|  | /* (same fmt as LOGPENDP()) */ | ||||||
|  | #define LOG_MGCP_PDATA(PDATA, LEVEL, FMT, ARGS...) \ | ||||||
|  | 	LOGP(DLMGCP, LEVEL, "endpoint:%s " FMT, (PDATA) ? ((PDATA)->epname ? : "null-epname") : "null-pdata", ##ARGS) | ||||||
|  |  | ||||||
| /*! Display an mgcp message on the log output. | /*! Display an mgcp message on the log output. | ||||||
|  *  \param[in] message mgcp message string |  *  \param[in] message mgcp message string | ||||||
|  *  \param[in] len message mgcp message string length |  *  \param[in] len message mgcp message string length | ||||||
| @@ -76,61 +81,24 @@ void mgcp_disp_msg(unsigned char *message, unsigned int len, char *preamble) | |||||||
|  |  | ||||||
| /*! Parse connection mode. | /*! Parse connection mode. | ||||||
|  *  \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback) |  *  \param[in] mode as string (recvonly, sendrecv, sendonly confecho or loopback) | ||||||
|  *  \param[in] endp pointer to endpoint (only used for log output) |  *  \returns MGCP_CONN_* on success, MGCP_CONN_NONE on error */ | ||||||
|  *  \param[out] associated connection to be modified accordingly | enum mgcp_connection_mode mgcp_parse_conn_mode(const char *mode) | ||||||
|  *  \returns 0 on success, -1 on error */ |  | ||||||
| int mgcp_parse_conn_mode(const char *mode, struct mgcp_endpoint *endp, |  | ||||||
| 			 struct mgcp_conn *conn) |  | ||||||
| { | { | ||||||
| 	int ret = 0; |  | ||||||
|  |  | ||||||
| 	if (!mode) { | 	if (!mode) | ||||||
| 		LOGPCONN(conn, DLMGCP, LOGL_ERROR, | 		return MGCP_CONN_NONE; | ||||||
| 			 "missing connection mode\n"); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
| 	if (!conn) |  | ||||||
| 		return -1; |  | ||||||
| 	if (!endp) |  | ||||||
| 		return -1; |  | ||||||
|  |  | ||||||
| 	if (strcasecmp(mode, "recvonly") == 0) | 	if (strcasecmp(mode, "recvonly") == 0) | ||||||
| 		conn->mode = MGCP_CONN_RECV_ONLY; | 		return MGCP_CONN_RECV_ONLY; | ||||||
| 	else if (strcasecmp(mode, "sendrecv") == 0) | 	if (strcasecmp(mode, "sendrecv") == 0) | ||||||
| 		conn->mode = MGCP_CONN_RECV_SEND; | 		return MGCP_CONN_RECV_SEND; | ||||||
| 	else if (strcasecmp(mode, "sendonly") == 0) | 	if (strcasecmp(mode, "sendonly") == 0) | ||||||
| 		conn->mode = MGCP_CONN_SEND_ONLY; | 		return MGCP_CONN_SEND_ONLY; | ||||||
| 	else if (strcasecmp(mode, "confecho") == 0) | 	if (strcasecmp(mode, "confecho") == 0) | ||||||
| 		conn->mode = MGCP_CONN_CONFECHO; | 		return MGCP_CONN_CONFECHO; | ||||||
| 	else if (strcasecmp(mode, "loopback") == 0) | 	if (strcasecmp(mode, "loopback") == 0) | ||||||
| 		conn->mode = MGCP_CONN_LOOPBACK; | 		return MGCP_CONN_LOOPBACK; | ||||||
| 	else { | 	return MGCP_CONN_NONE; | ||||||
| 		LOGPCONN(conn, DLMGCP, LOGL_ERROR, |  | ||||||
| 			 "unknown connection mode: '%s'\n", mode); |  | ||||||
| 		ret = -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Special handling for RTP connections */ |  | ||||||
| 	if (conn->type == MGCP_CONN_TYPE_RTP) { |  | ||||||
| 		conn->u.rtp.end.output_enabled = !!(conn->mode & MGCP_CONN_SEND_ONLY); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	LOGPENDP(endp, DLMGCP, LOGL_DEBUG, "conn:%s\n", mgcp_conn_dump(conn)); |  | ||||||
|  |  | ||||||
| 	LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "connection mode '%s' %d\n", |  | ||||||
| 		 mode, conn->mode); |  | ||||||
|  |  | ||||||
| 	/* Special handling für RTP connections */ |  | ||||||
| 	if (conn->type == MGCP_CONN_TYPE_RTP) { |  | ||||||
| 		LOGPCONN(conn, DLMGCP, LOGL_DEBUG, "output_enabled %u\n", |  | ||||||
| 			 conn->u.rtp.end.output_enabled); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* The VTY might change the connection mode at any time, so we have |  | ||||||
| 	 * to hold a copy of the original connection mode */ |  | ||||||
| 	conn->mode_orig = conn->mode; |  | ||||||
|  |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! Analyze and parse the the hader of an MGCP messeage string. | /*! Analyze and parse the the hader of an MGCP messeage string. | ||||||
| @@ -159,8 +127,7 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data) | |||||||
| 			break; | 			break; | ||||||
| 		case 2: | 		case 2: | ||||||
| 			if (strcasecmp("MGCP", elem)) { | 			if (strcasecmp("MGCP", elem)) { | ||||||
| 				LOGP(DLMGCP, LOGL_ERROR, | 				LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP header parsing error\n"); | ||||||
| 				     "MGCP header parsing error\n"); |  | ||||||
| 				return -510; | 				return -510; | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| @@ -173,13 +140,87 @@ int mgcp_parse_header(struct mgcp_parse_data *pdata, char *data) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (i != 4) { | 	if (i != 4) { | ||||||
| 		LOGP(DLMGCP, LOGL_ERROR, "MGCP status line too short.\n"); | 		LOG_MGCP_PDATA(pdata, LOGL_ERROR, "MGCP status line too short.\n"); | ||||||
| 		return -510; | 		return -510; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static bool parse_x_osmo_ign(struct mgcp_parse_data *pdata, char *line) | ||||||
|  | { | ||||||
|  | 	char *saveptr = NULL; | ||||||
|  |  | ||||||
|  | 	if (strncasecmp(line, MGCP_X_OSMO_IGN_HEADER, strlen(MGCP_X_OSMO_IGN_HEADER))) | ||||||
|  | 		return false; | ||||||
|  | 	line += strlen(MGCP_X_OSMO_IGN_HEADER); | ||||||
|  |  | ||||||
|  | 	while (1) { | ||||||
|  | 		char *token = strtok_r(line, " ", &saveptr); | ||||||
|  | 		line = NULL; | ||||||
|  | 		if (!token) | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		if (!strcasecmp(token, "C")) | ||||||
|  | 			pdata->hpars.x_osmo_ign |= MGCP_X_OSMO_IGN_CALLID; | ||||||
|  | 		else | ||||||
|  | 			LOG_MGCP_PDATA(pdata, LOGL_ERROR, "received unknown X-Osmo-IGN item '%s'\n", token); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! Analyze and parse the the header of an MGCP message string. | ||||||
|  |  *  \param[inout] pdata caller provided memory to store the parsing results. | ||||||
|  |  *  \returns 0 when parsing was successful, negative (MGCP cause code) on error. */ | ||||||
|  | int mgcp_parse_hdr_pars(struct mgcp_parse_data *pdata) | ||||||
|  | { | ||||||
|  | 	struct mgcp_parse_hdr_pars *hp = &pdata->hpars; | ||||||
|  | 	char *line; | ||||||
|  |  | ||||||
|  | 	mgcp_parse_hdr_pars_init(hp); | ||||||
|  |  | ||||||
|  | 	for_each_line(line, pdata->save) { | ||||||
|  | 		if (!mgcp_check_param(line)) { | ||||||
|  | 			LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		switch (toupper(line[0])) { | ||||||
|  | 		case 'L': | ||||||
|  | 			hp->local_options = (const char *)line + 3; | ||||||
|  | 			break; | ||||||
|  | 		case 'C': | ||||||
|  | 			hp->callid = (const char *)line + 3; | ||||||
|  | 			break; | ||||||
|  | 		case 'I': | ||||||
|  | 			hp->connid = (const char *)line + 3; | ||||||
|  | 			break; | ||||||
|  | 		case 'M': | ||||||
|  | 			hp->mode = mgcp_parse_conn_mode((const char *)line + 3); | ||||||
|  | 			break; | ||||||
|  | 		case 'X': | ||||||
|  | 			if (strncasecmp("Osmux: ", line + 2, strlen("Osmux: ")) == 0) { | ||||||
|  | 				hp->remote_osmux_cid = mgcp_parse_osmux_cid(line); | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			if (parse_x_osmo_ign(pdata, line)) | ||||||
|  | 				break; | ||||||
|  | 			/* Ignore unknown X-headers */ | ||||||
|  | 			break; | ||||||
|  | 		case '\0': | ||||||
|  | 			hp->have_sdp = true; | ||||||
|  | 			goto mgcp_header_done; | ||||||
|  | 		default: | ||||||
|  | 			LOG_MGCP_PDATA(pdata, LOGL_NOTICE, "CRCX: unhandled option: '%c'/%d\n", *line, *line); | ||||||
|  | 			return -539; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | mgcp_header_done: | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| /*! Extract OSMUX CID from an MGCP parameter line (string). | /*! Extract OSMUX CID from an MGCP parameter line (string). | ||||||
|  *  \param[in] line single parameter line from the MGCP message |  *  \param[in] line single parameter line from the MGCP message | ||||||
|  *  \returns OSMUX CID, -1 wildcard, -2 on error */ |  *  \returns OSMUX CID, -1 wildcard, -2 on error */ | ||||||
| @@ -190,19 +231,19 @@ int mgcp_parse_osmux_cid(const char *line) | |||||||
|  |  | ||||||
| 	if (strcasecmp(line + 2, "Osmux: *") == 0) { | 	if (strcasecmp(line + 2, "Osmux: *") == 0) { | ||||||
| 		LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n"); | 		LOGP(DLMGCP, LOGL_DEBUG, "Parsed wilcard Osmux CID\n"); | ||||||
| 		return -1; | 		return MGCP_PARSE_HDR_PARS_OSMUX_CID_WILDCARD; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) { | 	if (sscanf(line + 2 + 7, "%u", &osmux_cid) != 1) { | ||||||
| 		LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n", | 		LOGP(DLMGCP, LOGL_ERROR, "Failed parsing Osmux in MGCP msg line: %s\n", | ||||||
| 		     line); | 		     line); | ||||||
| 		return -2; | 		return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (osmux_cid > OSMUX_CID_MAX) { | 	if (osmux_cid > OSMUX_CID_MAX) { | ||||||
| 		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n", | 		LOGP(DLMGCP, LOGL_ERROR, "Osmux ID too large: %u > %u\n", | ||||||
| 		     osmux_cid, OSMUX_CID_MAX); | 		     osmux_cid, OSMUX_CID_MAX); | ||||||
| 		return -2; | 		return MGCP_PARSE_HDR_PARS_OSMUX_CID_UNSET; | ||||||
| 	} | 	} | ||||||
| 	LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid); | 	LOGP(DLMGCP, LOGL_DEBUG, "MGCP client offered Osmux CID %u\n", osmux_cid); | ||||||
|  |  | ||||||
| @@ -210,20 +251,13 @@ int mgcp_parse_osmux_cid(const char *line) | |||||||
| } | } | ||||||
|  |  | ||||||
| /*! Check MGCP parameter line (string) for plausibility. | /*! Check MGCP parameter line (string) for plausibility. | ||||||
|  *  \param[in] endp pointer to endpoint (only used for log output, may be NULL) |  | ||||||
|  *  \param[in] trunk pointer to trunk (only used for log output, may be NULL if endp is not NULL) |  | ||||||
|  *  \param[in] line single parameter line from the MGCP message |  *  \param[in] line single parameter line from the MGCP message | ||||||
|  *  \returns true when line seems plausible, false on error */ |  *  \returns true when line seems plausible, false on error */ | ||||||
| bool mgcp_check_param(const struct mgcp_endpoint *endp, struct mgcp_trunk *trunk, const char *line) | bool mgcp_check_param(const char *line) | ||||||
| { | { | ||||||
| 	const size_t line_len = strlen(line); | 	const size_t line_len = strlen(line); | ||||||
| 	if (line[0] != '\0' && line_len < 2) { | 	if (line[0] != '\0' && line_len < 2) | ||||||
| 		if (endp) |  | ||||||
| 			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line); |  | ||||||
| 		else |  | ||||||
| 			LOGPTRUNK(trunk, DLMGCP, LOGL_NOTICE, "wrong MGCP option format: '%s'\n", line); |  | ||||||
| 		return false; | 		return false; | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* FIXME: A couple more checks wouldn't hurt... */ | 	/* FIXME: A couple more checks wouldn't hurt... */ | ||||||
|  |  | ||||||
| @@ -294,7 +328,7 @@ int mgcp_verify_ci(struct mgcp_endpoint *endp, const char *conn_id) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Check if connection exists */ | 	/* Check if connection exists */ | ||||||
| 	if (mgcp_conn_get(endp, conn_id)) | 	if (mgcp_endp_get_conn(endp, conn_id)) | ||||||
| 		return 0; | 		return 0; | ||||||
|  |  | ||||||
| 	LOGPENDP(endp, DLMGCP, LOGL_ERROR, | 	LOGPENDP(endp, DLMGCP, LOGL_ERROR, | ||||||
|   | |||||||
| @@ -85,12 +85,6 @@ static inline struct msgb *mgw_msgb_copy_c(void *ctx, struct msgb *msg, const ch | |||||||
|  |  | ||||||
| static int rx_rtp(struct msgb *msg); | static int rx_rtp(struct msgb *msg); | ||||||
|  |  | ||||||
| bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end) |  | ||||||
| { |  | ||||||
| 	return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) && |  | ||||||
| 	       (osmo_sockaddr_is_any(&rtp_end->addr) == 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*! Determine the local rtp bind IP-address. | /*! Determine the local rtp bind IP-address. | ||||||
|  *  \param[out] addr caller provided memory to store the resulting IP-Address. |  *  \param[out] addr caller provided memory to store the resulting IP-Address. | ||||||
|  *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters. |  *  \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters. | ||||||
| @@ -338,7 +332,7 @@ static int adjust_rtp_timestamp_offset(const struct mgcp_endpoint *endp, | |||||||
| 				 osmo_sockaddr_ntop(&addr->u.sa, ipbuf), | 				 osmo_sockaddr_ntop(&addr->u.sa, ipbuf), | ||||||
| 				 osmo_sockaddr_port(&addr->u.sa)); | 				 osmo_sockaddr_port(&addr->u.sa)); | ||||||
| 		} else { | 		} else { | ||||||
| 			tsdelta = rtp_end->codec->rate * 20 / 1000; | 			tsdelta = rtp_end->cset.codec->rate * 20 / 1000; | ||||||
| 			LOGPENDP(endp, DRTP, LOGL_NOTICE, | 			LOGPENDP(endp, DRTP, LOGL_NOTICE, | ||||||
| 				 "Fixed packet duration and last timestamp delta " | 				 "Fixed packet duration and last timestamp delta " | ||||||
| 				 "are not available, " | 				 "are not available, " | ||||||
| @@ -502,11 +496,11 @@ static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_dst, struct msgb *msg) | |||||||
| 	} | 	} | ||||||
| 	rtp_hdr = (struct rtp_hdr *)msgb_data(msg); | 	rtp_hdr = (struct rtp_hdr *)msgb_data(msg); | ||||||
|  |  | ||||||
| 	if (!conn_dst->end.codec) { | 	if (!conn_dst->end.cset.codec) { | ||||||
| 		LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n"); | 		LOG_CONN_RTP(conn_dst, LOGL_NOTICE, "no codec set on destination connection!\n"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 	rtp_hdr->payload_type = (uint8_t) conn_dst->end.codec->payload_type; | 	rtp_hdr->payload_type = (uint8_t) conn_dst->end.cset.codec->payload_type; | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @@ -529,7 +523,8 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | |||||||
| 	uint32_t timestamp, ssrc; | 	uint32_t timestamp, ssrc; | ||||||
| 	bool marker_bit; | 	bool marker_bit; | ||||||
| 	struct rtp_hdr *rtp_hdr; | 	struct rtp_hdr *rtp_hdr; | ||||||
| 	int payload = rtp_end->codec->payload_type; | 	struct mgcp_rtp_codec *codec = rtp_end->cset.codec; | ||||||
|  | 	int payload = codec->payload_type; | ||||||
| 	unsigned int len = msgb_length(msg); | 	unsigned int len = msgb_length(msg); | ||||||
|  |  | ||||||
| 	if (len < sizeof(*rtp_hdr)) | 	if (len < sizeof(*rtp_hdr)) | ||||||
| @@ -538,7 +533,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | |||||||
| 	rtp_hdr = (struct rtp_hdr *)msgb_data(msg); | 	rtp_hdr = (struct rtp_hdr *)msgb_data(msg); | ||||||
| 	seq = ntohs(rtp_hdr->sequence); | 	seq = ntohs(rtp_hdr->sequence); | ||||||
| 	timestamp = ntohl(rtp_hdr->timestamp); | 	timestamp = ntohl(rtp_hdr->timestamp); | ||||||
| 	arrival_time = mgcp_get_current_ts(rtp_end->codec->rate); | 	arrival_time = mgcp_get_current_ts(codec->rate); | ||||||
| 	ssrc = ntohl(rtp_hdr->ssrc); | 	ssrc = ntohl(rtp_hdr->ssrc); | ||||||
| 	marker_bit = !!rtp_hdr->marker; | 	marker_bit = !!rtp_hdr->marker; | ||||||
| 	transit = arrival_time - timestamp; | 	transit = arrival_time - timestamp; | ||||||
| @@ -547,16 +542,16 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | |||||||
|  |  | ||||||
| 	if (!state->initialized) { | 	if (!state->initialized) { | ||||||
| 		state->initialized = 1; | 		state->initialized = 1; | ||||||
|  | 		state->packet_duration = mgcp_rtp_packet_duration(endp, rtp_end); | ||||||
| 		state->in_stream.last_seq = seq - 1; | 		state->in_stream.last_seq = seq - 1; | ||||||
| 		state->in_stream.ssrc = state->patch.orig_ssrc = ssrc; | 		state->in_stream.ssrc = ssrc; | ||||||
| 		state->in_stream.last_tsdelta = 0; | 		state->in_stream.last_tsdelta = 0; | ||||||
| 		state->packet_duration = |  | ||||||
| 		    mgcp_rtp_packet_duration(endp, rtp_end); |  | ||||||
| 		state->out_stream.last_seq = seq - 1; | 		state->out_stream.last_seq = seq - 1; | ||||||
| 		state->out_stream.ssrc = state->patch.orig_ssrc = ssrc; |  | ||||||
| 		state->out_stream.last_tsdelta = 0; | 		state->out_stream.last_tsdelta = 0; | ||||||
| 		state->out_stream.last_timestamp = timestamp; | 		state->out_stream.last_timestamp = timestamp; | ||||||
| 		state->out_stream.ssrc = ssrc - 1;	/* force output SSRC change */ | 		state->out_stream.ssrc = ssrc - 1;	/* force output SSRC change */ | ||||||
|  | 		state->patch.orig_ssrc = ssrc; | ||||||
|  | 		state->patch.patch_ssrc = rtp_end->force_constant_ssrc; | ||||||
| 		LOGPENDP(endp, DRTP, LOGL_INFO, | 		LOGPENDP(endp, DRTP, LOGL_INFO, | ||||||
| 			 "initializing stream, SSRC: %u timestamp: %u " | 			 "initializing stream, SSRC: %u timestamp: %u " | ||||||
| 			 "pkt-duration: %d, from %s:%d\n", | 			 "pkt-duration: %d, from %s:%d\n", | ||||||
| @@ -566,7 +561,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | |||||||
| 			 osmo_sockaddr_port(&addr->u.sa)); | 			 osmo_sockaddr_port(&addr->u.sa)); | ||||||
| 		if (state->packet_duration == 0) { | 		if (state->packet_duration == 0) { | ||||||
| 			state->packet_duration = | 			state->packet_duration = | ||||||
| 			    rtp_end->codec->rate * 20 / 1000; | 			    codec->rate * 20 / 1000; | ||||||
| 			LOGPENDP(endp, DRTP, LOGL_NOTICE, | 			LOGPENDP(endp, DRTP, LOGL_NOTICE, | ||||||
| 				 "fixed packet duration is not available, " | 				 "fixed packet duration is not available, " | ||||||
| 				 "using fixed 20ms instead: %d from %s:%d\n", | 				 "using fixed 20ms instead: %d from %s:%d\n", | ||||||
| @@ -583,7 +578,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | |||||||
| 			 osmo_sockaddr_port(&addr->u.sa)); | 			 osmo_sockaddr_port(&addr->u.sa)); | ||||||
|  |  | ||||||
| 		state->in_stream.ssrc = ssrc; | 		state->in_stream.ssrc = ssrc; | ||||||
| 		if (rtp_end->force_constant_ssrc) { | 		if (state->patch.patch_ssrc) { | ||||||
| 			int16_t delta_seq; | 			int16_t delta_seq; | ||||||
|  |  | ||||||
| 			/* Always increment seqno by 1 */ | 			/* Always increment seqno by 1 */ | ||||||
| @@ -599,10 +594,7 @@ void mgcp_patch_and_count(const struct mgcp_endpoint *endp, | |||||||
| 			adjust_rtp_timestamp_offset(endp, state, rtp_end, addr, | 			adjust_rtp_timestamp_offset(endp, state, rtp_end, addr, | ||||||
| 						    delta_seq, timestamp, marker_bit); | 						    delta_seq, timestamp, marker_bit); | ||||||
|  |  | ||||||
| 			state->patch.patch_ssrc = true; |  | ||||||
| 			ssrc = state->patch.orig_ssrc; | 			ssrc = state->patch.orig_ssrc; | ||||||
| 			if (rtp_end->force_constant_ssrc != -1) |  | ||||||
| 				rtp_end->force_constant_ssrc -= 1; |  | ||||||
|  |  | ||||||
| 			LOGPENDP(endp, DRTP, LOGL_NOTICE, | 			LOGPENDP(endp, DRTP, LOGL_NOTICE, | ||||||
| 				 "SSRC patching enabled, SSRC: %u " | 				 "SSRC patching enabled, SSRC: %u " | ||||||
| @@ -822,8 +814,8 @@ static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end, | |||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	hdr->version = 2; | 	hdr->version = 2; | ||||||
| 	hdr->payload_type = rtp_end->codec->payload_type; | 	hdr->payload_type = rtp_end->cset.codec->payload_type; | ||||||
| 	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->codec->rate)); | 	hdr->timestamp = osmo_htonl(mgcp_get_current_ts(rtp_end->cset.codec->rate)); | ||||||
| 	hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence); | 	hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence); | ||||||
| 	hdr->ssrc = state->alt_rtp_tx_ssrc; | 	hdr->ssrc = state->alt_rtp_tx_ssrc; | ||||||
| } | } | ||||||
| @@ -1189,6 +1181,8 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr | |||||||
| 			 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port) | 			 osmo_sockaddr_port(&rtp_end->addr.u.sa), ntohs(rtp_end->rtcp_port) | ||||||
| 		    ); | 		    ); | ||||||
| 	} else if (is_rtp) { | 	} else if (is_rtp) { | ||||||
|  | 		struct mgcp_rtp_codec *src_codec; | ||||||
|  | 		struct mgcp_rtp_codec *dst_codec; | ||||||
| 		/* Make sure we have a valid RTP header, in cases where no RTP | 		/* Make sure we have a valid RTP header, in cases where no RTP | ||||||
| 		 * header is present, we will generate one. */ | 		 * header is present, we will generate one. */ | ||||||
| 		gen_rtp_header(msg, rtp_end, rtp_state); | 		gen_rtp_header(msg, rtp_end, rtp_state); | ||||||
| @@ -1204,19 +1198,21 @@ int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct osmo_sockaddr *addr | |||||||
| 		if (addr) | 		if (addr) | ||||||
| 			mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg); | 			mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, msg); | ||||||
|  |  | ||||||
|  | 		src_codec = conn_src->end.cset.codec; | ||||||
|  | 		dst_codec = conn_dst->end.cset.codec; | ||||||
| 		if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) { | 		if (mgcp_conn_rtp_is_iuup(conn_dst) || mgcp_conn_rtp_is_iuup(conn_src)) { | ||||||
| 			/* the iuup code will correctly transform to the correct AMR mode */ | 			/* the iuup code will correctly transform to the correct AMR mode */ | ||||||
| 		} else if (mgcp_codec_amr_align_mode_is_indicated(conn_dst->end.codec)) { | 		} else if (mgcp_codec_amr_align_mode_is_indicated(dst_codec)) { | ||||||
| 			rc = amr_oa_bwe_convert(endp, msg, conn_dst->end.codec->param.amr_octet_aligned); | 			rc = amr_oa_bwe_convert(endp, msg, dst_codec->param.amr_octet_aligned); | ||||||
| 			if (rc < 0) { | 			if (rc < 0) { | ||||||
| 				LOGPENDP(endp, DRTP, LOGL_ERROR, | 				LOGPENDP(endp, DRTP, LOGL_ERROR, | ||||||
| 					 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n", | 					 "Error in AMR octet-aligned <-> bandwidth-efficient mode conversion (target=%s)\n", | ||||||
| 					 conn_dst->end.codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient"); | 					 dst_codec->param.amr_octet_aligned ? "octet-aligned" : "bandwidth-efficient"); | ||||||
| 				msgb_free(msg); | 				msgb_free(msg); | ||||||
| 				return rc; | 				return rc; | ||||||
| 			} | 			} | ||||||
| 		} else if (rtp_end->rfc5993_hr_convert && | 		} else if (rtp_end->rfc5993_hr_convert && | ||||||
| 			   strcmp(conn_src->end.codec->subtype_name, "GSM-HR-08") == 0) { | 			   strcmp(src_codec->subtype_name, "GSM-HR-08") == 0) { | ||||||
| 			rc = rfc5993_hr_convert(endp, msg); | 			rc = rfc5993_hr_convert(endp, msg); | ||||||
| 			if (rc < 0) { | 			if (rc < 0) { | ||||||
| 				LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n"); | 				LOGPENDP(endp, DRTP, LOGL_ERROR, "Error while converting to GSM-HR-08\n"); | ||||||
| @@ -1343,13 +1339,13 @@ int mgcp_dispatch_rtp_bridge_cb(struct msgb *msg) | |||||||
| 		 * packets back to their origin. We will use the originating | 		 * packets back to their origin. We will use the originating | ||||||
| 		 * address data from the UDP packet header to patch the | 		 * address data from the UDP packet header to patch the | ||||||
| 		 * outgoing address in connection on the fly */ | 		 * outgoing address in connection on the fly */ | ||||||
| 		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) { | 		if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) { | ||||||
| 			memcpy(&conn->u.rtp.end.addr, from_addr, | 			memcpy(&conn_src->end.addr, from_addr, | ||||||
| 			       sizeof(conn->u.rtp.end.addr)); | 			       sizeof(conn_src->end.addr)); | ||||||
| 			LOG_CONN_RTP(conn_src, LOGL_NOTICE, | 			LOG_CONN_RTP(conn_src, LOGL_NOTICE, | ||||||
| 				     "loopback mode: implicitly using source address (%s:%u) as destination address\n", | 				     "loopback mode: implicitly using source address (%s:%u) as destination address\n", | ||||||
| 				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf), | 				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf), | ||||||
| 				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa)); | 				     osmo_sockaddr_port(&conn_src->end.addr.u.sa)); | ||||||
| 		} | 		} | ||||||
| 		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg); | 		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg); | ||||||
| 	} | 	} | ||||||
| @@ -1428,19 +1424,19 @@ int mgcp_dispatch_e1_bridge_cb(struct msgb *msg) | |||||||
| 		 * packets back to their origin. We will use the originating | 		 * packets back to their origin. We will use the originating | ||||||
| 		 * address data from the UDP packet header to patch the | 		 * address data from the UDP packet header to patch the | ||||||
| 		 * outgoing address in connection on the fly */ | 		 * outgoing address in connection on the fly */ | ||||||
| 		if (osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa) == 0) { | 		if (osmo_sockaddr_port(&conn_src->end.addr.u.sa) == 0) { | ||||||
| 			memcpy(&conn->u.rtp.end.addr, from_addr, | 			memcpy(&conn_src->end.addr, from_addr, | ||||||
| 			       sizeof(conn->u.rtp.end.addr)); | 			       sizeof(conn_src->end.addr)); | ||||||
| 			LOG_CONN_RTP(conn_src, LOGL_NOTICE, | 			LOG_CONN_RTP(conn_src, LOGL_NOTICE, | ||||||
| 				     "loopback mode: implicitly using source address (%s:%u) as destination address\n", | 				     "loopback mode: implicitly using source address (%s:%u) as destination address\n", | ||||||
| 				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf), | 				     osmo_sockaddr_ntop(&from_addr->u.sa, ipbuf), | ||||||
| 				     osmo_sockaddr_port(&conn->u.rtp.end.addr.u.sa)); | 				     osmo_sockaddr_port(&conn_src->end.addr.u.sa)); | ||||||
| 		} | 		} | ||||||
| 		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg); | 		return mgcp_conn_rtp_dispatch_rtp(conn_src, msg); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Forward to E1 */ | 	/* Forward to E1 */ | ||||||
| 	return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg); | 	return mgcp_e1_send_rtp(conn->endp, conn_src->end.cset.codec, msg); | ||||||
| } | } | ||||||
|  |  | ||||||
| /*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed. | /*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed. | ||||||
| @@ -1562,18 +1558,18 @@ static int rx_rtp(struct msgb *msg) | |||||||
|  |  | ||||||
| 	/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */ | 	/* Handle AMR frame format conversion (octet-aligned vs. bandwith-efficient) */ | ||||||
| 	if (mc->proto == MGCP_PROTO_RTP | 	if (mc->proto == MGCP_PROTO_RTP | ||||||
| 	    && conn_src->end.codec | 	    && conn_src->end.cset.codec | ||||||
| 	    && mgcp_codec_amr_align_mode_is_indicated(conn_src->end.codec)) { | 	    && mgcp_codec_amr_align_mode_is_indicated(conn_src->end.cset.codec)) { | ||||||
| 		/* Make sure that the incoming AMR frame format matches the frame format that the call agent has | 		/* Make sure that the incoming AMR frame format matches the frame format that the call agent has | ||||||
| 		 * communicated via SDP when the connection was created/modfied. */ | 		 * communicated via SDP when the connection was created/modfied. */ | ||||||
| 		int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg)); | 		int oa = amr_oa_check((char*)msgb_data(msg), msgb_length(msg)); | ||||||
| 		if (oa < 0) | 		if (oa < 0) | ||||||
| 			goto out_free; | 			goto out_free; | ||||||
| 		if (((bool)oa) != conn_src->end.codec->param.amr_octet_aligned) { | 		if (((bool)oa) != conn_src->end.cset.codec->param.amr_octet_aligned) { | ||||||
| 			LOG_CONN_RTP(conn_src, LOGL_NOTICE, | 			LOG_CONN_RTP(conn_src, LOGL_NOTICE, | ||||||
| 				     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u." | 				     "rx_rtp(%u bytes): Expected RTP AMR octet-aligned=%u but got octet-aligned=%u." | ||||||
| 				     " check the config of your call-agent!\n", | 				     " check the config of your call-agent!\n", | ||||||
| 				     msgb_length(msg), conn_src->end.codec->param.amr_octet_aligned, oa); | 				     msgb_length(msg), conn_src->end.cset.codec->param.amr_octet_aligned, oa); | ||||||
| 			goto out_free; | 			goto out_free; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -1629,78 +1625,23 @@ int mgcp_create_bind(const char *source_addr, int port, uint8_t dscp, uint8_t pr | |||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */ |  | ||||||
| static int bind_rtp(struct mgcp_config *cfg, const char *source_addr, |  | ||||||
| 		    struct mgcp_rtp_end *rtp_end, struct mgcp_endpoint *endp) |  | ||||||
| { |  | ||||||
| 	int rc, rtp_fd, rtcp_fd; |  | ||||||
|  |  | ||||||
| 	/* NOTE: The port that is used for RTCP is the RTP port incremented by one |  | ||||||
| 	 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */ |  | ||||||
|  |  | ||||||
| 	rc = mgcp_create_bind(source_addr, rtp_end->local_port, cfg->endp_dscp, cfg->endp_priority); |  | ||||||
| 	if (rc < 0) { |  | ||||||
| 		LOGPENDP(endp, DRTP, LOGL_ERROR, |  | ||||||
| 			 "failed to create RTP port: %s:%d\n", |  | ||||||
| 			 source_addr, rtp_end->local_port); |  | ||||||
| 		goto cleanup0; |  | ||||||
| 	} |  | ||||||
| 	rtp_fd = rc; |  | ||||||
|  |  | ||||||
| 	rc = mgcp_create_bind(source_addr, rtp_end->local_port + 1, cfg->endp_dscp, cfg->endp_priority); |  | ||||||
| 	if (rc < 0) { |  | ||||||
| 		LOGPENDP(endp, DRTP, LOGL_ERROR, |  | ||||||
| 			 "failed to create RTCP port: %s:%d\n", |  | ||||||
| 			 source_addr, rtp_end->local_port + 1); |  | ||||||
| 		goto cleanup1; |  | ||||||
| 	} |  | ||||||
| 	rtcp_fd = rc; |  | ||||||
|  |  | ||||||
| 	if (osmo_iofd_register(rtp_end->rtp, rtp_fd) < 0) { |  | ||||||
| 		LOGPENDP(endp, DRTP, LOGL_ERROR, |  | ||||||
| 			 "failed to register RTP port %d\n", |  | ||||||
| 			 rtp_end->local_port); |  | ||||||
| 		goto cleanup2; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (osmo_iofd_register(rtp_end->rtcp, rtcp_fd) != 0) { |  | ||||||
| 		LOGPENDP(endp, DRTP, LOGL_ERROR, |  | ||||||
| 			 "failed to register RTCP port %d\n", |  | ||||||
| 			 rtp_end->local_port + 1); |  | ||||||
| 		goto cleanup3; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
|  |  | ||||||
| cleanup3: |  | ||||||
| 	osmo_iofd_unregister(rtp_end->rtp); |  | ||||||
| cleanup2: |  | ||||||
| 	close(rtcp_fd); |  | ||||||
| cleanup1: |  | ||||||
| 	close(rtp_fd); |  | ||||||
| cleanup0: |  | ||||||
| 	return -1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*! bind RTP port to endpoint/connection. | /*! bind RTP port to endpoint/connection. | ||||||
|  *  \param[in] endp endpoint that holds the RTP connection. |  | ||||||
|  *  \param[in] rtp_port port number to bind on. |  | ||||||
|  *  \param[in] conn associated RTP connection. |  *  \param[in] conn associated RTP connection. | ||||||
|  |  *  \param[in] rtp_port port number to bind on. | ||||||
|  *  \returns 0 on success, -1 on ERROR. */ |  *  \returns 0 on success, -1 on ERROR. */ | ||||||
| int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port, | int mgcp_conn_rtp_bind_rtp_ports(struct mgcp_conn_rtp *conn_rtp, int rtp_port) | ||||||
| 			   struct mgcp_conn_rtp *conn) |  | ||||||
| { | { | ||||||
| 	char name[512]; | 	char name[512]; | ||||||
| 	struct mgcp_rtp_end *end; | 	struct mgcp_conn *conn = conn_rtp->conn; | ||||||
|  | 	struct mgcp_config *cfg = conn->endp->trunk->cfg; | ||||||
|  | 	struct mgcp_rtp_end *end = &conn_rtp->end; | ||||||
|  | 	int rc, rtp_fd, rtcp_fd; | ||||||
|  |  | ||||||
| 	snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id); | 	snprintf(name, sizeof(name), "%s-%s", conn->name, conn->id); | ||||||
| 	end = &conn->end; |  | ||||||
|  |  | ||||||
| 	if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) || | 	if ((end->rtp && osmo_iofd_get_fd(end->rtp) != -1) || | ||||||
| 	    (end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) { | 	    (end->rtcp && osmo_iofd_get_fd(end->rtcp) != -1)) { | ||||||
| 		LOGPENDP(endp, DRTP, LOGL_ERROR, "%u was already bound on conn:%s\n", | 		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "%u was already bound\n", rtp_port); | ||||||
| 			 rtp_port, mgcp_conn_dump(conn->conn)); |  | ||||||
|  |  | ||||||
| 		/* Double bindings should never occour! Since we always allocate | 		/* Double bindings should never occour! Since we always allocate | ||||||
| 		 * connections dynamically and free them when they are not | 		 * connections dynamically and free them when they are not | ||||||
| 		 * needed anymore, there must be no previous binding leftover. | 		 * needed anymore, there must be no previous binding leftover. | ||||||
| @@ -1710,33 +1651,55 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port, | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	end->local_port = rtp_port; | 	end->local_port = rtp_port; | ||||||
| 	end->rtp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn); | 	end->rtp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp); | ||||||
| 	if (!end->rtp) | 	if (!end->rtp) | ||||||
| 		return -EIO; | 		goto free_iofd_ret; | ||||||
| 	osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0); | 	osmo_iofd_set_alloc_info(end->rtp, RTP_BUF_SIZE, 0); | ||||||
| 	end->rtcp = osmo_iofd_setup(conn->conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn); | 	end->rtcp = osmo_iofd_setup(conn, -1, name, OSMO_IO_FD_MODE_RECVFROM_SENDTO, &rtp_ioops, conn_rtp); | ||||||
| 	if (!end->rtcp) { | 	if (!end->rtcp) | ||||||
| 		osmo_iofd_free(end->rtp); | 		goto free_iofd_ret; | ||||||
| 		end->rtp = NULL; |  | ||||||
| 		return -EIO; |  | ||||||
| 	} |  | ||||||
| 	osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0); | 	osmo_iofd_set_alloc_info(end->rtcp, RTP_BUF_SIZE, 0); | ||||||
| 	osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */ | 	osmo_iofd_set_priv_nr(end->rtcp, 1); /* we use priv_nr as identifier for RTCP */ | ||||||
|  |  | ||||||
| 	return bind_rtp(endp->trunk->cfg, conn->end.local_addr, end, endp); | 	/* NOTE: The port that is used for RTCP is the RTP port incremented by one | ||||||
| } | 	 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */ | ||||||
|  |  | ||||||
| /*! free allocated RTP and RTCP ports. | 	rc = mgcp_create_bind(end->local_addr, end->local_port, cfg->endp_dscp, cfg->endp_priority); | ||||||
|  *  \param[in] end RTP end */ | 	if (rc < 0) { | ||||||
| void mgcp_free_rtp_port(struct mgcp_rtp_end *end) | 		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTP port: %s:%d\n", end->local_addr, end->local_port); | ||||||
| { | 		goto free_iofd_ret; | ||||||
| 	if (end->rtp) { | 	} | ||||||
| 		osmo_iofd_free(end->rtp); | 	rtp_fd = rc; | ||||||
| 		end->rtp = NULL; |  | ||||||
|  | 	rc = mgcp_create_bind(end->local_addr, end->local_port + 1, cfg->endp_dscp, cfg->endp_priority); | ||||||
|  | 	if (rc < 0) { | ||||||
|  | 		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to create RTCP port: %s:%d\n", end->local_addr, end->local_port + 1); | ||||||
|  | 		goto cleanup1; | ||||||
|  | 	} | ||||||
|  | 	rtcp_fd = rc; | ||||||
|  |  | ||||||
|  | 	if (osmo_iofd_register(end->rtp, rtp_fd) < 0) { | ||||||
|  | 		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTP port %d\n", end->local_port); | ||||||
|  | 		goto cleanup2; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (end->rtcp) { | 	if (osmo_iofd_register(end->rtcp, rtcp_fd) != 0) { | ||||||
| 		osmo_iofd_free(end->rtcp); | 		LOG_CONN_RTP(conn_rtp, LOGL_ERROR, "failed to register RTCP port %d\n", end->local_port + 1); | ||||||
| 		end->rtcp = NULL; | 		goto cleanup3; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | cleanup3: | ||||||
|  | 	osmo_iofd_unregister(end->rtp); | ||||||
|  | cleanup2: | ||||||
|  | 	close(rtcp_fd); | ||||||
|  | cleanup1: | ||||||
|  | 	close(rtp_fd); | ||||||
|  | free_iofd_ret: | ||||||
|  | 	osmo_iofd_free(end->rtcp); | ||||||
|  | 	end->rtcp = NULL; | ||||||
|  | 	osmo_iofd_free(end->rtp); | ||||||
|  | 	end->rtp = NULL; | ||||||
|  | 	return -EIO; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -265,7 +265,7 @@ osmux_conn_lookup(const struct mgcp_trunk *trunk, uint8_t local_cid, const struc | |||||||
| 			if (conn->type != MGCP_CONN_TYPE_RTP) | 			if (conn->type != MGCP_CONN_TYPE_RTP) | ||||||
| 				continue; | 				continue; | ||||||
|  |  | ||||||
| 			conn_rtp = &conn->u.rtp; | 			conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
| 			if (!mgcp_conn_rtp_is_osmux(conn_rtp)) | 			if (!mgcp_conn_rtp_is_osmux(conn_rtp)) | ||||||
| 				continue; | 				continue; | ||||||
|  |  | ||||||
| @@ -651,7 +651,7 @@ int conn_osmux_enable(struct mgcp_conn_rtp *conn) | |||||||
| 	osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out, | 	osmux_xfrm_output_set_rtp_ssrc(conn->osmux.out, | ||||||
| 				       (conn->osmux.remote_cid * rtp_ssrc_winlen) + | 				       (conn->osmux.remote_cid * rtp_ssrc_winlen) + | ||||||
| 				       (random() % rtp_ssrc_winlen)); | 				       (random() % rtp_ssrc_winlen)); | ||||||
| 	osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.codec->payload_type); | 	osmux_xfrm_output_set_rtp_pl_type(conn->osmux.out, conn->end.cset.codec->payload_type); | ||||||
| 	osmux_xfrm_output_set_tx_cb(conn->osmux.out, | 	osmux_xfrm_output_set_tx_cb(conn->osmux.out, | ||||||
| 				    scheduled_from_osmux_tx_rtp_cb, conn); | 				    scheduled_from_osmux_tx_rtp_cb, conn); | ||||||
|  |  | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/libosmo-mgcp/mgcp_rtp_end.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | |||||||
|  | /* 'mgcp_rtp_end': basically a wrapper around the RTP+RTCP ports */ | ||||||
|  | /* | ||||||
|  |  * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org> | ||||||
|  |  * (C) 2009-2012 by On-Waves | ||||||
|  |  * (C) 2013-2024 by sysmocom - s.f.m.c. GmbH | ||||||
|  |  * All Rights Reserved | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU Affero General Public License as published by | ||||||
|  |  * the Free Software Foundation; either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU Affero General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU Affero General Public License | ||||||
|  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
|  | #include <osmocom/core/select.h> | ||||||
|  | #include <osmocom/core/socket.h> | ||||||
|  | #include <osmocom/core/osmo_io.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_rtp_end.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_codec.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_conn.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_endp.h> | ||||||
|  | #include <osmocom/mgcp/mgcp_trunk.h> | ||||||
|  |  | ||||||
|  | /*********************** | ||||||
|  |  * mgcp_rtp_end | ||||||
|  |  **********************/ | ||||||
|  |  | ||||||
|  | void mgcp_rtp_end_init(struct mgcp_rtp_end *end, struct mgcp_conn_rtp *conn_rtp) | ||||||
|  | { | ||||||
|  | 	struct mgcp_trunk *trunk = conn_rtp->conn->endp->trunk; | ||||||
|  | 	struct mgcp_config *cfg = trunk->cfg; | ||||||
|  |  | ||||||
|  | 	end->conn_rtp = conn_rtp; | ||||||
|  | 	end->rtp = NULL; | ||||||
|  | 	end->rtcp = NULL; | ||||||
|  | 	memset(&end->addr, 0, sizeof(end->addr)); | ||||||
|  | 	end->rtcp_port = 0; | ||||||
|  |  | ||||||
|  | 	/* Set default values */ | ||||||
|  | 	end->frames_per_packet = 0;	/* unknown */ | ||||||
|  | 	end->output_enabled = false; | ||||||
|  | 	end->maximum_packet_time = -1; | ||||||
|  |  | ||||||
|  | 	end->force_aligned_timing = trunk->force_aligned_timing; | ||||||
|  | 	end->force_constant_ssrc = trunk->force_constant_ssrc; | ||||||
|  | 	end->rfc5993_hr_convert = trunk->rfc5993_hr_convert; | ||||||
|  |  | ||||||
|  | 	if (cfg->force_ptime) { | ||||||
|  | 		end->packet_duration_ms = cfg->force_ptime; | ||||||
|  | 		end->force_output_ptime = 1; | ||||||
|  | 	} else { | ||||||
|  | 		end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Make sure codec table is reset */ | ||||||
|  | 	mgcp_codecset_reset(&end->cset); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mgcp_rtp_end_cleanup(struct mgcp_rtp_end *end) | ||||||
|  | { | ||||||
|  | 	mgcp_rtp_end_free_port(end); | ||||||
|  | 	mgcp_codecset_reset(&end->cset); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mgcp_rtp_end_set_packet_duration_ms(struct mgcp_rtp_end *end, uint32_t packet_duration_ms) | ||||||
|  | { | ||||||
|  | 	if (end->force_output_ptime) | ||||||
|  | 		return; | ||||||
|  | 	end->packet_duration_ms = packet_duration_ms; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool mgcp_rtp_end_remote_addr_available(const struct mgcp_rtp_end *rtp_end) | ||||||
|  | { | ||||||
|  | 	return (osmo_sockaddr_port(&rtp_end->addr.u.sa) != 0) && | ||||||
|  | 	       (osmo_sockaddr_is_any(&rtp_end->addr) == 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*! free allocated RTP and RTCP ports. | ||||||
|  |  *  \param[in] end RTP end */ | ||||||
|  | void mgcp_rtp_end_free_port(struct mgcp_rtp_end *end) | ||||||
|  | { | ||||||
|  | 	if (end->rtp) { | ||||||
|  | 		osmo_iofd_free(end->rtp); | ||||||
|  | 		end->rtp = NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (end->rtcp) { | ||||||
|  | 		osmo_iofd_free(end->rtcp); | ||||||
|  | 		end->rtcp = NULL; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -312,16 +312,13 @@ static struct mgcp_codec_param *param_by_pt(int pt, struct sdp_fmtp_param *fmtp_ | |||||||
| } | } | ||||||
|  |  | ||||||
| /*! Analyze SDP input string. | /*! Analyze SDP input string. | ||||||
|  *  \param[in] endp trunk endpoint. |  *  \param[inout] p provided memory to store the parsing results. | ||||||
|  *  \param[out] conn associated rtp connection. |  | ||||||
|  *  \param[out] caller provided memory to store the parsing results. |  | ||||||
|  * |  * | ||||||
|  *  Note: In conn (conn->end) the function returns the packet duration, |  | ||||||
|  *  rtp port, rtcp port and the codec information. |  | ||||||
|  *  \returns 0 on success, -1 on failure. */ |  *  \returns 0 on success, -1 on failure. */ | ||||||
| int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, | int mgcp_parse_sdp_data(struct mgcp_parse_data *p) | ||||||
| 			struct mgcp_conn_rtp *conn, struct mgcp_parse_data *p) |  | ||||||
| { | { | ||||||
|  | 	OSMO_ASSERT(p); | ||||||
|  | 	struct mgcp_parse_sdp *sdp = &p->sdp; | ||||||
| 	struct sdp_rtp_map codecs[MGCP_MAX_CODECS]; | 	struct sdp_rtp_map codecs[MGCP_MAX_CODECS]; | ||||||
| 	unsigned int codecs_used = 0; | 	unsigned int codecs_used = 0; | ||||||
| 	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS]; | 	struct sdp_fmtp_param fmtp_params[MGCP_MAX_CODECS]; | ||||||
| @@ -331,19 +328,14 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, | |||||||
| 	char *line; | 	char *line; | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	void *tmp_ctx = talloc_new(NULL); | 	void *tmp_ctx = talloc_new(NULL); | ||||||
| 	struct mgcp_rtp_end *rtp; |  | ||||||
|  |  | ||||||
| 	int payload_type; | 	int payload_type; | ||||||
| 	int ptime, ptime2 = 0; | 	int ptime, ptime2 = 0; | ||||||
| 	char audio_name[64]; | 	char audio_name[64]; | ||||||
| 	int port, rc; | 	int port, rc; | ||||||
|  |  | ||||||
| 	OSMO_ASSERT(endp); |  | ||||||
| 	OSMO_ASSERT(conn); |  | ||||||
| 	OSMO_ASSERT(p); |  | ||||||
|  |  | ||||||
| 	rtp = &conn->end; |  | ||||||
| 	memset(&codecs, 0, sizeof(codecs)); | 	memset(&codecs, 0, sizeof(codecs)); | ||||||
|  | 	mgcp_parse_sdp_init(sdp); | ||||||
|  |  | ||||||
| 	for_each_line(line, p->save) { | 	for_each_line(line, p->save) { | ||||||
| 		switch (line[0]) { | 		switch (line[0]) { | ||||||
| @@ -361,19 +353,19 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, | |||||||
|  |  | ||||||
| 			if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) { | 			if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) { | ||||||
| 				if (ptime2 > 0 && ptime2 != ptime) | 				if (ptime2 > 0 && ptime2 != ptime) | ||||||
| 					rtp->packet_duration_ms = 0; | 					sdp->ptime = 0; | ||||||
| 				else | 				else | ||||||
| 					rtp->packet_duration_ms = ptime; | 					sdp->ptime = ptime; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) { | 			if (sscanf(line, "a=maxptime:%d", &ptime2) == 1) { | ||||||
| 				rtp->maximum_packet_time = ptime2; | 				sdp->maxptime = ptime2; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (strncmp("a=fmtp:", line, 6) == 0) { | 			if (strncmp("a=fmtp:", line, 6) == 0) { | ||||||
| 				rc = fmtp_from_sdp(conn->conn, &fmtp_params[fmtp_used], line); | 				rc = fmtp_from_sdp(tmp_ctx, &fmtp_params[fmtp_used], line); | ||||||
| 				if (rc >= 0) | 				if (rc >= 0) | ||||||
| 					fmtp_used++; | 					fmtp_used++; | ||||||
| 				break; | 				break; | ||||||
| @@ -382,33 +374,23 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, | |||||||
| 			break; | 			break; | ||||||
| 		case 'm': | 		case 'm': | ||||||
| 			rc = sscanf(line, "m=audio %d RTP/AVP", &port); | 			rc = sscanf(line, "m=audio %d RTP/AVP", &port); | ||||||
| 			if (rc == 1) { | 			if (rc == 1) | ||||||
| 				osmo_sockaddr_set_port(&rtp->addr.u.sa, port); | 				sdp->rtp_port = port; | ||||||
| 				rtp->rtcp_port = htons(port + 1); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			rc = pt_from_sdp(conn->conn, codecs, | 			rc = pt_from_sdp(tmp_ctx, codecs, ARRAY_SIZE(codecs), line); | ||||||
| 					 ARRAY_SIZE(codecs), line); |  | ||||||
| 			if (rc > 0) | 			if (rc > 0) | ||||||
| 				codecs_used = rc; | 				codecs_used = rc; | ||||||
| 			break; | 			break; | ||||||
| 		case 'c': | 		case 'c': | ||||||
| 			if (audio_ip_from_sdp(&rtp->addr, line) < 0) { | 			if (audio_ip_from_sdp(&sdp->rem_addr, line) < 0) { | ||||||
| 				talloc_free(tmp_ctx); | 				talloc_free(tmp_ctx); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			if (endp) | 			LOGP(DLMGCP, LOGL_NOTICE, | ||||||
| 				/* TODO: Check spec: We used the bare endpoint number before, | 			     "Unhandled SDP option: '%c'/%d on %s\n", | ||||||
| 				 * now we use the endpoint name as a whole? Is this allowed? */ | 			     line[0], line[0], p->epname); | ||||||
| 				LOGP(DLMGCP, LOGL_NOTICE, |  | ||||||
| 				     "Unhandled SDP option: '%c'/%d on %s\n", |  | ||||||
| 				     line[0], line[0], endp->name); |  | ||||||
| 			else |  | ||||||
| 				LOGP(DLMGCP, LOGL_NOTICE, |  | ||||||
| 				     "Unhandled SDP option: '%c'/%d\n", |  | ||||||
| 				     line[0], line[0]); |  | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -422,23 +404,22 @@ int mgcp_parse_sdp_data(const struct mgcp_endpoint *endp, | |||||||
| 	/* Store parsed codec information */ | 	/* Store parsed codec information */ | ||||||
| 	for (i = 0; i < codecs_used; i++) { | 	for (i = 0; i < codecs_used; i++) { | ||||||
| 		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used); | 		codec_param = param_by_pt(codecs[i].payload_type, fmtp_params, fmtp_used); | ||||||
| 		rc = mgcp_codec_add(conn, codecs[i].payload_type, codecs[i].map_line, codec_param); | 		rc = mgcp_codecset_add_codec(&sdp->cset, codecs[i].payload_type, codecs[i].map_line, codec_param); | ||||||
| 		if (rc < 0) | 		if (rc < 0) | ||||||
| 			LOGPENDP(endp, DLMGCP, LOGL_NOTICE, "failed to add codec\n"); | 			LOGP(DLMGCP, LOGL_NOTICE, "%s: failed to add codec\n", p->epname); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	talloc_free(tmp_ctx); | 	talloc_free(tmp_ctx); | ||||||
|  |  | ||||||
| 	LOGPCONN(conn->conn, DLMGCP, LOGL_NOTICE, | 	LOGP(DLMGCP, LOGL_NOTICE, | ||||||
| 	     "Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:", | 	     "%s: Got media info via SDP: port:%d, addr:%s, duration:%d, payload-types:", | ||||||
| 	     osmo_sockaddr_port(&rtp->addr.u.sa), osmo_sockaddr_ntop(&rtp->addr.u.sa, ipbuf), | 	     p->epname, sdp->rtp_port, osmo_sockaddr_ntop(&sdp->rem_addr.u.sa, ipbuf), sdp->ptime); | ||||||
| 	     rtp->packet_duration_ms); |  | ||||||
| 	if (codecs_used == 0) | 	if (codecs_used == 0) | ||||||
| 		LOGPC(DLMGCP, LOGL_NOTICE, "none"); | 		LOGPC(DLMGCP, LOGL_NOTICE, "none"); | ||||||
| 	for (i = 0; i < codecs_used; i++) { | 	for (i = 0; i < codecs_used; i++) { | ||||||
| 		LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s", | 		LOGPC(DLMGCP, LOGL_NOTICE, "%d=%s", | ||||||
| 		      rtp->codecs[i].payload_type, | 		      sdp->cset.codecs[i].payload_type, | ||||||
| 		      strlen(rtp->codecs[i].subtype_name) ? rtp->codecs[i].subtype_name : "unknown"); | 		      strlen(sdp->cset.codecs[i].subtype_name) ? sdp->cset.codecs[i].subtype_name : "unknown"); | ||||||
| 		LOGPC(DLMGCP, LOGL_NOTICE, " "); | 		LOGPC(DLMGCP, LOGL_NOTICE, " "); | ||||||
| 	} | 	} | ||||||
| 	LOGPC(DLMGCP, LOGL_NOTICE, "\n"); | 	LOGPC(DLMGCP, LOGL_NOTICE, "\n"); | ||||||
| @@ -542,7 +523,7 @@ int mgcp_write_response_sdp(const struct mgcp_endpoint *endp, | |||||||
| 	OSMO_ASSERT(sdp); | 	OSMO_ASSERT(sdp); | ||||||
| 	OSMO_ASSERT(addr); | 	OSMO_ASSERT(addr); | ||||||
|  |  | ||||||
| 	codec = conn->end.codec; | 	codec = conn->end.cset.codec; | ||||||
|  |  | ||||||
| 	audio_name = codec->audio_name; | 	audio_name = codec->audio_name; | ||||||
| 	payload_type = codec->payload_type; | 	payload_type = codec->payload_type; | ||||||
|   | |||||||
| @@ -141,7 +141,7 @@ void mgcp_format_stats(char *str, size_t str_len, struct mgcp_conn *conn) | |||||||
| 	 * keep this option open: */ | 	 * keep this option open: */ | ||||||
| 	switch (conn->type) { | 	switch (conn->type) { | ||||||
| 	case MGCP_CONN_TYPE_RTP: | 	case MGCP_CONN_TYPE_RTP: | ||||||
| 		mgcp_format_stats_rtp(str, str_len, &conn->u.rtp); | 		mgcp_format_stats_rtp(str, str_len, mgcp_conn_get_conn_rtp(conn)); | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		break; | 		break; | ||||||
|   | |||||||
| @@ -306,3 +306,43 @@ struct mgcp_trunk *mgcp_trunk_by_line_num(const struct mgcp_config *cfg, unsigne | |||||||
|  |  | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Try to find a free port by attempting to bind on it. Also handle the | ||||||
|  |  * counter that points on the next free port. Since we have a pointer | ||||||
|  |  * to the next free port, binding should in work on the first attempt in | ||||||
|  |  * general. In case of failure the next port is tried until the whole port | ||||||
|  |  * range is tried once. */ | ||||||
|  | int mgcp_trunk_allocate_conn_rtp_ports(struct mgcp_trunk *trunk, struct mgcp_conn_rtp *conn_rtp) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	struct mgcp_port_range *range; | ||||||
|  | 	unsigned int tries; | ||||||
|  |  | ||||||
|  | 	OSMO_ASSERT(trunk); | ||||||
|  | 	OSMO_ASSERT(conn_rtp); | ||||||
|  |  | ||||||
|  | 	range = &trunk->cfg->net_ports; | ||||||
|  |  | ||||||
|  | 	pthread_mutex_lock(&range->lock); | ||||||
|  | 	/* attempt to find a port */ | ||||||
|  | 	tries = (range->range_end - range->range_start) / 2; | ||||||
|  | 	for (i = 0; i < tries; ++i) { | ||||||
|  | 		int rc; | ||||||
|  |  | ||||||
|  | 		if (range->last_port >= range->range_end) | ||||||
|  | 			range->last_port = range->range_start; | ||||||
|  |  | ||||||
|  | 		rc = mgcp_conn_rtp_bind_rtp_ports(conn_rtp, range->last_port); | ||||||
|  |  | ||||||
|  | 		range->last_port += 2; | ||||||
|  | 		if (rc == 0) { | ||||||
|  | 			pthread_mutex_unlock(&range->lock); | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | 	pthread_mutex_unlock(&range->lock); | ||||||
|  | 	LOGPCONN(conn_rtp->conn, DLMGCP, LOGL_ERROR, | ||||||
|  | 		 "Allocating a RTP/RTCP port failed %u times.\n", tries); | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -165,7 +165,7 @@ static void dump_rtp_end(struct vty *vty, struct mgcp_conn_rtp *conn) | |||||||
| { | { | ||||||
| 	struct mgcp_rtp_state *state = &conn->state; | 	struct mgcp_rtp_state *state = &conn->state; | ||||||
| 	struct mgcp_rtp_end *end = &conn->end; | 	struct mgcp_rtp_end *end = &conn->end; | ||||||
| 	struct mgcp_rtp_codec *codec = end->codec; | 	struct mgcp_rtp_codec *codec = end->cset.codec; | ||||||
| 	struct rate_ctr *tx_packets, *tx_bytes; | 	struct rate_ctr *tx_packets, *tx_bytes; | ||||||
| 	struct rate_ctr *rx_packets, *rx_bytes; | 	struct rate_ctr *rx_packets, *rx_bytes; | ||||||
| 	struct rate_ctr *dropped_packets; | 	struct rate_ctr *dropped_packets; | ||||||
| @@ -254,7 +254,8 @@ static void dump_endpoint(struct vty *vty, struct mgcp_endpoint *endp, | |||||||
| 			 * connection types (E1) as soon as | 			 * connection types (E1) as soon as | ||||||
| 			 * the implementation is available */ | 			 * the implementation is available */ | ||||||
| 			if (conn->type == MGCP_CONN_TYPE_RTP) { | 			if (conn->type == MGCP_CONN_TYPE_RTP) { | ||||||
| 				dump_rtp_end(vty, &conn->u.rtp); | 				struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
|  | 				dump_rtp_end(vty, conn_rtp); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -856,7 +857,7 @@ DEFUN_USRATTR(cfg_mgcp_patch_rtp_ssrc, | |||||||
| { | { | ||||||
| 	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); | 	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); | ||||||
| 	OSMO_ASSERT(trunk); | 	OSMO_ASSERT(trunk); | ||||||
| 	trunk->force_constant_ssrc = 1; | 	trunk->force_constant_ssrc = true; | ||||||
| 	return CMD_SUCCESS; | 	return CMD_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -867,7 +868,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp_ssrc, | |||||||
| { | { | ||||||
| 	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); | 	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); | ||||||
| 	OSMO_ASSERT(trunk); | 	OSMO_ASSERT(trunk); | ||||||
| 	trunk->force_constant_ssrc = 0; | 	trunk->force_constant_ssrc = false; | ||||||
| 	return CMD_SUCCESS; | 	return CMD_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -922,7 +923,7 @@ DEFUN_USRATTR(cfg_mgcp_no_patch_rtp, | |||||||
| { | { | ||||||
| 	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); | 	struct mgcp_trunk *trunk = mgcp_trunk_by_num(g_cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID); | ||||||
| 	OSMO_ASSERT(trunk); | 	OSMO_ASSERT(trunk); | ||||||
| 	trunk->force_constant_ssrc = 0; | 	trunk->force_constant_ssrc = false; | ||||||
| 	trunk->force_aligned_timing = 0; | 	trunk->force_aligned_timing = 0; | ||||||
| 	trunk->rfc5993_hr_convert = false; | 	trunk->rfc5993_hr_convert = false; | ||||||
| 	return CMD_SUCCESS; | 	return CMD_SUCCESS; | ||||||
| @@ -1196,7 +1197,7 @@ DEFUN_USRATTR(cfg_trunk_patch_rtp_ssrc, | |||||||
| 	      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n") | 	      "rtp-patch ssrc", RTP_PATCH_STR "Force a fixed SSRC\n") | ||||||
| { | { | ||||||
| 	struct mgcp_trunk *trunk = vty->index; | 	struct mgcp_trunk *trunk = vty->index; | ||||||
| 	trunk->force_constant_ssrc = 1; | 	trunk->force_constant_ssrc = true; | ||||||
| 	return CMD_SUCCESS; | 	return CMD_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1206,7 +1207,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp_ssrc, | |||||||
| 	      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n") | 	      "no rtp-patch ssrc", NO_STR RTP_PATCH_STR "Force a fixed SSRC\n") | ||||||
| { | { | ||||||
| 	struct mgcp_trunk *trunk = vty->index; | 	struct mgcp_trunk *trunk = vty->index; | ||||||
| 	trunk->force_constant_ssrc = 0; | 	trunk->force_constant_ssrc = false; | ||||||
| 	return CMD_SUCCESS; | 	return CMD_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1256,7 +1257,7 @@ DEFUN_USRATTR(cfg_trunk_no_patch_rtp, | |||||||
| 	      "no rtp-patch", NO_STR RTP_PATCH_STR) | 	      "no rtp-patch", NO_STR RTP_PATCH_STR) | ||||||
| { | { | ||||||
| 	struct mgcp_trunk *trunk = vty->index; | 	struct mgcp_trunk *trunk = vty->index; | ||||||
| 	trunk->force_constant_ssrc = 0; | 	trunk->force_constant_ssrc = false; | ||||||
| 	trunk->force_aligned_timing = 0; | 	trunk->force_aligned_timing = 0; | ||||||
| 	trunk->rfc5993_hr_convert = false; | 	trunk->rfc5993_hr_convert = false; | ||||||
| 	return CMD_SUCCESS; | 	return CMD_SUCCESS; | ||||||
| @@ -1357,10 +1358,11 @@ DEFUN(loop_conn, | |||||||
| 	endp = trunk->endpoints[endp_no]; | 	endp = trunk->endpoints[endp_no]; | ||||||
| 	int loop = atoi(argv[2]); | 	int loop = atoi(argv[2]); | ||||||
| 	llist_for_each_entry(conn, &endp->conns, entry) { | 	llist_for_each_entry(conn, &endp->conns, entry) { | ||||||
| 		if (conn->type == MGCP_CONN_TYPE_RTP) | 		if (conn->type == MGCP_CONN_TYPE_RTP) { | ||||||
| 			/* Handle it like a MDCX, switch on SSRC patching if enabled */ | 			/* Handle it like a MDCX, switch on SSRC patching if enabled */ | ||||||
| 			mgcp_rtp_end_config(endp, 1, &conn->u.rtp.end); | 			struct mgcp_conn_rtp *conn_rtp = mgcp_conn_get_conn_rtp(conn); | ||||||
| 		else { | 			conn_rtp->state.patch.patch_ssrc = true; | ||||||
|  | 		} else { | ||||||
| 			/* FIXME: Introduce support for other connection (E1) | 			/* FIXME: Introduce support for other connection (E1) | ||||||
| 			 * types when implementation is available */ | 			 * types when implementation is available */ | ||||||
| 			vty_out(vty, "%%Can't enable SSRC patching," | 			vty_out(vty, "%%Can't enable SSRC patching," | ||||||
| @@ -1418,7 +1420,7 @@ DEFUN(tap_rtp, | |||||||
| 	endp = trunk->endpoints[endp_no]; | 	endp = trunk->endpoints[endp_no]; | ||||||
|  |  | ||||||
| 	conn_id = argv[2]; | 	conn_id = argv[2]; | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	if (!conn) { | 	if (!conn) { | ||||||
| 		vty_out(vty, "Conn ID %s is invalid.%s", | 		vty_out(vty, "Conn ID %s is invalid.%s", | ||||||
| 			conn_id, VTY_NEWLINE); | 			conn_id, VTY_NEWLINE); | ||||||
|   | |||||||
| @@ -965,7 +965,7 @@ static void test_messages(void) | |||||||
| 			endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 			endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 			OSMO_ASSERT(endp); | 			OSMO_ASSERT(endp); | ||||||
|  |  | ||||||
| 			conn = mgcp_conn_get_rtp(endp, "1"); | 			conn = mgcp_endp_get_conn_rtp(endp, "1"); | ||||||
| 			if (conn) { | 			if (conn) { | ||||||
| 				OSMO_ASSERT(conn); | 				OSMO_ASSERT(conn); | ||||||
|  |  | ||||||
| @@ -1023,14 +1023,14 @@ static void test_messages(void) | |||||||
| 			fprintf(stderr, "endpoint:%s: " | 			fprintf(stderr, "endpoint:%s: " | ||||||
| 				"payload type %d (expected %d)\n", | 				"payload type %d (expected %d)\n", | ||||||
| 				last_endpoint, | 				last_endpoint, | ||||||
| 				conn->end.codec->payload_type, t->ptype); | 				conn->end.cset.codec->payload_type, t->ptype); | ||||||
|  |  | ||||||
| 			if (t->ptype != PTYPE_IGNORE) | 			if (t->ptype != PTYPE_IGNORE) | ||||||
| 				OSMO_ASSERT(conn->end.codec->payload_type == | 				OSMO_ASSERT(conn->end.cset.codec->payload_type == | ||||||
| 					    t->ptype); | 					    t->ptype); | ||||||
|  |  | ||||||
| 			/* Reset them again for next test */ | 			/* Reset them again for next test */ | ||||||
| 			conn->end.codec->payload_type = PTYPE_NONE; | 			conn->end.cset.codec->payload_type = PTYPE_NONE; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1209,7 +1209,7 @@ static void test_packet_loss_calc(void) | |||||||
| 		    mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP, | 		    mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP, | ||||||
| 				    "test-connection"); | 				    "test-connection"); | ||||||
| 		OSMO_ASSERT(_conn); | 		OSMO_ASSERT(_conn); | ||||||
| 		conn = mgcp_conn_get_rtp(&endp, _conn->id); | 		conn = mgcp_endp_get_conn_rtp(&endp, _conn->id); | ||||||
| 		OSMO_ASSERT(conn); | 		OSMO_ASSERT(conn); | ||||||
| 		state = &conn->state; | 		state = &conn->state; | ||||||
| 		packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR); | 		packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR); | ||||||
| @@ -1230,7 +1230,7 @@ static void test_packet_loss_calc(void) | |||||||
| 			     pl_test_dat[i].expected); | 			     pl_test_dat[i].expected); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		mgcp_conn_free_all(&endp); | 		mgcp_endp_free_conn_all(&endp); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	talloc_free(trunk); | 	talloc_free(trunk); | ||||||
| @@ -1461,13 +1461,13 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) | |||||||
| 	_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP, | 	_conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP, | ||||||
| 				"test-connection"); | 				"test-connection"); | ||||||
| 	OSMO_ASSERT(_conn); | 	OSMO_ASSERT(_conn); | ||||||
| 	conn = mgcp_conn_get_rtp(&endp, _conn->id); | 	conn = mgcp_endp_get_conn_rtp(&endp, _conn->id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
|  |  | ||||||
| 	rtp = &conn->end; | 	rtp = &conn->end; | ||||||
|  |  | ||||||
| 	OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0); | 	OSMO_ASSERT(mgcp_codecset_add_codec(&conn->end.cset, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0); | ||||||
| 	rtp->codec = &rtp->codecs[0]; | 	rtp->cset.codec = &rtp->cset.codecs[0]; | ||||||
|  |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { | 	for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { | ||||||
| 		struct rtp_packet_info *info = test_rtp_packets1 + i; | 		struct rtp_packet_info *info = test_rtp_packets1 + i; | ||||||
| @@ -1479,7 +1479,6 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) | |||||||
| 		OSMO_ASSERT(info->len >= 0); | 		OSMO_ASSERT(info->len >= 0); | ||||||
| 		msg->l3h = msgb_put(msg, info->len); | 		msg->l3h = msgb_put(msg, info->len); | ||||||
| 		memcpy((char*)msgb_l3(msg), info->data, info->len); | 		memcpy((char*)msgb_l3(msg), info->data, info->len); | ||||||
| 		mgcp_rtp_end_config(&endp, 1, rtp); |  | ||||||
|  |  | ||||||
| 		mgcp_patch_and_count(&endp, &state, rtp, &addr, msg); | 		mgcp_patch_and_count(&endp, &state, rtp, &addr, msg); | ||||||
|  |  | ||||||
| @@ -1513,7 +1512,7 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	force_monotonic_time_us = -1; | 	force_monotonic_time_us = -1; | ||||||
| 	mgcp_conn_free_all(&endp); | 	mgcp_endp_free_conn_all(&endp); | ||||||
| 	talloc_free(trunk); | 	talloc_free(trunk); | ||||||
| 	talloc_free(cfg); | 	talloc_free(cfg); | ||||||
| } | } | ||||||
| @@ -1548,9 +1547,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 18); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 18); | ||||||
|  |  | ||||||
| 	/* Allocate 2@mgw with three codecs, last one ignored */ | 	/* Allocate 2@mgw with three codecs, last one ignored */ | ||||||
| 	last_endpoint[0] = '\0'; | 	last_endpoint[0] = '\0'; | ||||||
| @@ -1564,9 +1563,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 18); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 18); | ||||||
|  |  | ||||||
| 	/* Allocate 3@mgw with no codecs, check for PT == 0 */ | 	/* Allocate 3@mgw with no codecs, check for PT == 0 */ | ||||||
| 	/* Note: It usually makes no sense to leave the payload type list | 	/* Note: It usually makes no sense to leave the payload type list | ||||||
| @@ -1585,9 +1584,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 0); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 0); | ||||||
|  |  | ||||||
| 	/* Allocate 4@mgw with a single codec */ | 	/* Allocate 4@mgw with a single codec */ | ||||||
| 	last_endpoint[0] = '\0'; | 	last_endpoint[0] = '\0'; | ||||||
| @@ -1601,9 +1600,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 18); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 18); | ||||||
|  |  | ||||||
| 	/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */ | 	/* Allocate 5@mgw and let osmo-mgw pick a codec from the list */ | ||||||
| 	last_endpoint[0] = '\0'; | 	last_endpoint[0] = '\0'; | ||||||
| @@ -1617,9 +1616,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 0); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 0); | ||||||
|  |  | ||||||
| 	inp = create_msg(MDCX_NAT_DUMMY, conn_id); | 	inp = create_msg(MDCX_NAT_DUMMY, conn_id); | ||||||
| 	last_endpoint[0] = '\0'; | 	last_endpoint[0] = '\0'; | ||||||
| @@ -1629,9 +1628,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 3); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 3); | ||||||
| 	OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434); | 	OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434); | ||||||
| 	memset(&addr, 0, sizeof(addr)); | 	memset(&addr, 0, sizeof(addr)); | ||||||
| 	inet_aton("8.8.8.8", &addr); | 	inet_aton("8.8.8.8", &addr); | ||||||
| @@ -1646,7 +1645,7 @@ static void test_multilple_codec(void) | |||||||
| 	talloc_free(endp->last_response); | 	talloc_free(endp->last_response); | ||||||
| 	talloc_free(endp->last_trans); | 	talloc_free(endp->last_trans); | ||||||
| 	endp->last_response = endp->last_trans = NULL; | 	endp->last_response = endp->last_trans = NULL; | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(!conn); | 	OSMO_ASSERT(!conn); | ||||||
|  |  | ||||||
| 	last_endpoint[0] = '\0'; | 	last_endpoint[0] = '\0'; | ||||||
| @@ -1660,9 +1659,9 @@ static void test_multilple_codec(void) | |||||||
| 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0); | 	OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0); | ||||||
| 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | 	endp = mgcp_endp_by_name(NULL, last_endpoint, cfg); | ||||||
| 	OSMO_ASSERT(endp); | 	OSMO_ASSERT(endp); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, conn_id); | 	conn = mgcp_endp_get_conn_rtp(endp, conn_id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
| 	OSMO_ASSERT(conn->end.codec->payload_type == 0); | 	OSMO_ASSERT(conn->end.cset.codec->payload_type == 0); | ||||||
|  |  | ||||||
| 	mgcp_endpoints_release(trunk); | 	mgcp_endpoints_release(trunk); | ||||||
| 	talloc_free(cfg); | 	talloc_free(cfg); | ||||||
| @@ -1689,7 +1688,7 @@ static void test_no_cycle(void) | |||||||
| 	_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, | 	_conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP, | ||||||
| 				"test-connection"); | 				"test-connection"); | ||||||
| 	OSMO_ASSERT(_conn); | 	OSMO_ASSERT(_conn); | ||||||
| 	conn = mgcp_conn_get_rtp(endp, _conn->id); | 	conn = mgcp_endp_get_conn_rtp(endp, _conn->id); | ||||||
| 	OSMO_ASSERT(conn); | 	OSMO_ASSERT(conn); | ||||||
|  |  | ||||||
| 	OSMO_ASSERT(conn->state.stats.initialized == 0); | 	OSMO_ASSERT(conn->state.stats.initialized == 0); | ||||||
| @@ -2195,7 +2194,7 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s | |||||||
| 	int payload_type_conn_dst; | 	int payload_type_conn_dst; | ||||||
|  |  | ||||||
| 	printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst); | 	printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst); | ||||||
| 	if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) { | 	if (mgcp_codecset_decide(&conn[index_conn_src].end.cset, &conn[index_conn_dst].end.cset) != 0) { | ||||||
| 		if (expect->payload_type_map[index_conn_src] == -EINVAL | 		if (expect->payload_type_map[index_conn_src] == -EINVAL | ||||||
| 		    && expect->payload_type_map[index_conn_dst] == -EINVAL) | 		    && expect->payload_type_map[index_conn_dst] == -EINVAL) | ||||||
| 			printf("    codec decision failed (expected)!\n"); | 			printf("    codec decision failed (expected)!\n"); | ||||||
| @@ -2205,19 +2204,19 @@ static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_s | |||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		printf("    Codec decision result:\n"); | 		printf("    Codec decision result:\n"); | ||||||
| 		if (conn[index_conn_src].end.codec) { | 		if (conn[index_conn_src].end.cset.codec) { | ||||||
| 			payload_type_conn_src = conn[index_conn_src].end.codec->payload_type; | 			payload_type_conn_src = conn[index_conn_src].end.cset.codec->payload_type; | ||||||
| 			printf("    conn[%u]: codec:%s, pt:%d\n", | 			printf("    conn[%u]: codec:%s, pt:%d\n", | ||||||
| 			       index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src); | 			       index_conn_src, conn[index_conn_src].end.cset.codec->subtype_name, payload_type_conn_src); | ||||||
| 		} else { | 		} else { | ||||||
| 			payload_type_conn_src = -EINVAL; | 			payload_type_conn_src = -EINVAL; | ||||||
| 			printf("    conn[%u]: codec:none, pt:none\n", index_conn_src); | 			printf("    conn[%u]: codec:none, pt:none\n", index_conn_src); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (conn[index_conn_dst].end.codec) { | 		if (conn[index_conn_dst].end.cset.codec) { | ||||||
| 			payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type; | 			payload_type_conn_dst = conn[index_conn_dst].end.cset.codec->payload_type; | ||||||
| 			printf("    conn[%u]: codec:%s, pt:%d\n", | 			printf("    conn[%u]: codec:%s, pt:%d\n", | ||||||
| 			       index_conn_dst, conn[index_conn_dst].end.codec->subtype_name, | 			       index_conn_dst, conn[index_conn_dst].end.cset.codec->subtype_name, | ||||||
| 			       payload_type_conn_dst); | 			       payload_type_conn_dst); | ||||||
| 		} else { | 		} else { | ||||||
| 			payload_type_conn_dst = -EINVAL; | 			payload_type_conn_dst = -EINVAL; | ||||||
| @@ -2265,8 +2264,8 @@ static void test_mgcp_codec_decide(void) | |||||||
| 				if (!codec->audio_name) | 				if (!codec->audio_name) | ||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, | 				rc = mgcp_codecset_add_codec(&conn[conn_i].end.cset, codec->payload_type, | ||||||
| 						    codec->param); | 							     codec->audio_name, codec->param); | ||||||
|  |  | ||||||
| 				printf("   %2d: %3d %s%s  -> rc=%d\n", c, codec->payload_type, codec->audio_name, | 				printf("   %2d: %3d %s%s  -> rc=%d\n", c, codec->payload_type, codec->audio_name, | ||||||
| 				       codec->param ? | 				       codec->param ? | ||||||
| @@ -2332,7 +2331,7 @@ void test_conn_id_matching(void) | |||||||
| 	for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) { | 	for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) { | ||||||
| 		const char *needle = conn_id_request[i]; | 		const char *needle = conn_id_request[i]; | ||||||
| 		printf("needle='%s' ", needle); | 		printf("needle='%s' ", needle); | ||||||
| 		conn_match = mgcp_conn_get(&endp, needle); | 		conn_match = mgcp_endp_get_conn(&endp, needle); | ||||||
| 		OSMO_ASSERT(conn_match); | 		OSMO_ASSERT(conn_match); | ||||||
| 		printf("found '%s'\n", conn_match->id); | 		printf("found '%s'\n", conn_match->id); | ||||||
| 		OSMO_ASSERT(conn_match == conn); | 		OSMO_ASSERT(conn_match == conn); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user