1 /*
2  liblinphone_tester - liblinphone test suite
3  Copyright (C) 2013  Belledonne Communications SARL
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 
20 #include "linphone/core.h"
21 #include "private.h"
22 #include "liblinphone_tester.h"
23 
24 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
25 #pragma GCC diagnostic push
26 #endif
27 #ifdef _MSC_VER
28 #pragma warning(disable : 4996)
29 #else
30 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
31 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
32 #endif
33 
34 #ifdef HAVE_GTK
35 #include <gtk/gtk.h>
36 #endif
37 
38 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
39 #pragma GCC diagnostic pop
40 #endif
41 
42 
43 static FILE * log_file = NULL;
44 
45 #ifdef __ANDROID__
46 
47 #include <android/log.h>
48 #include <jni.h>
49 #define CALLBACK_BUFFER_SIZE  1024
50 
51 static JNIEnv *current_env = NULL;
52 static jobject current_obj = 0;
53 static const char* LogDomain = "liblinphone_tester";
54 
55 int main(int argc, char** argv);
56 
liblinphone_android_log_handler(int prio,const char * fmt,va_list args)57 void liblinphone_android_log_handler(int prio, const char *fmt, va_list args) {
58 	char str[4096];
59 	char *current;
60 	char *next;
61 
62 	vsnprintf(str, sizeof(str) - 1, fmt, args);
63 	str[sizeof(str) - 1] = '\0';
64 	if (strlen(str) < 512) {
65 		__android_log_write(prio, LogDomain, str);
66 	} else {
67 		current = str;
68 		while ((next = strchr(current, '\n')) != NULL) {
69 			*next = '\0';
70 			__android_log_write(prio, LogDomain, current);
71 			current = next + 1;
72 		}
73 		__android_log_write(prio, LogDomain, current);
74 	}
75 }
76 
liblinphone_android_ortp_log_handler(const char * domain,OrtpLogLevel lev,const char * fmt,va_list args)77 static void liblinphone_android_ortp_log_handler(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args) {
78 	int prio;
79 	switch(lev){
80 		case ORTP_DEBUG:	prio = ANDROID_LOG_DEBUG;	break;
81 		case ORTP_MESSAGE:	prio = ANDROID_LOG_INFO;	break;
82 		case ORTP_WARNING:	prio = ANDROID_LOG_WARN;	break;
83 		case ORTP_ERROR:	prio = ANDROID_LOG_ERROR;	break;
84 		case ORTP_FATAL:	prio = ANDROID_LOG_FATAL;	break;
85 		default:			prio = ANDROID_LOG_DEFAULT;	break;
86 	}
87 	liblinphone_android_log_handler(prio, fmt, args);
88 }
89 
liblinphone_android_bctbx_log_handler(const char * domain,BctbxLogLevel lev,const char * fmt,va_list args)90 static void liblinphone_android_bctbx_log_handler(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args) {
91 	int prio;
92 	switch(lev){
93 		case BCTBX_LOG_DEBUG:	prio = ANDROID_LOG_DEBUG;	break;
94 		case BCTBX_LOG_MESSAGE:	prio = ANDROID_LOG_INFO;	break;
95 		case BCTBX_LOG_WARNING:	prio = ANDROID_LOG_WARN;	break;
96 		case BCTBX_LOG_ERROR:	prio = ANDROID_LOG_ERROR;	break;
97 		case BCTBX_LOG_FATAL:	prio = ANDROID_LOG_FATAL;	break;
98 		default:			prio = ANDROID_LOG_DEFAULT;	break;
99 	}
100 	liblinphone_android_log_handler(prio, fmt, args);
101 }
102 
bcunit_android_trace_handler(int level,const char * fmt,va_list args)103 void bcunit_android_trace_handler(int level, const char *fmt, va_list args) {
104 	char buffer[CALLBACK_BUFFER_SIZE];
105 	jstring javaString;
106 	jclass cls;
107 	jmethodID method;
108 	jint javaLevel = level;
109 	JNIEnv *env = current_env;
110 	if(env == NULL) return;
111 	vsnprintf(buffer, CALLBACK_BUFFER_SIZE, fmt, args);
112 	javaString = (*env)->NewStringUTF(env, buffer);
113 	cls = (*env)->GetObjectClass(env, current_obj);
114 	method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V");
115 	(*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString);
116 	(*env)->DeleteLocalRef(env,javaString);
117 	(*env)->DeleteLocalRef(env,cls);
118 }
119 
Java_org_linphone_tester_Tester_run(JNIEnv * env,jobject obj,jobjectArray stringArray)120 JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) {
121 	int i, ret;
122 	int argc = (*env)->GetArrayLength(env, stringArray);
123 	char **argv = (char**) malloc(sizeof(char*) * argc);
124 
125 	for (i=0; i<argc; i++) {
126 		jstring string = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
127 		const char *rawString = (const char *) (*env)->GetStringUTFChars(env, string, 0);
128 		argv[i] = strdup(rawString);
129 		(*env)->ReleaseStringUTFChars(env, string, rawString);
130 	}
131 	current_env = env;
132 	current_obj = obj;
133 	bc_set_trace_handler(bcunit_android_trace_handler);
134 	ret = main(argc, argv);
135 	current_env = NULL;
136 	bc_set_trace_handler(NULL);
137 	for (i=0; i<argc; i++) {
138 		free(argv[i]);
139 	}
140 	free(argv);
141 	return ret;
142 }
143 
Java_org_linphone_tester_Tester_keepAccounts(JNIEnv * env,jclass c,jboolean keep)144 JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_keepAccounts(JNIEnv *env, jclass c, jboolean keep) {
145 	liblinphone_tester_keep_accounts((int)keep);
146 }
147 
Java_org_linphone_tester_Tester_clearAccounts(JNIEnv * env,jclass c)148 JNIEXPORT void JNICALL Java_org_linphone_tester_Tester_clearAccounts(JNIEnv *env, jclass c) {
149 	liblinphone_tester_clear_accounts();
150 }
151 #endif /* __ANDROID__ */
152 
log_handler(int lev,const char * fmt,va_list args)153 static void log_handler(int lev, const char *fmt, va_list args) {
154 #ifdef _WIN32
155 	vfprintf(lev == ORTP_ERROR ? stderr : stdout, fmt, args);
156 	fprintf(lev == ORTP_ERROR ? stderr : stdout, "\n");
157 #else
158 	va_list cap;
159 	va_copy(cap,args);
160 #ifdef __ANDROID__
161 	/* IMPORTANT: needed by liblinphone tester to retrieve suite list...*/
162 	bcunit_android_trace_handler(lev == ORTP_ERROR, fmt, cap);
163 #else
164 	/* Otherwise, we must use stdio to avoid log formatting (for autocompletion etc.) */
165 	vfprintf(lev == ORTP_ERROR ? stderr : stdout, fmt, cap);
166 	fprintf(lev == ORTP_ERROR ? stderr : stdout, "\n");
167 #endif
168 	va_end(cap);
169 #endif
170 	if (log_file){
171 		ortp_logv_out(ORTP_LOG_DOMAIN, lev, fmt, args);
172 	}
173 }
174 
liblinphone_tester_init(void (* ftester_printf)(int level,const char * fmt,va_list args))175 void liblinphone_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args)) {
176 	if (! log_file) {
177 #if defined(__ANDROID__)
178 		linphone_core_set_log_handler(liblinphone_android_ortp_log_handler);
179 		bctbx_set_log_handler(liblinphone_android_bctbx_log_handler);
180 #endif
181 	}
182 
183 	if (ftester_printf == NULL) ftester_printf = log_handler;
184 	bc_tester_init(ftester_printf, ORTP_MESSAGE, ORTP_ERROR, "rcfiles");
185 	liblinphone_tester_add_suites();
186 }
187 
liblinphone_tester_set_log_file(const char * filename)188 int liblinphone_tester_set_log_file(const char *filename) {
189 	if (log_file) {
190 		fclose(log_file);
191 	}
192 	log_file = fopen(filename, "w");
193 	if (!log_file) {
194 		ms_error("Cannot open file [%s] for writing logs because [%s]", filename, strerror(errno));
195 		return -1;
196 	}
197 	ms_message("Redirecting traces to file [%s]", filename);
198 	bctbx_set_log_file(log_file);
199 	ortp_set_log_file(log_file);
200 	return 0;
201 }
202 
203 
204 #if !TARGET_OS_IPHONE && !(defined(LINPHONE_WINDOWS_PHONE) || defined(LINPHONE_WINDOWS_UNIVERSAL))
205 
206 static const char* liblinphone_helper =
207 		"\t\t\t--verbose\n"
208 		"\t\t\t--silent\n"
209 		"\t\t\t--log-file <output log file path>\n"
210 		"\t\t\t--domain <test sip domain>\n"
211 		"\t\t\t--auth-domain <test auth domain>\n"
212 		"\t\t\t--dns-hosts </etc/hosts -like file to used to override DNS names (default: tester_hosts)>\n"
213 		"\t\t\t--keep-recorded-files\n"
214 		"\t\t\t--disable-leak-detector\n"
215 		"\t\t\t--disable-tls-support\n"
216 		"\t\t\t--no-ipv6 (turn off IPv6 in LinphoneCore, tests requiring IPv6 will be skipped)\n"
217 		"\t\t\t--show-account-manager-logs (show temporary test account creation logs)\n"
218 		;
219 
main(int argc,char * argv[])220 int main (int argc, char *argv[])
221 {
222 	int i;
223 	int ret;
224 
225 #ifdef HAVE_GTK
226 	gtk_init(&argc, &argv);
227 #if !GLIB_CHECK_VERSION(2,32,0) // backward compatibility with Debian 6 and CentOS 6
228 	g_thread_init(NULL);
229 #endif
230 	gdk_threads_init();
231 #endif
232 
233 	liblinphone_tester_init(NULL);
234 	linphone_core_set_log_level(ORTP_ERROR);
235 
236 	for(i = 1; i < argc; ++i) {
237 		if (strcmp(argv[i], "--verbose") == 0) {
238 			linphone_core_set_log_level(ORTP_MESSAGE);
239 		} else if (strcmp(argv[i], "--silent") == 0) {
240 			linphone_core_set_log_level(ORTP_FATAL);
241 		} else if (strcmp(argv[i],"--log-file")==0){
242 			CHECK_ARG("--log-file", ++i, argc);
243 			if (liblinphone_tester_set_log_file(argv[i]) < 0) return -2;
244 		} else if (strcmp(argv[i],"--domain")==0){
245 			CHECK_ARG("--domain", ++i, argc);
246 			test_domain=argv[i];
247 		} else if (strcmp(argv[i],"--auth-domain")==0){
248 			CHECK_ARG("--auth-domain", ++i, argc);
249 			auth_domain=argv[i];
250 		}else if (strcmp(argv[i],"--dns-hosts")==0){
251 			CHECK_ARG("--dns-hosts", ++i, argc);
252 			userhostsfile=argv[i];
253 		} else if (strcmp(argv[i],"--keep-recorded-files")==0){
254 			liblinphone_tester_keep_recorded_files(TRUE);
255 		} else if (strcmp(argv[i],"--disable-leak-detector")==0){
256 			liblinphone_tester_disable_leak_detector(TRUE);
257 		} else if (strcmp(argv[i],"--disable-tls-support")==0){
258 			liblinphone_tester_tls_support_disabled = TRUE;
259 		} else if (strcmp(argv[i],"--no-ipv6")==0){
260 			liblinphonetester_ipv6 = FALSE;
261 		} else if (strcmp(argv[i],"--show-account-manager-logs")==0){
262 			liblinphonetester_show_account_manager_logs=TRUE;
263 		} else {
264 			int bret = bc_tester_parse_args(argc, argv, i);
265 			if (bret>0) {
266 				i += bret - 1;
267 				continue;
268 			} else if (bret<0) {
269 				bc_tester_helper(argv[0], liblinphone_helper);
270 			}
271 			return bret;
272 		}
273 	}
274 
275 	ret = bc_tester_start(argv[0]);
276 	liblinphone_tester_uninit();
277 	return ret;
278 }
279 
280 
281 #endif
282