1 #define MODULE_LOG_PREFIX "work"
4 #include "module-cacheex.h"
5 #include "oscam-client.h"
8 #include "oscam-lock.h"
10 #include "oscam-reader.h"
11 #include "oscam-string.h"
12 #include "oscam-work.h"
13 #include "reader-common.h"
14 #include "module-cccam.h"
15 #include "module-cccam-data.h"
16 #include "module-cccshare.h"
17 #include "oscam-time.h"
19 extern CS_MUTEX_LOCK system_lock
;
20 extern int32_t thread_pipe
[2];
32 static void free_job_data(struct job_data
*data
)
36 if(data
->len
&& data
->ptr
)
38 // special free checks
39 if(data
->action
==ACTION_ECM_ANSWER_CACHE
)
41 NULLFREE(((struct s_write_from_cache
*)data
->ptr
)->er_cache
);
49 void free_joblist(struct s_client
*cl
)
51 int32_t lock_status
= pthread_mutex_trylock(&cl
->thread_lock
);
52 LL_ITER it
= ll_iter_create(cl
->joblist
);
54 struct job_data
*data
;
55 while((data
= ll_iter_next(&it
)))
60 ll_destroy(&cl
->joblist
);
63 if(cl
->work_job_data
) // Free job_data that was not freed by work_thread
64 { free_job_data(cl
->work_job_data
); }
66 cl
->work_job_data
= NULL
;
69 { SAFE_MUTEX_UNLOCK(&cl
->thread_lock
); }
71 pthread_mutex_destroy(&cl
->thread_lock
);
75 Work threads are named like this:
76 w[r|c]XX-[rdr->label|client->username]
78 w - work thread prefix
79 [r|c] - depending whether the the action is related to reader or client
80 XX - two digit action code from enum actions
81 label - reader label or client username (see username() function)
83 static void set_work_thread_name(struct job_data
*data
)
85 char thread_name
[16 + 1];
86 snprintf(thread_name
, sizeof(thread_name
), "w%c%02d-%s",
87 data
->action
< ACTION_CLIENT_FIRST
? 'r' : 'c',
91 set_thread_name(thread_name
);
94 #define __free_job_data(client, job_data) \
96 client->work_job_data = NULL; \
97 if(job_data && job_data != &tmp_data) { \
98 free_job_data(job_data); \
103 void *work_thread(void *ptr
)
105 struct job_data
*data
= (struct job_data
*)ptr
;
106 struct s_client
*cl
= data
->cl
;
107 struct s_reader
*reader
= cl
->reader
;
108 struct timeb start
, end
; // start time poll, end time poll
110 struct job_data tmp_data
;
111 struct pollfd pfd
[1];
113 SAFE_SETSPECIFIC(getclient
, cl
);
114 cl
->thread
= pthread_self();
115 cl
->thread_active
= 1;
117 set_work_thread_name(data
);
119 struct s_module
*module
= get_module(cl
);
120 uint16_t bufsize
= module
->bufsize
; // CCCam needs more than 1024bytes!
122 { bufsize
= DEFAULT_MODULE_BUFSIZE
; }
125 if(!cs_malloc(&mbuf
, bufsize
))
128 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
129 int32_t n
= 0, rc
= 0, i
, idx
, s
;
131 int8_t restart_reader
= 0;
133 while(cl
->thread_active
)
135 cs_ftime(&start
); // register start time
137 while(cl
->thread_active
)
139 if(!cl
|| cl
->kill
|| !is_valid_client(cl
))
141 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
142 cl
->thread_active
= 0;
143 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
144 cs_log_dbg(D_TRACE
, "ending thread (kill)");
145 __free_job_data(cl
, data
);
146 cl
->work_mbuf
= NULL
; // Prevent free_client from freeing mbuf (->work_mbuf)
149 { restart_cardreader(reader
, 0); }
155 if(data
&& data
->action
!= ACTION_READER_CHECK_HEALTH
)
156 { cs_log_dbg(D_TRACE
, "data from add_job action=%d client %c %s", data
->action
, cl
->typ
, username(cl
)); }
160 if(!cl
->kill
&& cl
->typ
!= 'r')
161 { client_check_status(cl
); } // do not call for physical readers as this might cause an endless job loop
163 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
164 if(cl
->joblist
&& ll_count(cl
->joblist
) > 0)
166 LL_ITER itr
= ll_iter_create(cl
->joblist
);
167 data
= ll_iter_next_remove(&itr
);
169 { set_work_thread_name(data
); }
170 //cs_log_dbg(D_TRACE, "start next job from list action=%d", data->action);
172 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
177 /* for serial client cl->pfd is file descriptor for serial port not socket
178 for example: pfd=open("/dev/ttyUSB0"); */
179 if(!cl
->pfd
|| module
->listenertype
== LIS_SERIAL
)
183 pfd
[0].events
= POLLIN
| POLLPRI
;
185 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
186 cl
->thread_active
= 2;
187 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
189 rc
= poll(pfd
, 1, 3000);
191 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
192 cl
->thread_active
= 1;
193 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
197 cs_ftime(&end
); // register end time
198 cs_log_dbg(D_TRACE
, "[OSCAM-WORK] new event %d occurred on fd %d after %"PRId64
" ms inactivity", pfd
[0].revents
,
199 pfd
[0].fd
, comp_timeb(&end
, &start
));
202 cs_ftime(&start
); // register start time for new poll next run
205 { data
->action
= ACTION_READER_REMOTE
; }
210 data
->action
= ACTION_CLIENT_UDP
;
215 { data
->action
= ACTION_CLIENT_TCP
; }
217 if(pfd
[0].revents
& (POLLHUP
| POLLNVAL
| POLLERR
))
226 if(!reader
&& data
->action
< ACTION_CLIENT_FIRST
)
228 __free_job_data(cl
, data
);
235 struct timeb actualtime
;
236 cs_ftime(&actualtime
);
237 int64_t gone
= comp_timeb(&actualtime
, &data
->time
);
238 if(data
!= &tmp_data
&& gone
> (int) cfg
.ctimeout
+1000)
240 cs_log_dbg(D_TRACE
, "dropping client data for %s time %"PRId64
" ms", username(cl
), gone
);
241 __free_job_data(cl
, data
);
245 if(data
!= &tmp_data
)
246 { cl
->work_job_data
= data
; } // Track the current job_data
250 case ACTION_READER_IDLE
:
251 reader_do_idle(reader
);
254 case ACTION_READER_REMOTE
:
255 s
= check_fd_for_data(cl
->pfd
);
256 if(s
== 0) // no data, another thread already read from fd?
260 if(reader
->ph
.type
== MOD_CONN_TCP
)
261 { network_tcp_connection_close(reader
, "disconnect"); }
264 rc
= reader
->ph
.recv(cl
, mbuf
, bufsize
);
267 if(reader
->ph
.type
== MOD_CONN_TCP
)
268 { network_tcp_connection_close(reader
, "disconnect on receive"); }
271 cl
->last
= time(NULL
); // *********************************** TO BE REPLACE BY CS_FTIME() LATER ****************
272 idx
= reader
->ph
.c_recv_chk(cl
, dcw
, &rc
, mbuf
, rc
);
273 if(idx
< 0) { break; } // no dcw received
274 if(!idx
) { idx
= cl
->last_idx
; }
275 reader
->last_g
= time(NULL
); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** // for reconnect timeout
276 for(i
= 0, n
= 0; i
< cfg
.max_pending
&& n
== 0; i
++)
278 if(cl
->ecmtask
[i
].idx
== idx
)
281 casc_check_dcw(reader
, i
, rc
, dcw
);
287 case ACTION_READER_RESET
:
288 cardreader_do_reset(reader
);
291 case ACTION_READER_ECM_REQUEST
:
292 reader_get_ecm(reader
, data
->ptr
);
295 case ACTION_READER_EMM
:
296 reader_do_emm(reader
, data
->ptr
);
299 case ACTION_READER_CARDINFO
:
300 reader_do_card_info(reader
);
303 case ACTION_READER_POLL_STATUS
:
304 cardreader_poll_status(reader
);
307 case ACTION_READER_INIT
:
309 { reader_init(reader
); }
312 case ACTION_READER_RESTART
:
317 case ACTION_READER_RESET_FAST
:
318 reader
->card_status
= CARD_NEED_INIT
;
319 cardreader_do_reset(reader
);
322 case ACTION_READER_CHECK_HEALTH
:
323 cardreader_do_checkhealth(reader
);
326 case ACTION_READER_CAPMT_NOTIFY
:
327 if(reader
->ph
.c_capmt
) { reader
->ph
.c_capmt(cl
, data
->ptr
); }
330 case ACTION_CLIENT_UDP
:
331 n
= module
->recv(cl
, data
->ptr
, data
->len
);
333 module
->s_handler(cl
, data
->ptr
, n
);
336 case ACTION_CLIENT_TCP
:
337 s
= check_fd_for_data(cl
->pfd
);
338 if(s
== 0) // no data, another thread already read from fd?
340 if(s
< 0) // system error or fd wants to be closed
342 cl
->kill
= 1; // kill client on next run
345 n
= module
->recv(cl
, mbuf
, bufsize
);
348 cl
->kill
= 1; // kill client on next run
351 module
->s_handler(cl
, mbuf
, n
);
354 case ACTION_CACHEEX1_DELAY
:
355 cacheex_mode1_delay(data
->ptr
);
358 case ACTION_CACHEEX_TIMEOUT
:
359 cacheex_timeout(data
->ptr
);
362 case ACTION_FALLBACK_TIMEOUT
:
363 fallback_timeout(data
->ptr
);
366 case ACTION_CLIENT_TIMEOUT
:
367 ecm_timeout(data
->ptr
);
370 case ACTION_ECM_ANSWER_READER
:
374 case ACTION_ECM_ANSWER_CACHE
:
375 write_ecm_answer_fromcache(data
->ptr
);
378 case ACTION_CLIENT_INIT
:
380 { module
->s_init(cl
); }
381 cl
->is_udp
= module
->type
== MOD_CONN_UDP
;
385 case ACTION_CLIENT_IDLE
:
387 { module
->s_idle(cl
); }
390 cs_log("user %s reached %d sec idle limit.", username(cl
), cfg
.cmaxidle
);
395 case ACTION_CACHE_PUSH_OUT
:
396 cacheex_push_out(cl
, data
->ptr
);
399 case ACTION_CLIENT_KILL
:
403 case ACTION_CLIENT_SEND_MSG
:
405 if (config_enabled(MODULE_CCCAM
))
407 struct s_clientmsg
*clientmsg
= (struct s_clientmsg
*)data
->ptr
;
408 cc_cmd_send(cl
, clientmsg
->msg
, clientmsg
->len
, clientmsg
->cmd
);
413 case ACTION_PEER_IDLE
:
414 if(module
->s_peer_idle
)
415 { module
->s_peer_idle(cl
); }
417 case ACTION_CLIENT_HIDECARDS
:
420 if(config_enabled(MODULE_CCCSHARE
))
422 int32_t hidetime
= (cl
->account
->acosc_penalty_duration
== -1 ? cfg
.acosc_penalty_duration
: cl
->account
->acosc_penalty_duration
);
428 LLIST
**sharelist
= get_and_lock_sharelist();
429 LLIST
*sharelist2
= ll_create("hidecards-sharelist");
431 for(ii
= 0; ii
< CAID_KEY
; ii
++)
435 ll_putall(sharelist2
, sharelist
[ii
]);
441 struct cc_card
**cardarray
= get_sorted_card_copy(sharelist2
, 0, &cardsize
);
442 ll_destroy(&sharelist2
);
444 for(ii
= 0; ii
< cardsize
; ii
++)
446 if(hidecards_card_valid_for_client(cl
, cardarray
[ii
]))
448 if (cardarray
[ii
]->id
)
450 hide_count
= hide_card_to_client(cardarray
[ii
], cl
);
453 cs_log_dbg(D_TRACE
, "Hiding card_%d caid=%04x remoteid=%08x from %s for %d %s",
454 uu
, cardarray
[ii
]->caid
, cardarray
[ii
]->remote_id
, username(cl
), hidetime
, hidetime
>1 ? "secconds" : "seccond");
461 cs_sleepms(hidetime
* 1000);
464 for(ii
= 0; ii
< cardsize
; ii
++)
466 if(hidecards_card_valid_for_client(cl
, cardarray
[ii
]))
468 if (cardarray
[ii
]->id
)
470 hide_count
= unhide_card_to_client(cardarray
[ii
], cl
);
473 cs_log_dbg(D_TRACE
, "Unhiding card_%d caid=%04x remoteid=%08x for %s",
474 uu
, cardarray
[ii
]->caid
, cardarray
[ii
]->remote_id
, username(cl
));
486 } // case ACTION_CLIENT_HIDECARDS
490 __free_job_data(cl
, data
);
493 if(thread_pipe
[1] && (mbuf
[0] != 0x00))
495 cs_log_dump_dbg(D_TRACE
, mbuf
, 1, "[OSCAM-WORK] Write to pipe:");
496 if(write(thread_pipe
[1], mbuf
, 1) == -1) // wakeup client check
498 cs_log_dbg(D_TRACE
, "[OSCAM-WORK] Writing to pipe failed (errno=%d %s)", errno
, strerror(errno
));
502 // Check for some race condition where while we ended, another thread added a job
503 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
504 if(cl
->joblist
&& ll_count(cl
->joblist
) > 0)
506 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
511 cl
->thread_active
= 0;
512 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
516 cl
->thread_active
= 0;
517 cl
->work_mbuf
= NULL
; // Prevent free_client from freeing mbuf (->work_mbuf)
524 * adds a job to the job queue
525 * if ptr should be free() after use, set len to the size
528 int32_t add_job(struct s_client
*cl
, enum actions action
, void *ptr
, int32_t len
)
533 { cs_log("WARNING: add_job failed. Client killed!"); } // Ignore jobs for killed clients
539 if(action
== ACTION_CACHE_PUSH_OUT
&& cacheex_check_queue_length(cl
))
546 struct job_data
*data
;
547 if(!cs_malloc(&data
, sizeof(struct job_data
)))
554 data
->action
= action
;
558 cs_ftime(&data
->time
);
560 SAFE_MUTEX_LOCK(&cl
->thread_lock
);
561 if(cl
&& !cl
->kill
&& cl
->thread_active
)
564 { cl
->joblist
= ll_create("joblist"); }
565 ll_append(cl
->joblist
, data
);
566 if(cl
->thread_active
== 2)
567 { pthread_kill(cl
->thread
, OSCAM_SIGNAL_WAKEUP
); }
568 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);
569 cs_log_dbg(D_TRACE
, "add %s job action %d queue length %d %s",
570 action
> ACTION_CLIENT_FIRST
? "client" : "reader", action
,
571 ll_count(cl
->joblist
), username(cl
));
575 /* pcsc doesn't like this; segfaults on x86, x86_64 */
576 int8_t modify_stacksize
= 0;
577 struct s_reader
*rdr
= cl
->reader
;
578 if(cl
->typ
!= 'r' || !rdr
|| rdr
->typ
!= R_PCSC
)
579 { modify_stacksize
= 1; }
581 if(action
!= ACTION_READER_CHECK_HEALTH
)
583 cs_log_dbg(D_TRACE
, "start %s thread action %d",
584 action
> ACTION_CLIENT_FIRST
? "client" : "reader", action
);
587 int32_t ret
= start_thread("client work", work_thread
, (void *)data
, &cl
->thread
, 1, modify_stacksize
);
590 cs_log("ERROR: can't create thread for %s (errno=%d %s)",
591 action
> ACTION_CLIENT_FIRST
? "client" : "reader", ret
, strerror(ret
));
595 cl
->thread_active
= 1;
596 SAFE_MUTEX_UNLOCK(&cl
->thread_lock
);