📄 http_proxy.c
字号:
/* * Copyright (c) 1996-2000 University of Utah and the Flux Group. * All rights reserved. * * This file is part of the Flux OSKit. The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF). To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. * * The OSKit 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. See the GPL for more details. You should have * received a copy of the GPL along with the OSKit; see the file COPYING. If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. *//* * HTTP Proxy: This example is intended to demonstrate a multi-threaded * program that uses the BSD socket layer. This is a simple HTTP proxy * that listens on port 6969. It can handle basic methods like GET, HEAD, * CONNECT, and POST, but is by no means a correct, complete, or optimal * implementation of the HTTP spec. Its just a demonstration. * * Big Picture: For each new connection received on port 6969, 3 new threads * are launched. The first parses the connection request and gets it sent * off to the actual server. The other two threads simply loop, reading from * the client and server sides, passing data along to the other side. When * either side closes it connection (usually the server when the file has * been transferred), all the connections are torn down and the 3 threads * are terminated. * * To test this with Netscape you need to tell it to use a proxy. * Under version 3 this is done through the Options -> Network Preferences -> * Proxies -> Manual -> Config -> View dialog box. * Set HTTP and Security to machine name and port 6969. * Under version 4 this is done through the Preferences -> Advanced -> * Proxies -> Manual -> View dialog box. * * Note: the filesytem stuff is only so libstartup can set up things in /etc * for us (like /etc/resolv.conf). * We could use the bmodfs but we use the netbsd filesystem to test more stuff. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/inet.h>#include <sys/ioctl.h>#include <errno.h>#include <ctype.h>#include <strings.h>#include <string.h>#include <dirent.h>#include <fcntl.h>#include <oskit/threads/pthread.h>#include <oskit/startup.h>#include <oskit/clientos.h>#include <assert.h>#include <sys/stat.h>#include <oskit/queue.h>#include <time.h>#if !defined(OSKIT_UNIX) && defined(OSKIT_X86)#include <oskit/x86/base_gdt.h>#endifint proxy_socket;int death_socket;int create_listener_socket(int port);void *deathwatch(void *foo);pthread_mutex_t gethostname_mutex;int threads_stack_back_trace(int, int);#include <oskit/dev/dev.h>#include <oskit/dev/linux.h>#ifdef OSKIT_UNIXvoid start_fs_native_pthreads(char *root);#endif/* * Each connection has this associated data structure. */typedef struct _connection { int client_sock; /* Connection from the client */ int server_sock; /* Connection to the server */ pthread_mutex_t mutex; /* A lock to protect this structure */ pthread_cond_t condvar; /* Condition for signal */ int died; /* One side or the other died. */} connection_t;void *connection_manager(void *arg);/* * Act as simple HTTP proxy. */intmain(){ int length, sock; struct sockaddr client; pthread_t death_tid, tid; extern int threads_debug; /* * Init the OS. */ oskit_clientos_init_pthreads(); start_clock(); start_pthreads(); threads_debug = 0; #ifndef OSKIT_UNIX start_world_pthreads();#else#ifdef REALSTUFF start_fs_pthreads("/dev/oskitfs", 0); start_network_pthreads();#else start_fs_native_pthreads("/tmp"); start_network_native_pthreads();#endif#endif pthread_mutex_init(&gethostname_mutex, 0); proxy_socket = create_listener_socket(6969); death_socket = create_listener_socket(6666); /* * Create a thread so I can talk to the program via telnet. */ pthread_create(&death_tid, 0, deathwatch, (void *) 0); /* * The main thread will do nothing except look for new * connections. */ while (1) { sock = accept(proxy_socket, &client, &length); if (sock < 0) { if (errno == ECONNABORTED) { /* * The deathwatch has cut us off at the * knees. Just wait for the end. */ oskit_pthread_sleep(100000); } perror("accept"); exit(1); } /* * Create a thread to manage this connection. */ pthread_create(&tid, 0, connection_manager, (void *) sock); pthread_detach(tid); } return 0;}/* * This program creates a datagram socket, binds a name to it, then reads * from the socket. */intcreate_listener_socket(int port){ int sock, length, data; struct sockaddr_in name; /* Create socket from which to read. */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("opening datagram socket"); exit(1); } data = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &data, sizeof(data)) < 0) { perror("setsockopt"); exit(1); } /* Create name with wildcards. */ name.sin_family = AF_INET; name.sin_addr.s_addr = INADDR_ANY; name.sin_port = htons(port); if (bind(sock, (struct sockaddr *) &name, sizeof(name))) { perror("binding datagram socket"); exit(1); } /* Find assigned port value and print it out. */ length = sizeof(name); if (getsockname(sock, (struct sockaddr *) &name, &length)) { perror("getting socket name"); exit(1); } printf("Socket has port #%d\n", ntohs(name.sin_port)); if (listen(sock, 20) < 0) { perror("listen on socket"); exit(1); } return sock;}intconnect_to_host(char *host, char *port, int *server_sock){ int sock, data; struct sockaddr_in name; struct hostent *hp, *gethostbyname(); struct timeval timeo; /* Create socket on which to send. */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("connect_to_host: opening datagram socket"); return 1; } data = 1024 * 32; if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &data, sizeof(data)) < 0) { perror("setsockopt SO_SNDBUF"); return 1; } data = 1024 * 32; if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &data, sizeof(data)) < 0) { perror("setsockopt SO_RCVBUF"); return 1; } data = 1; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &data, sizeof(data)) < 0) { perror("setsockopt SO_KEEPALIVE"); return 1; } timeo.tv_sec = 30; timeo.tv_usec = 0; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)) < 0) { perror("setsockopt SO_RCVTIMEO");#if 0 panic("SETSOCKOPT");#endif } /* * Construct name, with no wildcards, of the socket to send to. * Gethostbyname() returns a structure including the network address * of the specified host. The port number is taken from the command * line. */ pthread_mutex_lock(&gethostname_mutex); hp = gethostbyname(host); pthread_mutex_unlock(&gethostname_mutex); if (hp == 0) { printf("connect_to_host: unknown host: %s\n", host); return 1; } bcopy(hp->h_addr, &name.sin_addr, hp->h_length); name.sin_family = AF_INET; name.sin_port = htons((port ? atoi(port) : 80)); if (connect(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { perror("connect_to_host: connecting stream socket"); return 1; } *server_sock = sock; return 0;}/* * Setup a new connection. */intsetup_connection(int client_sock, connection_t **return_connp){ int data, c, len, server_sock, tunneling = 0; char buf[BUFSIZ], str[BUFSIZ], *bp; char *last = 0, *method, *url, *rest, *host, *port; connection_t *connp; struct timeval timeo; data = 1; if (setsockopt(client_sock, SOL_SOCKET, SO_KEEPALIVE, &data, sizeof(data)) < 0) { perror("setsockopt SO_KEEPALIVE"); return 1; } /* * Set the recv timeout so that reads do not block forever. */ timeo.tv_sec = 10; timeo.tv_usec = 0; if (setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)) < 0) { perror("setsockopt SO_RCVTIMEO");#if 0 return 1;#endif } /* * Read the first block of data to get the URL info. */ bzero(buf, BUFSIZ); if ((c = recv(client_sock, buf, BUFSIZ, 0)) <= 0) { if (c <= 0) { if (c == 0) { printf("Closing down Client side\n"); return 1; } if (errno && errno != EINTR) { perror("First read on client side"); return 1; } } } /* * Parse the URL info. */ bp = buf; if ((method = strtok_r(bp, " \t\n\r", &last)) == NULL) { printf("Bad Method: %s\n", buf); return 1; } if ((url = strtok_r(NULL, " \t\n\r", &last)) == NULL) { printf("Bad URL(1): %s\n", buf); return 1; } printf("%d: %s %s\n", (int) pthread_self(), method, url); rest = &url[strlen(url)]; rest++; /* * Look at the method. Support just GET/POST/HEAD and CONNECT. */ if (strncasecmp(method, "GET", 3) == 0 || strncasecmp(method, "POST", 4) == 0 || strncasecmp(method, "HEAD", 4) == 0) { /* * Separate the host name from the actual url. */ if (strncasecmp(url, "http://", 7) != 0) { printf("Bad URL(2): %s\n", url); return 1; } host = url+7; } else if (strncasecmp(method, "CONNECT", 7) == 0) { printf("%d: %s\n", (int) pthread_self(), rest); host = url; tunneling = 1; } else { printf("%d: Bad METHOD: %s %s\n", (int) pthread_self(), method, url); return 1; } /* * Extract the port and the url. */ bp = host; port = (char *) 0; while (*bp && !(*bp == '/' || *bp == ':')) ++bp; if (*bp == 0) { url = (char *) 0; } else { if (*bp == ':') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -