/* * FTP/HTTP daemon * process.cc Copyright (C) 1995, 96 Alex Belits * * This source/code is public free; you can distribute it and/or modify * it under terms of the GNU General Public License (published by the * Free Software Foundation) either version two of this License, or any * later version. * */ #include "fhttpd.h" #include "process.h" #include "log.h" #ifdef NEED_CRYPT_H #include #endif #ifdef USE_GETSPNAM #include #endif #ifdef AIX4 extern "C" int initgroups(const char *user, gid_t group); #endif #ifdef IRIX #include "irix-fix.h" #endif class ProcessServer *processserver=NULL; int ApplicationInstance::Send(char *data,int size){ if(size<0) return -1; if(process){ if(process->writehandlepos>=0){ //sending to application (pipe) return process->wheel->getbufferbynumber(process->writehandlepos)->put(data,size); }else{ return -1; } }else{ if(connection){ if(connection->indexforwheel>=0){ //sending to application (socket) return connection->wheel->getbufferbynumber(connection->indexforwheel)->put(data,size); }else{ return -1; } }else{ return -1; } } } Application::Application(ProcessServer *xserver,char *xappname,char *xurl, char *xusername,int xmax_requests_per_instance, int xmax_instances,char *xmappedname,char *xpathname,int xargc,char **xargv, __s32 xaddress,int xusesocket,int xmax_instances_for_uid, int xauthentication){ usesocket=xusesocket; address=xaddress; server=xserver; appname=NULL; processflag=0; authentication=xauthentication; if(xappname){ appname=(char*)malloc(strlen(xappname)+1); if(appname)strcpy(appname,xappname); } url=NULL; if(xurl){ url=(char*)malloc(strlen(xurl)+1); if(url)strcpy(url,xurl); } username=NULL; if(xusername){ username=(char*)malloc(strlen(xusername)+1); if(username)strcpy(username,xusername); } mappedname=NULL; if(xmappedname){ mappedname=(char*)malloc(strlen(xmappedname)+1); if(mappedname)strcpy(mappedname,xmappedname); } pathname=NULL; if(xpathname){ pathname=(char*)malloc(strlen(xpathname)+1); if(pathname)strcpy(pathname,xpathname); } max_requests_per_instance=xmax_requests_per_instance; max_instances=xmax_instances; max_instances_for_uid=xmax_instances_for_uid; argv=NULL; argc=0; if(xargc&&xargv){ argv=(char**)malloc((xargc+1)*sizeof(char*)); if(argv){ int failure=0; for(argc=0;argc0); } free(argv); } } ApplicationInstance *Application::MakeInstance(int xmap_uid){ ServerProcess *instproc; ApplicationInstance *inst; if(pathname){ server->tmppathname=pathname; if(xmap_uid>=0){ server->tmpuser=getpwuid(xmap_uid); }else{ if(username) server->tmpuser=getpwnam(username); else server->tmpuser=NULL; } server->tmpargc=argc; server->tmpargv=argv; instproc=new ServerProcess(server->wheel,server->emptyclient->indexforwheel, APP_MESSAGE_BUFFER_SIZE,usesocket?2:1,0,1); //nevercloseonexit=1 (never close empty connection) if(instproc){ //Process created if(instproc->writehandlepos>=0){ inst=new ApplicationInstance(this,instproc,NULL,xmap_uid); if(inst){ //Instance created instances.Add(inst); return inst; }else delete instproc; }else delete instproc; } } return NULL; } ApplicationInstance *Application::MakeInstance(ServerConnection *conn){ ApplicationInstance *inst; if(!pathname){ inst=new ApplicationInstance(this,NULL,conn); if(inst) instances.Add(inst); return inst; } return NULL; } static __s32 instsequencenumber=0; ApplicationInstance::ApplicationInstance(Application *xapplication,ServerProcess *xprocess,ServerConnection *xconnection,int xmap_uid){ currmessage=NULL; currresponse=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; capabilities=0; exitreq=0; queuesize=0; lastrequesttime=0; lastrequestcounter=0; map_uid=xmap_uid; application=xapplication; if(application) application->processflag=1; process=xprocess; connection=xconnection; instsequencenumber++; if(!instsequencenumber) instsequencenumber++; preassigned_id=instsequencenumber; if(connection){ if(connection->gethandle()!=0){ //reserved file handle for "empty" connection if(connection->app){ ((ProcessServerApp*)(connection->app))->appinst=this; } } } if(!glob_wheel->current_process){ LogMessage(NULL,NULL,this,NULL,0,"INSTANCE_CREATED", application?application->appname:NULL); } } ProcessServerApp::ProcessServerApp(ServerConnection *c):ServerConnectionApp(c){ username[0]=0; if(c&&c->gethandle()!=0){ buffsize=APP_MESSAGE_BUFFER_SIZE+1; buffer=(char*)malloc(buffsize); }else{ buffsize=0; buffer=NULL; } if(!buffer) buffsize=0; boffset=0; bufflen=0; lastchar=0; userid=-1; gid=-1; auth=-1; appinst=NULL; } ProcessServerApp::~ProcessServerApp(void){ if(appinst){ appinst->connection=NULL; delete appinst; } if(buffer) free(buffer); } void ProcessServer::response(ServerConnection *client,char *fmt,...){ char buffer[MESSAGE_BUFFER_SIZE]; va_list ap; va_start(ap,fmt); if(logfd<0) return; vsprintf(buffer,fmt,ap); strcat(buffer,"\r\n"); if(client->indexforwheel>=0){ client->wheel->getbufferbynumber(client->indexforwheel)->put(buffer,strlen(buffer)); } va_end(ap); } void ProcessServer::setexitafterresponse(ServerConnection *client,int closeonexit){ if(client->indexforwheel>=0){ client->wheel->getbufferbynumber(client->indexforwheel)->setcloseonexit(closeonexit); } } ProcessServer::ProcessServer(char *xname,int xport,int xmaxclients,__s32 xlocaladdr):ServerSocket(xname,xport,xmaxclients,xlocaladdr){ emptyclient=NULL; tmppathname=NULL; tmpuser=NULL; tmpargc=0; tmpargv=NULL; } ProcessServer::~ProcessServer(void){ } CtrlAppPtrApplicationRequest::CtrlAppPtrApplicationRequest(ApplicationRequest *xrequest){ request=xrequest; if(request){ request->ctrlappptr=this; } } CtrlAppPtrApplicationRequest::~CtrlAppPtrApplicationRequest(void){ if(request){ if(request->ctrlappptr==this){ if(!request->reported_deleted){ LogMessage(request->ctrlapp,request,request->instance,NULL,0,"REQUEST_DELETED","Delayed"); request->reported_deleted=1; } request->ctrlappptr=NULL; request->ctrlapp=NULL; } } } int ApplicationRequest::InitResponse(long xresponsesize){ int i; char *p; long *mbnew; if(xresponsesize<(long)sizeof(__s32)*3) return -1; if(!marksbuffer){ marksbuffer=(long*)malloc(sizeof(long)*10); if(!marksbuffer) return -1; marksbuffersize=10; marksinbuffer=0; }else{ if(marksbuffersize<=marksinbuffer){ mbnew=(long*)realloc(marksbuffer,(marksbuffersize+10)*sizeof(long)); if(!mbnew) return -1; marksbuffersize+=10; marksbuffer=mbnew; } } if(!responsebuffer){ responseoffset=0; responsereadoffset=0; responsesize=xresponsesize-sizeof(__s32)*3; responsebuffer=(char*)malloc(responsesize); if(!responsebuffer) return -1; responsebuffersize=responsesize; }else{ if(responsesize!=responseoffset) return -1; if((long)responsesize+xresponsesize-(long)sizeof(__s32)*3>responsebuffersize){ p=(char*)realloc(responsebuffer,responsesize+xresponsesize-sizeof(__s32)*3); }else{ p=responsebuffer; } if(p){ responsesize+=xresponsesize-sizeof(__s32)*3; responsebuffer=p; }else return -1; } for(i=marksinbuffer;i>0;i--){ marksbuffer[i]=marksbuffer[i-1]; } marksbuffer[0]=responsesize; marksinbuffer++; if(instance){ if(instance->capabilities&APP_CAP_ACKFINISH) ack_finish=1; } GetSize(); return 0; } int ApplicationRequest::CopyResponseData(char *data, int size){ if(!responsebuffer) return size; if(size>responsesize-responseoffset) size=responsesize-responseoffset; memcpy(responsebuffer+responseoffset,data,size); responseoffset+=size; GetSize(); return size; } void ApplicationRequest::SendResponseBuffer(void){ } int ApplicationInstance::CheckInstanceRules(ApplicationRequest *currequest){ ConfigArgs *line,*currline; int retval=0,acceptreject,requestlinecheck,eq; if(!currequest) return 0; if(!currequest->requestline) return 0; line=(ConfigArgs*)configlines.start; while(line){ if(line->paramc==2||line->paramc==3){ if(line->params){ switch(line->params[0][0]){ case 'a': case 'A': acceptreject=1; break; case 'r': case 'R': acceptreject=0; break; default: acceptreject=-1; } if(acceptreject!=-1){ switch(line->params[0][1]){ case 'l': case 'L': requestlinecheck=1; break; case 'h': case 'H': requestlinecheck=0; break; default: requestlinecheck=-1; } if(requestlinecheck!=-1){ switch(line->params[0][2]){ case 'e': case 'E': eq=1; break; case 'n': case 'N': eq=0; break; default: eq=-1; } if(eq!=-1){ if(!line->params[0][3]){ if(requestlinecheck){ if(line->paramc==2){ if(wildmat(currequest->requestline,line->params[1])==eq){ retval=acceptreject?1:-1; } } }else{ currline=(ConfigArgs*)currequest->lines.start; while(currline){ if(currline->paramc==2&&line->paramc==3){ if(!strcmp(line->params[1],currline->params[0])){ if(wildmat(currline->params[1],line->params[2])==eq){ retval=acceptreject?1:-1; } } } currline=(ConfigArgs*)currline->next; } } } } } } } } line=(ConfigArgs*)line->next; } return retval; } ApplicationMessage::ApplicationMessage(Application *xapplication,ApplicationInstance *xinstance){ application=xapplication; instance=xinstance; responsebuffer=NULL; responsesize=0; responseoffset=0; responsereadoffset=0; appresponsefinished=0; } ApplicationMessage::~ApplicationMessage(void){ if(instance){ if(instance->currmessage==this) instance->currmessage=NULL; } if(responsebuffer) free(responsebuffer); } int ApplicationMessage::CopyMessageData(char *data, int size){ if(!responsebuffer||size<=0) return size; if(size>responsesize-responseoffset) size=responsesize-responseoffset; memcpy(responsebuffer+responseoffset,data,size); responseoffset+=size; return size; } int ApplicationMessage::Process(long opnumber){ int i=0,j,matches; char *p,*lines[20]; ConfigArgs *line; if(!responsebuffer) return -1; switch(opnumber){ case FHTTPD_INST_SELECT: case FHTTPD_INST_DESELECT: p=responsebuffer; i=0; do{ lines[i]=p; p=strchr(p,'\n'); if(p){ i++; *p=0; p++; } }while(p&&i<20); if(i<20) i++; } switch(opnumber){ case FHTTPD_INST_SELECT: line=new ConfigArgs(i,lines); // log("added line %d \"%s\"",i,responsebuffer); if(line) instance->configlines.Add(line); break; case FHTTPD_INST_DESELECT: line=(ConfigArgs*)instance->configlines.start; while(line){ if(line->paramc==i){ if(line->params){ matches=1; for(j=0;jparams[j]&&lines[j]){ if(strcmp(line->params[j],lines[j])){ matches=0; } }else matches=0; } }else matches=0; if(matches){ // log("deleted line \"%s\"",responsebuffer); delete line; line=NULL; } } if(line) line=(ConfigArgs*)line->next; } break; case FHTTPD_INST_CAP: if(responsesize>=(long)sizeof(__s32)){ instance->capabilities=htonl(*(__s32*)responsebuffer); //Capabilities changed } break; case FHTTPD_INST_EXITREQ: if(responsesize>=(long)sizeof(__s32)){ instance->exitreq=htonl(*(__s32*)responsebuffer); if(instance->exitreq&&!instance->queuesize){ instance->ConfirmExit(); } } break; case FHTTPD_LOG_MESSAGE: p=strchr(responsebuffer+sizeof(__s32)*2,'\n'); if(p){ *p=0; p++; } if(!p){ LogMessage(NULL,NULL,instance,NULL,0,"LOG_MESSAGE",responsebuffer+sizeof(__s32)*2, *(__s32*)responsebuffer,*(((__s32*)responsebuffer)+1)); }else{ int keylen; keylen=(p-responsebuffer)-sizeof(__s32)*2+sizeof("LOG_")-1; if(keylen<=1024){ char key1[1024]; memcpy(key1,"LOG_",sizeof("LOG_")-1); memcpy(key1+sizeof("LOG_")-1,responsebuffer+sizeof(__s32)*2,keylen-sizeof("LOG_")+1); LogMessage(NULL,NULL,instance,NULL,0,key1,p, *(__s32*)responsebuffer,*(((__s32*)responsebuffer)+1)); }else{ char *key=(char*)malloc(keylen); if(key){ memcpy(key,"LOG_",sizeof("LOG_")-1); memcpy(key+sizeof("LOG_")-1,responsebuffer+sizeof(__s32)*2,keylen-sizeof("LOG_")+1); LogMessage(NULL,NULL,instance,NULL,0,key,p, *(__s32*)responsebuffer,*(((__s32*)responsebuffer)+1)); free(key); } } } break; } return 0; } unsigned long requestcounter=0; struct finishedmessage outputfinishedbuffer={ #ifdef HTONL_WORKS_IN_CONSTANTS htonl(sizeof(struct disconnectmessage)), #else 0, #endif 0, #ifdef HTONL_WORKS_IN_CONSTANTS htonl(FHTTPD_ACK), #else 0, #endif 0, 0, sizeof(__s32), 0 }; //Global buffer, just set to copy the data from void ApplicationInstance::ConfirmExit(void){ disconnectbuffer.buffsize=htonl(sizeof(struct disconnectmessage)); disconnectbuffer.reqtype=htonl(FHTTPD_EXITOK); ApplicationRequest *exitok=new ApplicationRequest(application,NULL,NULL,0,0,-1); if(exitok){ requests.Add(exitok); queuesize++; lastrequesttime=global_time; requestcounter++; lastrequestcounter=requestcounter; exitok->specialmessage=1; exitok->instance=this; exitok->buffer=(char*)malloc(sizeof(struct disconnectmessage)); if(exitok->buffer){ memcpy(exitok->buffer,&disconnectbuffer,sizeof(struct disconnectmessage)); ((struct disconnectmessage*)exitok->buffer)->sequencenumber=0; exitok->offset=0; exitok->buffsize=sizeof(struct disconnectmessage); exitreq=2; }else{ queuesize--; delete exitok; } } } int ApplicationMessage::InitMessage(long xresponsesize){ char *p; if(xresponsesize<(long)sizeof(__s32)*3) return -1; if(!responsebuffer){ responseoffset=0; responsereadoffset=0; responsesize=xresponsesize-sizeof(__s32)*3; responsebuffer=(char*)malloc(responsesize+1); if(responsebuffer) responsebuffer[responsesize]=0; else return -1; }else{ if(responsesize!=responseoffset) return -1; p=(char*)realloc(responsebuffer,responsesize+xresponsesize-sizeof(__s32)*3+1); if(p){ responsesize+=xresponsesize-sizeof(__s32)*3; responsebuffer=p; responsebuffer[responsesize]=0; }else return -1; } return 0; } ApplicationInstance::~ApplicationInstance(void){ if(!glob_wheel->current_process){ LogMessage(NULL,NULL,this,NULL,0,"INSTANCE_DELETED", application?application->appname:NULL); } if(application){ application->instances.Remove(this); //Should remove from application before //process will delete it again in // afterunsplitfn() application->processflag=1; } application=NULL; if(process){ delete process; } if(connection){ if(connection->gethandle()!=0){ //reserved file handle for "empty" connection if(connection->app){ //zeroing appinst in connection ((ProcessServerApp*)(connection->app))->appinst=NULL; } //deleting connection in ApplicationInstance destructor delete connection; } } if(currmessage) delete currmessage; currresponse=(ApplicationRequest*)requests.start; while(currresponse){ //deleting response in ApplicationInstance destructor if(!glob_wheel->current_process){ LogMessage(currresponse->ctrlapp,currresponse,this,NULL,0, "USER_ERROR","503 Backend unavailable"); if(currresponse->ctrlapp &&currresponse->ctrlapp->connection &&currresponse->ctrlapp->connection->socket){ ((ControlFTPServer*)currresponse->ctrlapp->connection->socket )->setexitafterresponse(currresponse->ctrlapp->connection,1); ((ControlFTPServer*)currresponse->ctrlapp->connection->socket )->response(currresponse->ctrlapp->connection, "HTTP/1.0 503 Backend unavailable\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

