1 /*
2  * Copyright (c) 2001-2014 Hypertriton, Inc. <http://hypertriton.com/>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 /*
27  * Core initialization routines.
28  */
29 
30 #include <agar/config/version.h>
31 #include <agar/config/release.h>
32 #include <agar/config/enable_nls.h>
33 #include <agar/config/localedir.h>
34 #include <agar/config/ag_threads.h>
35 #include <agar/config/ag_network.h>
36 #include <agar/config/have_clock_gettime.h>
37 #include <agar/config/have_nanosleep.h>
38 #include <agar/config/have_gettimeofday.h>
39 #include <agar/config/have_select.h>
40 #include <agar/config/have_db4.h>
41 #include <agar/config/have_getpwuid.h>
42 #include <agar/config/have_getuid.h>
43 #include <agar/config/have_getaddrinfo.h>
44 #include <agar/config/have_winsock1.h>
45 #include <agar/config/have_winsock2.h>
46 #include <agar/config/have_csidl.h>
47 #ifdef AG_THREADS
48 # include <agar/config/have_pthreads_xopen.h>
49 # include <agar/config/have_pthread_mutex_recursive.h>
50 # include <agar/config/have_pthread_mutex_recursive_np.h>
51 #endif
52 
53 #include <agar/core/core.h>
54 #include <agar/core/config.h>
55 #include <agar/core/dso.h>
56 
57 #include <stdio.h>
58 #include <stdlib.h>
59 #ifndef _WIN32
60 # include <unistd.h>
61 #endif
62 
63 #ifdef AG_THREADS
64 pthread_mutexattr_t agRecursiveMutexAttr;	/* Recursive mutex attributes */
65 AG_Thread agEventThread;			/* Event-processing thread */
66 #endif
67 
68 AG_Config *agConfig;				/* Global Agar config data */
69 void (*agAtexitFunc)(void) = NULL;		/* User exit function */
70 void (*agAtexitFuncEv)(AG_Event *) = NULL;	/* User exit handler */
71 char *agProgName = NULL;			/* Optional application name */
72 
73 int agVerbose = 0;				/* Verbose console output */
74 int agSoftTimers = 0;				/* Disable hardware timers */
75 
76 int
AG_InitCore(const char * progname,Uint flags)77 AG_InitCore(const char *progname, Uint flags)
78 {
79 	if (flags & AG_VERBOSE)
80 		agVerbose = 1;
81 	if (flags & AG_SOFT_TIMERS)
82 		agSoftTimers = 1;
83 
84 	if (progname != NULL) {
85 		if ((agProgName = TryStrdup(progname)) == NULL)
86 			return (-1);
87 	} else {
88 		agProgName = NULL;
89 	}
90 
91 #ifdef ENABLE_NLS
92 	bindtextdomain("agar", LOCALEDIR);
93 	bind_textdomain_codeset("agar", "UTF-8");
94 	textdomain("agar");
95 #endif
96 
97 	if (AG_InitErrorSubsystem() == -1 ||
98 	    AG_InitStringSubsystem() == -1 ||
99 	    AG_InitEventSubsystem(flags) == -1) {
100 		return (-1);
101 	}
102 	AG_GetCPUInfo(&agCPU);
103 
104 	/* Initialize the thread resources. */
105 #ifdef AG_THREADS
106 	agEventThread = AG_ThreadSelf();		/* Main thread */
107 # ifdef _XBOX
108 	ptw32_processInitialize();
109 # endif
110 	pthread_mutexattr_init(&agRecursiveMutexAttr);
111 # ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP
112 	pthread_mutexattr_settype(&agRecursiveMutexAttr,
113 	    PTHREAD_MUTEX_RECURSIVE_NP);
114 # else
115 	pthread_mutexattr_settype(&agRecursiveMutexAttr,
116 	    PTHREAD_MUTEX_RECURSIVE);
117 # endif
118 	AG_MutexInitRecursive(&agDSOLock);
119 #endif /* AG_THREADS */
120 
121 	/* Register the object classes from ag_core. */
122 	AG_InitClassTbl();
123 	AG_RegisterClass(&agConfigClass);
124 	AG_RegisterClass(&agDbClass);
125 #ifdef HAVE_DB4
126 	AG_RegisterClass(&agDbHashClass);
127 	AG_RegisterClass(&agDbBtreeClass);
128 #endif
129 
130 	/* Select the default AG_Time(3) backend. */
131 #if defined(_WIN32)
132 	AG_SetTimeOps(&agTimeOps_win32);
133 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_NANOSLEEP)
134 	AG_SetTimeOps(&agTimeOps_posix);
135 #elif defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SELECT)
136 	AG_SetTimeOps(&agTimeOps_gettimeofday);
137 #else
138 	AG_SetTimeOps(&agTimeOps_dummy);
139 #endif
140 
141 	/* Select the network access routines. */
142 #ifdef AG_NETWORK
143 	{
144 		int rv;
145 # if defined(HAVE_WINSOCK2)
146 		rv = AG_InitNetworkSubsystem(&agNetOps_winsock2);
147 # elif defined(HAVE_WINSOCK1)
148 		rv = AG_InitNetworkSubsystem(&agNetOps_winsock1);
149 # elif defined(HAVE_GETADDRINFO)
150 		rv = AG_InitNetworkSubsystem(&agNetOps_bsd);
151 # else
152 		rv = AG_InitNetworkSubsystem(&agNetOps_dummy);
153 # endif
154 		if (rv != 0)
155 			return (-1);
156 	}
157 #endif
158 
159 	/* Select the user account interface routines. */
160 #if defined(_XBOX)
161 	AG_SetUserOps(&agUserOps_xbox);
162 #elif defined(_WIN32) && defined(HAVE_CSIDL)
163 	AG_SetUserOps(&agUserOps_win32);
164 #elif defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
165 	AG_SetUserOps(&agUserOps_posix);
166 #else
167 	AG_SetUserOps(&agUserOps_dummy);
168 #endif
169 
170 	AG_InitTimers();
171 	AG_DataSourceInitSubsystem();
172 
173 	if ((agConfig = TryMalloc(sizeof(AG_Config))) == NULL) {
174 		return (-1);
175 	}
176 	if (AG_ConfigInit(agConfig, flags) == -1) {
177 		return (-1);
178 	}
179 	return (0);
180 }
181 
182 /* Register a function to invoke in AG_Quit(). */
183 void
AG_AtExitFunc(void (* func)(void))184 AG_AtExitFunc(void (*func)(void))
185 {
186 	agAtexitFunc = func;
187 }
188 
189 void
AG_AtExitFuncEv(void (* func)(AG_Event *))190 AG_AtExitFuncEv(void (*func)(AG_Event *))
191 {
192 	agAtexitFuncEv = func;
193 }
194 
195 /* Immediately terminate the application. */
196 void
AG_Quit(void)197 AG_Quit(void)
198 {
199 	AG_Destroy();
200 	exit(0);
201 }
202 
203 /* Clean up the resources allocated by Agar-Core. */
204 void
AG_Destroy(void)205 AG_Destroy(void)
206 {
207 	if (agAtexitFunc != NULL) { agAtexitFunc(); }
208 	if (agAtexitFuncEv != NULL) { agAtexitFuncEv(NULL); }
209 
210 	AG_ObjectDestroy(agConfig);
211 	AG_DataSourceDestroySubsystem();
212 	AG_DestroyTimers();
213 	if (agUserOps != NULL && agUserOps->destroy != NULL) {
214 		agUserOps->destroy();
215 		agUserOps = NULL;
216 	}
217 #ifdef AG_NETWORK
218 	AG_DestroyNetworkSubsystem();
219 #endif
220 	AG_DestroyClassTbl();
221 #ifdef AG_THREADS
222 	pthread_mutexattr_destroy(&agRecursiveMutexAttr);
223 	AG_MutexDestroy(&agDSOLock);
224 #endif
225 	AG_DestroyEventSubsystem();
226 	AG_DestroyStringSubsystem();
227 	AG_DestroyErrorSubsystem();
228 	Free(agProgName); agProgName = NULL;
229 }
230 
231 void
AG_GetVersion(AG_AgarVersion * ver)232 AG_GetVersion(AG_AgarVersion *ver)
233 {
234 	ver->major = AGAR_MAJOR_VERSION;
235 	ver->minor = AGAR_MINOR_VERSION;
236 	ver->patch = AGAR_PATCHLEVEL;
237 	ver->release = RELEASE;
238 }
239