2 * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <sys/types.h>
25 #include <sys/socket.h>
29 #include "download-provider.h"
30 #include "download-provider-log.h"
31 #include "download-provider-config.h"
32 #include "download-provider-slots.h"
33 #include "download-provider-socket.h"
34 #include "download-provider-pthread.h"
35 #include "download-provider-db.h"
36 #include "download-provider-queue.h"
37 #include "download-provider-network.h"
38 #include "download-provider-da-interface.h"
40 void dp_terminate(int signo);
42 pthread_mutex_t g_dp_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
43 pthread_cond_t g_dp_queue_cond = PTHREAD_COND_INITIALIZER;
46 //////////////////////////////////////////////////////////////////////////
47 /// @brief check network status is matched with the type setted by user
48 /// @return matched : 0 mispatch : -1
49 static int __is_matched_network(dp_network_type now_state, dp_network_type setted_state)
51 if (now_state == setted_state
52 || now_state == DP_NETWORK_TYPE_ETHERNET
53 || setted_state == DP_NETWORK_TYPE_ALL)
56 if (setted_state == DP_NETWORK_TYPE_ALL
57 || setted_state == DP_NETWORK_TYPE_DATA_NETWORK
58 || now_state == DP_NETWORK_TYPE_WIFI
59 || now_state == DP_NETWORK_TYPE_ETHERNET
60 || (setted_state == DP_NETWORK_TYPE_WIFI
61 && (now_state == DP_NETWORK_TYPE_WIFI
62 || now_state == DP_NETWORK_TYPE_ETHERNET))
69 //////////////////////////////////////////////////////////////////////////
70 /// @brief the count of slot downloading currently
71 static unsigned __get_active_count(dp_request_slots *requests)
79 for (i = 0; i < DP_MAX_REQUEST; i++) {
80 if (requests[i].request) {
81 if (requests[i].request->state == DP_STATE_CONNECTING ||
82 requests[i].request->state == DP_STATE_DOWNLOADING)
89 //////////////////////////////////////////////////////////////////////////
90 /// @brief index of slot which last time is oldest
91 static int __get_oldest_request_with_network(dp_request_slots *requests, dp_state_type state, dp_network_type now_state)
94 int oldest_time = (int)time(NULL);
95 oldest_time++; // most last time
96 int oldest_index = -1;
101 for (i = 0; i < DP_MAX_REQUEST; i++) {
102 if (requests[i].request) {
103 if (requests[i].request->state == state &&
104 requests[i].request->start_time > 0 &&
105 requests[i].request->start_time < oldest_time &&
107 (now_state, requests[i].request->network_type)
109 oldest_time = requests[i].request->start_time;
117 //////////////////////////////////////////////////////////////////////////
118 /// @brief THREAD function for calling da_start_download_with_extension.
119 /// @warning da_start_download_with_extension can take long time
120 /// @param the pointer of memory slot allocated for this request.
121 /// @todo simplify da_start_download_with_extension
122 static void *__request_download_start_agent(void *args)
124 dp_error_type errcode = DP_ERROR_NONE;
126 dp_request *request = (dp_request *) args;
128 TRACE_ERROR("[NULL-CHECK] download_clientinfo_slot");
133 if (dp_is_alive_download(request->agent_id)) {
134 errcode = dp_resume_agent_download(request->agent_id);
136 // call agent start function
137 errcode = dp_start_agent_download(request);
140 CLIENT_MUTEX_LOCK(&(request->mutex));
141 // send to state callback.
142 if (errcode == DP_ERROR_NONE) {
144 request->state = DP_STATE_CONNECTING;
145 request->error = DP_ERROR_NONE;
146 request->startcount++;
148 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STARTCOUNT,
149 DP_DB_COL_TYPE_INT, &request->startcount) < 0)
150 TRACE_ERROR("[ERROR][%d][SQL]", request->id);
151 } else if (errcode == DP_ERROR_TOO_MANY_DOWNLOADS) {
153 request->state = DP_STATE_QUEUED;
154 request->error = DP_ERROR_TOO_MANY_DOWNLOADS;
155 } else if (errcode == DP_ERROR_CONNECTION_FAILED) {
157 request->state = DP_STATE_FAILED;
158 request->error = DP_ERROR_CONNECTION_FAILED;
159 dp_ipc_send_event(request->group->event_socket,
160 request->id, request->state, request->error, 0);
161 dp_thread_queue_manager_wake_up();
163 request->state = DP_STATE_FAILED;
164 request->error = errcode;
165 dp_ipc_send_event(request->group->event_socket,
166 request->id, request->state, request->error, 0);
167 dp_thread_queue_manager_wake_up();
170 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
171 DP_DB_COL_TYPE_INT, &request->state) < 0)
172 TRACE_ERROR("[ERROR][%d][SQL]", request->id);
174 CLIENT_MUTEX_UNLOCK(&(request->mutex));
179 //////////////////////////////////////////////////////////////////////////
180 /// @brief create thread.
181 /// @warning if failed to create thread, change to PENED.
182 /// @param the pointer of memory slot allocated for this request.
183 static int __request_download_start_thread(dp_request *request)
185 // declare all resources
186 pthread_t thread_pid;
187 pthread_attr_t thread_attr;
191 TRACE_ERROR("[CRITICAL] Invalid Address");
196 if (pthread_attr_init(&thread_attr) != 0) {
197 TRACE_STRERROR("[ERROR][%d] pthread_attr_init", request->id);
200 if (pthread_attr_setdetachstate(&thread_attr,
201 PTHREAD_CREATE_DETACHED) != 0) {
203 ("[ERROR][%d] pthread_attr_setdetachstate", request->id);
207 request->state = DP_STATE_CONNECTING;
208 if (pthread_create(&thread_pid, &thread_attr,
209 __request_download_start_agent, request) != 0) {
210 TRACE_STRERROR("[ERROR][%d] pthread_create", request->id);
211 pthread_attr_destroy(&thread_attr);
212 request->state = DP_STATE_QUEUED;
215 pthread_attr_destroy(&thread_attr);
220 void dp_thread_queue_manager_wake_up()
223 CLIENT_MUTEX_LOCK(&(g_dp_queue_mutex));
224 pthread_cond_signal(&g_dp_queue_cond);
225 CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
229 // Main role : start download, check status of queue.
230 // No timeout. Wake up by Signal be sent from other thread
231 void *dp_thread_queue_manager(void *arg)
235 dp_client_group *group = NULL;
236 dp_request *request = NULL;
238 TRACE_INFO("Start Queue Thread");
240 dp_privates *privates = (dp_privates*)arg;
242 TRACE_ERROR("[CRITICAL] Invalid Address");
243 dp_terminate(SIGTERM);
248 pthread_cond_init(&g_dp_queue_cond, NULL);
249 while (privates != NULL && privates->listen_fd >= 0) {
251 CLIENT_MUTEX_LOCK(&(g_dp_queue_mutex));
252 pthread_cond_wait(&g_dp_queue_cond, &g_dp_queue_mutex);
254 if (privates == NULL || privates->requests == NULL ||
255 privates->listen_fd < 0) {
256 TRACE_INFO("Terminate Thread");
257 CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
261 if (!privates->connection)
262 privates->network_status =
263 dp_get_network_connection_instant_status();
265 if (privates->network_status == DP_NETWORK_TYPE_OFF) {
266 TRACE_INFO("[CHECK NETWORK STATE]");
267 CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
271 active_count = __get_active_count(privates->requests);
274 // 1. state is QUEUED
275 // 2. 1 QUEUED per 1 Group : need not to check max limitation.!!
276 // if no group, it will be started later.
277 // 3. most old last time : below conditions need max limitation.
278 // 4. match network connection type
280 // search group having 1 queued_count
281 // guarantee 1 instant download per 1 group
282 if (active_count >= DP_MAX_DOWNLOAD_AT_ONCE) {
283 for (i = 0; i < DP_MAX_REQUEST; i++) {
284 request = privates->requests[i].request;
285 if (request && request->state == DP_STATE_QUEUED) {
286 group = privates->requests[i].request->group;
287 if (group && group->queued_count == 1 &&
288 __is_matched_network(privates->network_status,
289 request->network_type) == 0 &&
290 __request_download_start_thread(request) ==
293 ("[Guarantee Intant Download] Group [%s]",
301 if (active_count >= DP_MAX_DOWNLOAD_AT_ONCE) {
302 TRACE_INFO("[BUSY] Active[%d] Max[%d]",
303 active_count, DP_MAX_DOWNLOAD_AT_ONCE);
304 CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
308 // can start download more.
309 // search oldest request
310 while(active_count < DP_MAX_DOWNLOAD_AT_ONCE) {
311 i = __get_oldest_request_with_network(privates->requests,
312 DP_STATE_QUEUED, privates->network_status);
315 ("No Request to can start now Active[%d] Max[%d]",
316 active_count, DP_MAX_DOWNLOAD_AT_ONCE);
320 ("QUEUE Status now %d active %d/%d", i, active_count,
321 DP_MAX_DOWNLOAD_AT_ONCE);
322 request = privates->requests[i].request;
323 __request_download_start_thread(request);
326 CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
328 pthread_cond_destroy(&g_dp_queue_cond);