#include "stdio.h"
#include "stdlib.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "netinet/tcp.h"
#include "arpa/inet.h"
#include "string.h"
#include <errno.h>
#include "sys/time.h"
#include "sys/times.h"
#include <unistd.h>
#include "sys/types.h"
#include "sys/stropts.h"
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include "sockopt.h"
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
#define msglen 1500
pthread_mutex_t counter_lock;
pthread_cond_t counter_nonzero;
int serverfd,clientfd;
int bindlisten();
int clientconn();
void DLog();
closemap(int sockfd,fd_set fdset);
#define MAX_MSG_LEN (1024+1)
void *m_cbf(void *__args);
fd_set ReadData (int fd,fd_set fdset);
int a[65535]={0},b[65535]={0};
int temp;
#define K_MILLISECPERSEC 1000
#define MSECWAITTIME 10000
#define SETTIMEOUT(x) (x).tv_sec = (MSECWAITTIME/K_MILLISECPERSEC),(x).tv_usec=(MSECWAITTIME%K_MILLISECPERSEC)*K_MILLISECPERSEC
main () {
struct sockaddr_in tcpaddr;
int retVal,ret;
char line[msglen]={0};
int tcpaddr_len;
int lstnScktNum;
int count=0,errno;
int max_fd,client;
int fd;
char *str;
fd_set fdset;
pthread_t m_threadId;
signal (SIGPIPE,SIG_IGN);
serverfd=bindlisten();
if (serverfd==-1) {
printf("line62:bind & listen fail\n");
return -1 ;
}
FD_ZERO(&fdset);
FD_SET(serverfd, &fdset);
max_fd = serverfd;
//first select then accept
//socket and select are event trigger
while (1) {
fd_set oset;
//select timeout all fd reset to 0, because we need check fd ,so we need recover the save value
oset = fdset;
struct timeval timeout;
SETTIMEOUT(timeout);
//select set noblock ,is set for timeout
//select test two read fd,one is from user, one is from proxy
count=select(max_fd+1,&oset,NULL,NULL,&timeout);
if(count > 0){
for(fd = 0; fd <= max_fd; fd++){
if(FD_ISSET(fd, &oset)){
//only for listen fd
//This is a new connection.
tcpaddr_len = sizeof(tcpaddr);
//the accept tcpaddr is diffrent from bind. it get cient ip with &
//the bind tcpaddr is server address
client =accept(fd, (struct sockaddr *)(&tcpaddr), &tcpaddr_len);
str=inet_ntoa(tcpaddr.sin_addr);
if(client > 0){
printf("Accept a new client: %d\n", client);
#if 1
ret=setTcpScktOptions(client);
if (ret <0) {
printf("line88 ret=%d\n",ret);
return -1;
}
#endif
retVal=pthread_create(&m_threadId,NULL,m_cbf,(void *)client);
if (retVal!=0) {
printf ("create thread fail:errno=%d\n",errno);
//only one thread don;t should
//affect other thread run well
continue;
}
}else{
//debug scoket error
perror("accept()");
}
}
}
} else if (count ==0) {
continue;
}else {
perror("line192\n");
printf("error:fd=%d\n",fd);
break;
}
}
for (fd=0;fd<=max_fd;fd++) {
if(FD_ISSET(fd, &fdset)){
close (fd);
}
}
}
int bindlisten() {
struct sockaddr_in tcpaddr;
struct in_addr intfIpAddr;
int tcpaddr_len;
int sockfd;
int client;
int port=9200;
int bReuseaddr=1;
int retVal;
int ret;
int buf,optlen;
int on,errno;
memset( &tcpaddr, 0, sizeof(tcpaddr) );
if ( (sockfd= socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf ("socket create fail\n");
return -1;
}
// intitalize to hold given restrictions
tcpaddr.sin_family = AF_INET;
tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);
tcpaddr.sin_port = htons(port);
tcpaddr_len = sizeof(tcpaddr);
on=1;
errno=0;
#if 0
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(char *)(&on),sizeof(on))<0)
{
printf("so_resueadd failed,error %d:%s\n",errno,strerror(errno));
return -2;
}
#endif
ret=setTcpScktOptions(sockfd);
if (ret <0)
printf("line253 setsockopt fail:ret=%d\n",ret);
// make bind call
if ((retVal = bind(sockfd, (struct sockaddr *)(&tcpaddr), sizeof(tcpaddr)))< 0 )
{
printf("bind() call failed. Error: %d, %s,port: %d\n ", errno, ( strerror(errno) ), port);
}
//listen have 5 queue
if (listen(sockfd, 5) < 0 )
{
printf("Error: Listen socket returned %d %s\n", errno, strerror(errno) );
return -1;
}
return sockfd;
}
int clientconn() {
struct sockaddr_in tcpaddr;
char ipHost[10]={0};
int ipPort=8000;
int ret;
int sockfd;
int bReuseaddr=1;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("socket create fail\n");
return -1;
}
/* Connect to the socket */
memset(&tcpaddr, 0, sizeof(tcpaddr));
//135.245.1.1 is default proxy ip
strcpy(ipHost, "135.245.1.1");
/* local host, processes must be running on the same machine ... */
/* intitalize to given address */
tcpaddr.sin_family = AF_INET;
tcpaddr.sin_addr.s_addr = inet_addr((const char *)ipHost);
tcpaddr.sin_port = htons(ipPort);
#if 1
ret=setTcpScktOptions(sockfd);
if (ret<0) {
printf("line257:ret=%d\n",ret);
return -1;
}
#endif
//basic connect is block, after timeout it return fail
if ((ret = connect(sockfd,(struct sockaddr *)(&tcpaddr),sizeof(tcpaddr))) < 0 ) {
printf("connect fail,retVal=%d,%s\n",errno,strerror(errno));
return 1;
}
return sockfd;
}
void closemap (int fd, fd_set fdset) {
pthread_mutex_lock(&counter_lock);
//The socket is wrong or closed.
close(fd);
FD_CLR(fd, &fdset);
printf("close %d\n",fd);
//remove the socketfd
//don;t judge from user or proxy ,set all kind to 0
//one sockfd close ,peer sockfd close
if (a[fd]!=0) {
temp=a[fd];
close (a[fd]);
printf("client close %d\n",a[fd]);
FD_CLR(a[fd], &fdset);
a[fd]=0;
b[temp]=0;
} else if (b[fd]!=0) {
temp=b[fd];
close(b[fd]);
printf("server close %d\n",b[fd]);
FD_CLR(b[fd], &fdset);
b[fd]=0;
a[temp]=0;
}
pthread_mutex_unlock(&counter_lock);
pthread_exit(NULL);
}
void *m_cbf(void *__args)
{
int connfd,max_fd=0;
int count;
fd_set pset;
char line[msglen];
int retVal,ret;
int clientfd;
int fd;
connfd=(int)__args;
FD_ZERO(&pset);
//put connfd and create connect to proxy and make map
FD_SET(connfd, &pset);
if(connfd> max_fd)
max_fd = connfd;
clientfd=clientconn();
if (clientfd==-1) {
printf("line398:clientfd fail\n");
return 0;
}
printf("create a new connect to proxy: %d\n", clientfd);
ret=setTcpScktOptions(clientfd);
if(ret<0) {
printf("line405:ret=%d\n",ret);
}
//put connect to proxy fd into fd_set
FD_SET(clientfd, &pset);
if(clientfd > max_fd)
max_fd = clientfd;
//map user and proxy socket
//a keep proxy,b keep user
pthread_mutex_lock(&counter_lock);
a[connfd]=clientfd;
b[clientfd]=connfd;
pthread_mutex_unlock(&counter_lock);
while (1) {
fd_set oset;
//select timeout all fd reset to 0, because we need check fd ,so we need recover the save value
//pset bit set 1
oset = pset;
struct timeval timeout;
SETTIMEOUT(timeout);
switch ((count=select(max_fd+1,&oset,NULL,NULL,&timeout)))
{
case 0://timeout
continue;
case -1://error
if (errno ==EINTR)
{
count=0;
break;
}
printf("ERROR:%d,%s\n",errno,strerror(errno));
break;
default://data found
break;
}
if (count <0)
continue;
//becasue the fd all read,not one accept ,the other read.we don;t need judge.
//it may come from proxy or user,we need tranverse
for(fd = 0; fd <= max_fd; fd++){
if(FD_ISSET(fd, &oset)) {
pset=ReadData(fd,pset);
break;
}
}
}
}
fd_set ReadData (int fd,fd_set oset) {
char line[msglen];
int ret ,retVal;
int fdmap;
memset(line,0x00,msglen);
//msglen is what i read, retVal is the real i read success ,they are not the same
retVal = read(fd, line, msglen);
if(retVal <= 0){
//EINTR means don;t red out data,but don;t close the fd
if (errno==EINTR)
return ;
else
closemap(fd,oset);
} else{
if (a[fd]!=0) {
fdmap=a[fd];
// if is in a, it come from proxy,so write to user
//forward message to ;ucent
printf("Write 1:from %d to %d\n",fd, fdmap);
ret=write(fdmap,line,retVal);
if (ret <=0) {
if (errno==EINTR)
return;
else {
perror("write() 1");
closemap(fdmap,oset);
}
} else {
printf("write to proxy\n");
}
} else if (b[fd]!=0) {
fdmap=b[fd];
//is in b, it come from user
//forward message to user
printf("Write 2 from %d to %d\n",fd, fdmap);
ret=write(fdmap,line,retVal);
if (ret <0) {
if (errno==EINTR)
return;
else {
printf("write to user error:%d:%s\n",errno,strerror(errno));
perror("write() 2");
closemap(fdmap,oset);
}
} else {
printf("write to user\n");
}
}
}
return oset;
}