503 Backend unavailable

"); } } delete currresponse; currresponse=(ApplicationRequest*)requests.start; } } int ApplicationInstance::RespondToApp(char *data,int size){ ApplicationRequest *currrequest; int l; if(size<=0) return 1; //processing data from application while(size){ if(!sizedefined){ if((long)sizeof(__s32)-(sizeptr-(char*)&responsesize)>size){ memcpy(sizeptr,data,size); sizeptr+=size; size=0; return 1; }else{ memcpy(sizeptr,data,sizeof(__s32)-(sizeptr-(char*)&responsesize)); data+=sizeof(__s32)-(sizeptr-(char*)&responsesize); size-=sizeof(__s32)-(sizeptr-(char*)&responsesize); responsesize=htonl(responsesize); sizedefined=1; } } if(!size) return 1; if(!opnumberdefined){ if((long)sizeof(__s32)-(opnumberptr-(char*)&opnumber)>size){ memcpy(opnumberptr,data,size); opnumberptr+=size; size=0; return 1; }else{ memcpy(opnumberptr,data,sizeof(__s32)-(opnumberptr-(char*)&opnumber)); data+=sizeof(__s32)-(opnumberptr-(char*)&opnumber); size-=sizeof(__s32)-(opnumberptr-(char*)&opnumber); opnumber=htonl(opnumber); opnumberdefined=1; } } if(!size) return 1; if(!iddefined){ if((long)sizeof(__s32)-(idptr-(char*)&id)>size){ memcpy(idptr,data,size); idptr+=size; size=0; return 1; }else{ memcpy(idptr,data,sizeof(__s32)-(idptr-(char*)&id)); data+=sizeof(__s32)-(idptr-(char*)&id); size-=sizeof(__s32)-(idptr-(char*)&id); id=htonl(id); iddefined=1; currmessage=NULL; currresponse=NULL; switch(opnumber){ case FHTTPD_SEND: case FHTTPD_FINISH: case FHTTPD_FINISH_DROP: currrequest=(ApplicationRequest*)requests.start; while(currrequest){ if(currrequest->id==id&&!currrequest->specialmessage){ currresponse=currrequest; currrequest=NULL; }else{ currrequest=(ApplicationRequest*)currrequest->next; } } if(currresponse){ //response found if(!responsesize){ if(opnumber==FHTTPD_FINISH_DROP){ if(currresponse->ctrlapp){ currresponse->ctrlapp->keepalive=0; } currresponse->FinishResponse(0); }else{ currresponse->FinishResponse(capabilities&APP_CAP_KEEPALIVE); } currresponse=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; }else{ switch(opnumber){ case FHTTPD_SEND: if(responsesize<=max_message_size){ currresponse->InitResponse(responsesize); }else{ if(currresponse->ctrlapp){ currresponse->ctrlapp->keepalive=0; } currresponse->FinishResponse(0); currresponse=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; } break; case FHTTPD_FINISH: case FHTTPD_FINISH_DROP: if(opnumber==FHTTPD_FINISH_DROP){ if(currresponse->ctrlapp){ currresponse->ctrlapp->keepalive=0; } currresponse->FinishResponse(0); }else{ currresponse->FinishResponse(capabilities&APP_CAP_KEEPALIVE); } currresponse=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; break; } } }else{ responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; return -1; } break; case FHTTPD_LOG_MESSAGE: currrequest=(ApplicationRequest*)requests.start; while(currrequest){ if(currrequest->id==id&&!currrequest->specialmessage){ currresponse=currrequest; currrequest=NULL; }else{ currrequest=(ApplicationRequest*)currrequest->next; } } if(!currmessage) currmessage=new ApplicationMessage(application,this); if(currmessage){ if(responsesize<=max_message_size){ currmessage->InitMessage(responsesize+sizeof(__s32)*2); __s32 tmpz[2]={0,0}; if(currresponse){ tmpz[1]=currresponse->preassigned_id; if(currresponse->ctrlapp) tmpz[0]=currresponse->ctrlapp->preassigned_id; } currmessage->CopyMessageData((char*)tmpz,sizeof(__s32)*2); }else{ delete currmessage; currmessage=NULL; responsesize=0; } } if(!responsesize){ if(currmessage){ currmessage->Process(opnumber); delete currmessage; } currmessage=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; } break; default: if(!currmessage) currmessage=new ApplicationMessage(application,this); if(currmessage){ if(responsesize<=max_message_size){ currmessage->InitMessage(responsesize); }else{ delete currmessage; currmessage=NULL; responsesize=0; } } if(!responsesize){ if(currmessage){ currmessage->Process(opnumber); delete currmessage; } currmessage=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; } } } } if(!size) return 1; if(iddefined){ switch(opnumber){ case FHTTPD_SEND: case FHTTPD_FINISH: case FHTTPD_FINISH_DROP: if(currresponse){ l=currresponse->CopyResponseData(data, size>currresponse->responsesize-currresponse->responseoffset? currresponse->responsesize-currresponse->responseoffset:size); size-=l; data+=l; if(currresponse->responsesize==currresponse->responseoffset){ currresponse->SendResponseBuffer(); currresponse=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; } }else{ if(sizedefined&&opnumberdefined&&iddefined) return -1; } break; // case FHTTPD_LOG_MESSAGE: // This is not a separate case in this branch default: if(currmessage){ l=currmessage->CopyMessageData(data, size>currmessage->responsesize-currmessage->responseoffset? currmessage->responsesize-currmessage->responseoffset:size); size-=l; data+=l; if(currmessage->responsesize==currmessage->responseoffset){ currmessage->Process(opnumber); delete currmessage; currmessage=NULL; responsesize=0; sizeptr=(char*)&responsesize; sizedefined=0; opnumber=0; opnumberptr=(char*)&opnumber; opnumberdefined=0; id=0; idptr=(char*)&id; iddefined=0; } }else{ if(sizedefined&&opnumberdefined&&iddefined) return -1; } } } } return 1; } void ProcessServer::emptyfn(ServerConnection *client){ } void Application::ProcessQueue(void){ ApplicationRequest *currequest,*nextrequest; ApplicationInstance *currinstance,*selectedinstance; int l,minqueuesize=-1,instanceselection,forcedinstance,instancesavailable, instancesforuid,totalsize=0; unsigned long minrequestcounter; long minrequesttime; if(processflag){ processflag=0; currequest=(ApplicationRequest*)requests.start; while(currequest){ totalsize+=currequest->totalsize; nextrequest=(ApplicationRequest*)currequest->next; currinstance=(ApplicationInstance*)instances.start; selectedinstance=NULL; minqueuesize=-1; minrequestcounter=0; minrequesttime=0; forcedinstance=0; instancesavailable=0; instancesforuid=0; if(totalsize<=max_totalsize){ while(currinstance){ if(!max_instances_for_uid // no uid limit defined <= uid mapping isn't used ||!pathname // remote ||(currequest->map_uid==currinstance->map_uid)){ // uid matches instancesforuid++; // counter for the current uid or no uid if(!currinstance->exitreq){ // instance exiting -- don't // include it in the search instanceselection=currinstance->CheckInstanceRules(currequest); // check for special conditions -- // >0 - positive, <0 - negative, 0 - no matches if(currinstance->queuesizelastrequestcounter; minrequesttime=currinstance->lastrequesttime; minqueuesize=currinstance->queuesize; selectedinstance=currinstance; }else{ if(currinstance->queuesize<=minqueuesize){ // select if better if(currinstance->queuesize==minqueuesize){ if(currinstance->lastrequesttime<=minrequesttime){ if(currinstance->lastrequesttime==minrequesttime){ if(currinstance->lastrequestcounter<=minrequestcounter){ minrequestcounter=currinstance->lastrequestcounter; minrequesttime=currinstance->lastrequesttime; minqueuesize=currinstance->queuesize; selectedinstance=currinstance; } }else{ minrequestcounter=currinstance->lastrequestcounter; minrequesttime=currinstance->lastrequesttime; minqueuesize=currinstance->queuesize; selectedinstance=currinstance; } } }else{ minrequestcounter=currinstance->lastrequestcounter; minrequesttime=currinstance->lastrequesttime; minqueuesize=currinstance->queuesize; selectedinstance=currinstance; } } } }else{ if(instanceselection>0){ // select if positive selection forcedinstance=1; selectedinstance=currinstance; currinstance=NULL; } // or skip if negative selection } }else{ if(instanceselection>0){ // it's selected, but over the limit forcedinstance=1; // -- abort the search selectedinstance=NULL; currinstance=NULL; } } } } if(currinstance) currinstance=(ApplicationInstance*)currinstance->next; } if(!selectedinstance // nothing found &&pathname // local application &&instances.countmap_uid:-1); if(selectedinstance) instancesavailable++; // create and select instance if created, do nothing on error } if(selectedinstance){ LogMessage(currequest->ctrlapp,currequest,selectedinstance,NULL,0, "INSTANCE_SELECTED",NULL); if(currequest->Convert()){ // if the request is in the *application* queue, it must be converted // before entering *instance* requests queue LogMessage(currequest->ctrlapp,currequest,selectedinstance,NULL,0, "INTERNAL_ERROR","Application data conversion failure"); delete currequest; }else{ selectedinstance->requests.Add(currequest); // will automatically remove from // application requests queue selectedinstance->queuesize++; selectedinstance->lastrequesttime=global_time; requestcounter++; selectedinstance->lastrequestcounter=requestcounter; currequest->instance=selectedinstance; } currequest=nextrequest; }else{ if(!instancesavailable&&!forcedinstance) currequest=NULL; else currequest=nextrequest; } }else{ LogMessage(currequest->ctrlapp,currequest,selectedinstance,NULL,0, "USER_ERROR","503 Insufficient resources"); if(currequest->ctrlapp &&currequest->ctrlapp->connection &&currequest->ctrlapp->connection->socket){ ((ControlFTPServer*)currequest->ctrlapp->connection->socket )->setexitafterresponse(currequest->ctrlapp->connection,1); ((ControlFTPServer*)currequest->ctrlapp->connection->socket )->response(currequest->ctrlapp->connection, "HTTP/1.0 503 Insufficient resources\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

