Tizen 2.1 base
[platform/framework/web/download-provider.git] / src / 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         // write IPC_FD_PATH. and lock
148         if ((lock_fd = dp_lock_pid(DP_LOCK_PID)) < 0) {
149                 TRACE_ERROR
150                         ("It need to check download-provider is already alive");
151                 TRACE_ERROR("Or fail to create pid file in (%s)",
152                                 DP_LOCK_PID);
153                 exit(EXIT_FAILURE);
154         }
155         // if exit socket file, delete it
156         if (access(DP_IPC, F_OK) == 0) {
157                 unlink(DP_IPC);
158         }
159
160         g_type_init();
161
162         privates = (dp_privates *) calloc(1, sizeof(dp_privates));
163         if (!privates) {
164                 TRACE_ERROR("[CRITICAL] failed to alloc for private info");
165                 goto DOWNLOAD_EXIT;
166         }
167         privates->groups = dp_client_group_slots_new(DP_MAX_GROUP);
168         if (privates->groups == NULL) {
169                 TRACE_ERROR("[CRITICAL]  failed to alloc for groups");
170                 goto DOWNLOAD_EXIT;
171         }
172         privates->requests = dp_request_slots_new(DP_MAX_REQUEST);
173         if (privates->requests == NULL) {
174                 TRACE_ERROR("[CRITICAL]  failed to alloc for requests");
175                 goto DOWNLOAD_EXIT;
176         }
177
178         // ready socket ( listen )
179         privates->listen_fd = dp_accept_socket_new();
180         if (privates->listen_fd < 0) {
181                 TRACE_ERROR("[CRITICAL] failed to bind SOCKET");
182                 goto DOWNLOAD_EXIT;
183         }
184
185 #ifdef DP_SUPPORT_DBUS_ACTIVATION
186         TRACE_INFO("SUPPORT DBUS-ACTIVATION");
187         if (__register_dbus_service() < 0) {
188                 TRACE_ERROR("[LAUNCH ERROR] __register_dbus_service");
189                 goto DOWNLOAD_EXIT;
190         }
191 #else
192         TRACE_INFO("Not SUPPORT DBUS-ACTIVATION");
193 #endif
194
195         dp_db_open();
196
197         // convert to request type, insert all to privates->requests
198         // timeout of request thread will start these jobs by queue thread
199         // load all list from (queue table)
200         if (dp_db_crashed_list(privates->requests, DP_MAX_REQUEST) > 0) {
201                 int i = 0;
202                 for (i = 0; i < DP_MAX_REQUEST; i++) {
203                         if (!privates->requests[i].request)
204                                 continue;
205                         dp_request *request = privates->requests[i].request;
206                         TRACE_INFO
207                                 ("ID [%d] state[%d]", request->id, request->state);
208
209                         // load to memory, Can be started automatically.
210                         if (request->state == DP_STATE_DOWNLOADING ||
211                                 request->state == DP_STATE_CONNECTING) {
212                                 request->state = DP_STATE_QUEUED;
213                                 if (dp_db_set_column
214                                                 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
215                                                 DP_DB_COL_TYPE_INT, &request->state) < 0) {
216                                         TRACE_ERROR("[CHECK SQL]");
217                                 }
218                         }
219
220                         if (request->state == DP_STATE_QUEUED) {
221                                 int auto_download = dp_db_get_int_column(request->id,
222                                                                         DP_DB_TABLE_REQUEST_INFO,
223                                                                         DP_DB_COL_AUTO_DOWNLOAD);
224                                 if (auto_download == 1) {
225                                         // auto retry... defaultly, show notification
226                                         request->auto_notification = 1;
227                                         request->start_time = (int)time(NULL);
228                                         continue;
229                                 }
230                                 // do not retry this request
231                                 request->state = DP_STATE_FAILED;
232                                 request->error = DP_ERROR_SYSTEM_DOWN;
233                                 if (dp_db_set_column
234                                                 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
235                                                 DP_DB_COL_TYPE_INT, &request->state) < 0) {
236                                         TRACE_ERROR("[CHECK SQL]");
237                                 }
238                                 if (dp_db_set_column
239                                                 (request->id, DP_DB_TABLE_LOG,
240                                                 DP_DB_COL_ERRORCODE, DP_DB_COL_TYPE_INT,
241                                                 &request->error) < 0) {
242                                         TRACE_ERROR("[CHECK SQL]");
243                                 }
244                         }
245
246                         // if wanna restart, call continue before this line.
247                         // default. update state/error. move to history. unload memory
248                         // remove from memory
249                         dp_request_free(request);
250                         privates->requests[i].request = NULL;
251                 }
252         } // query crashed_list
253
254         if (argc != 2 || memcmp(argv[1], "service", 7) != 0) {
255                 // in first launch in booting time, not request. terminate by self
256                 if (dp_get_request_count(privates->requests) <= 0) {
257                         TRACE_INFO("First Boot, No Request");
258                         goto DOWNLOAD_EXIT;
259                 }
260         }
261
262         dp_clear_downloadinginfo_notification();
263
264         if (dp_init_agent() != DP_ERROR_NONE) {
265                 TRACE_ERROR("[CRITICAL] failed to init agent");
266                 goto DOWNLOAD_EXIT;
267         }
268
269         privates->connection = 0;
270         privates->network_status = DP_NETWORK_TYPE_OFF;
271         if (dp_network_connection_init(privates) < 0) {
272                 TRACE_INFO("use instant network check");
273                 privates->connection = 0;
274         }
275
276         // libsoup need mainloop.
277         g_main_loop_handle = g_main_loop_new(NULL, 0);
278
279         g_idle_add(__dp_idle_start_service, privates);
280
281         g_main_loop_run(g_main_loop_handle);
282
283 DOWNLOAD_EXIT :
284
285         TRACE_INFO("Download-Provider will be terminated.");
286
287         dp_deinit_agent();
288
289         if (privates != NULL) {
290
291                 if (privates->connection)
292                         dp_network_connection_destroy(privates->connection);
293
294                 if (privates->listen_fd >= 0) {
295                         dp_socket_free(privates->listen_fd);
296                         privates->listen_fd = -1;
297                 }
298                 dp_request_slots_free(privates->requests, DP_MAX_REQUEST);
299                 privates->requests = NULL;
300                 dp_client_group_slots_free(privates->groups, DP_MAX_GROUP);
301                 privates->groups = NULL;
302                 free(privates);
303                 privates = NULL;
304         }
305         dp_db_close();
306
307         //send signal to queue thread
308         dp_thread_queue_manager_wake_up();
309
310         // if exit socket file, delete it
311         if (access(DP_IPC, F_OK) == 0) {
312                 unlink(DP_IPC);
313         }
314         // delete pid file
315         if (access(DP_LOCK_PID, F_OK) == 0) {
316                 close(lock_fd);
317                 unlink(DP_LOCK_PID);
318         }
319         exit(EXIT_SUCCESS);
320 }