2012-03-04 72 views
0

我試圖將一個順序代理轉換爲一個併發的代理,其中多個線程可以處理來自諸如Firefox等Web瀏覽器的多個請求。現在我被困在試圖使用信號量來使我的代理線程安全。通過用gethostbyname_r替換它,我已經處理了gethostby名稱不是線程安全的情況。這個問題可能出現在我的mallocing中,因爲我對這個概念還不熟悉。當我編譯時,我得到一個無效的點或一個男人。我不知道如果我甚至不需要malloc的,我做到了已經在PARSE URI部分線程與malloc在代理中干涉?

#include "csapp.h" 
#include <pthread.h> 
#include <semaphore.h> 

/* Globals */ 
FILE *log_file; /* Log file with one line per HTTP request */ 
sem_t mutex,maa, muu, mqq,mpp, mkk,mll; 

typedef struct { 
int clientfdpNum; 
struct sockaddr_in *sockaddrT; 
} thread_args; 
/* processRequest */ 
void processRequest(int proxyfd, struct sockaddr_in *sockaddr) { 
P(&maa); 
char fline[MAXLINE]; 
char rest[MAXLINE]; 
char method[MAXLINE], version[MAXLINE], uri[MAXLINE]; 
//P(&muu); 
readLine(proxyfd, fline, MAXLINE); //reads firstline 
read(proxyfd,rest, sizeof(rest)); //reads rest of request 

//Read request line and headers 
sscanf(fline, "%s %s %s", method, uri, version); 
//V(&muu); 
//printf("\n%s\n",method); 
//printf("URI %s\n",uri); 
// printf("%s\n",version); 
if (strcasecmp(method, "GET")) { 
clienterror(proxyfd, method, "501", "Not Implemented", 
      "Proxy does not implement this method"); 
return; 
} 

//********************************Parse URI***********************************// 

char *ip; 
ip = (char*) Malloc(MAXLINE); 
int newPort =80; 
char *page; 
page = (char*) Malloc(MAXLINE); 
char* slash; 
slash = (char*) Malloc(MAXLINE); 


sscanf(uri, "http://%99s[^:]:%99d/%99s[^\n]", ip, &newPort, page); 
//printf("IP: %s\n",ip); 
//printf("port: %d\n", newPort); 
printf("page: %s\n", page); 
page = strchr(ip,'/'); 
strcpy(slash,page); 

char* colon = strchr(ip,':'); //find where colon is if port specified 
if(colon != NULL){ //colon with new port is in ip 
    colon++; //skip over colon 
    newPort = atoi(colon); //convert to integer 
    //printf("colon part: %s \n",colon); 
    colon--; 
    *colon = '\0'; //terminate it earlier 
} else{ 
int size = strlen(ip); 
int size2 = strlen(page); 
ip[size-size2]='\0'; 
} 
V(&maa); 
P(&mqq); 
printf("\nnew IP: %s\n",ip); 
printf("new port: %d\n", newPort); 
printf("new page: %s\n", slash); 



//*****************************Proxy acting as client***************************// 
int clientfd; 
struct hostent *hp; 
struct sockaddr_in clientaddr; 

if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    return; 
/* 
// Fill in the server's IP address and port 
if ((hp = gethostbyname(ip)) == NULL){ 
    printf("Gethostbyname Problem\n"); 
    return; 
} 
*/ 


struct hostent hostbuf; 
size_t buflen; 
char *bufh; 
int res; 
int herr; 
buflen = 1024; 
/* Allocate buffer, remember to free it to avoid memory leakage. */ 
bufh = malloc (buflen); 
while((res = gethostbyname_r(ip, &hostbuf, bufh, buflen, &hp, &herr)) == ERANGE){ 
/* Enlarge the buffer. */ 
buflen *= 2; 
bufh = realloc(bufh, buflen); 
if(bufh == NULL) 
    perror("realloc"); 
} 
/* Check for errors. */ 
if (res != 0 || hp == NULL){ 
    printf("threadsafe null\n"); 
    return; 
} 
free(bufh); 



bzero((char *) &clientaddr, sizeof(clientaddr)); 
clientaddr.sin_family = AF_INET; 
bcopy((char *)hp->h_addr_list[0], 
(char *)&clientaddr.sin_addr.s_addr, hp->h_length); 
clientaddr.sin_port = htons(newPort); 

// Establish a connection with the server 
if (connect(clientfd, (SA *) &clientaddr, sizeof(clientaddr)) < 0) 
return; 
V(&mqq); 
P(&mpp); 
//*********************PRoxy acting as server back to browser****************// 
char theRequest[MAXLINE] = {0}; 
sprintf(theRequest, "%s %s %s\r\n%s",method, slash, version, rest); 
rio_writen(clientfd,theRequest,strlen(theRequest)); 

char buf[MAXLINE]={0}; 
int st,b; 
int responseSize = 0; 

do{ 
st = read(clientfd, buf, sizeof(buf)); 
    //printf("%s", buf); 
b = writenq(proxyfd, buf, st); 
responseSize += b; 
}while(st > 0); 

//while((r = recv(clientfd, buf, 1, 0))>0){ 
////rio_writen(proxyfd, webPAGE_buf, strlen(webPAGE_buf)); 
//printf("%s", buf); 
//st = send(proxyfd, buf, strlen(buf), 0); 
//} 
close(clientfd); 

//printf("Write Log\n"); 
//******************************WRITE LOG ***********************************// 
char logstring[256]; 
//formats data aquired. 
format_log_entry(logstring, sockaddr, ip, responseSize); 
//writes to log 
V(&mpp); 

P(&mutex); //Lock 

fputs(logstring, log_file); 
fflush(log_file); 
free(ip); 
free(slash); 
free(page); 

close(proxyfd); 

V(&mutex); //Unlock 
} 

