/* WebDownloader for X-Window * Copyright (C) 1999-2002 Koshelev Maxim * This Program is free but not GPL!!! You can't modify it * without agreement with author. You can't distribute modified * program but you can distribute unmodified program. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include "srvclt.h" #include "var.h" #include "main.h" #include "locstr.h" #include "signal.h" #include #include #include #include #include #include #include #include #include #include "face/lod.h" #if defined(sun) typedef int socklen_t; #endif void server_thread_stop(int i){ pthread_exit(NULL); }; static void *server_thread_run(void *what){ struct sigaction action,old_action; action.sa_handler=server_thread_stop; action.sa_flags=0; sigaction(SIGUSR2,&action,&old_action); sigset_t oldmask,newmask; sigemptyset(&newmask); sigaddset(&newmask,SIGTERM); sigaddset(&newmask,SIGINT); sigaddset(&newmask,SIGUSR1); pthread_sigmask(SIG_BLOCK,&newmask,&oldmask); tMsgServer *srv=(tMsgServer *)what; srv->run(); return NULL; }; tMsgServer::tMsgServer(){ file=NULL; fd=newfd=0; }; tMsgServer::~tMsgServer(){ if (fd>0) close(fd); if (newfd>0) close(newfd); unlink(file); delete[] file; }; void tMsgServer::run_thread(){ pthread_attr_t attr_p; pthread_attr_init(&attr_p); pthread_attr_setdetachstate(&attr_p,PTHREAD_CREATE_JOINABLE); pthread_attr_setscope(&attr_p,PTHREAD_SCOPE_SYSTEM); pthread_create(&thread_id,&attr_p,server_thread_run,this); }; void tMsgServer::stop_thread(){ void *rc; pthread_kill(thread_id,SIGUSR2); pthread_join(thread_id,(void **)&rc); }; int tMsgServer::init(){ struct sockaddr_un saddr; fd=socket(AF_UNIX,SOCK_STREAM,0); if (fd == -1) return(-1); saddr.sun_family = AF_UNIX; sprintf(saddr.sun_path, "%s/downloader_for_x_sock_%s", g_get_tmp_dir(), g_get_user_name()); unlink(saddr.sun_path); file=copy_string(saddr.sun_path); if (bind(fd,(struct sockaddr *)&saddr,sizeof(saddr)) == -1) return(-1); listen(fd,5); return(0); }; void tMsgServer::cmd_return_int(int what){ tPacket packet; packet.type=PACKET_ACK; packet.len=sizeof(int); write(newfd,&packet,sizeof(packet)); write(newfd,&what,sizeof(what)); }; void tMsgServer::cmd_ack(){ cmd_return_int(0); }; void tMsgServer::write_dwn_status(tDownload *dwn,int full){ tPacketStatus status; if (dwn){ if (full) status.url=copy_string(std::string(d4x::ShortURL(dwn->info)).c_str()); status.Size=dwn->finfo.size; status.Download=dwn->Size; status.Time=dwn->Start; status.Speed=dwn->Speed; status.Status=dwn->owner(); /* FIXME: possible race condition */ status.Attempt=dwn->Attempt; status.MaxAttempt=dwn->config?dwn->config->number_of_attempts:CFG.DEFAULT_CFG.number_of_attempts; }; ALL_DOWNLOADS->unlock(); tPacket packet; packet.type=PACKET_ACK; if (dwn){ packet.len=sizeof(tPacketStatus)-sizeof(char*); if (full) packet.len+=strlen(status.url)+1; write(newfd,&packet,sizeof(packet)); write(newfd,&status,sizeof(status)-sizeof(char*)); if (full) write(newfd,status.url,strlen(status.url)+1); }else{ packet.len=0; write(newfd,&packet,sizeof(packet)); }; }; static d4xDownloadQueue *_get_queue_sub_(tQueue *q,int &N){ d4xDownloadQueue *dq=(d4xDownloadQueue *)(q->first()); while(dq){ N--; if (N==0) return(dq); d4xDownloadQueue *rval=_get_queue_sub_(&(dq->child),N); if (N<=0) return(rval); dq=(d4xDownloadQueue *)(dq->prev); }; return(NULL); }; d4xDownloadQueue *d4x_get_queue_num(int N){ return(_get_queue_sub_(&D4X_QTREE,N)); }; void tMsgServer::cmd_ls(int len,int type){ if (!len) return; char *temp=new char[len+1]; int N=0; if (read(newfd,temp,len)!=len){ delete[] temp; return; }; temp[len]=0; if (sscanf(temp,"%i",&N)!=1 || N<0){ tDownload *dl=new tDownload; dl->info=std::string(temp); ALL_DOWNLOADS->lock(); tDownload *answer=ALL_DOWNLOADS->find(dl); delete(dl); write_dwn_status(answer); }else{ // output whole list ALL_DOWNLOADS->lock(); d4xDownloadQueue *q=d4x_get_queue_num(N); if (q!=NULL){ d4xWFNode *node=(d4xWFNode *)(q->qv.ListOfDownloadsWF.first()); while (node) { d4xWFNode *next=(d4xWFNode *)(node->prev); if (node->dwn){ write_dwn_status(node->dwn,1); ALL_DOWNLOADS->lock(); }; if (next==NULL || next->next==node) node=next; else break; }; }; ALL_DOWNLOADS->unlock(); }; delete[] temp; }; void tMsgServer::cmd_lstree_sub(tQueue *q){ char b=LST_SUBQUEUE; d4xDownloadQueue *dq=(d4xDownloadQueue *)(q->first()); write(newfd,&b,sizeof(b)); while(dq){ if (dq==D4X_QUEUE) b=LST_DQUEUE; else b=LST_QUEUE; write(newfd,&b,sizeof(b)); int len=strlen(dq->name.get()); write(newfd,&len,sizeof(len)); write(newfd,dq->name.get(),len); len=dq->count(); write(newfd,&len,sizeof(len)); len=dq->count(DL_RUN); write(newfd,&len,sizeof(len)); len=dq->count(DL_COMPLETE); write(newfd,&len,sizeof(len)); len=dq->MAX_ACTIVE; write(newfd,&len,sizeof(len)); cmd_lstree_sub(&(dq->child)); dq=(d4xDownloadQueue *)(dq->prev); }; b=LST_UPQUEUE; write(newfd,&b,sizeof(b)); }; void tMsgServer::cmd_lstree(){ ALL_DOWNLOADS->lock(); cmd_lstree_sub(&D4X_QTREE); ALL_DOWNLOADS->unlock(); }; void tMsgServer::cmd_add(int len,int type){ char *temp=new char[len+1]; if (read(newfd,temp,len)==len){ temp[len]=0; d4x::RemoteCommand ncmd; ncmd.type=type; char *a=temp; while(a-temp0){ tPacket packet; struct sockaddr_un addr; int tmp=sizeof(addr); newfd=accept(fd,(sockaddr *)&addr,(socklen_t *)&tmp); if (newfd>0 && read(newfd,&packet,sizeof (packet))>=0){ switch (packet.type){ case PACKET_EXIT_TIME: case PACKET_RERUN_FAILED: case PACKET_ADD_OPEN: case PACKET_SET_MAX_THREADS: case PACKET_DEL_COMPLETED: case PACKET_SET_SAVE_PATH: case PACKET_SET_SPEED_LIMIT: case PACKET_ICONIFY: case PACKET_POPUP: case PACKET_MSG: case PACKET_STOP: case PACKET_DEL: case PACKET_OPENLIST: case PACKET_ADD:{ cmd_add(packet.len,packet.type); break; }; case PACKET_ASK_SPEED:{ cmd_return_int(GlobalMeter->last_value()); break; }; case PACKET_ASK_RUN:{ cmd_return_int(D4X_QUEUE->count(DL_RUN)); break; }; case PACKET_ASK_STOP:{ cmd_return_int(D4X_QUEUE->count(DL_STOP)); break; }; case PACKET_ASK_PAUSE:{ cmd_return_int(D4X_QUEUE->count(DL_PAUSE)+D4X_QUEUE->count(DL_STOPWAIT)); break; }; case PACKET_ASK_COMPLETE:{ cmd_return_int(D4X_QUEUE->count(DL_COMPLETE)); break; }; case PACKET_ASK_READED_BYTES:{ cmd_return_int(GVARS.READED_BYTES); break; }; case PACKET_ASK_FULLAMOUNT:{ int a=D4X_QUEUE->count(); cmd_return_int(a); break; }; case PACKET_ACK:{ cmd_ack(); break; }; case PACKET_LS:{ cmd_ls(packet.len,packet.type); break; }; case PACKET_LSTREE:{ cmd_lstree(); break; }; case PACKET_SWITCH_QUEUE:{ cmd_add(packet.len,packet.type); break; }; default: case PACKET_NOP: break; }; }; if (newfd>0) close(newfd); newfd=0; }; }; pthread_exit(NULL); }; bool tMsgServer::empty(){ lock.lock(); bool rval=COMMANDS.empty(); lock.unlock(); return rval; }; d4x::RemoteCommand tMsgServer::get_command(){ lock.lock(); d4x::RemoteCommand temp=*(COMMANDS.begin()); COMMANDS.pop_front(); lock.unlock(); return temp; }; /* tMsgClient, send command if Downloader already run */ tMsgClient::tMsgClient(){ fd=0; buf=NULL; bufsize=0; }; int tMsgClient::init(){ done(); uid_t stored_uid, euid; struct sockaddr_un saddr; if ((fd=socket(AF_UNIX, SOCK_STREAM, 0)) > 0){ saddr.sun_family = AF_UNIX; stored_uid = getuid(); euid = geteuid(); setuid(euid); sprintf(saddr.sun_path, "%s/downloader_for_x_sock_%s", g_get_tmp_dir(), g_get_user_name()); setreuid(stored_uid, euid); if (connect(fd,(struct sockaddr *) &saddr, sizeof (saddr)) <0) return -1; return 0; }; return -1; }; int tMsgClient::send_command(int cmd,char *data,int len){ if (init()) return -1; tPacket command; command.type=cmd; command.len = data!=NULL ? len:0; write(fd, &command, sizeof (command)); if (command.len) write(fd, data, command.len); if (read(fd,&command,sizeof(command))<0) return -1; if (command.type!=PACKET_ACK) return -1; if (buf) delete[] buf; if (command.len){ buf=new char[command.len]; read(fd,buf,command.len); }else buf=NULL; bufsize=command.len; return 0; }; int tMsgClient::send_command_short(int cmd,char *data,int len){ if (init()) return -1; tPacket command; command.type=cmd; command.len = data!=NULL ? len:0; write(fd, &command, sizeof (command)); if (command.len) write(fd, data, command.len); return 0; }; int tMsgClient::get_answer_int(){ int tmp=0; if (bufsize==sizeof(int)){ memcpy(&tmp,buf,sizeof(int)); }; return tmp; }; int tMsgClient::get_answer_status(tPacketStatus *status){ tPacket command; command.type=PACKET_NOP; if (read(fd,&command,sizeof(command))<=0) return 0; if (command.type!=PACKET_ACK) return 0; if (buf) delete[] buf; if (command.len){ buf=new char[command.len]; read(fd,buf,command.len); }else buf=NULL; bufsize=command.len; int size=sizeof(tPacketStatus)-sizeof(char *); if (bufsize>=size){ memcpy(status,buf,size); if (bufsize>size){ int len=bufsize-size; status->url=new char[len+1]; memcpy(status->url,buf+size,len); status->url[len]=0; }; return(1); }; return(0); }; void tMsgClient::done(){ if (fd>0){ close(fd); fd=0; }; }; int tMsgClient::readdata(void *buf,int len){ return(read(fd,buf,len)); }; tMsgClient::~tMsgClient(){ done(); if (buf) delete[] buf; };