merge with master
[platform/framework/web/download-provider.git] / provider / download-provider-main.c
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <glib.h>
21 #include <glib-object.h>
22 #include <pthread.h>
23
24 #ifdef DP_SUPPORT_DBUS_ACTIVATION
25 #include <dbus/dbus.h>
26 #endif
27
28 #include "download-provider-config.h"
29 #include "download-provider-log.h"
30 #include "download-provider-socket.h"
31 #include "download-provider-pthread.h"
32 #include "download-provider-slots.h"
33 #include "download-provider-db.h"
34 #include "download-provider-network.h"
35 #include "download-provider-queue.h"
36 #include "download-provider-notification.h"
37 #include "download-provider-da-interface.h"
38
39 // declare functions
40 int dp_lock_pid(char *path);
41 void *dp_thread_requests_manager(void *arg);
42
43 // declare global variables
44 // need for libsoup, decided the life-time by mainloop.
45 GMainLoop *g_main_loop_handle = 0;
46
47 #ifdef DP_SUPPORT_DBUS_ACTIVATION
48 static int __register_dbus_service(void)
49 {
50         DBusError dbus_error;
51         DBusConnection *dp_dbus_connection = NULL;
52
53         dbus_error_init(&dbus_error);
54
55         dp_dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
56         if (dp_dbus_connection == NULL) {
57                 TRACE_ERROR("[DBUS] dbus_bus_get: %s", dbus_error.message);
58                 dbus_error_free(&dbus_error);
59                 return -1;
60         }
61
62         if (dbus_bus_request_name
63                         (dp_dbus_connection, DP_DBUS_SERVICE_DBUS, 0, &dbus_error) < 0 ||
64                         dbus_error_is_set(&dbus_error)) {
65                 TRACE_ERROR("[DBUS] request_name %s", dbus_error.message);
66                 dbus_error_free(&dbus_error);
67                 dbus_connection_unref(dp_dbus_connection);
68                 dp_dbus_connection = NULL;
69                 return -1;
70         }
71         dbus_connection_unref(dp_dbus_connection);
72         dp_dbus_connection = NULL;
73         return 0;
74 }
75
76 #endif
77
78 void dp_terminate(int signo)
79 {
80         TRACE_INFO("Received SIGTERM");
81         if (g_main_loop_is_running(g_main_loop_handle))
82                 g_main_loop_quit(g_main_loop_handle);
83 }
84
85 static gboolean __dp_idle_start_service(void *data)
86 {
87         TRACE_INFO("Launch threads .....");
88
89         // declare all resources
90         pthread_t thread_pid;
91         pthread_attr_t thread_attr;
92
93         // initialize
94         if (pthread_attr_init(&thread_attr) != 0) {
95                 TRACE_STRERROR("failed to init pthread attr");
96                 dp_terminate(SIGTERM);
97                 return FALSE;
98         }
99         if (pthread_attr_setdetachstate(&thread_attr,
100                                                                         PTHREAD_CREATE_DETACHED) != 0) {
101                 TRACE_STRERROR("failed to set detach option");
102                 dp_terminate(SIGTERM);
103                 return FALSE;
104         }
105
106         // create thread for managing QUEUEs
107         if (pthread_create
108                 (&thread_pid, &thread_attr, dp_thread_queue_manager,
109                 data) != 0) {
110                 TRACE_STRERROR
111                         ("failed to create pthread for run_manage_download_server");
112                 dp_terminate(SIGTERM);
113         }
114
115         // start service, accept url-download ( client package )
116         if (pthread_create
117                 (&thread_pid, &thread_attr, dp_thread_requests_manager,
118                 data) != 0) {
119                 TRACE_STRERROR
120                         ("failed to create pthread for run_manage_download_server");
121                 dp_terminate(SIGTERM);
122         }
123         return FALSE;
124 }
125
126 int main(int argc, char **argv)
127 {
128         dp_privates *privates = NULL;
129         int lock_fd = -1;
130
131         if (chdir("/") < 0) {
132                 TRACE_STRERROR("failed to call setsid or chdir");
133                 exit(EXIT_FAILURE);
134         }
135
136 #if 0
137         // close all console I/O
138         close(STDIN_FILENO);
139         close(STDOUT_FILENO);
140         close(STDERR_FILENO);
141 #endif
142
143         if (signal(SIGTERM, dp_terminate) == SIG_ERR) {
144                 TRACE_ERROR("failed to register signal callback");
145                 exit(EXIT_FAILURE);
146         }
147         if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
148                 TRACE_ERROR("failed to register signal callback");
149                 exit(EXIT_FAILURE);
150         }
151         // write IPC_FD_PATH. and lock
152         if ((lock_fd = dp_lock_pid(DP_LOCK_PID)) < 0) {
153                 TRACE_ERROR
154                         ("It need to check download-provider is already alive");
155                 TRACE_ERROR("Or fail to create pid file in (%s)",
156                                 DP_LOCK_PID);
157                 exit(EXIT_FAILURE);
158         }
159         // if exit socket file, delete it
160         if (access(DP_IPC, F_OK) == 0) {
161                 unlink(DP_IPC);
162         }
163
164         g_type_init();
165
166         privates = (dp_privates *) calloc(1, sizeof(dp_privates));
167         if (!privates) {
168                 TRACE_ERROR("[CRITICAL] failed to alloc for private info");
169                 goto DOWNLOAD_EXIT;
170         }
171         privates->groups = dp_client_group_slots_new(DP_MAX_GROUP);
172         if (privates->groups == NULL) {
173                 TRACE_ERROR("[CRITICAL]  failed to alloc for groups");
174                 goto DOWNLOAD_EXIT;
175         }
176         privates->requests = dp_request_slots_new(DP_MAX_REQUEST);
177         if (privates->requests == NULL) {
178                 TRACE_ERROR("[CRITICAL]  failed to alloc for requests");
179                 goto DOWNLOAD_EXIT;
180         }
181
182         // ready socket ( listen )
183         privates->listen_fd = dp_accept_socket_new();
184         if (privates->listen_fd < 0) {
185                 TRACE_ERROR("[CRITICAL] failed to bind SOCKET");
186                 goto DOWNLOAD_EXIT;
187         }
188
189 #ifdef DP_SUPPORT_DBUS_ACTIVATION
190         TRACE_INFO("SUPPORT DBUS-ACTIVATION");
191         if (__register_dbus_service() < 0) {
192                 TRACE_ERROR("[LAUNCH ERROR] __register_dbus_service");
193                 goto DOWNLOAD_EXIT;
194         }
195 #else
196         TRACE_INFO("Not SUPPORT DBUS-ACTIVATION");
197 #endif
198
199         dp_db_open();
200
201         // convert to request type, insert all to privates->requests
202         // timeout of request thread will start these jobs by queue thread
203         // load all list from (queue table)
204         if (dp_db_crashed_list(privates->requests, DP_MAX_REQUEST) > 0) {
205                 int i = 0;
206                 for (i = 0; i < DP_MAX_REQUEST; i++) {
207                         if (!privates->requests[i].request)
208                                 continue;
209                         dp_request *request = privates->requests[i].request;
210                         TRACE_INFO
211                                 ("ID [%d] state[%d]", request->id, request->state);
212
213                         // load to memory, Can be started automatically.
214                         if (request->state == DP_STATE_DOWNLOADING ||
215                                 request->state == DP_STATE_CONNECTING) {
216                                 request->state = DP_STATE_QUEUED;
217                                 if (dp_db_set_column
218                                                 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
219                                                 DP_DB_COL_TYPE_INT, &request->state) < 0) {
220                                         TRACE_ERROR("[CHECK SQL]");
221                                 }
222                         }
223
224                         if (request->state == DP_STATE_QUEUED) {
225                                 int auto_download = dp_db_get_int_column(request->id,
226                                                                         DP_DB_TABLE_REQUEST_INFO,
227                                                                         DP_DB_COL_AUTO_DOWNLOAD);
228                                 if (auto_download == 1) {
229                                         // auto retry... defaultly, show notification
230                                         request->auto_notification = 1;
231                                         request->start_time = (int)time(NULL);
232                                         continue;
233                                 }
234                                 // do not retry this request
235                                 request->state = DP_STATE_FAILED;
236                                 request->error = DP_ERROR_SYSTEM_DOWN;
237                                 if (dp_db_set_column
238                                                 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
239                                                 DP_DB_COL_TYPE_INT, &request->state) < 0) {
240                                         TRACE_ERROR("[CHECK SQL]");
241                                 }
242                                 if (dp_db_set_column
243                                                 (request->id, DP_DB_TABLE_LOG,
244                                                 DP_DB_COL_ERRORCODE, DP_DB_COL_TYPE_INT,
245                                                 &request->error) < 0) {
246                                         TRACE_ERROR("[CHECK SQL]");
247                                 }
248                         }
249
250                         // if wanna restart, call continue before this line.
251                         // default. update state/error. move to history. unload memory
252                         // remove from memory
253                         dp_request_free(request);
254                         privates->requests[i].request = NULL;
255                 }
256         } // query crashed_list
257
258         if (argc != 2 || memcmp(argv[1], "service", 7) != 0) {
259                 // in first launch in booting time, not request. terminate by self
260                 if (dp_get_request_count(privates->requests) <= 0) {
261                         TRACE_INFO("First Boot, No Request");
262                         goto DOWNLOAD_EXIT;
263                 }
264         }
265
266         dp_clear_downloadinginfo_notification();
267
268         if (dp_init_agent() != DP_ERROR_NONE) {
269                 TRACE_ERROR("[CRITICAL] failed to init agent");
270                 goto DOWNLOAD_EXIT;
271         }
272
273         privates->connection = 0;
274         privates->network_status = DP_NETWORK_TYPE_OFF;
275         if (dp_network_connection_init(privates) < 0) {
276                 TRACE_INFO("use instant network check");
277                 privates->connection = 0;
278         }
279
280         // libsoup need mainloop.
281         g_main_loop_handle = g_main_loop_new(NULL, 0);
282
283         g_idle_add(__dp_idle_start_service, privates);
284
285         g_main_loop_run(g_main_loop_handle);
286
287 DOWNLOAD_EXIT :
288
289         TRACE_INFO("Download-Provider will be terminated.");
290
291         dp_deinit_agent();
292
293         if (privates != NULL) {
294
295                 if (privates->connection)
296                         dp_network_connection_destroy(privates->connection);
297
298                 if (privates->listen_fd >= 0) {
299                         dp_socket_free(privates->listen_fd);
300                         privates->listen_fd = -1;
301                 }
302                 dp_request_slots_free(privates->requests, DP_MAX_REQUEST);
303                 privates->requests = NULL;
304                 dp_client_group_slots_free(privates->groups, DP_MAX_GROUP);
305                 privates->groups = NULL;
306                 free(privates);
307                 privates = NULL;
308         }
309         dp_db_close();
310
311         //send signal to queue thread
312         dp_thread_queue_manager_wake_up();
313
314         // if exit socket file, delete it
315         if (access(DP_IPC, F_OK) == 0) {
316                 unlink(DP_IPC);
317         }
318         // delete pid file
319         if (access(DP_LOCK_PID, F_OK) == 0) {
320                 close(lock_fd);
321                 unlink(DP_LOCK_PID);
322         }
323         exit(EXIT_SUCCESS);
324 }