503 Insufficient resources

"); } delete currequest; currequest=nextrequest; } } } currinstance=(ApplicationInstance*)instances.start; while(currinstance){ currequest=(ApplicationRequest*)currinstance->requests.start; while(currequest){ // log("processing request (in instance)"); nextrequest=(ApplicationRequest*)currequest->next; //FIXME: responses may be sent in wrong order if the client does not wait for the response //before sending next request with Keep-Alive enabled if(!currequest->ctrlapp&&currequest->id){ // request ID is mandatory for cancel if(!currequest->disconnectflag){ if(currequest->appresponsefinished){ currinstance->queuesize--; //response lost - client dropped connection delete currequest; currequest=NULL; }else{ currequest->NotifyDisconnect(); } } if(currequest&&!currequest->specialmessage&&currequest->responsebuffer){ currequest->DiscardResponseData(); } }else{ if((currequest->responsebuffer||currequest->appresponsefinished)){ if(currequest->responseoffset==currequest->responsereadoffset){ l=0; }else{ //responding to user... l=currequest->RespondToUser(currinstance->capabilities&APP_CAP_KEEPALIVE); } if(l<0){ currinstance->queuesize--; delete currequest; currequest=NULL; //response deleted because of some error }else{ if(currequest->ack_finish&&currequest->markssent){ //ADDED outputfinishedbuffer.buffsize=htonl(sizeof(struct finishedmessage)); outputfinishedbuffer.reqtype=htonl(FHTTPD_ACK); outputfinishedbuffer.sequencenumber=htonl(currequest->id); outputfinishedbuffer.databuffer=htonl(currequest->markssent); ApplicationRequest *outputfinished=new ApplicationRequest(this,NULL,NULL,0,0,-1); if(outputfinished){ currinstance->requests.Add(outputfinished); currinstance->queuesize++; currinstance->lastrequesttime=global_time; requestcounter++; currinstance->lastrequestcounter=requestcounter; outputfinished->specialmessage=1; outputfinished->instance=currinstance; outputfinished->buffer=(char*)malloc(sizeof(struct finishedmessage)); if(outputfinished->buffer){ memcpy(outputfinished->buffer,&outputfinishedbuffer,sizeof(struct finishedmessage)); outputfinished->offset=0; outputfinished->buffsize=sizeof(struct finishedmessage); currequest->markssent=0; }else{ currinstance->queuesize--; delete outputfinished; } } } if(!l&&currequest->appresponsefinished){ //response passed to the client currinstance->queuesize--; delete currequest; currequest=NULL; } } } } if(currequest){ // log("sending request to app"); l=currequest->Send(); if(l<0){ currinstance->queuesize--; delete currequest; currequest=NULL; //request deleted because of some error }else{ if(!l){ if(currequest->disconnectflag&&currequest->appresponsefinished){ //disconnect message passed to the application currinstance->queuesize--; delete currequest; currequest=NULL; }else{ if(currequest->specialmessage){ //special message passed to the application currinstance->queuesize--; delete currequest; currequest=NULL; }else{ // log("request passed to the application"); if(usesocket){ if(currequest->buffer // if there is no buffer, it's or empty &&!currequest->disconnectflag // if it has disconnectflag, // it's disconnect message &&currinstance->process &&currinstance->process->wheel->getbufferbynumber(currinstance->process->writehandlepos)){ if(currequest->ctrlapp&&currequest->ctrlapp->connection){ currinstance->process->wheel->getbufferbynumber(currinstance->process->writehandlepos)->PutConnection(currequest->ctrlapp->connection); }else{ // request belongs to dropped connection currinstance->process->wheel->getbufferbynumber(currinstance->process->writehandlepos)->PutConnection(NULL); } } } currequest->FreeResources(); } } } } } currequest=nextrequest; } if(currinstance->exitreq==1&&!currinstance->queuesize){ currinstance->ConfirmExit(); } currinstance=(ApplicationInstance*)currinstance->next; } } void ProcessServer::connectfn(ServerConnection *client){ if(client&&wheel){ if(client->gethandle()==0){ //reserved file handle for "empty" connection wheel->stoppolling(client->indexforwheel); fcntl(0,F_SETFL,0); //empty process connected }else{ client->app=new ProcessServerApp(client); response(client,"220 Process server ready."); } } } void ProcessServer::disconnectfn(ServerConnection *client){ } void ProcessServer::splitfn(ServerConnection *client,ServerProcess *process){ struct passwd *pw; FILE *f; char buffer[MESSAGE_BUFFER_SIZE],*p,shell[129]; int i,l,readboffset=0; int syncexpected=0; char onebyte=0; int zerofound=0; if(client->gethandle()==0){ if(tmppathname&&tmpuser){ #ifdef DEBUG printf("starting \"%s\"",tmppathname); #endif if(!setgid(tmpuser->pw_gid)){ initgroups(tmpuser->pw_name,tmpuser->pw_gid); if(!setuid(tmpuser->pw_uid)){ if(dup2(process->readhandle,0)>=0){ if(process->readhandle!=process->writehandle) close(process->readhandle); if(dup2(process->writehandle,1)>=0){ close(process->writehandle); process->readhandle=0; process->writehandle=1; dup2(1,2); if(tmpargc&&tmpargv){ execv(tmppathname,tmpargv); }else{ execl(tmppathname,tmppathname,NULL); } delete process; } } } } } }else{ if(!client->app){ return; } if(process->readhandle<0){ //no input required - finishing return; } do{ l=read(process->readhandle,buffer+readboffset,(MESSAGE_BUFFER_SIZE-1)-readboffset); if(l<0) l=0; readboffset+=l; if(readboffset>0){ if(!buffer[readboffset-1]){ zerofound=1; readboffset--; } } }while(!zerofound&&readboffset<(MESSAGE_BUFFER_SIZE-1)); l=readboffset; buffer[l]=0; for(i=0;ipw_uid; *((int*)(buffer+4+sizeof(int)))=pw->pw_gid; #ifdef USE_GETSPNAM if(spw->sp_pwdp&&spw->sp_pwdp[0]){ if(spw->sp_pwdp[0]=='*'){ #else if(pw->pw_passwd&&pw->pw_passwd[0]){ if(pw->pw_passwd[0]=='*'){ #endif swrite(client->gethandle(),"530 Account disabled.\r\n"); process->closeonexit=1; delete process; }else *((int*)(buffer+4+2*sizeof(int)))=1;/*password needed*/ }else{ f=fopen("/etc/shells","r"); if(f){ *((int*)(buffer+4+2*sizeof(int)))=1;/*no password needed?*/ while(fgets(shell,128,f)){ if((p=strchr(shell,'\n'))) *p=0; else if((p=strchr(shell,'\r'))) *p=0; else if((p=strchr(shell,026))) *p=0; if(!strcmp(shell,pw->pw_shell)){ *((int*)(buffer+4+2*sizeof(int)))=0; } } fclose(f); if(*((int*)(buffer+4+2*sizeof(int)))){ swrite(client->gethandle(),"530 Special account, processes are not allowed.\r\n"); process->closeonexit=1; delete process; } }else{ swrite(client->gethandle(),"530 Special account, processes are not allowed.\r\n"); process->closeonexit=1; delete process; } } #ifdef USE_GETSPNAM }else{ swrite(client->gethandle(),"530 No such user.\r\n"); process->closeonexit=1; delete process; } #endif }else{ swrite(client->gethandle(),"530 No such user.\r\n"); process->closeonexit=1; delete process; } write(process->writehandle,buffer,4+3*sizeof(int)); syncexpected=1; break; case PROC_PASS: if(((ProcessServerApp*)client->app)->userid>=0){ pw=getpwnam(((ProcessServerApp*)client->app)->username); #ifdef USE_GETSPNAM struct spwd *spw=getspnam(((ProcessServerApp*)client->app)->username); if(pw&&spw&&spw->sp_pwdp&&strlen(spw->sp_pwdp)>=2){ if(strcmp(crypt(buffer+4,spw->sp_pwdp),spw->sp_pwdp)){ #else if(pw&&pw->pw_passwd&&strlen(pw->pw_passwd)>=2){ if(strcmp(crypt(buffer+4,pw->pw_passwd),pw->pw_passwd)){ #endif *((int*)(buffer+4))=0; LogMessage(NULL,NULL,NULL,NULL,0,"PROCESS_LOGIN_FAILURE",((ProcessServerApp*)client->app)->username); }else{ *((int*)(buffer+4))=1; LogMessage(NULL,NULL,NULL,NULL,0,"PROCESS_LOGIN",((ProcessServerApp*)client->app)->username); } }else{ *((int*)(buffer+4))=0; LogMessage(NULL,NULL,NULL,NULL,0,"PROCESS_LOGIN_FAILURE",((ProcessServerApp*)client->app)->username); } write(process->writehandle,buffer,4+sizeof(int)); syncexpected=1; }else{ swrite(client->gethandle(),"500 No username.\r\n"); process->closeonexit=1; delete process; } break; } if(syncexpected) read(process->readhandle,&onebyte,1); } } /* void ProcessServer::splitparentfn(ServerConnection *client,ServerProcess *process){ } void ProcessServer::unsplitfn(ServerConnection *client,ServerProcess *process){ } */ void ProcessServer::afterunsplitfn(ServerConnection *client,ServerProcess *process){ Application *currapp; ApplicationInstance *currinst; if(client&&wheel){ if(client->gethandle()==0){ //empty connection... wheel->stoppolling(client->indexforwheel); fcntl(0,F_SETFL,0); int found=0; currapp=(Application*)applist.start; while(currapp){ currinst=(ApplicationInstance*)currapp->instances.start; while(currinst){ if(currinst->process==process){ currinst->process=NULL; // zero process pointer to avoid recursion delete currinst; // This is why instance should be removed //from the list in application, when deleted currinst=NULL; currapp=NULL; found=1; }else currinst=(ApplicationInstance*)currinst->next; } if(currapp) currapp=(Application*)currapp->next; } if(!found){ currapp=(Application*)logapplications.start; while(currapp){ currinst=(ApplicationInstance*)currapp->instances.start; while(currinst){ if(currinst->process==process){ currinst->process=NULL; // zero process pointer to avoid recursion delete currinst; // This is why instance should be removed //from the list in application, when deleted currinst=NULL; currapp=NULL; }else currinst=(ApplicationInstance*)currinst->next; } if(currapp) currapp=(Application*)currapp->next; } } } } } int ProcessServer::prioritydatafn(ServerConnection *client){ return datafn(client); } int ProcessServer::datafn(ServerConnection *client){ int i,l,l0,dl,nparam=0,crlf,appfound; int dataleftsize=0; char *buffer,*param[5],a,*p,*dataleft=NULL; l0=0; a=0; ServerProcess *proc; Application *currapp; if(client->gethandle()==0){ //reserved file handle for "empty" connection wheel->stoppolling(client->indexforwheel); }else{ if(!client->app) return 0; if(!((ProcessServerApp*)client->app)->buffsize){ // still not allocated? ((ProcessServerApp*)client->app)->buffsize=APP_MESSAGE_BUFFER_SIZE+1; ((ProcessServerApp*)client->app)->buffer=(char*)malloc(((ProcessServerApp*)client->app)->buffsize); if(!((ProcessServerApp*)client->app)->buffer){ // ok, no memory, // leave it alone ((ProcessServerApp*)client->app)->buffsize=0; return 0; } } buffer=((ProcessServerApp*)client->app)->buffer; if(((ProcessServerApp*)client->app)->boffset>=((ProcessServerApp*)client->app)->buffsize-1) ((ProcessServerApp*)client->app)->boffset=0; dl=read(client->gethandle(),buffer+((ProcessServerApp*)client->app)->boffset, ((ProcessServerApp*)client->app)->buffsize-1-((ProcessServerApp*)client->app)->boffset); if(dl<0) dl=0; p=buffer+((ProcessServerApp*)client->app)->boffset; ((ProcessServerApp*)client->app)->boffset+=dl; if(dl){ l0+=dl; }else return 0; do{ l=0; if(((ProcessServerApp*)client->app)->boffset>0){ if(((ProcessServerApp*)client->app)->appinst){ //response(client,"Application..."); ((ProcessServerApp*)client->app)->appinst->RespondToApp(p,buffer+((ProcessServerApp*)client->app)->boffset-p); p=buffer+((ProcessServerApp*)client->app)->boffset; dataleftsize=0; }else{ while((unsigned char)*p>=' '&&papp)->boffset-1) p++; a=*p; if((unsigned char)a<' '){ crlf=(a=='\n'&&((ProcessServerApp*)client->app)->lastchar=='\r'&&p==buffer); ((ProcessServerApp*)client->app)->lastchar=a; if(p<=buffer+((ProcessServerApp*)client->app)->boffset-1){ dataleft=p+1; dataleftsize=buffer+((ProcessServerApp*)client->app)->boffset-p-1; }else{ dataleftsize=0; } l=(p-buffer); buffer[l]=0; ((ProcessServerApp*)client->app)->bufflen=l; if(!crlf){ i=0; nparam=0; while(buffer[i]&&buffer[i]<=' '||(unsigned char)buffer[i]>127) i++; if(strncasecmp(buffer+i,"PASS",4)){ LogMessage(NULL,NULL,NULL,NULL,0,"USER_PROCESS_COMMAND",buffer); }else{ LogMessage(NULL,NULL,NULL,NULL,0,"USER_PROCESS_COMMAND","PASS "); } do{ while(buffer[i]==' ') i++; param[nparam]=buffer+i; for(;buffer[i]>' ';i++); if(buffer[i]==' '){ buffer[i]=0; i++; } if(!nparam){ strupr(param[0]); } nparam++; }while(iapp)->appinst){ // response(client,"Application..."); // }else{ for(i=0;iapp))->username,param[1],128); proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("USER",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(((ProcessServerApp*)(client->app))->username, strlen(((ProcessServerApp*)(client->app))->username)); client->wheel->getbufferbynumber(proc->writehandlepos)->put("",1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"500 'USER': line too long."); } }else{ response(client,"500 'USER': syntax error."); } break; case PROC_PASS: proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("PASS",4); if(nparam==2){ client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else client->wheel->getbufferbynumber(proc->writehandlepos)->put("",1); }else{ proc->killme(); // delete proc; } } break; case PROC_APPLICATION: if(nparam==2){ if(((ProcessServerApp*)client->app)->auth==1){ appfound=0; currapp=(Application*)applist.start; while(currapp){ if(currapp->appname){ if(!strcmp(currapp->appname,param[1])){ if(currapp->username&&((ProcessServerApp*)(client->app))->username){ if(!currapp->pathname){ if(!strcmp(currapp->username,((ProcessServerApp*)(client->app))->username)){ if(currapp->instances.countmax_instances){ if(currapp->MakeInstance(client)){ response(client,"200 OK."); }else response(client,"550 Can't make instance."); }else response(client,"550 Instances limit exceeded."); }else response(client,"530 Wrong user."); }else response(client,"530 Local application, can't be requested."); }else response(client,"530 No username."); appfound=1; currapp=NULL; } } if(currapp) currapp=(Application*)currapp->next; } if(!appfound) response(client,"550 No such application."); }else response(client,"530 Not logged in."); }else response(client,"500 'APPLICATION': syntax error."); break; case PROC_LOGAPPLICATION: if(nparam==2){ if(((ProcessServerApp*)client->app)->auth==1){ appfound=0; currapp=(Application*)logapplications.start; while(currapp){ if(currapp->appname){ if(!strcmp(currapp->appname,param[1])){ if(currapp->username&&((ProcessServerApp*)(client->app))->username){ if(!currapp->pathname){ if(!strcmp(currapp->username,((ProcessServerApp*)(client->app))->username)){ if(currapp->instances.countmax_instances){ ApplicationInstance *newloginstance; if((newloginstance=currapp->MakeInstance(client))){ response(client,"200 OK."); newloginstance->LogReportStatus(); }else response(client,"550 Can't make instance."); }else response(client,"550 Instances limit exceeded."); }else response(client,"530 Wrong user."); }else response(client,"530 Local application, can't be requested."); }else response(client,"530 No username."); appfound=1; currapp=NULL; } } if(currapp) currapp=(Application*)currapp->next; } if(!appfound) response(client,"550 No such application."); }else response(client,"530 Not logged in."); }else response(client,"500 'LOGAPPLICATION': syntax error."); break; case PROC_QUIT: response(client,"221 Goodbye."); setexitafterresponse(client,1); break; } } // } } if(dataleftsize>0){ for(i=0;i<(int)dataleftsize;i++){ buffer[i]=dataleft[i]; } p=buffer; ((ProcessServerApp*)client->app)->boffset-=dataleft-buffer; }else ((ProcessServerApp*)client->app)->boffset=0; }else dataleftsize=0; } }else dataleftsize=0; }while(dataleftsize>0); } return l0; } int ProcessServer::pipeprioritydatafn(ServerConnection *client,ServerProcess *process){ return pipedatafn(client,process); } int ProcessServer::pipedatafn(ServerConnection *client,ServerProcess *process){ int l; Application *currapp; ApplicationInstance *appinst,*currinst; char buffer[APP_MESSAGE_BUFFER_SIZE]; if(process->readhandle<0){ //handle doesn't exist return 0; } if(client->gethandle()==0){ //reserved file handle for "empty" connection //local app sent some data // if(!client->app) return 0; //log("application returned data"); //buffer=((ProcessServerApp*)client->app)->buffer; //if(((ProcessServerApp*)client->app)->boffset>=2048) ((ProcessServerApp*)client->app)->boffset=0; l=read(process->readhandle,buffer,APP_MESSAGE_BUFFER_SIZE); if(l<0) l=0; if(!l) return 0; appinst=NULL; currapp=(Application*)applist.start; while(currapp){ currinst=(ApplicationInstance*)currapp->instances.start; while(currinst){ if(currinst->process==process){ appinst=currinst; currinst=NULL; currapp=NULL; } if(currinst) currinst=(ApplicationInstance*)currinst->next; } if(currapp) currapp=(Application*)currapp->next; } if(!appinst){ currapp=(Application*)logapplications.start; while(currapp){ currinst=(ApplicationInstance*)currapp->instances.start; while(currinst){ if(currinst->process==process){ appinst=currinst; currinst=NULL; currapp=NULL; } if(currinst) currinst=(ApplicationInstance*)currinst->next; } if(currapp) currapp=(Application*)currapp->next; } } if(appinst){ //application response processing //response(client,"Application..."); appinst->RespondToApp(buffer,l); }else{ //application instance not found return 0; } return l; }else{ l=read(process->readhandle,buffer,(APP_MESSAGE_BUFFER_SIZE-1)); if(l<0) l=0; buffer[l]=0; if(l){ if(!memcmp(buffer,"USER",4)&&l==4+3*sizeof(int)){ client->wheel->startpolling(client->indexforwheel); ((ProcessServerApp*)client->app)->userid=*((int*)(buffer+4)); ((ProcessServerApp*)client->app)->gid=*((int*)(buffer+4+sizeof(int))); switch(*((int*)(buffer+4+2*sizeof(int)))){ case 1: ((ProcessServerApp*)client->app)->auth=0 ; response(client,"331 Password required for %s.",((ProcessServerApp*)client->app)->username); break; case 0: ((ProcessServerApp*)client->app)->auth=1; response(client,"230 User %s logged in.",((ProcessServerApp*)client->app)->username); break; } }else{ if(!memcmp(buffer,"PASS",4)&&l==4+sizeof(int)){ ((ProcessServerApp*)client->app)->auth=*((int*)(buffer+4)); if(((ProcessServerApp*)client->app)->auth){ response(client,"230 User %s logged in.",((ProcessServerApp*)client->app)->username); }else{ response(client,"530 Login incorrect."); } client->wheel->startpolling(client->indexforwheel); }else{ } } } if(process->writehandlepos>=0){ client->wheel->getbufferbynumber(process->writehandlepos)->put("*",1); } return l; } } int ApplicationRequest::ReadData(int handle, int size){ int l; if(databuffsize-dataoffset>size) size=databuffsize-dataoffset; l=read(handle,databuffer+dataoffset,size); if(l<0) return l; dataoffset+=l; return l; } int ApplicationRequest::Ready(void){ /* if(Convert()){ log("Application data conversion failure"); }else{ */ LogMessage(ctrlapp,this,NULL,NULL,0,&lines); if(application){ application->requests.Add(this); application->processflag=1; return 0; } // } return -1; } __s32 sequencenumber=0; ApplicationRequest::ApplicationRequest(Application *xapplication,ApplicationInstance *xinstance, ControlFTPServerApp *xctrlapp, char *xdataleft,int xdataleftsize, int xmap_uid){ int i; char numbuffer[40]; char *mark; char query_string_buffer[256]; application=xapplication; instance=xinstance; ctrlappptr=NULL; ctrlapp=xctrlapp; map_uid=xmap_uid; reported_deleted=0; if(ctrlapp){ new CtrlAppPtrApplicationRequest(this); if(ctrlappptr){ ctrlapp->requestptrs.Add(ctrlappptr); } } nlines=0; buffer=NULL; offset=0; buffsize=0; databuffer=0; databuffsize=0; dataoffset=0; marksbuffer=NULL; marksbuffersize=0; marksinbuffer=0; markssent=0; responsebuffer=NULL; responsebuffersize=0; responsesize=0; responseoffset=0; responsereadoffset=0; appresponsefinished=0; disconnectflag=0; ack_finish=0; specialmessage=0; id=0; sequencenumber++; if(!sequencenumber) sequencenumber++; preassigned_id=sequencenumber; if(ctrlapp){ LogMessage(ctrlapp,this,instance,NULL,0,"REQUEST_CREATED",NULL); if(*ctrlapp->urlbuffer){ requestline=(char*)malloc(strlen(ctrlapp->urlbuffer)+1); if(requestline) strcpy(requestline,ctrlapp->urlbuffer); }else requestline=NULL; if(*ctrlapp->http_accept_buffer) AddLine("HTTP_ACCEPT",ctrlapp->http_accept_buffer); if(*ctrlapp->http_user_agent_buffer) AddLine("HTTP_USER_AGENT",ctrlapp->http_user_agent_buffer); if(*ctrlapp->query_type_buffer) AddLine("CONTENT_TYPE",ctrlapp->query_type_buffer); if(ctrlapp->ifmodifiedsince){ sprintf(numbuffer,"%lu",ctrlapp->ifmodifiedsince); AddLine("HTTP_IF_MODIFIED_SINCE",numbuffer); } if(*ctrlapp->auth_user_buffer){ AddLine("REMOTE_USER",ctrlapp->auth_user_buffer); if(application->authentication&&*ctrlapp->auth_password_buffer) AddLine("REMOTE_PW",ctrlapp->auth_password_buffer); } sprintf(numbuffer,"%u",http_server_port); AddLine("SERVER_PORT",numbuffer); AddLine("SERVER_SOFTWARE",SERVERSOFTWARE); AddLine("GATEWAY_INTERFACE",GATEWAYINTERFACE); AddLine("SERVER_NAME",ctrlapp->localhostname); AddLine("SCRIPT_NAME",ctrlapp->srcbuffer); AddLine("SCRIPT_NAME_RESOLVED",ctrlapp->translatedbuf); if(ctrlapp->keepalive) AddLine("KEEPALIVE","Y"); mark=strchr(ctrlapp->urlbuffer,'?'); if(mark){ strncpy(query_string_buffer,mark+1,255); query_string_buffer[254]=0; AddLine("QUERY_STRING",query_string_buffer); *mark=0; } AddLine("SCRIPT_NAME_ORIGINAL",ctrlapp->urlbuffer); if(mark) *mark='?'; __s32 laddr; unsigned n1,n2,n3,n4; if(ctrlapp->connection){ laddr=htonl(((sockaddr_in*)ctrlapp->connection->getaddress())->sin_addr.s_addr); n4=laddr&0xff; n3=(laddr>>8)&0xff; n2=(laddr>>16)&0xff; n1=(laddr>>24)&0xff; sprintf(numbuffer,"%u.%u.%u.%u",n1,n2,n3,n4); AddLine("REMOTE_ADDR",numbuffer); } if(*ctrlapp->resolvedname) AddLine("REMOTE_HOST",ctrlapp->resolvedname); if(ctrlapp->content_length){ sprintf(numbuffer,"%u",ctrlapp->content_length); AddLine("CONTENT_LENGTH",numbuffer); } if(ctrlapp->nparam>2) AddLine("SERVER_PROTOCOL","HTTP/1.0"); else AddLine("SERVER_PROTOCOL","HTTP/0.9"); switch (ctrlapp->method){ case GET: AddLine("REQUEST_METHOD","GET"); break; case HEAD: AddLine("REQUEST_METHOD","HEAD"); break; case POST: AddLine("REQUEST_METHOD","POST"); break; case PUT: AddLine("REQUEST_METHOD","PUT"); break; } for(i=0;inexecenv;i++){ /* if(ctrlapp->execenv[i]) AddLine("ENV",ctrlapp->execenv[i]); */ if(ctrlapp->execenv[i]){ char *envp=strchr(ctrlapp->execenv[i],'='); if(envp){ *envp=0; AddLine(ctrlapp->execenv[i],envp+1); *envp='='; } } } //if(application) application->requests.Add(this); if(ctrlapp->content_length>0){ if((databuffer=(char*)malloc(ctrlapp->content_length))){ databuffsize=ctrlapp->content_length; dataoffset=xdataleftsize; if(dataoffset<0){ dataoffset=0; }else{ if(dataoffset>databuffsize) dataoffset=databuffsize; } memcpy(databuffer,xdataleft,dataoffset); } } }else requestline=NULL; GetSize(); } ApplicationRequest::~ApplicationRequest(void){ ConfigArgs *currline; if(application) application->processflag=1; if(ctrlapp){ if(!reported_deleted){ LogMessage(ctrlapp,this,instance,NULL,0,"REQUEST_DELETED",NULL); reported_deleted=1; } if(!appresponsefinished) FinishResponse(0); // if it's not finished gracefully, drop it if(ctrlapp->appreq==this) ctrlapp->appreq=NULL; } if(ctrlappptr){ delete ctrlappptr; } if(instance){ if(instance->currresponse==this) instance->currresponse=NULL; } currline=(ConfigArgs*)lines.start; while((currline=(ConfigArgs*)lines.start)){ delete currline; } if(requestline) free(requestline); if(databuffer) free(databuffer); if(buffer) free(buffer); if(responsebuffer) free(responsebuffer); if(marksbuffer) free(marksbuffer); } void ApplicationRequest::AddLine(char *key,char *line){ char *currlines[2]; ConfigArgs *currline; currlines[0]=key; currlines[1]=line; if(key){ if(line){ currline=new ConfigArgs(2,currlines); }else{ currline=new ConfigArgs(1,currlines); } if(currline){ lines.Add(currline); nlines++; } GetSize(); } } void ApplicationRequest::AddLine(char *line){ char *p,*currlines[2]; ConfigArgs *currline; p=strchr(line,':'); currlines[0]=line; if(p){ *p=0; currlines[1]=p+1; currline=new ConfigArgs(2,currlines); *p=':'; }else{ currline=new ConfigArgs(1,currlines); } if(currline){ lines.Add(currline); nlines++; GetSize(); } } /* ------------ A buffsize | sequencenumber | FHTTPD_REQUEST buffsize | rl requestline[rl] | nlines (paramc (rln line[rln])) V databuffsize databuffer[databuffsize] ------------ */ int ApplicationRequest::Convert(void){ ConfigArgs *currline; int i; __s32 *lp; char *cp; #ifdef MUST_ALIGN char *cp0; __s32 q; #else __s32 *lp0; #endif __s32 rl=1,ll; buffsize=sizeof(__s32)*6; if(requestline){ rl=strlen(requestline)+1; buffsize+=rl; } currline=(ConfigArgs*)lines.start; while(currline){ buffsize+=(currline->paramc+1)*(sizeof(__s32)); for(i=0;iparamc;i++) buffsize+=strlen(currline->params[i])+1; currline=(ConfigArgs*)currline->next; } buffsize+=databuffsize; buffer=(char*)malloc(buffsize); if(buffer){ lp=(__s32*)buffer; *lp=htonl(buffsize); lp++; id=preassigned_id; *lp=htonl(id); lp++; *lp=htonl(FHTTPD_REQUEST); lp++; *lp=htonl(rl); lp++; cp=(char*)lp; if(rl>1){ memcpy(cp,requestline,rl); cp+=rl; }else{ *cp=0; cp++; } #ifdef MUST_ALIGN cp0=cp; cp+=sizeof(__s32); #else lp=(__s32*)cp; lp0=lp; lp++; #endif ll=0; currline=(ConfigArgs*)lines.start; while(currline){ ll++; #ifdef MUST_ALIGN q=htonl(currline->paramc); memcpy(cp,&q,sizeof(__s32)); cp+=sizeof(__s32); #else *lp=htonl(currline->paramc); lp++; #endif for(i=0;iparamc;i++){ rl=strlen(currline->params[i])+1; #ifdef MUST_ALIGN q=htonl(rl); memcpy(cp,&q,sizeof(__s32)); cp+=sizeof(__s32); #else *lp=htonl(rl); lp++; cp=(char*)lp; #endif memcpy(cp,currline->params[i],rl); cp+=rl; #ifndef MUST_ALIGN lp=(__s32*)cp; #endif } currline=(ConfigArgs*)currline->next; } #ifdef MUST_ALIGN q=htonl(ll); memcpy(cp0,&q,sizeof(__s32)); q=htonl(databuffsize); memcpy(cp,&q,sizeof(__s32)); cp+=sizeof(__s32); #else *lp0=htonl(ll); *lp=htonl(databuffsize); lp++; cp=(char*)lp; #endif memcpy(cp,databuffer,databuffsize); }else{ buffsize=0; } currline=(ConfigArgs*)lines.start; while((currline=(ConfigArgs*)lines.start)){ delete currline; } if(requestline) free(requestline); if(databuffer) free(databuffer); nlines=0; offset=0; databuffer=NULL; requestline=NULL; GetSize(); if(!buffsize) return -1; else return 0; } void ApplicationRequest::FreeResources(void){ ConfigArgs *currline; currline=(ConfigArgs*)lines.start; while((currline=(ConfigArgs*)lines.start)){ delete currline; } if(requestline) free(requestline); if(databuffer) free(databuffer); if(buffer) free(buffer); requestline=NULL; databuffer=NULL; buffer=NULL; GetSize(); } int ApplicationRequest::GetSize(void){ int j; totalsize=sizeof(class ApplicationRequest) +sizeof(CtrlAppPtrApplicationRequest) +buffsize+marksbuffersize+responsebuffersize+responsebuffersize; if(requestline) totalsize+=strlen(requestline)+1; ConfigArgs *currline; currline=(ConfigArgs*)lines.start; while(currline){ totalsize+=sizeof(class ConfigArgs); for(j=0;jparamc;j++){ totalsize+=strlen(currline->params[j])+1; } currline=(ConfigArgs*)currline->next; } return totalsize; } struct disconnectmessage disconnectbuffer={ #ifdef HTONL_WORKS_IN_CONSTANTS htonl(sizeof(struct disconnectmessage)), #else 0, #endif 0, #ifdef HTONL_WORKS_IN_CONSTANTS htonl(FHTTPD_DISCONNECT), #else 0, #endif 0, 0, 0 }; //Global buffer, just set to copy the data from int ApplicationRequest::Send(void){ char *buffer1; int l; disconnectbuffer.buffsize=htonl(sizeof(struct disconnectmessage)); disconnectbuffer.reqtype=htonl(FHTTPD_DISCONNECT); if(instance){ if(buffer){ l=instance->Send(buffer+offset,buffsize-offset); if(l>0) offset+=l; if(offset>buffsize) offset=buffsize; if(buffsize==offset&&disconnectflag==1){ disconnectflag=2; buffer1=(char*)realloc(buffer,sizeof(struct disconnectmessage)); if(!buffer1){ log("Can't allocate memory for disconnect message"); //That will be really bizzare... I hope, it will never happen GetSize(); return 0; }else{ buffer=buffer1; memcpy(buffer,&disconnectbuffer,sizeof(struct disconnectmessage)); ((struct disconnectmessage*)buffer)->sequencenumber=htonl(id); offset=0; buffsize=sizeof(struct disconnectmessage); return Send(); } } GetSize(); return buffsize-offset; }else{ if(buffsize==offset&&disconnectflag==1){ disconnectflag=2; buffer=(char*)malloc(sizeof(struct disconnectmessage)); if(!buffer){ log("Can't allocate memory for disconnect message"); //That will be really bizzare... I hope, it will never happen GetSize(); return 0; }else{ memcpy(buffer,&disconnectbuffer,sizeof(struct disconnectmessage)); ((struct disconnectmessage*)buffer)->sequencenumber=htonl(id); offset=0; buffsize=sizeof(struct disconnectmessage); return Send(); } } GetSize(); return 0; } }else{ return -1; } } int ApplicationRequest::NotifyDisconnect(void){ if(disconnectflag) return -1; disconnectflag=1; return 0; } void ApplicationRequest::FinishResponse(int cankeepalive){ if(ctrlapp){ if(ctrlapp->connection){ if(ctrlapp->connection->indexforwheel>=0){ if((!responsebuffer||/*responsebuffer&&*/ responseoffset==responsereadoffset) &&(!ctrlapp->keepalive||!cankeepalive ||(ctrlapp->connection->wheel->fdarraysize -fhttpd_nconnections-fhttpd_npipes connection->socket))->setexitafterresponse(ctrlapp->connection,1); }else{ ((ControlFTPServer*)(ctrlapp->connection->socket))->suspendpollforresponse(ctrlapp->connection,1); } } } } appresponsefinished=1; } int ApplicationRequest::RespondToUser(int cankeepalive){ int i,l; if(ctrlapp){ if(ctrlapp->connection){ if(ctrlapp->connection->indexforwheel>=0){ if(responsebuffer){ l=ctrlapp->connection->wheel->getbufferbynumber(ctrlapp->connection->indexforwheel)->put(responsebuffer+responsereadoffset,responseoffset-responsereadoffset); if(l>0) responsereadoffset+=l; if(responsereadoffset>responseoffset) responsereadoffset=responseoffset; for(i=marksinbuffer-1;i>=0&&responsereadoffset>=marksbuffer[i];i--){ marksinbuffer--; markssent++; } //ADDED for(i=0;ikeepalive||!cankeepalive ||(ctrlapp->connection->wheel->fdarraysize -fhttpd_nconnections-fhttpd_npipes connection->socket))->setexitafterresponse(ctrlapp->connection,1); }else{ ((ControlFTPServer*)(ctrlapp->connection->socket))->suspendpollforresponse(ctrlapp->connection,1); } return responseoffset-responsereadoffset; }else{ return 0; } }else{ return -1; } }else{ return -1; } }else{ return -1; } } void ApplicationRequest::DiscardResponseData(void){ responsesize-=responseoffset; responsereadoffset=0; responseoffset=0; marksinbuffer=0; }