All pastes #897216 Raw Edit

SEXY: Small package proxy for ge

public c v1 · immutable
#897216 ·published 2008-02-09 10:21 UTC
rendered paste body
#if 0#!/bin/env sh[ -e /etc/make.conf ] && source /etc/make.confecho gcc -Wall $CFLAGS -pthread -o sexy main.cgcc -Wall $CFLAGS -pthread -o sexy main.cexit#endif/** * sexy: Small package proxy for gentoo, without features. * Author: Nelnire * Contact: nelnire@gmail.com * Licence: GPL-2 * * Change: *  Juanary  09 2008 - First change *  December 07 2007 - First version */#include "conf.h" /* Edit conf.h */#include <arpa/inet.h>#include <fcntl.h>#include <netdb.h>#include <pthread.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <unistd.h>#define BUFSIZE 4096#define TIMEOUT 3int mksfd(int port){   int sfd, opt = 1;   struct sockaddr_in saddr;      sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);   if(sfd<0)      return -1;   saddr.sin_family = AF_INET;   saddr.sin_port = htons(PORT);   saddr.sin_addr.s_addr = INADDR_ANY;   if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))<0)      return -1;   if(bind(sfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr))<0)      return -1;   if(listen(sfd, 5)<0)      return -1;   return sfd;}void connclose(int cfd, int code){   char buf[BUFSIZE];   snprintf(buf, BUFSIZE,            "HTTP/1.1 %d\r\n"	    "Connection: close\r\n"            "Content-type: text/html\r\n"            "\r\n"            "<html><head>\n"            "<title>%d</title>\n"            "</head><body>\n"            "<h1>%d</h1>\n"            "</body></html>\n",	    code, code, code);   send(cfd, buf, strlen(buf), 0);   close(cfd);   pthread_exit(NULL);}int timeout(int cfd){   fd_set fdset;   struct timeval timeout;   FD_ZERO(&fdset);   FD_SET(cfd, &fdset);   timeout.tv_sec = TIMEOUT;   timeout.tv_usec = 0;   return select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);}int checkquery(int cfd, char *file, int max){   char r;   char *tok, query[256];   int n=0;   query[0] = '\0';   /* Get the query */   while(1)   {      if(timeout(cfd)==0)	 return -1;      recv(cfd, &r, 1, 0);      strncat(query, &r, 1);      if(query[n] == '\n' &&         (n>1 && query[n-1] == '\r')) /* strtok segfault avec n>0 */      {	 query[n-1] = '\0';	 break;      }      n++;      if(n==256)	 connclose(cfd, 500);   }   /* Check the query */   tok = strtok(query, " ");   if(!strcmp(tok, "\r\n"))      connclose(cfd, 400);   if(strcmp(tok, "GET"))      connclose(cfd, 501);   tok = strtok(NULL, " ");   if(strncmp(tok, "/distfiles/", 11))      connclose(cfd, 403);   /* ... */   if(strlen(tok) == 11)      connclose(cfd, 403);   if(tok[11] == '.')      connclose(cfd, 403);   strncpy(file, tok+11, max);      return 0;}int findfile(char *file){   int fd = open(file, O_RDONLY);   if(fd<0)      return 0;   close(fd);   return 1;}int gf_checkresp(char *resp){   /* The next supose that "resp" is    * the first buffer receved */   if(strncmp(resp+9, "200", 3)==0)      return 0;   else if(strncmp(resp+9, "404", 3)==0)      return 1;   else      return -1;}int gf_getlen(char *noname){   int size;   if(sscanf(noname, "Content-Length: %d", &size))      return size;   return 0;}int getfile(char *file){   int fd = -1;   socklen_t s;   struct sockaddr_in saddr;   struct hostent *h;   int r;   char buf[BUFSIZE+1];   int check; /* Check the serv resp */   int shift; /* Header shift */   if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0)      return -1;   if((h = gethostbyname(GENTOO_MIRROR))==NULL)      return -1;   saddr.sin_family = AF_INET;   saddr.sin_port = htons(80);   bcopy(h->h_addr, &(saddr.sin_addr), h->h_length);   if(connect(s, (struct sockaddr *)&saddr, sizeof(saddr))<0)      return -1;   /* Send the header */   /* NOTE: "Connection: close" is precised in order to not wait    * for server deconnection if the size isn't known.    */   snprintf(buf, BUFSIZE,            "GET /distfiles/%s HTTP/1.1\r\n"            "host: %s\r\n"            "Connection: Close\r\n"            "\r\n"            , file, GENTOO_MIRROR);   send(s, buf, strlen(buf), 0);   /* Get the file */   enum e_stage {GETRESP, GETHEAD, GETDATA};   enum e_stage stage = GETRESP;   int size = 0, tsize = 0;   while( (r = read(s, buf, BUFSIZE)) )   {      buf[r] = '\0';      shift = 0;      if(r<0)	 return -1;      if(stage == GETRESP)      {	 check = gf_checkresp(buf);	 if(check)	    return check;	 /* Open the file to save */	 if(fd == -1)	 {	    fd = open(file, O_WRONLY | O_CREAT | O_EXCL,		            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);	    if(fd<0)	       return -1;	 }	 stage = GETHEAD;      }      if( stage == GETHEAD)      {	 if(strstr(buf, "Content-Length:"))	    tsize = gf_getlen(strstr(buf, "Content-Length:"));	 /* NOTE: This may fail if the CRLF is cut on two 'buf' */	 if(strstr(buf, "\r\n\r\n"))	 {	    shift += strlen(buf)-strlen(strstr(buf, "\r\n\r\n"))+4;	    stage = GETDATA;	 }      }      if(stage == GETDATA)      {	 write(fd, buf+shift, r-shift);	 if((size += r-shift)==tsize)	    break;      }   }   close(fd);   return 0;}void sendfile(int cfd, char *file){   int fd, r, w;   struct stat st;   char buf[BUFSIZE];   fd = open(file, O_RDONLY);   if(fd<0)      connclose(cfd, 500);   if(fstat(fd, &st)<0)      connclose(cfd, 500);      snprintf(buf, BUFSIZE,             "HTTP/1.1 200\r\n"            "Connection: close\r\n"            "Content-Length: %d\r\n"            "\r\n", (int)st.st_size);   w = send(cfd, buf, strlen(buf), 0);   if(w<0)      return;   while( (r = read(fd, buf, BUFSIZE)) )   {      if(r<0)	 connclose(cfd, 500);      w = send(cfd, buf, r, 0);      if(w<0)	 return;   }}void *handler(void *data){   int cfd = (int)data;   char file[256];   int v;   v = checkquery(cfd, file, 255);   if(v==-1){      close(cfd);      return NULL;   }   if(!findfile(file)) {      v = getfile(file);      if(v== 1) connclose(cfd, 404);      if(v==-1) connclose(cfd, 500);   }   sendfile(cfd, file);   sleep(1); /* */   close(cfd);   return NULL;}int run(int sfd){   if(sfd<0)      return 1;   int cfd;   pthread_t th;   while(1)   {      cfd = accept(sfd, NULL, 0);      if(cfd<0)	 return 1;      if(pthread_create(&th, NULL, handler, (void*)cfd)<0)	 return 1;      if(pthread_detach(th)<0)	 return 1;   }}int main(void){   if(chdir(DISTDIR)<0)      return 1;   signal(SIGPIPE, SIG_IGN);   pid_t pid = fork();   if(pid<0)      return 1;   else if(pid>0)      exit(0);   return run(mksfd(PORT));}