- fix for ticker #4787
[oscam.git] / oscam-work.c
blob79c440e3a932e6f7f6408e05cb0291dbeb166810
1 #define MODULE_LOG_PREFIX "work"
3 #include "globals.h"
4 #include "module-cacheex.h"
5 #include "oscam-client.h"
6 #include "oscam-ecm.h"
7 #include "oscam-emm.h"
8 #include "oscam-lock.h"
9 #include "oscam-net.h"
10 #include "oscam-reader.h"
11 #include "oscam-string.h"
12 #include "oscam-work.h"
13 #include "reader-common.h"
14 #ifdef READER_NAGRA_MERLIN
15 #include "reader-nagracak7.h"
16 #endif
17 #include "module-cccam.h"
18 #include "module-cccam-data.h"
19 #include "module-cccshare.h"
20 #include "oscam-time.h"
22 extern CS_MUTEX_LOCK system_lock;
23 extern int32_t thread_pipe[2];
25 struct job_data
27 enum actions action;
28 struct s_reader *rdr;
29 struct s_client *cl;
30 void *ptr;
31 struct timeb time;
32 uint16_t len;
35 static void free_job_data(struct job_data *data)
37 if(!data)
38 { return; }
39 if(data->len && data->ptr)
41 // special free checks
42 if(data->action==ACTION_ECM_ANSWER_CACHE)
44 NULLFREE(((struct s_write_from_cache *)data->ptr)->er_cache);
47 NULLFREE(data->ptr);
49 NULLFREE(data);
52 void free_joblist(struct s_client *cl)
54 int32_t lock_status = pthread_mutex_trylock(&cl->thread_lock);
55 LL_ITER it = ll_iter_create(cl->joblist);
57 struct job_data *data;
58 while((data = ll_iter_next(&it)))
60 free_job_data(data);
63 ll_destroy(&cl->joblist);
64 cl->account = NULL;
66 if(cl->work_job_data) // Free job_data that was not freed by work_thread
67 { free_job_data(cl->work_job_data); }
69 cl->work_job_data = NULL;
71 if(lock_status == 0)
72 { SAFE_MUTEX_UNLOCK(&cl->thread_lock); }
74 pthread_mutex_destroy(&cl->thread_lock);
78 Work threads are named like this:
79 w[r|c]XX-[rdr->label|client->username]
81 w - work thread prefix
82 [r|c] - depending whether the the action is related to reader or client
83 XX - two digit action code from enum actions
84 label - reader label or client username (see username() function)
86 static void set_work_thread_name(struct job_data *data)
88 char thread_name[16 + 1];
89 snprintf(thread_name, sizeof(thread_name), "w%c%02d-%s",
90 data->action < ACTION_CLIENT_FIRST ? 'r' : 'c',
91 data->action,
92 username(data->cl)
94 set_thread_name(thread_name);
97 #define __free_job_data(client, job_data) \
98 do { \
99 client->work_job_data = NULL; \
100 if(job_data && job_data != &tmp_data) { \
101 free_job_data(job_data); \
103 job_data = NULL; \
104 } while(0)
106 void *work_thread(void *ptr)
108 struct job_data *data = (struct job_data *)ptr;
109 struct s_client *cl = data->cl;
110 struct s_reader *reader = cl->reader;
111 struct timeb start, end; // start time poll, end time poll
113 struct job_data tmp_data;
114 struct pollfd pfd[1];
116 SAFE_SETSPECIFIC(getclient, cl);
117 cl->thread = pthread_self();
118 cl->thread_active = 1;
120 set_work_thread_name(data);
122 struct s_module *module = get_module(cl);
123 uint16_t bufsize = module->bufsize; // CCCam needs more than 1024bytes!
124 if(!bufsize)
125 { bufsize = DEFAULT_MODULE_BUFSIZE; }
127 uint8_t *mbuf;
128 if(!cs_malloc(&mbuf, bufsize))
129 { return NULL; }
131 cl->work_mbuf = mbuf; // Track locally allocated data, because some callback may call cs_exit/cs_disconect_client/pthread_exit and then mbuf would be leaked
132 int32_t n = 0, rc = 0, i, idx, s;
133 uint8_t dcw[16];
134 int8_t restart_reader = 0;
136 while(cl->thread_active)
138 cs_ftime(&start); // register start time
140 while(cl->thread_active)
142 if(!cl || cl->kill || !is_valid_client(cl))
144 SAFE_MUTEX_LOCK(&cl->thread_lock);
145 cl->thread_active = 0;
146 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
147 cs_log_dbg(D_TRACE, "ending thread (kill)");
148 __free_job_data(cl, data);
149 cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf)
150 free_client(cl);
151 if(restart_reader)
152 { restart_cardreader(reader, 0); }
153 NULLFREE(mbuf);
154 pthread_exit(NULL);
155 return NULL;
158 if(data && data->action != ACTION_READER_CHECK_HEALTH)
159 { cs_log_dbg(D_TRACE, "data from add_job action=%d client %c %s", data->action, cl->typ, username(cl)); }
161 if(!data)
163 if(!cl->kill && cl->typ != 'r')
164 { client_check_status(cl); } // do not call for physical readers as this might cause an endless job loop
166 SAFE_MUTEX_LOCK(&cl->thread_lock);
167 if(cl->joblist && ll_count(cl->joblist) > 0)
169 LL_ITER itr = ll_iter_create(cl->joblist);
170 data = ll_iter_next_remove(&itr);
171 if(data)
172 { set_work_thread_name(data); }
173 //cs_log_dbg(D_TRACE, "start next job from list action=%d", data->action);
175 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
178 if(!data)
180 /* for serial client cl->pfd is file descriptor for serial port not socket
181 for example: pfd=open("/dev/ttyUSB0"); */
182 if(!cl->pfd || module->listenertype == LIS_SERIAL)
183 { break; }
185 pfd[0].fd = cl->pfd;
186 pfd[0].events = POLLIN | POLLPRI;
188 SAFE_MUTEX_LOCK(&cl->thread_lock);
189 cl->thread_active = 2;
190 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
192 rc = poll(pfd, 1, 3000);
194 SAFE_MUTEX_LOCK(&cl->thread_lock);
195 cl->thread_active = 1;
196 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
198 if(rc > 0)
200 cs_ftime(&end); // register end time
201 cs_log_dbg(D_TRACE, "[OSCAM-WORK] new event %d occurred on fd %d after %"PRId64" ms inactivity", pfd[0].revents,
202 pfd[0].fd, comp_timeb(&end, &start));
203 data = &tmp_data;
204 data->ptr = NULL;
205 cs_ftime(&start); // register start time for new poll next run
207 if(reader)
208 { data->action = ACTION_READER_REMOTE; }
209 else
211 if(cl->is_udp)
213 data->action = ACTION_CLIENT_UDP;
214 data->ptr = mbuf;
215 data->len = bufsize;
217 else
218 { data->action = ACTION_CLIENT_TCP; }
220 if(pfd[0].revents & (POLLHUP | POLLNVAL | POLLERR))
221 { cl->kill = 1; }
226 if(!data)
227 { continue; }
229 if(!reader && data->action < ACTION_CLIENT_FIRST)
231 __free_job_data(cl, data);
232 break;
235 if(!data->action)
236 { break; }
238 struct timeb actualtime;
239 cs_ftime(&actualtime);
240 int64_t gone = comp_timeb(&actualtime, &data->time);
241 if(data != &tmp_data && gone > (int) cfg.ctimeout+1000)
243 cs_log_dbg(D_TRACE, "dropping client data for %s time %"PRId64" ms", username(cl), gone);
244 __free_job_data(cl, data);
245 continue;
248 if(data != &tmp_data)
249 { cl->work_job_data = data; } // Track the current job_data
251 switch(data->action)
253 case ACTION_READER_IDLE:
254 reader_do_idle(reader);
255 break;
257 case ACTION_READER_REMOTE:
258 s = check_fd_for_data(cl->pfd);
259 if(s == 0) // no data, another thread already read from fd?
260 { break; }
261 if(s < 0)
263 if(reader->ph.type == MOD_CONN_TCP)
264 { network_tcp_connection_close(reader, "disconnect"); }
265 break;
267 rc = reader->ph.recv(cl, mbuf, bufsize);
268 if(rc < 0)
270 if(reader->ph.type == MOD_CONN_TCP)
271 { network_tcp_connection_close(reader, "disconnect on receive"); }
272 break;
274 cl->last = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER ****************
275 idx = reader->ph.c_recv_chk(cl, dcw, &rc, mbuf, rc);
276 if(idx < 0) { break; } // no dcw received
277 if(!idx) { idx = cl->last_idx; }
278 reader->last_g = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** // for reconnect timeout
279 for(i = 0, n = 0; i < cfg.max_pending && n == 0; i++)
281 if(cl->ecmtask[i].idx == idx)
283 cl->pending--;
284 casc_check_dcw(reader, i, rc, dcw);
285 n++;
288 break;
290 case ACTION_READER_RESET:
291 cardreader_do_reset(reader);
292 break;
294 case ACTION_READER_ECM_REQUEST:
295 reader_get_ecm(reader, data->ptr);
296 break;
298 case ACTION_READER_EMM:
299 reader_do_emm(reader, data->ptr);
300 break;
302 case ACTION_READER_CARDINFO:
303 reader_do_card_info(reader);
304 break;
306 case ACTION_READER_POLL_STATUS:
307 cardreader_poll_status(reader);
308 break;
310 #ifdef READER_NAGRA_MERLIN
311 case ACTION_READER_RENEW_SK:
312 CAK7_getCamKey(reader);
313 break;
314 #endif
316 case ACTION_READER_INIT:
317 if(!cl->init_done)
318 { reader_init(reader); }
319 break;
321 case ACTION_READER_RESTART:
322 cl->kill = 1;
323 restart_reader = 1;
324 break;
326 case ACTION_READER_RESET_FAST:
327 reader->card_status = CARD_NEED_INIT;
328 cardreader_do_reset(reader);
329 break;
331 case ACTION_READER_CHECK_HEALTH:
332 cardreader_do_checkhealth(reader);
333 break;
335 case ACTION_READER_CAPMT_NOTIFY:
336 if(reader->ph.c_capmt) { reader->ph.c_capmt(cl, data->ptr); }
337 break;
339 case ACTION_CLIENT_UDP:
340 n = module->recv(cl, data->ptr, data->len);
341 if(n < 0) { break; }
342 module->s_handler(cl, data->ptr, n);
343 break;
345 case ACTION_CLIENT_TCP:
346 s = check_fd_for_data(cl->pfd);
347 if(s == 0) // no data, another thread already read from fd?
348 { break; }
349 if(s < 0) // system error or fd wants to be closed
351 cl->kill = 1; // kill client on next run
352 continue;
354 n = module->recv(cl, mbuf, bufsize);
355 if(n < 0)
357 cl->kill = 1; // kill client on next run
358 continue;
360 module->s_handler(cl, mbuf, n);
361 break;
363 case ACTION_CACHEEX1_DELAY:
364 cacheex_mode1_delay(data->ptr);
365 break;
367 case ACTION_CACHEEX_TIMEOUT:
368 cacheex_timeout(data->ptr);
369 break;
371 case ACTION_FALLBACK_TIMEOUT:
372 fallback_timeout(data->ptr);
373 break;
375 case ACTION_CLIENT_TIMEOUT:
376 ecm_timeout(data->ptr);
377 break;
379 case ACTION_ECM_ANSWER_READER:
380 chk_dcw(data->ptr);
381 break;
383 case ACTION_ECM_ANSWER_CACHE:
384 write_ecm_answer_fromcache(data->ptr);
385 break;
387 case ACTION_CLIENT_INIT:
388 if(module->s_init)
389 { module->s_init(cl); }
390 cl->is_udp = module->type == MOD_CONN_UDP;
391 cl->init_done = 1;
392 break;
394 case ACTION_CLIENT_IDLE:
395 if(module->s_idle)
396 { module->s_idle(cl); }
397 else
399 cs_log("user %s reached %d sec idle limit.", username(cl), cfg.cmaxidle);
400 cl->kill = 1;
402 break;
404 case ACTION_CACHE_PUSH_OUT:
405 cacheex_push_out(cl, data->ptr);
406 break;
408 case ACTION_CLIENT_KILL:
409 cl->kill = 1;
410 break;
412 case ACTION_CLIENT_SEND_MSG:
414 if (config_enabled(MODULE_CCCAM))
416 struct s_clientmsg *clientmsg = (struct s_clientmsg *)data->ptr;
417 cc_cmd_send(cl, clientmsg->msg, clientmsg->len, clientmsg->cmd);
419 break;
422 case ACTION_PEER_IDLE:
423 if(module->s_peer_idle)
424 { module->s_peer_idle(cl); }
425 break;
427 case ACTION_CLIENT_HIDECARDS:
429 #ifdef CS_ANTICASC
430 if(config_enabled(MODULE_CCCSHARE))
432 int32_t hidetime = (cl->account->acosc_penalty_duration == -1 ? cfg.acosc_penalty_duration : cl->account->acosc_penalty_duration);
433 if(hidetime)
435 int32_t hide_count;
436 int32_t cardsize;
437 int32_t ii, uu=0;
438 LLIST **sharelist = get_and_lock_sharelist();
439 LLIST *sharelist2 = ll_create("hidecards-sharelist");
441 for(ii = 0; ii < CAID_KEY; ii++)
443 if(sharelist[ii])
445 ll_putall(sharelist2, sharelist[ii]);
449 unlock_sharelist();
451 struct cc_card **cardarray = get_sorted_card_copy(sharelist2, 0, &cardsize);
452 ll_destroy(&sharelist2);
454 for(ii = 0; ii < cardsize; ii++)
456 if(hidecards_card_valid_for_client(cl, cardarray[ii]))
458 if (cardarray[ii]->id)
460 hide_count = hide_card_to_client(cardarray[ii], cl);
461 if(hide_count)
463 cs_log_dbg(D_TRACE, "Hiding card_%d caid=%04x remoteid=%08x from %s for %d %s",
464 uu, cardarray[ii]->caid, cardarray[ii]->remote_id, username(cl), hidetime, hidetime>1 ? "secconds" : "seccond");
465 uu += 1;
471 cs_sleepms(hidetime * 1000);
472 uu = 0;
474 for(ii = 0; ii < cardsize; ii++)
476 if(hidecards_card_valid_for_client(cl, cardarray[ii]))
478 if (cardarray[ii]->id)
480 hide_count = unhide_card_to_client(cardarray[ii], cl);
481 if(hide_count)
483 cs_log_dbg(D_TRACE, "Unhiding card_%d caid=%04x remoteid=%08x for %s",
484 uu, cardarray[ii]->caid, cardarray[ii]->remote_id, username(cl));
485 uu += 1;
491 NULLFREE(cardarray);
494 #endif
495 break;
496 } // case ACTION_CLIENT_HIDECARDS
498 } // switch
500 __free_job_data(cl, data);
503 if(thread_pipe[1] && (mbuf[0] != 0x00))
505 cs_log_dump_dbg(D_TRACE, mbuf, 1, "[OSCAM-WORK] Write to pipe:");
506 if(write(thread_pipe[1], mbuf, 1) == -1) // wakeup client check
508 cs_log_dbg(D_TRACE, "[OSCAM-WORK] Writing to pipe failed (errno=%d %s)", errno, strerror(errno));
512 // Check for some race condition where while we ended, another thread added a job
513 SAFE_MUTEX_LOCK(&cl->thread_lock);
514 if(cl->joblist && ll_count(cl->joblist) > 0)
516 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
517 continue;
519 else
521 cl->thread_active = 0;
522 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
523 break;
526 cl->thread_active = 0;
527 cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf)
528 NULLFREE(mbuf);
529 pthread_exit(NULL);
530 return NULL;
534 * adds a job to the job queue
535 * if ptr should be free() after use, set len to the size
536 * else set size to 0
538 int32_t add_job(struct s_client *cl, enum actions action, void *ptr, int32_t len)
540 if(!cl || cl->kill)
542 if(!cl)
543 { cs_log("WARNING: add_job failed. Client killed!"); } // Ignore jobs for killed clients
544 if(len && ptr)
545 { NULLFREE(ptr); }
546 return 0;
549 if(action == ACTION_CACHE_PUSH_OUT && cacheex_check_queue_length(cl))
551 if(len && ptr)
552 { NULLFREE(ptr); }
553 return 0;
556 struct job_data *data;
557 if(!cs_malloc(&data, sizeof(struct job_data)))
559 if(len && ptr)
560 { NULLFREE(ptr); }
561 return 0;
564 data->action = action;
565 data->ptr = ptr;
566 data->cl = cl;
567 data->len = len;
568 cs_ftime(&data->time);
570 SAFE_MUTEX_LOCK(&cl->thread_lock);
571 if(cl && !cl->kill && cl->thread_active)
573 if(!cl->joblist)
574 { cl->joblist = ll_create("joblist"); }
575 ll_append(cl->joblist, data);
576 if(cl->thread_active == 2)
577 { pthread_kill(cl->thread, OSCAM_SIGNAL_WAKEUP); }
578 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
579 cs_log_dbg(D_TRACE, "add %s job action %d queue length %d %s",
580 action > ACTION_CLIENT_FIRST ? "client" : "reader", action,
581 ll_count(cl->joblist), username(cl));
582 return 1;
585 /* pcsc doesn't like this; segfaults on x86, x86_64 */
586 int8_t modify_stacksize = 0;
587 struct s_reader *rdr = cl->reader;
588 if(cl->typ != 'r' || !rdr || rdr->typ != R_PCSC)
589 { modify_stacksize = 1; }
591 if(action != ACTION_READER_CHECK_HEALTH)
593 cs_log_dbg(D_TRACE, "start %s thread action %d",
594 action > ACTION_CLIENT_FIRST ? "client" : "reader", action);
597 int32_t ret = start_thread("client work", work_thread, (void *)data, &cl->thread, 1, modify_stacksize);
598 if(ret)
600 cs_log("ERROR: can't create thread for %s (errno=%d %s)",
601 action > ACTION_CLIENT_FIRST ? "client" : "reader", ret, strerror(ret));
602 free_job_data(data);
605 cl->thread_active = 1;
606 SAFE_MUTEX_UNLOCK(&cl->thread_lock);
607 return 1;