- 论坛徽章:
- 0
|
第2部分
- #define ERR_SOCKET -5
- #define ERR_GETHOSTBYNAME -6
- #define ERR_CONNECT -7
- #define ERR_CONNECT_TIMEOUT -8
- int connectto(char *hote, int port, int sockIn)
- {
- #if 1 /*
- * use gethostbyname
- */
- struct hostent *ServerName;
- struct sockaddr_in OutputSocket; /* output socket descriptor */
- int sockOut, retval;
- if ((sockOut = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- return ERR_SOCKET;
- }
- pthread_mutex_lock(&gethostbyname_mu);
- if ((ServerName = gethostbyname(hote)) == NULL) {
- pthread_mutex_unlock(&gethostbyname_mu);
- return ERR_GETHOSTBYNAME;
- }
- bzero((char *) &OutputSocket, sizeof(OutputSocket));
- OutputSocket.sin_family = AF_INET;
- OutputSocket.sin_port = htons(port);
- bcopy((char *) ServerName->h_addr,
- (char *) &OutputSocket.sin_addr,
- ServerName->h_length);
- pthread_mutex_unlock(&gethostbyname_mu);
- #else
- /*
- * use gethostbyname_r
- */
- struct hostent ServerName;
- struct sockaddr_in OutputSocket; /* output socket descriptor */
- int sockOut, retval;
- char buf[1024];
- int hst_errno;
- if ((sockOut = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- return ERR_SOCKET;
- }
- /*
- * pointers used in struct hostent ServerName will be point to space
- * which user give to function (the buf variable)
- */
- if (gethostbyname_r(hote, &ServerName, buf, sizeof(buf), &hst_errno)
- == NULL) {
- if (hst_errno == ERANGE) {
- /* the buf is to short for store all informations */
- }
- return ERR_GETHOSTBYNAME;
- }
- bzero((char *) &OutputSocket, sizeof(OutputSocket));
- OutputSocket.sin_family = AF_INET;
- OutputSocket.sin_port = htons(port);
- bcopy((char *) ServerName.h_addr,
- (char *) &OutputSocket.sin_addr,
- ServerName.h_length);
- #endif
- alarm(timeout_out);
- retval = connect(sockOut, (struct sockaddr *) &OutputSocket, sizeof(OutputSocket));
- alarm(0);
- if (retval == -1) {
- close(sockOut);
- return ERR_CONNECT;
- }
- return sockOut; /* connection OK */
- }
- /* this function should be called only by the child */
- void sayerror(char *msg, int sockIn, int sockOut)
- {
- struct linger linger;
- pthread_setspecific(key_alarm, NULL);
-
- write(sockIn, msg, strlen(msg));
-
- linger.l_onoff = 1;
- linger.l_linger = 4;
- setsockopt(sockIn, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
- linger.l_onoff = 1;
- linger.l_linger = 1;
- setsockopt(sockOut, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
- close(sockOut);
- close(sockIn);
- #ifdef DEBUG
- {
- char buf[1024];
- char *p, *end;
-
- p = strstr(msg, "Reason:");
- end = strstr(p, "<P>");
- if (!p || !end)
- buf[0] = 0;
- else {
- strncpy(buf, p, end - p);
- buf[end - p] = 0;
- }
- printf("%d --- request error %s\n", sockIn, buf);
- }
- #endif
- }
- void request_alarm(int i)
- {
- sigjmp_buf *jmp;
- if ((jmp = pthread_getspecific(key_alarm))) {
- pthread_setspecific(key_alarm, NULL);
- siglongjmp(*jmp, 1);
- }
- }
- #define METHOD_GET 1
- #define METHOD_POST 2
- #define METHOD_HEAD 3
- int process_request(int sockIn)
- {
- char data[LDATA];
- char adr[LADR], *p;
- int ldata, lreq, port, req_len, req_method;
- FILE *fsin;
- sigjmp_buf timeout_jmp;
- int sockOut = -1;
- int val;
-
- /* let's reopen input socket as a file */
- if ((fsin = fdopen(sockIn, "rw")) == NULL)
- goto serverr;
- /* prepares for connection abort */
- /* avoid some sockets problems ... */
- val = 1;
- setsockopt(sockIn, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
- /*
- * here, we'll analyze the request and get rid of "http://adr:port".
- * The address and port willbe duplicated and used to open the connection.
- */
- if (sigsetjmp(timeout_jmp, 1) != 0)
- goto timeout;
- pthread_setspecific(key_alarm, &timeout_jmp);
- #ifdef DEBUG
- printf("%d --- request begin\n", sockIn);
- #endif
- if (fgets(data, LDATA, fsin) == NULL)
- goto badreq;
- #ifdef DEBUG
- printf("%d %s", sockIn, data);
- #endif
- /* it's easy to log all requests here */
- /* fprintf(stderr,"requete recue: %s",data); */
- ldata = strlen(data);
- if (strncmp(data, "GET ", 4) == 0) {
- req_len = 4;
- req_method = METHOD_GET;
- } else if (strncmp(data, "POST ", 5) == 0) {
- req_len = 5;
- req_method = METHOD_POST;
- } else if (strncmp(data, "HEAD ", 5) == 0) {
- req_len = 5;
- req_method = METHOD_HEAD;
- } else
- goto badreq;
- if (!ConnectToProxy) { /* if proxy-to-proxy connection, we don't modify the request */
- char *str;
- str = data + req_len;
- while (*str == ' ')
- str++;
- if (!strncmp(str, "http://", 7))
- str += 7;
- if ((p = strchr(str, '/')) != NULL) {
- strncpy(adr, str, (p - str)); /* copies addresse in adr */
- adr[p - str] = 0;
- str = p; /* points to the rest of the request (without address) */
- lreq = ldata - (str - data);
- } else
- goto badreq; /* if no /, error */
- /* at this stage, adr contains addr[:port], and str points to the local URL with the first '/' */
- if (adr[0] == 0)
- goto badreq;
- p = strchr(adr, ':');
- if (p == NULL) /* unspecified port. The default one will be used */
- port = DEFAULTPORT;
- else { /* port is available. let's read it */
- *(p++) = 0; /* ends hostname */
- port = atoi(p);
- }
- /* end of request analysis. The hostname is in "adr", and the port in "port" */
- if ((sockOut = connectto(adr, port, sockIn)) < 0) {
- switch (sockOut) {
- case ERR_GETHOSTBYNAME:
- goto servdnserr;
- }
- goto servcoerr;
- }
- /* As it becomes a local URL, we only say "GET" and the end of the request. */
- alarm(timeout_out);
- switch (req_method) {
- case METHOD_GET:
- write(sockOut, "GET ", 4);
- break;
- case METHOD_POST:
- write(sockOut, "POST ", 5);
- break;
- case METHOD_HEAD:
- write(sockOut, "HEAD ", 5);
- break;
- }
- write(sockOut, str, lreq);
- alarm(0);
- } else { /* proxy-to-proxy connection ! */
- if ((sockOut = connectto(NextProxyAdr, NextProxyPort, sockIn)) < 0) {
- switch (sockOut) {
- case ERR_GETHOSTBYNAME:
- goto servdnserr;
- }
- goto servcoerr;
- }
- alarm(timeout_out);
- write(sockOut, data, ldata);
- alarm(0);
- }
- /* now, let's copy all what we don't have copied yet */
- if (req_method == METHOD_POST) {
- int c_len = 0;
- char *p;
- do {
- fgets(data, LDATA, fsin);
- #ifdef DEBUG
- printf("%d %s", sockIn, data);
- #endif
- ldata = strlen(data);
- if (strncasecmp(data, "Content-Length", 14) == 0) {
- p = data + 14;
- while (*p != ':')
- p++;
- c_len = atoi(++p);
- }
- write(sockOut, data, ldata);
- } while (ldata && data[0] != '\n' && data[0] != '\r');
- if (c_len == 0)
- goto posterr;
- #ifdef DEBUG
- printf("%d ", sockIn);
- #endif
- while (c_len) {
- ldata = fread(data, 1,
- (LDATA > c_len ? c_len : LDATA), fsin);
- #ifdef DEBUG
- fwrite(data, 1, ldata, stdout);
- #endif
- write(sockOut, data, ldata);
- c_len -= ldata;
- }
- #ifdef DEBUG
- printf("\n");
- #endif
- } else { /*
- * METHOD_GET, METHOD_HEAD
- */
- do {
- fgets(data, LDATA, fsin);
- #ifdef DEBUG
- printf("%d %s", sockIn, data);
- #endif
- ldata = strlen(data);
- if (!NoCache || (strncmp(data, "If-Mod", 6)))
- write(sockOut, data, ldata);
- } while (ldata && data[0] != '\n' && data[0] != '\r');
- }
- /* retrieve data from server */
- do {
- int err;
- do {
- alarm(timeout_out);
- ldata = read(sockOut, data, LDATA);
- alarm(0);
- } while (ldata == -1 && errno == EINTR); /* retry on interrupt */
- if (ldata < 0)
- goto serverr;
- if (ldata) { /* if ldata > 0, it's not the end yet */
- do {
- err = write(sockIn, data, ldata);
- } while (err == -1 && errno == EINTR);
- if (errno == EPIPE) { /* other end (client) closed the conection */
- #ifdef DEBUG
- printf("%d - client closed connection\n", sockIn);
- #endif
- goto end;
- }
- if (err == -1)
- goto serverr;
- }
- } while (ldata > 0); /* loops while more data available */
- end:
- close(sockIn); /* close the sockets */
- close(sockOut);
- pthread_setspecific(key_alarm, NULL);
- #ifdef DEBUG
- printf("%d --- request successful\n", sockIn);
- #endif
- return 0; /* no error */
- badreq:
- sayerror(BADREQ, sockIn, sockOut);
- return -1;
- serverr:
- sayerror(SERVERR, sockIn, sockOut);
- return -2;
- timeout:
- sayerror(SERVTIMEOUT, sockIn, sockOut);
- return -3;
- servcoerr:
- sayerror(SERVCOERR, sockIn, sockOut);
- return -4;
- servdnserr:
- sayerror(SERVDNSERR, sockIn, sockOut);
- return -5;
- posterr:
- sayerror(POSTERR, sockIn, sockOut);
- return -6;
- }
- void *client(struct th_proxy_struct *th_proxy)
- {
- struct timespec ts;
- struct timeval tv;
- int retval;
- struct th_proxy_struct **th;
- signal(SIGPIPE, SIG_IGN);
- for (;;) {
- pthread_mutex_lock(&th_proxy->mu);
- while (th_proxy->sock_in < 0) {
- #if 0
- pthread_cond_wait(&th_proxy->cond, &th_proxy->mu);
- #else
- gettimeofday(&tv, NULL);
- ts.tv_sec = tv.tv_sec + TIMEOUT_THREAD_EXIT;
- ts.tv_nsec = 0;
- retval = pthread_cond_timedwait(
- &th_proxy->cond, &th_proxy->mu, &ts);
- if (retval == ETIMEDOUT) {
- pthread_mutex_lock(&free_q_mu);
- th = &free_q;
- while (*th && *th != th_proxy)
- th = &((*th)->next_free);
- if (*th == th_proxy) {
- /*
- * remove yourself from queue
- * and exit
- */
- *th = th_proxy->next_free;
- thread_count--;
- pthread_mutex_unlock(&free_q_mu);
- free(th_proxy);
- pthread_exit(0);
- }
- pthread_mutex_unlock(&free_q_mu);
- }
- #endif
- }
- pthread_mutex_unlock(&th_proxy->mu);
- pthread_setspecific(key_alarm, (void *) 0);
- process_request(th_proxy->sock_in);
- pthread_mutex_lock(&th_proxy->mu);
- th_proxy->sock_in = -1;
- pthread_mutex_unlock(&th_proxy->mu);
- pthread_mutex_lock(&free_q_mu);
- th_proxy->next_free = free_q;
- free_q = th_proxy;
- pthread_mutex_unlock(&free_q_mu);
- pthread_cond_signal(&free_q_cond);
- }
- }
- /* displays the right syntax to call Webroute */
- void displaysyntax(void)
- {
- fprintf(stderr, "Syntax:\n");
- fprintf(stderr, "webroute [ -p port ] [ -x h:p ] [ -t timeout ] [ -m max_threads ] [ -n ]\n");
- fprintf(stderr, "Available options are:\n");
- fprintf(stderr, " -p allows you to run webroute on the port <port>.\n");
- fprintf(stderr, " If you don't have superuser privileges, you must use a port > 5000.\n");
- fprintf(stderr, " The default port is %d.\n", LISTENPORT);
- fprintf(stderr, " -x enables multi-proxy feature. This means that this instance of Webroute\n");
- fprintf(stderr, " doesn't have itself access to the internet, but the one which is running\n");
- fprintf(stderr, " on port <p> of host <h> can provide an access. It's possible to chain\n");
- fprintf(stderr, " as many instances of Webroute as you want. That depends of your network\n");
- fprintf(stderr, " topology\n");
- fprintf(stderr, " -t <timeout> specifies how many seconds the connection will stay connected (or trying to connect) when\n");
- fprintf(stderr, " no data arrives. After this time, the connection will be canceled.\n");
- fprintf(stderr, " -n prevents browsers from retrieving web pages from their own cache when the\n");
- fprintf(stderr, " user asks for a \"Reload\". The page will then always be reloaded.\n");
- fprintf(stderr, " -m max count of proxy threads allocated to serve the requests\n");
- }
复制代码 |
|