/* * * server.c - part of Danovitsch Webcam * * Copyright (C) 2001 by Daan Vreeken * * Published under the terms of the GNU Public License 2.0 * (or any later version) * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "webcam.h" #include "server.h" #include "http.h" int Clients = 0; int AcceptSock = -1; long ImagesServed = 0; long ImagesSinceRestart = 0; const char *StateName[] = {"Waiting for request", "Getting header", "Getting POST data", "Sending response", "Zombie"}; struct Connection *Server_CurrentConnection = NULL; struct Connection Client[MaxClients]; int SockSend(struct Connection *C, void *Buf, size_t Len) { long Error; socklen_t OptLen = sizeof(Error); int Bytes; if (!C->Close) { //fcntl(C->FD,F_SETFD,O_NONBLOCK); Server_CurrentConnection=C; Bytes=send(C->FD,Buf,Len,0); if (Bytes==-1) { Debug(50,"fd:%d b:%d l:%d",C->FD,Buf,Len); Debug(50,"(send) Socket just died..."); C->Close=1; } Server_CurrentConnection=NULL; //fcntl(C->FD,F_SETFD,0); } else return 1000; return Bytes; } size_t SockRecv(struct Connection *C, void *Buf, size_t Len) { return recv(C->FD,Buf,Len,0); } void Print(struct Connection *C, char *Txt) { SockSend(C,Txt,strlen(Txt)); } void PrintF(struct Connection *C, char *Txt, ...) { char Temp[200]; va_list List; va_start(List,Txt); vsprintf(Temp,Txt,List); Print(C,Temp); va_end(List); } void Server_CloseConnection(int Nr) { struct Connection *C = &Client[Nr]; if (C->Line!=NULL) free(C->Line); //shutdown(C->FD,SHUT_RDWR); close(C->FD); if (NrState) { case GetData: if (Size+C->PostLength>C->ContentLength) { Error("Got more data than expected!"); } if (C->PostData==NULL) C->PostData=(char *)malloc(Size); else C->PostData=(char *)realloc(C->PostData,C->PostLength+Size); if (C->PostData==NULL) { Error("Could not allocate PostData buffer! (dropping connection)"); C->Close=1; return; } Ptr=C->PostData + C->PostLength; memcpy(Ptr,Data,Size); C->PostLength+=Size; if (C->PostLength>=C->ContentLength) { Debug(60,"Received POST data"); //Let's start answering the thing... C->State=Response; shutdown(C->FD,SHUT_RD); } break; default: Error("Should not have gotten here!!"); } } void Server_HandleLine(struct Connection *C) { char **Ptr; char *Temp; switch (C->State) { case GetRequest: C->Request=(char *)malloc(C->Length+1); if (C->Request==NULL) { Error("Could not allocate memory for Request! (client will be dropped)"); C->Close=1; break; } else { memcpy(C->Request,C->Line,C->Length+1); } //split request in 3 parts Temp=C->Request; for (Ptr=C->RequestArg; (*Ptr=strsep(&Temp," "))!=NULL;) if (**Ptr!=0) if (++Ptr>=&(C->RequestArg[3])) break; //Check action if (((C->RequestArg[0]==NULL) || (C->RequestArg[1]==NULL) || (C->RequestArg[2]==NULL)) || ((strcmp(C->RequestArg[0],"GET")) && (strcmp(C->RequestArg[0],"POST")))) { HTTP_Header(C,501,NULL); C->Close=1; return; } Debug(90,"Request: %s",C->RequestArg[1]); C->State=GetHeader; break; case GetHeader: if (C->Length==0) { if (C->Request==NULL) { HTTP_Header(C,501,NULL); //Dump connection now... C->Close=1; C->State=Zombie; Debug(50,"Closing connection..."); return; } //GET or POST ? if (!strcmp(C->RequestArg[0],"GET")) { C->State=Response; shutdown(C->FD,SHUT_RD); } else { C->State=GetData; C->Mode=ByteMode; } } else { //Get 'Content-length' if (!strncasecmp(C->Line,"Content-length: ",16)) { sscanf(&C->Line[16],"%d",&C->ContentLength); if (C->ContentLength>HTTP_MaxContentLength) { HTTP_Header(C,501,NULL); C->Close=1; return; } } Debug(70,"Header: %s",C->Line); } break; default: Debug(10,"Dumped line..."); } } void Server_HandleData(int Conn) { struct Connection *C = &Client[Conn]; int Readed; char Temp[1000]; int Cnt; int WasInLineMode = 0; int LastLineByte = 0; if (C->Line==NULL) { C->Line=(char *)malloc(MaxLineSize+1); if (C->Line==NULL) { Error("Could not allocate Line buffer! - dumping client"); C->Close=1; return; } } Readed=SockRecv(C,&Temp,sizeof(Temp)-1); Temp[Readed]=0; if (Readed==0) { Debug(50,"(read) Connection lost..."); C->Close=1; } if (C->Mode==LineMode) { for (Cnt=0; CntLine+C->Length)=0; Server_HandleLine(C); if (C->Mode==ByteMode) { LastLineByte=Cnt; WasInLineMode=1; Cnt=Readed+1; } C->Length=0; break; default: if (C->Length==MaxLineSize) break; *(C->Line+C->Length++)=Temp[Cnt]; } } if (C->Mode==ByteMode) { if (WasInLineMode) Server_HandleBytes(C,&Temp[LastLineByte+1],(Readed-LastLineByte)-1); else Server_HandleBytes(C,&Temp[0],Readed); } } void Server_Init(void) { FILE *CountFile = fopen("webcam.count","r"); if (CountFile!=NULL) { fread(&ImagesServed,sizeof(ImagesServed),1,CountFile); fclose(CountFile); Output("Restarting ImagesServed counter at %ld",ImagesServed); } else { CountFile=fopen("webcam.count","w"); if (CountFile!=NULL) { ImagesServed=0; fwrite(&ImagesServed,sizeof(ImagesServed),1,CountFile); fclose(CountFile); Output("webcam.count did not exits. -has been created-"); } else Output("Failed to create webcam.count. (do we have permission?)"); } ImagesSinceRestart=0; } void Server_Shutdown(void) { int Cnt; FILE *CountFile = fopen("webcam.count","w"); //drop accept socket if (AcceptSock!=-1) close(AcceptSock); //drop all clients if (Clients>0) { Output("Dropping %d client(s).",Clients); while (Clients>0) Server_CloseConnection(Clients-1); } //Write ImagesServer to count file... if (CountFile!=NULL) { fwrite(&ImagesServed,sizeof(ImagesServed),1,CountFile); fclose(CountFile); } else Output("Could not write webcam.count! (do we have permission?)"); Output("Shutdown server"); }