1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2010, Mathieu Parent <math.parent@gmail.com>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Mathieu Parent <math.parent@gmail.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Mathieu Parent <math.parent@gmail.com>
27  *
28  *
29  * mod_skinny.h -- Skinny Call Control Protocol (SCCP) Endpoint Module
30  *
31  */
32 
33 #ifndef _MOD_SKINNY_H
34 #define _MOD_SKINNY_H
35 
36 #include <switch.h>
37 
38 /*****************************************************************************/
39 /* UTILITY MACROS */
40 /*****************************************************************************/
41 #define empty_null(a) ((a)?(a):NULL)
42 #define empty_null2(a,b) ((a)?(a):empty_null(b))
43 
44 /*****************************************************************************/
45 /* LOGGING FUNCTIONS */
46 /*****************************************************************************/
47 #define skinny_undef_str(x) (zstr(x) ? "_undef_" : x)
48 
49 #define skinny_log_l(listener, level, _fmt, ...) switch_log_printf(SWITCH_CHANNEL_LOG, level, \
50     "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \
51     listener->remote_port, __VA_ARGS__)
52 
53 #define skinny_log_l_msg(listener, level, _fmt) switch_log_printf(SWITCH_CHANNEL_LOG, level, \
54     "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \
55     listener->remote_port)
56 
57 #define skinny_log_l_ffl(listener, file, func, line, level, _fmt, ...) switch_log_printf( \
58 	SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, level, \
59     "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \
60     listener->remote_port, __VA_ARGS__)
61 
62 #define skinny_log_l_ffl_msg(listener, file, func, line, level, _fmt) switch_log_printf( \
63 	SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, level, \
64     "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \
65     listener->remote_port)
66 
67 #define skinny_log_ls(listener, session, level, _fmt, ...) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), level, \
68     "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \
69     listener->remote_port, __VA_ARGS__)
70 
71 #define skinny_log_ls_msg(listener, session, level, _fmt) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), level, \
72     "[%s:%d @ %s:%d] " _fmt, skinny_undef_str(listener->device_name), listener->device_instance, skinny_undef_str(listener->remote_ip), \
73     listener->remote_port)
74 
75 #define skinny_log_s(session, level, _fmt, ...) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), level, \
76     _fmt, __VA_ARGS__)
77 
78 
79 /*****************************************************************************/
80 /* MODULE TYPES */
81 /*****************************************************************************/
82 #define SKINNY_EVENT_REGISTER "skinny::register"
83 #define SKINNY_EVENT_UNREGISTER "skinny::unregister"
84 #define SKINNY_EVENT_EXPIRE "skinny::expire"
85 #define SKINNY_EVENT_ALARM "skinny::alarm"
86 #define SKINNY_EVENT_XML_ALARM "skinny::xml_alarm"
87 #define SKINNY_EVENT_CALL_STATE "skinny::call_state"
88 #define SKINNY_EVENT_USER_TO_DEVICE "skinny::user_to_device"
89 #define SKINNY_EVENT_DEVICE_TO_USER "skinny::device_to_user"
90 
91 struct skinny_globals {
92 	int running;
93 	switch_memory_pool_t *pool;
94 	switch_mutex_t *mutex;
95 	switch_hash_t *profile_hash;
96 	switch_event_node_t *user_to_device_node;
97 	switch_event_node_t *call_state_node;
98 	switch_event_node_t *message_waiting_node;
99 	switch_event_node_t *trap_node;
100 	int auto_restart;
101 };
102 typedef struct skinny_globals skinny_globals_t;
103 
104 extern skinny_globals_t skinny_globals;
105 
106 typedef enum {
107 	PFLAG_LISTENER_READY = (1 << 0),
108 	PFLAG_SHOULD_RESPAWN = (1 << 1),
109 	PFLAG_RESPAWN = (1 << 2),
110 } profile_flag_t;
111 
112 struct skinny_profile {
113 	/* prefs */
114 	char *name;
115 	char *domain;
116 	char *ip;
117 	unsigned int port;
118 	char *dialplan;
119 	char *context;
120 	char *patterns_dialplan;
121 	char *patterns_context;
122 	uint32_t keep_alive;
123 	uint32_t digit_timeout;
124 	char date_format[6];
125 	int debug;
126 	int auto_restart;
127 	int non_blocking;
128 	switch_hash_t *soft_key_set_sets_hash;
129 	switch_hash_t *device_type_params_hash;
130 	/* lock on device names for multiple connection handling */
131 	switch_mutex_t *device_name_lock_mutex;
132 	switch_hash_t *device_name_lock_hash;
133 	/* extensions */
134 	char *ext_voicemail;
135 	char *ext_redial;
136 	char *ext_meetme;
137 	char *ext_pickup;
138 	char *ext_cfwdall;
139 	/* db */
140 	char *dbname;
141 	char *odbc_dsn;
142 	switch_odbc_handle_t *master_odbc;
143 	switch_mutex_t *sql_mutex;
144 	/* stats */
145 	uint32_t ib_calls;
146 	uint32_t ob_calls;
147 	uint32_t ib_failed_calls;
148 	uint32_t ob_failed_calls;
149 	/* listener */
150 	int listener_threads;
151 	switch_mutex_t *listener_mutex;
152 	switch_socket_t *sock;
153 	switch_mutex_t *sock_mutex;
154 	struct listener *listeners;
155 	int flags;
156 	switch_mutex_t *flag_mutex;
157 	/* call id */
158 	uint32_t next_call_id;
159 	/* others */
160 	switch_memory_pool_t *pool;
161 };
162 typedef struct skinny_profile skinny_profile_t;
163 
164 struct skinny_device_type_params {
165 	char firmware_version[16];
166 };
167 typedef struct skinny_device_type_params skinny_device_type_params_t;
168 
169 typedef enum {
170 	SKINNY_ACTION_PROCESS,
171 	SKINNY_ACTION_DROP,
172 	SKINNY_ACTION_WAIT
173 } skinny_action_t;
174 
175 
176 
177 /*****************************************************************************/
178 /* DEVICE NAME LOCK TYPES */
179 /*****************************************************************************/
180 typedef enum {
181 	DNLFLAG_INUSE = (1 << 0),
182 } device_name_lock_flag_t;
183 
184 struct device_name_lock {
185 	char device_name[16];
186 	switch_mutex_t *flag_mutex;
187 	uint32_t flags;
188 };
189 
190 typedef struct device_name_lock device_name_lock_t;
191 
192 /*****************************************************************************/
193 /* LISTENERS TYPES */
194 /*****************************************************************************/
195 
196 typedef enum {
197 	LFLAG_RUNNING = (1 << 0),
198 } listener_flag_t;
199 
200 #define SKINNY_MAX_LINES 42
201 struct listener {
202 	skinny_profile_t *profile;
203 	char device_name[16];
204 	uint32_t device_instance;
205 	uint32_t device_type;
206 
207 	char firmware_version[16];
208 	char *soft_key_set_set;
209 
210 	switch_socket_t *sock;
211 	switch_memory_pool_t *pool;
212 	switch_thread_rwlock_t *rwlock;
213 	char remote_ip[50];
214 	switch_port_t remote_port;
215 	char local_ip[50];
216 	switch_port_t local_port;
217 	switch_mutex_t *flag_mutex;
218 	uint32_t flags;
219 	time_t expire_time;
220 	time_t connect_time;
221 	switch_time_t digit_timeout_time;
222 	struct listener *next;
223 	char *ext_voicemail;
224 	char *ext_redial;
225 	char *ext_meetme;
226 	char *ext_pickup;
227 	char *ext_cfwdall;
228 	char *ext_autodial;
229 };
230 
231 typedef struct listener listener_t;
232 
233 typedef switch_status_t (*skinny_listener_callback_func_t) (listener_t *listener, void *pvt);
234 
235 /*****************************************************************************/
236 /* CHANNEL TYPES */
237 /*****************************************************************************/
238 typedef enum {
239 	TFLAG_FORCE_ROUTE = (1 << 0),
240 	TFLAG_EARLY_MEDIA = (1 << 1),
241 	TFLAG_IO = (1 << 2),
242 	TFLAG_READING = (1 << 3),
243 	TFLAG_WRITING = (1 << 4)
244 } TFLAGS;
245 
246 typedef enum {
247 	GFLAG_MY_CODEC_PREFS = (1 << 0)
248 } GFLAGS;
249 
250 struct private_object {
251 	unsigned int flags;
252 	switch_mutex_t *flag_mutex;
253 	switch_frame_t read_frame;
254 	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
255 	switch_core_session_t *session;
256 	switch_caller_profile_t *caller_profile;
257 	switch_mutex_t *mutex;
258 
259 	/* identification */
260 	skinny_profile_t *profile;
261 	uint32_t call_id;
262 	uint32_t party_id;
263 
264 	/* related calls */
265 	uint32_t transfer_to_call_id;
266 	uint32_t transfer_from_call_id;
267 
268 	/* codec */
269 	char *iananame;
270 	switch_codec_t read_codec;
271 	switch_codec_t write_codec;
272 	switch_codec_implementation_t read_impl;
273 	switch_codec_implementation_t write_impl;
274 	unsigned long rm_rate;
275 	uint32_t codec_ms;
276 	char *rm_encoding;
277 	char *rm_fmtp;
278 	switch_payload_t agreed_pt;
279 	/* RTP */
280 	switch_rtp_t *rtp_session;
281 	char *local_sdp_audio_ip;
282 	switch_port_t local_sdp_audio_port;
283 	char *remote_sdp_audio_ip;
284 	switch_port_t remote_sdp_audio_port;
285 };
286 
287 typedef struct private_object private_t;
288 
289 /*****************************************************************************/
290 /* PROFILES FUNCTIONS */
291 /*****************************************************************************/
292 skinny_profile_t *skinny_find_profile(const char *profile_name);
293 switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stream_handle_t *stream);
294 switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener);
295 switch_status_t skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t *profile, const char *device_name, uint32_t device_instance, listener_t **listener);
296 char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id);
297 #ifdef SWITCH_DEBUG_RWLOCKS
298 switch_core_session_t * skinny_profile_perform_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id, const char *file, const char *func, int line);
299 #define skinny_profile_find_session(profile, listener, line_instance_p, call_id) skinny_profile_perform_find_session(profile, listener, line_instance_p, call_id, __FILE__, __SWITCH_FUNC__, __LINE__)
300 #else
301 switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id);
302 #endif
303 switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream);
304 switch_status_t skinny_profile_respawn(skinny_profile_t *profile, int force);
305 switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, const char *val);
306 void profile_walk_listeners(skinny_profile_t *profile, skinny_listener_callback_func_t callback, void *pvt);
307 
308 /*****************************************************************************/
309 /* SQL FUNCTIONS */
310 /*****************************************************************************/
311 switch_cache_db_handle_t *skinny_get_db_handle(skinny_profile_t *profile);
312 switch_status_t skinny_execute_sql(skinny_profile_t *profile, char *sql, switch_mutex_t *mutex);
313 switch_bool_t skinny_execute_sql_callback(skinny_profile_t *profile,
314 		switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata);
315 
316 /*****************************************************************************/
317 /* LISTENER FUNCTIONS */
318 /*****************************************************************************/
319 uint8_t listener_is_ready(listener_t *listener);
320 switch_status_t kill_listener(listener_t *listener, void *pvt);
321 switch_status_t keepalive_listener(listener_t *listener, void *pvt);
322 void skinny_clean_listener_from_db(listener_t *listener);
323 void skinny_clean_device_from_db(listener_t *listener, char *device_name);
324 
325 /*****************************************************************************/
326 /* DEVICE NAME LOCK FUNCTIONS */
327 /*****************************************************************************/
328 void skinny_lock_device_name(listener_t *listener, char *device_name);
329 void skinny_unlock_device_name(listener_t *listener, char *device_name);
330 
331 /*****************************************************************************/
332 /* CHANNEL FUNCTIONS */
333 /*****************************************************************************/
334 void skinny_line_perform_set_state(const char *file, const char *func, int line, listener_t *listener, uint32_t line_instance, uint32_t call_id, uint32_t call_state);
335 #define  skinny_line_set_state(listener, line_instance, call_id, call_state)  skinny_line_perform_set_state(__FILE__, __SWITCH_FUNC__, __LINE__, listener, line_instance, call_id, call_state)
336 
337 uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uint32_t call_id);
338 uint32_t skinny_line_count_active(listener_t *listener);
339 
340 switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force);
341 void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_session_t *session);
342 switch_status_t channel_on_init(switch_core_session_t *session);
343 switch_status_t channel_on_hangup(switch_core_session_t *session);
344 switch_status_t channel_on_destroy(switch_core_session_t *session);
345 switch_status_t channel_on_routing(switch_core_session_t *session);
346 switch_status_t channel_on_exchange_media(switch_core_session_t *session);
347 switch_status_t channel_on_soft_execute(switch_core_session_t *session);
348 switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
349 		switch_caller_profile_t *outbound_profile,
350 		switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
351 switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
352 switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
353 switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
354 
355 /*****************************************************************************/
356 /* MODULE FUNCTIONS */
357 /*****************************************************************************/
358 switch_endpoint_interface_t *skinny_get_endpoint_interface();
359 
360 /*****************************************************************************/
361 /* TEXT FUNCTIONS */
362 /*****************************************************************************/
363 #define skinny_textid2raw(label) (label > 0 ? switch_mprintf("\200%c", label) : switch_mprintf(""))
364 char *skinny_format_message(const char *str);
365 
366 #define SKINNY_MAX_STRING 16384
367 
368 #endif /* _MOD_SKINNY_H */
369 
370 /* For Emacs:
371  * Local Variables:
372  * mode:c
373  * indent-tabs-mode:t
374  * tab-width:4
375  * c-basic-offset:4
376  * End:
377  * For VIM:
378  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
379  */
380 
381