⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpgate.c

📁 A very small LISP implementation with several packages and demo programs.
💻 C
字号:
/* 10sep07abu * (c) Software Lab. Alexander Burger */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <ctype.h>#include <string.h>#include <signal.h>#include <netdb.h>#include <time.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/tcp.h>#include <netinet/in.h>#include <syslog.h>#include <openssl/pem.h>#include <openssl/ssl.h>#include <openssl/err.h>typedef enum {NO,YES} bool;static bool Bin;static int Http1, Timeout;static char Head_200[] =   "HTTP/1.0 200 OK\r\n"   "Server: PicoLisp\r\n"   "Content-Type: text/html; charset=utf-8\r\n"   "\r\n";static void logger(char *fmt, ...) {   va_list ap;   va_start(ap,fmt);   vsyslog(LOG_ERR, fmt, ap);   va_end(ap);}static void giveup(char *msg) {   fprintf(stderr, "httpGate: %s\n", msg);   exit(2);}static inline bool pre(char *p, char *s) {   while (*s)      if (*p++ != *s++)         return NO;   return YES;}static char *ses(char *buf, int port, int *len) {   int np;   char *p, *q;   if (Bin || Http1 == 0)      return buf;   if (pre(buf, "GET /")) {      np = (int)strtol(buf+5, &q, 10);      if (q == buf+5 || *q != '/' || np < 1024 || np > 65535)         return buf;      p = q++ - 4;      do         if (*q < '0' || *q > '9')            return buf;      while (*++q != '~');      if (np == port) {         p[0] = 'G',  p[1] = 'E',  p[2] = 'T',  p[3] = ' ';         *len -= p - buf;         return p;      }      return NULL;   }   if (pre(buf, "POST /")) {      np = (int)strtol(buf+6, &q, 10);      if (q == buf+6 || *q != '/' || np < 1024 || np > 65535)         return buf;      p = q++ - 5;      do         if (*q < '0' || *q > '9')            return buf;      while (*++q != '~');      if (np == port) {         p[0] = 'P',  p[1] = 'O',  p[2] = 'S',  p[3] = 'T',  p[4] = ' ';         *len -= p - buf;         return p;      }      return NULL;   }   return buf;}static int slow(SSL *ssl, int fd, char *p, int cnt) {   int n;   while ((n = ssl? SSL_read(ssl, p, cnt) : read(fd, p, cnt)) < 0)      if (errno != EINTR)         return 0;   return n;}static void wrBytes(int fd, char *p, int cnt) {   int n;   do      if ((n = write(fd, p, cnt)) >= 0)         p += n, cnt -= n;      else if (errno != EINTR) {         logger("%d wrBytes error", fd);         exit(1);      }   while (cnt);}static void sslWrite(SSL *ssl, void *p, int cnt) {   if (SSL_write(ssl, p, cnt) <= 0) {      logger("SSL_write error");      exit(1);   }}static int gateSocket(void) {   int sd;   if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {      logger("socket error");      exit(1);   }   return sd;}static int gatePort(int port) {   int n, sd;   struct sockaddr_in addr;   memset(&addr, 0, sizeof(addr));   addr.sin_family = AF_INET;   addr.sin_addr.s_addr = htonl(INADDR_ANY);   addr.sin_port = htons((unsigned short)port);   n = 1,  setsockopt(sd = gateSocket(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));   if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {      logger("%d bind error", sd);      exit(1);   }   if (listen(sd,5) < 0) {      logger("%d listen error", sd);      exit(1);   }   return sd;}static int gateConnect(unsigned short port) {   int sd;   struct sockaddr_in addr;   memset(&addr, 0, sizeof(addr));   addr.sin_addr.s_addr = inet_addr("127.0.0.1");   sd = gateSocket();   addr.sin_family = AF_INET;   addr.sin_port = htons(port);   return connect(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0? -1 : sd;}static pid_t Buddy;static void doSigAlarm(int n __attribute__((unused))) {   logger("Timeout %d", Timeout);   kill(Buddy, SIGTERM);   exit(0);}static void doSigUsr1(int n __attribute__((unused))) {   alarm(Timeout);}int main(int ac, char *av[]) {   int cnt = ac>4? ac-3 : 1, ports[cnt], n, sd, cli, srv;   struct sockaddr_in addr;   char *gate;   SSL_CTX *ctx;   SSL *ssl;   if (ac < 3)      giveup("port dflt [pem [alt ..]]");   sd = gatePort(atoi(av[1]));  // e.g. 80 or 443   ports[0] = atoi(av[2]);  // e.g. 8080   if (ac == 3 || *av[3] == '\0')      ssl = NULL,  gate = "Gate: http %s\r\n";   else {      SSL_library_init();      SSL_load_error_strings();      if (!(ctx = SSL_CTX_new(SSLv23_server_method())) ||            !SSL_CTX_use_certificate_file(ctx, av[3], SSL_FILETYPE_PEM) ||               !SSL_CTX_use_PrivateKey_file(ctx, av[3], SSL_FILETYPE_PEM) ||                                          !SSL_CTX_check_private_key(ctx) ) {         ERR_print_errors_fp(stderr);         giveup("SSL init");      }      ssl = SSL_new(ctx),  gate = "Gate: https %s\r\n";   }   for (n = 1; n < cnt; ++n)      ports[n] = atoi(av[n+3]);   signal(SIGCHLD,SIG_IGN);  /* Prevent zombies */   if ((n = fork()) < 0)      giveup("detach");   if (n)      return 0;   setsid();   openlog("httpGate", LOG_CONS|LOG_PID, 0);   for (;;) {      socklen_t len = sizeof(addr);      if ((cli = accept(sd, (struct sockaddr*)&addr, &len)) >= 0 && (n = fork()) >= 0) {         if (n)            close(cli);         else {            int fd, port;            char *p, *q, buf[4096], buf2[64];            close(sd);            alarm(Timeout = 420);            if (ssl) {               SSL_set_fd(ssl, cli);               if (SSL_accept(ssl) < 0)                  return 1;               n = SSL_read(ssl, buf, sizeof(buf));            }            else               n = read(cli, buf, sizeof(buf));            alarm(0);            if (n < 6)               return 1;            /* "@8080 "             * "GET /url HTTP/1.x"             * "GET /8080/url HTTP/1.x"             * "POST /url HTTP/1.x"             * "POST /8080/url HTTP/1.x"             */            Bin = NO;            if (buf[0] == '@')               p = buf + 1,  Bin = YES,  Timeout = 3600;            else if (pre(buf, "GET /"))               p = buf + 5;            else if (pre(buf, "POST /"))               p = buf + 6;            else               return 1;            port = (int)strtol(p, &q, 10);            if (q == p  ||  *q != ' ' && *q != '/')               port = ports[0],  q = p;            else if (port < cnt)               port = ports[port];            else if (port < 1024)               return 1;            if ((srv = gateConnect((unsigned short)port)) < 0) {               logger("Can't connect to %d", port);               if (!memchr(q,'~', buf + n - q)) {                  buf[n] = '\0';                  logger("Bad request: %s", buf);                  return 1;               }               if ((fd = open("void", O_RDONLY)) < 0)                  return 1;               alarm(Timeout);               if (ssl)                  sslWrite(ssl, Head_200, strlen(Head_200));               else                  wrBytes(cli, Head_200, strlen(Head_200));               alarm(0);               while ((n = read(fd, buf, sizeof(buf))) > 0) {                  alarm(Timeout);                  if (ssl)                     sslWrite(ssl, buf, n);                  else                     wrBytes(cli, buf, n);                  alarm(0);               }               return 0;            }            Http1 = 0;            if (buf[0] == '@')               p = q + 1;            else {               wrBytes(srv, buf, p - buf);               if (*q == '/')                  ++q;               p = q;               while (*p++ != '\n')                  if (p >= buf + n) {                     buf[n] = '\0';                     logger("Bad header: %s", buf);                     return 1;                  }               wrBytes(srv, q, p - q);               if (pre(p-10, "HTTP/1."))                  Http1 = *(p-3) - '0';               wrBytes(srv, buf2, sprintf(buf2, gate, inet_ntoa(addr.sin_addr)));            }            wrBytes(srv, p, buf + n - p);            signal(SIGALRM, doSigAlarm);            signal(SIGUSR1, doSigUsr1);            if (Buddy = fork()) {               for (;;) {                  alarm(Timeout);                  n = slow(ssl, cli, buf, sizeof(buf));                  alarm(0);                  if (!n || !(p = ses(buf, port, &n)))                     break;                  wrBytes(srv, p, n);               }               shutdown(cli, SHUT_RD);               shutdown(srv, SHUT_WR);            }            else {               Buddy = getppid();               while ((n = read(srv, buf, sizeof(buf))) > 0) {                  kill(Buddy, SIGUSR1);                  alarm(Timeout);                  if (ssl)                     sslWrite(ssl, buf, n);                  else                     wrBytes(cli, buf, n);                  alarm(0);               }               shutdown(srv, SHUT_RD);               shutdown(cli, SHUT_WR);            }            return 0;         }      }   }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -