void Rio_writen(int fd, void *usrbuf, size_t n) { if (rio_writen(fd, usrbuf, n) != n) unix_error("Rio_writen error"); }
/* Analyze the request from browser and decide whether retrieve from * cache or connect to the server*/ void* request (void* data){ pthread_detach(pthread_self()); Signal(SIGPIPE,SIG_IGN); signal(SIGPIPE,SIG_IGN); int serverfd=*(int*)data; int clientfd; char headerBuff[MAXHEADERSIZE],Buffer[MAXBUFFERSIZE]; char hostname[300],uriname[MAXHEADERSIZE],urlname[MAXHEADERSIZE]; char* cache_buff; int getbyte,error; int cachehit = 0; int cache_size = 0; free(data); rio_t serverrio_t; rio_readinitb(&serverrio_t,serverfd); rio_readlineb(&serverrio_t,headerBuff,sizeof(headerBuff)); if (takeHostUriUrl(headerBuff,hostname,uriname,urlname) ==0){ perror("Get Host Uri Url error\n"); close(serverfd); pthread_exit(NULL); } /* Try to get cached data, must check no thread writing the cache, * * and use FILO architecture to lock when there threads reading cache*/ P(&mutex); readcnt++; if(readcnt == 1) P(&w); V(&mutex); if( Get_cachedata(urlname,serverfd) > 0){ cachehit = 1; } P(&mutex); readcnt--; if(readcnt == 0) V(&w); V(&mutex); if(cachehit){ printf("Cache Hit!!!!\n"); close(serverfd); pthread_exit(NULL); } if( (clientfd=socket(AF_INET,SOCK_STREAM,0))<0){ perror("socket"); close(serverfd); pthread_exit(NULL); } /*get server's address info*/ struct addrinfo *hostinfo; if( (error=getaddrinfo(hostname,"http",NULL,&hostinfo)) >0){ perror("hostinfo"); close(serverfd); close(clientfd); pthread_exit(NULL); } /* connect to the server*/ if( (connect(clientfd,hostinfo->ai_addr,hostinfo->ai_addrlen))<0){ perror("connect"); close(serverfd); close(clientfd); return NULL; } cache_buff = (char*) malloc(MAX_OBJECT_SIZE*sizeof(char)); cache_size = 0; /* Send the request to the server */ SendRequest(clientfd,serverrio_t,hostname,uriname); /*read the information from web server and send it to browser*/ while(1){ getbyte = rio_readn(clientfd,Buffer,sizeof(Buffer)); if(getbyte <= 0 ) break; if(cache_size + getbyte < MAX_OBJECT_SIZE){ memcpy(cache_buff + cache_size,Buffer,getbyte); } cache_size += getbyte; rio_writen(serverfd,Buffer,getbyte); } /* if size fit in cache, write into cache, else free the content*/ if(cache_size < MAX_OBJECT_SIZE){ char* new_cache_buff = realloc(cache_buff,cache_size); free(cache_buff); if(new_cache_buff == NULL){ perror("Realloc fail\n"); close(clientfd); close(serverfd); pthread_exit(NULL); } P(&w); char *saveurlname = (char*)malloc(strlen(urlname)*sizeof(char)); memcpy(saveurlname,urlname,strlen(urlname)); Create_cache(saveurlname,new_cache_buff,cache_size); V(&w); } else{ free(cache_buff); } close(clientfd); close(serverfd); pthread_exit(NULL); }
int main(int argc, char *argv[]){ int target_port,local_port; char *target_ip,*local_ip; if(argc !=5){ printf("please enter arguments in format:./name target_ip,target_port,local_ip,local_port\n"); } target_ip = argv[1]; // reserver ip information for future extension target_port = atoi(argv[2]); local_ip =argv[3]; local_port = atoi(argv[4]); // printf("the target ip is :%s\nthe target port is:%d\n",target_ip,target_port); //start listening int args[2]; args[0] = local_port; args[1] = target_port; pthread_t hear; Pthread_create(&hear,NULL,start_listen,(void*)args); Pthread_detach(hear); //create connectionfd with server int targetfd; targetfd = open_clientfd(target_ip,target_port); if(targetfd < 0){ printf("targetfd error!\n"); return EXIT_FAILURE; } char *cmd, *signature; //hand shake start //_____________send client hello infromation to server with protocol infromation_______________ char content[MAXLINE]; sprintf(content, "ClientHello,sslv2.0"); rio_writen(targetfd,content,strlen(content)); //receive response from server, confirm protocol int len; char answer[MAXLINE]; len = rio_readp(targetfd,answer,MAXLINE); printf("content received from server is: %s\n",answer); if(strstr(answer,"ServerHello")!=NULL){ printf("hello ends\n"); } //______________________DH exchange___________________________ int dh_g = 3; int dh_b = 7; int dh_a = 0; int *g_ptr = &dh_g; int *a_ptr = &dh_a; int *b_ptr = &dh_b; DH_change_client (targetfd, g_ptr, a_ptr,b_ptr); printf("After DH function: g is %d,a is %d,b is %d\n", dh_g, dh_a, dh_b); //receive ditial singature from server and authenticate len = rio_readp(targetfd,answer,MAXLINE); for(int i = 0;i<strlen(answer)-1;i++){ answer[i] = answer[i]+dh_a; } cmd = strtok_r(answer,",",&signature); printf("signature is %s\n",signature); if(strcmp(signature,target_ip) == 0){ printf("digital signature verified\n"); } //create private key-public key pair and send public key to server uisng DH method int p = 11; int q = 19; int public_n; int public_e; int private_n; int private_d; int *public_n_ptr = &public_n; int *private_n_ptr = &private_n; int *public_e_ptr = &public_e; int *private_d_ptr = &private_d; RSA_generate(p,q,public_n_ptr,private_n_ptr,public_e_ptr,private_d_ptr); printf("public <n,e> = <%d,%d>\n", public_n, public_e); printf("private <n,d> = <%d,%d>\n", private_n, private_d); memset(content,0,sizeof(content)); sprintf(content,"ClientKeyExchange,RSA %d %d,TLSv1",p,q); for (int i = 0; i<strlen(content);i++){ content[i] = content[i]+dh_a; } rio_writen(targetfd,content,strlen(content)); //__________________first talk______________________ //receive infromation from server and decryption by RSA method memset(answer, 0, sizeof(answer)); len = rio_readp(targetfd,answer,MAXLINE); char count_buffer[MAXLINE]; memset(count_buffer, 0, sizeof(count_buffer)); len = rio_readp(targetfd, count_buffer, MAXLINE); int word_count = atoi(count_buffer); printf("word count is: %d\n", word_count); char *decrypt = NULL; long long *ip2 = (long long *)answer; decrypt = decryption(ip2, word_count, private_n); printf("After decryption:%s\n", decrypt); //______________second talk_______________________ memset(content,0,sizeof(content)); sprintf(content,"ClientFinish"); //encryption int ans_len = strlen(content); long long *ip = NULL; word_count = 0; int *word_count_ptr = &word_count; ip = encryption(content,ans_len, word_count_ptr, public_e, public_n); printf("Before encryption: %s\n", content); printf("After encryption,send:"); char *ch = (char*)ip; printf("%s\n", ch); //send content rio_writen(targetfd,ch,sizeof(ch)*word_count); //send word count memset(content, 0, sizeof(content)); sprintf(content, "%d", word_count); printf("word count: %s\n", content); rio_writen(targetfd, content, sizeof(content)); memset(content, 0, sizeof(content)); printf("===============hand shake ends==================\n"); printf("please input your message now\n\n"); //start talking while (1){ //send information to server printf("Client:"); memset(content, 0, sizeof(content)); scanf("%s", content); ans_len = strlen(content); ip = NULL; word_count = 0; word_count_ptr = &word_count; ip = encryption(content, ans_len, word_count_ptr, public_e, public_n);; char *ch = (char*)ip; //send content rio_writen(targetfd, ch, sizeof(ch)*word_count); //send word count memset(content, 0, sizeof(content)); sprintf(content, "%d", word_count); rio_writen(targetfd, content, sizeof(content)); memset(content, 0, sizeof(content)); //receive information from server printf("Server:"); memset(answer, 0, sizeof(answer)); len = rio_readp(targetfd, answer, MAXLINE); if (strcmp(answer, "You end the talk. Sever disconnect.") == 0){ printf("%s\n", answer); break; } memset(count_buffer, 0, sizeof(count_buffer)); len = rio_readp(targetfd, count_buffer, MAXLINE); word_count = atoi(count_buffer); decrypt = NULL; ip2 = (long long *)answer; decrypt = decryption(ip2, word_count, private_n); printf("%s\n", decrypt); } close (targetfd); return EXIT_SUCCESS; }
/* * forward_response - send request to server, then store resposne content * in cache if necessary */ int forward_response(int client_fd, int server_fd, Response *response) { #ifdef DEBUG printf("enter forward_response\n"); #endif size_t n; int length = -1; int read_size; rio_t server_rio; char header_buffer[MAXLINE]; char temp_buffer[MAX_OBJECT_SIZE]; char buffer[10 * MAX_OBJECT_SIZE]; char content_buffer[10 * MAX_OBJECT_SIZE]; rio_readinitb(&server_rio, server_fd); int buffer_pos = 0; while ((n = rio_readlineb(&server_rio, header_buffer, MAXLINE)) != 0) { memcpy(response->header + buffer_pos, header_buffer, sizeof(char) * n); buffer_pos += n; /*specify content-length info if header has this info */ if (strstr(header_buffer, "Content-Length: ")) { sscanf(header_buffer + 16, "%d", &length); } if (!strcmp(header_buffer, "\r\n")) { break; } } if (length == -1) read_size = MAX_OBJECT_SIZE; else read_size = min(length, MAX_OBJECT_SIZE); #ifdef DEBUG printf("finish response header\n"); #endif int sum = 0; while ((n = rio_readnb(&server_rio, temp_buffer, read_size)) != 0) { memcpy(content_buffer + sum, temp_buffer, sizeof(char) * n); sum += n; } memcpy(buffer, response->header, sizeof(char) * buffer_pos); memcpy(buffer + buffer_pos, content_buffer, sizeof(char) * sum); if (rio_writen(client_fd, buffer, buffer_pos + sum) < 0) { sleep(1); if (rio_writen(client_fd, buffer, buffer_pos + sum) < 0) { sleep(2); if (rio_writen(client_fd, buffer, buffer_pos + sum) < 0) proxy_error("rio_writen in forward_response" " header content error"); return -1; } } #ifdef DEBUG printf("read byte size:%u\n", sum); #endif if (sum <= MAX_OBJECT_SIZE) { response->content = Malloc(sizeof(char) * sum); memcpy(response->content, content_buffer, sum * sizeof(char)); response->content_size = sum; } else { response->content_size = sum; } #ifdef DEBUG printf("leave forward_response\n"); #endif return 1; }
void Rio_writen_s(int fd, void *usrbuf, size_t n){ if (rio_writen(fd, usrbuf, n) != n) printf("Rio_writen error\n"); }
void *thread(void *p) { //可以自动释放线程 Pthread_detach(pthread_self()); int connfd=((struct args*)p)->connfd,turn=((struct args*)p)->turn; free(p); char buf[MAXLINE]; char method[MAXLINE],version[MAXLINE],url[MAXLINE]; char host[MAXLINE],query[MAXLINE]; char url_tmp[300],*data_tmp; rio_t rio; int index,port,content_length; int serverfd; rio_readinitb(&rio,connfd); rio_readlineb(&rio,buf,MAXLINE); sscanf(buf,"%s %s %s",method,url,version); if(strcasecmp(method,"GET")) { printf("Not GET\r\n"); Close(connfd); return NULL; } //忽视客户端的请求 do { rio_readlineb(&rio,buf,MAXLINE-1); }while(strcmp(buf,"\r\n")); /* find cache block */ for(index=0;index<10;index++) { cache_read_url(index,url_tmp); /* the block'url is same as current url */ if(!strcmp(url,url_tmp)) break; } data_tmp=(char*)Malloc(MAX_OBJECT_SIZE); data_tmp[0]='\0'; if(index <10) { /* if have cached */ cache_read_data(index,data_tmp,turn); rio_writen(connfd,data_tmp,strlen(data_tmp)); Close(connfd); free(data_tmp); return NULL; } /* connect to server */ parse_url(url,host,query,&port); if((serverfd=connect_server(host,port,query))<0) { /* connect to server failed, return */ free(data_tmp); Close(connfd); return NULL; } rio_readinitb(&rio,serverfd); content_length=0; /* read response head line */ do { int t=rio_readlineb(&rio,buf,MAXLINE-1); if(t<=0) break; strncat(data_tmp,buf,t); if(strstr(buf,"Content-length")!=NULL) sscanf(buf,"Content-length: %d\r\n",&content_length); rio_writen(connfd,buf,t); }while(strcmp(buf,"\r\n")); /* read response body */ /* response is small enough to cache */ if(content_length+strlen(data_tmp)<MAX_OBJECT_SIZE) { while(content_length>0) { int t= rio_readnb(&rio,buf,(content_length<MAXLINE-1)?content_length:MAXLINE-1); if(t<=0) continue; content_length-=t; strncat(data_tmp,buf,t); rio_writen(connfd,buf,t); } index=0; int i; /* least-recently-used */ for(i=1;i<10;i++) { if(cache_read_turn(i)<cache_read_turn(index)) { index=i; } } /* cache write */ cache_write(index,url,data_tmp,turn); } /* ignore store and write to client */ else { while(content_length>0) { int t= rio_readnb(&rio,buf,(content_length<MAXLINE-1)?content_length:MAXLINE-1); if(t<=0) break; content_length-=t; rio_writen(connfd,buf,t); } } Close(connfd); Close(serverfd); free(data_tmp); return NULL; }
/* * handle_request - handle one HTTP request from client and * make request for actual server. It will wait for response * and forward response back to client. */ void handle_request(int clientfd) { char buf[MAXLINE], method[MAXLINE], url[MAXLINE]; char hostname[MAXLINE], uri[MAXLINE], version[MAXLINE]; rio_t rio; char port[] = "80"; /* http request use port 80 */ /* Read request line and headers */ Rio_readinitb(&rio, clientfd); Rio_readlineb(&rio, buf, MAXLINE); sscanf(buf, "%s %s %s", method, url, version); if (strcasecmp(method, "GET")) { clienterror(clientfd, method, "501", "Not Implemented", "Proxy does not implement this method"); return; } parse_url(url, hostname, uri); /* connect to host server by hostname */ int serverfd; if ((serverfd = open_clientfd(hostname, port)) < 0) { pthread_mutex_lock(&print_lock); printf("Open_clientfd error\n"); pthread_mutex_unlock(&print_lock); return; } /* construct a new request line */ char requestLine[MAXLINE]; strcpy(requestLine, method); strcat(requestLine, uri); strcat(requestLine, "HTTP/1.0"); rio_readinitb(&rio, serverfd); rio_writen(serverfd, buf, strlen(buf)); /* send request line to server */ /* read and send request header to server */ char requesthrds[MAXLINE]; cat_requesthdrs(requesthrds, hostname); rio_writen(serverfd, requesthrds, strlen(requesthrds)); //rio_readlineb(&rio, buf, MAXLINE); //rio_writen(serverfd, buf, strlen(buf)); //while(strcmp(buf, "\r\n")) //{ // rio_readlineb(&rio, buf, MAXLINE); // rio_writen(serverfd, buf, strlen(buf)); //} char emptyline[] = "\r\n"; rio_writen(serverfd, emptyline, strlen(emptyline)); /* get response from server and send it back to client */ rio_writen(clientfd, emptyline, strlen(emptyline)); read_requesthdrs(&rio); size_t n; while ((n = rio_readlineb(&rio, buf, MAXLINE)) != 0) rio_writen(clientfd, buf, strlen(buf)); /* close connection to server */ int rc; if ((rc = close(serverfd)) < 0) { pthread_mutex_lock(&print_lock); printf("Close error\n"); pthread_mutex_unlock(&print_lock); } pthread_mutex_lock(&print_lock); printf("Connection to server closed.\n"); pthread_mutex_unlock(&print_lock); }
void send_msg_back(int connfd,char* msg){ //DEBUG printf(" # MSG BACK TO %d:\n\t%s\n", connfd,msg); rio_writen(connfd,msg,strlen(msg)); }
/* $begin doit */ void doit(int fd_client) { rio_t rio_client; rio_t rio_server; int fd_server=0; int is_cached=0; char buf[MAXLINE],method[MAXLINE],uri[MAXLINE],version[MAXLINE]; char pathname[MAXLINE],hostname[MAXLINE],hdr_server[MAXLINE]; char *port=(char*)malloc(sizeof(port)); strcpy(port,PORT_DEFAULT); rio_readinitb(&rio_client,fd_client); rio_readlineb(&rio_client,buf,MAXLINE); sscanf(buf,"%s %s %s",method,uri,version); if (strcasecmp(method, "GET")) { clienterror(fd_client, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } is_cached = in_cache(mycache, uri); if (is_cached) { printf("Cache hit\n"); doit_cached(mycache, uri, fd_client); } else { printf("Cache miss\n"); parse_uri(uri,pathname,hostname,port); fd_server=Open_clientfd(hostname,port); hdr_concat(&rio_client,hdr_server,hostname,pathname); // printf("%s",hdr_server); rio_writen(fd_server, hdr_server, strlen(hdr_server)); rio_readinitb(&rio_server,fd_server); char buf_server[MAXLINE],file_buf[MAX_OBJECT_SIZE]; int n=0; int size=0; memset(buf_server, 0, MAXLINE); while((n=rio_readlineb(&rio_server,buf_server,MAXLINE))!=0){ if (size+n <= MAX_OBJECT_SIZE) { memcpy(file_buf+size, buf_server, n); size += n; } rio_writen(fd_client, buf_server, n); memset(buf_server, 0, n); } if (size <= MAX_OBJECT_SIZE) { insert(mycache, uri, file_buf, size); } close(fd_server); free(port); } }
/* $begin doit_cached */ void doit_cached (Cache *proxy, char *uri, int fd_client) { Block *found_block =search(proxy, uri); if (rio_writen(fd_client, found_block->data, found_block->size) < 0) { printf("Error writing from cache to client\n"); } }
void* HttpRequest::RequestParse(void*arg) { int n; int again_flag = true; //again flag decide to close the fd or try again while(true) { errno = 0; //this is important memset(usr_buf,0,RIO_BUFSIZE); //reset the buf n = rio_readn(fd,(void*)usr_buf,RIO_BUFSIZE-1); if(n==-1) { debug("error."); again_flag = false; break; } else if(n==0) { if(errno==EAGAIN) { //debug("again read"); again_flag = true; } else //EOF { //debug("EOF read close fd"); again_flag = false; } //debug("there is not any more data,errno is: %d",errno); break; } read_data = usr_buf; /* cout<<"read data:--------------------------------------------"<<endl; cout<<read_data<<endl; cout<<"-------------------------------------------------------"<<endl; */ //debug_cpp(read_data.size()); CommandParse(); //requese line parse HeaderParse(); //head parse //int data_n = read_data.size(); if(read_data.size()!=0) { BodyParse(); //body parse } /*parse complete,do method,url ,version check*/ HttpError e; int check_res = e.RequireCheck(command,head,out,file_stat); if(check_res!=D_OK) { //debug("require error: %d",check_res); //then send the wrong information page command.uri = "/40x.html"; // reset the file_stat; string file_name = file_root+command.uri; stat(file_name.c_str(),&file_stat); out.SetStaticServer(true); } /**********check over,send the result to the client********/ if(out.GetStaticServer()) { //set the length out.SetFileSize(file_stat.st_size); auto out_line = out.SetOutLine_C(); out_line += out.SetOutHeaders_C(head); char* res_line_buf = const_cast<char*>(out_line.c_str()); n = rio_writen(fd,(void*)res_line_buf,strlen(res_line_buf)); //write command line //debug("send Response line and Out Header."); StaticServer(); //debug("----------static server over-----------"); } else //dynamic server { //debug("----------dynamic server on-------------"); DynamicServer(); //debug("----------dynamic server over-----------"); } //server -------**over**---------- if(head.head.find("Connection")==head.head.end()) //keep alive { again_flag = false; //debug("-----------no keep alive,will break---------"); break; } else { again_flag = true; } } if(!again_flag) { //debug("close fd ,%d",fd); close(fd); //close fd ,there is no other request } else { head.head.clear(); //clear the request head read_data=""; again_flag = true; out.clear(); //clear the output data InitHttpRequest(ep,fd,epfd); //no need to initialize.because the ep,fd,and the epfd etc do not change ep->SetEpollEvent((void*)this,D_EPOLLIN|D_EPOLLET|D_EPOLLONESHOT); //set event ep->EpollCTL(D_EPOLL_CTL_MOD,fd); //add fd to the event module } return NULL; }