/* Thread routine */ 
void *thread(void *vargp){ 
    P(&mkk); 
Pthread_detach(pthread_self()); 
thread_args *my_args = (thread_args *)vargp; 
int clientfdp = my_args->clientfdpNum; 
struct sockaddr_in *sockaddr = my_args->sockaddrT; 

free(vargp); 
V(&mkk); 
//printf("process request in thread %d\n", clientfdp); 
processRequest(clientfdp, sockaddr); 

return NULL; 
} 

/* main - Main routine for the proxy program* 
int main(int argc, char **argv) 
{ 
int sockfd, clientfdp, port; 
struct sockaddr_in Clientaddr; 
socklen_t clientlen = sizeof(Clientaddr); 
pthread_t tid; 
sem_init(&mutex, 0, 1); 
sem_init(&muu, 0, 1); 
sem_init(&maa, 0, 1); 
sem_init(&mqq, 0, 1); 
sem_init(&mpp, 0, 1); 
sem_init(&mkk, 0, 1); 
sem_init(&mll, 0, 1); 

/* Check arguments */ 
if (argc != 2) { 
    fprintf(stderr, "Usage: %s <port number>\n", argv[0]); 
    exit(0); 
} 
signal(SIGPIPE, SIG_IGN); 
//convert second Argument to integer 
port = atoi(argv[1]); 

//open log file 
log_file = Fopen("Proxy.log","a"); 
if(log_file == NULL){ 
puts ("Cannot open Log file\n"); 
exit(1); 
} 

sockfd = open_listenfd(port); 
//takes care of Socket, Bind, and Listen 

while(1){ 
if((clientfdp = Accept(sockfd, (SA *)&Clientaddr, &clientlen)) < 0) 
    err_exit(); 

thread_args *arguments = malloc(sizeof(thread_args)); 
arguments->clientfdpNum = clientfdp; 
arguments->sockaddrT = &Clientaddr; 
Pthread_create(&tid, NULL, thread, arguments); 

//processRequest(clientfd, &Clientaddr); >> in thread 
//close client fill descriptor 
//close(clientfd); >>in thread 
} 
exit(0); 
} 


void format_log_entry(char *logstring, struct sockaddr_in *sockaddr, char *uri, int size) { 
time_t now; 
char time_str[MAXLINE]; 
unsigned long host; 
unsigned char a, b, c, d; 

/* Get a formatted time string */ 
now = time(NULL); 
strftime(time_str, MAXLINE, "%a %d %b %Y %H:%M:%S %Z", localtime(&now)); 
host = ntohl(sockaddr->sin_addr.s_addr); 
a = host >> 24; 
b = (host >> 16) & 0xff; 
c = (host >> 8) & 0xff; 
d = host & 0xff; 
/* Return the formatted log entry string */ 
sprintf(logstring, "%s: %d.%d.%d.%d %s %d\n", time_str, a, b, c, d, uri, size); 
} 

char* readLine(int clientfd, char* line, int maxlen) { 
// read one character at a time until we encounter \n 
char c='a'; 
char* lineptr=line; 
int nread=0;  
do { 
if(read(clientfd, &c, sizeof(c)) < 0) { 
    if(errno==EINTR) 
continue; 
    err_exit(); 
} 
nread++; 
*lineptr++=c;  
} while(c != '\n' && nread<maxlen-1); 

if(c=='\n') 
    *(lineptr-1)=0; // overwrite \n if present 
else 
    *lineptr=0; // do not overwrite if different character 
return line; 
} 

/* writenq - writes and also handles SIGIN the signal interupt. */ 
size_t writenq(int fd, void *vptr, size_t n){ 
size_t nleft; 
size_t nwrite; 
char *ptr; 
ptr = vptr; 
nleft = n; 

while(nleft >0){ 
if((nwrite= write(fd, ptr, n)) <0){ 
    if(errno == EINTR) 
nwrite=0; 
    else 
return -1; 
} 
else if(nwrite ==0) 
    break; 

nleft -=nwrite; 
ptr += nwrite; 
} 
return (n-nleft); 
} 

回答

0

不要使用線程的變量,使用異步IO來避免這些問題。

+0

我需要做2個實施。一個使用線程,另一個分叉多個進程 – Krzysztof 2012-03-05 19:54:46

+0

我明白這可能是一個更好的解決方案。顯示的代碼是我的線程實現 – Krzysztof 2012-03-05 20:04:40