I'm working on recoding the dvbapi of a specific softcam, but as I'm unexperienced coder right now I'm stuck.
That specific softcam is fetching with poll() events on sockets. No matter what I change in the code every time the poll returns event 3 on far too many sockets.
Always after exact 100ms the poll() returns an event 3 on some filedescriptors
Event 3 is POLLIN + POLLPRI, if I ignore them no decoding is done ever, if I handle them as they should: the cam is asking over and over the exact same ecm to be decrypted.
Right now I'm thinking that poll() isnt the right way to ask enigma2 for events. Perhaps it must be done differently but I dont know how.
Is there any good documentation to read for me how to do this in a correct way? I already found some info on dvb3 api but it seems outdated and not covering any part that is interesting to know in combination with a softcam.
Is it possible / better to switch from poll() to async io ? If so, since I'm unexperienced coder can someone give me a small example code I can adopt further to implement in the dvbapi?
Here my (bad) poll() code, returning approx every 100ms an POLLIN/POLLPRI and asking over and over the same ecm.
Any pointers on this topic are appriciated!
static void * dvbapi_main_local(void *cli) {#ifdef WITH_AZBOX return azbox_main_thread(cli);#endif#ifdef WITH_MCA selected_box = selected_api = 0; // Prevent compiler warning about out of bounds array access return mca_main_thread(cli);#endif struct s_client * client = (struct s_client *) cli; client->thread=pthread_self(); pthread_setspecific(getclient, cli); dvbapi_client=cli; int32_t maxpfdsize=(MAX_DEMUX*MAX_FILTER)+MAX_DEMUX+2; struct pollfd pfd2[maxpfdsize]; int32_t i,rc,pfdcount,g,connfd,clilen,j; int32_t ids[maxpfdsize], fdn[maxpfdsize], type[maxpfdsize]; struct sockaddr_un servaddr; ssize_t len=0; uchar mbuf[1024]; struct timeb start, end; struct s_auth *account; int32_t ok=0; for (account = cfg.account; account; account=account->next) { if ((ok = streq(cfg.dvbapi_usr, account->usr))) break; } cs_auth_client(client, ok ? account : (struct s_auth *)(-1), "dvbapi"); memset(demux, 0, sizeof(struct demux_s) * MAX_DEMUX); memset(ca_fd, 0, sizeof(ca_fd)); dvbapi_read_priority(); dvbapi_detect_api(); if (selected_box == -1 || selected_api==-1) { cs_log("ERROR: Could not detect DVBAPI version."); return NULL; } if (cfg.dvbapi_pmtmode == 1) disable_pmt_files=1; int32_t listenfd = -1; if (cfg.dvbapi_boxtype != BOXTYPE_IPBOX_PMT && cfg.dvbapi_pmtmode != 2 && cfg.dvbapi_pmtmode != 5) { listenfd = dvbapi_init_listenfd(); if (listenfd < 1) { cs_log("ERROR: Could not init camd.socket."); return NULL; } } pthread_mutex_init(&event_handler_lock, NULL); if (cfg.dvbapi_pmtmode != 4 && cfg.dvbapi_pmtmode != 5) { struct sigaction signal_action; signal_action.sa_handler = event_handler; sigemptyset(&signal_action.sa_mask); signal_action.sa_flags = SA_RESTART; sigaction(SIGRTMIN + 1, &signal_action, NULL); dir_fd = open(TMPDIR, O_RDONLY); if (dir_fd >= 0) { fcntl(dir_fd, F_SETSIG, SIGRTMIN + 1); fcntl(dir_fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_DELETE | DN_MULTISHOT); event_handler(SIGRTMIN + 1); } } else { pthread_t event_thread; int32_t ret = pthread_create(&event_thread, NULL, dvbapi_event_thread, (void*) dvbapi_client); if(ret){ cs_log("ERROR: Can't create dvbapi event thread (errno=%d %s)", ret, strerror(ret)); return NULL; } else pthread_detach(event_thread); } pfd2[0].fd = listenfd; pfd2[0].events = (POLLIN | POLLPRI); type[0]=1;#ifdef WITH_COOLAPI system("pzapit -rz");#endif while (1) { pfdcount = (listenfd > -1) ? 1 : 0; for (i=0;i<MAX_DEMUX;i++) { for (g=0;g<MAX_FILTER;g++) { if (demux[i].demux_fd[g].fd>0 && selected_api != STAPI && selected_api != COOLAPI) { pfd2[pfdcount].fd = demux[i].demux_fd[g].fd; pfd2[pfdcount].events = (POLLIN | POLLPRI); pfd2[pfdcount].revents = 0; ids[pfdcount]=i; fdn[pfdcount]=g; type[pfdcount++]=0; } } if (demux[i].socket_fd>0) { rc=0; if (cfg.dvbapi_boxtype==BOXTYPE_IPBOX) { for (j = 0; j < pfdcount; j++) { if (pfd2[j].fd == demux[i].socket_fd) { rc=1; break; } } if (rc==1) continue; } pfd2[pfdcount].fd=demux[i].socket_fd; pfd2[pfdcount].events = (POLLIN | POLLPRI); pfd2[pfdcount].revents = 0; ids[pfdcount]=i; type[pfdcount++]=1; } } cs_ftime(&start); // register start time rc = poll(pfd2, pfdcount, -1); if (rc<1) continue; cs_ftime(&end); // register end time for (i = 0; (i < pfdcount); i++) { if (!(pfd2[i])->revents) continue; // no event on this socket? -> checkout next one //if (type[i]==1 && (pfd2+i)->revents == 3) continue; // no new event on this socket -> checkout next one cs_debug_mask(D_TRACE, "[DVBAPI] %d new event %d occurred on fd %d after %ld ms inactivity", selected_api, pfd2[i].revents, pfd2[i].fd,1000*(end.time-start.time)+end.millitm-start.millitm); rc--; // handling this event, so decrease total number events to handle if (pfd2[i].revents & (POLLHUP | POLLNVAL)) { // we got an close message if (type[i]==1) { // 0=free socket, 1=occupied socket for (j=0;j<MAX_DEMUX;j++) { if (demux[j].socket_fd==pfd2[i].fd) { dvbapi_stop_descrambling(j); // stop descrambling this pid } } close(pfd2[i].fd); // close socket } } if (pfd2[i].revents & (POLLIN | POLLPRI)) { // check for new messages on sockets if (type[i]==1) { // 0=free socket, 1=occupied socket if (pfd2[i].fd==listenfd) { clilen = sizeof(servaddr); connfd = accept(listenfd, (struct sockaddr *)&servaddr, (socklen_t *)&clilen); cs_debug_mask(D_DVBAPI, "[DVBAPI] new socket connection fd: %d", connfd); disable_pmt_files=1; if (connfd <= 0) { cs_debug_mask(D_DVBAPI,"[DVBAPI] accept() returns error on fd event %d (errno=%d %s)", pfd2[i].revents, errno, strerror(errno)); continue; } } else { cs_debug_mask(D_DVBAPI, "[DVBAPI] PMT Update on existing socket %d.", pfd2[i].fd); connfd = pfd2[i].fd; } len = read(connfd, mbuf, sizeof(mbuf)); if (len < 3) { cs_debug_mask(D_DVBAPI, "[DVBAPI] camd.socket: too small message received"); continue; } dvbapi_handlesockmsg(mbuf, len, connfd); } else { // type==0 -> got new message on free socket int32_t demux_index=ids[i]; int32_t n=fdn[i]; if ((len=dvbapi_read_device(pfd2[i].fd, mbuf, sizeof(mbuf))) <= 0) { if (demux[demux_index].pidindex==-1) { dvbapi_try_next_caid(demux_index); } continue; } if (pfd2[i].fd==(int)demux[demux_index].demux_fd[n].fd) { dvbapi_process_input(demux_index,n,mbuf,len); // start ecmfilter if (cfg.dvbapi_au>0) dvbapi_start_emm_filter(demux_index); // start emmfilter (if enabled by user) } } } } } return NULL;}
Edited by Frenske, 14 April 2013 - 09:24.
Some details adapted at the request of TS.