/* * handle accept event */ int accept_handle( conn_t *pconn ) { int fd; struct sockaddr_in addr; socklen_t addrlen; conn_t *client_conn; bzero( &addr, sizeof(struct sockaddr_in) ); addrlen = sizeof(struct sockaddr_in); fd = accept( pconn->fd, (struct sockaddr*)&addr, &addrlen ); epoll_mod_connection( pconn, EPOLLIN ); //重新把监听套接子添加到epoll中 if ( fd < 0 ) { log_message( LOG_WARNING, "accept error:%s.", strerror(errno) ); return -1; //惊群现象 } client_conn = get_conns_slot(); if ( NULL == client_conn ) { log_message( LOG_WARNING, "get_conns_slot NULL." ); return -2; } client_conn->fd = fd; client_conn->read_handle = read_client_handle; client_conn->write_handle = write_client_handle; client_conn->read_buffer = new_buffer(); //这里有内存泄漏 client_conn->write_buffer = new_buffer(); //这里有内存泄漏 client_conn->server_conn = NULL; client_conn->addr = addr; client_conn->read_closed = client_conn->write_closed = 0; client_conn->type = C_CLIENT; char *ip = NULL; ip = inet_ntoa( addr.sin_addr ); log_message( LOG_CONN, "create a new conn[fd:%d] client[%s:%d]--proxy.", client_conn->fd, ip, ntohs(addr.sin_port) ); epoll_add_connection( client_conn, EPOLLIN ); return TRUE; }
int init_conns_array( int epfd ) { int i; conn_t *pconn; for ( i = 1; i < MAXCONNSLOTS; ++ i ) { conns[i-1].data = &conns[i]; } conns[i-1].data = NULL; free_conn = &conns[0]; fullcnt = 0; for ( i = 0; i < MAXCONNSLOTS; ++ i ) { conns[i].read_buffer = NULL; conns[i].write_buffer = NULL; conns[i].read_closed = conns[i].write_closed = 0; } for ( i = 0; i < listenfd_cnt; ++ i ) { pconn = get_conns_slot(); if ( NULL == pconn ) { log_message( LOG_WARNING, "conns array full, refusing service." ); return -1; } pconn->fd = listenfds[i].fd; pconn->read_handle = accept_handle; pconn->write_handle = NULL; pconn->read_buffer = pconn->write_buffer = NULL; pconn->type = C_LISTEN; epoll_add_connection( pconn, EPOLLIN ); log_message( LOG_DEBUG, "init_conns_array: add listenfd into epoll." ); } return TRUE; }
static int tcp_connect(TNetWorkMsg *_ptNetWorkMsg, const char *_pcIP, int _iPort) { if(NULL == _ptNetWorkMsg || NULL == _pcIP) { dbg(); return ERR; } int iRet = ERR; unsigned int ul; dbgprintf(0, "start tcp connect to %s:%d", _ptNetWorkMsg->m_pcIp, _ptNetWorkMsg->m_iPort); fd_set rdevents,wrevents,exevents; struct timeval tv; socklen_t sLen; struct sockaddr_in ptDestAddr; if(INVALID_SOCKET == _ptNetWorkMsg->m_iSocket) { struct linger so_linger; _ptNetWorkMsg->m_iSocket = socket(AF_INET, SOCK_STREAM, 0); if(INVALID_SOCKET == _ptNetWorkMsg->m_iSocket) { dbg(); iRet = ERR; goto EXIT; } so_linger.l_onoff = 1; so_linger.l_linger = 0; iRet = setsockopt(_ptNetWorkMsg->m_iSocket, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)); int cnt = SO_RCVBUF_LEN; iRet = setsockopt(_ptNetWorkMsg->m_iSocket, SOL_SOCKET, SO_RCVBUF, (int *)&cnt,sizeof(int)); cnt = SO_SNDBUF_LEN; iRet = setsockopt(_ptNetWorkMsg->m_iSocket, SOL_SOCKET, SO_SNDBUF, (int *)&cnt, sizeof(int)); } #if 0 // 绑定指定网卡或IP strut sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = xxx; sin.sin_port = xxx; bind(sock, (struct sockaddr *)&sin, sizeof(sin)); // 绑定结束 #endif //设置为非阻塞模式 ul = 1; ioctl(_ptNetWorkMsg->m_iSocket, FIONBIO, &ul); // 指定地址和端口 memset(&ptDestAddr, 0, sizeof(struct sockaddr_in)); ptDestAddr.sin_family = AF_INET; ptDestAddr.sin_port = htons(_iPort); ptDestAddr.sin_addr.s_addr = inet_addr(_pcIP); // 与服务器端建立连接 iRet = connect(_ptNetWorkMsg->m_iSocket,(struct sockaddr*)&ptDestAddr, sizeof(ptDestAddr)); dbgint(iRet); dbgint(errno); if(-1 == iRet && errno != EINPROGRESS) { dbg(); iRet = ERR; goto EXIT; } //若没有直接连接成功则需要等待 if(0 != iRet) { //把先前的套接字加到读集合里面 FD_ZERO(&rdevents); FD_SET(_ptNetWorkMsg->m_iSocket, &rdevents); wrevents = rdevents; //异常集合 exevents = rdevents; #if 1 //设置时间为5秒 tv.tv_sec = 5; tv.tv_usec = 0; #else //设置时间为10秒 tv.tv_sec = 10; tv.tv_usec = 0; #endif iRet = select(_ptNetWorkMsg->m_iSocket + 1, &rdevents, &wrevents, &exevents, &tv); dbgint(iRet); if(iRet <= 0) { dbg(); dbgint(errno); //错误处理 iRet = ERR; goto EXIT; } #if 0 else if(0 == iRet) { //超时处理 close(_pConnection->m_iSocKet); _pConnection->m_iSocKet = INVALID_SOCKET; iRet = ERR; goto leave; } #endif else { if(2 == iRet) { int iErr; int iLen = sizeof(iErr); getsockopt(_ptNetWorkMsg->m_iSocket, SOL_SOCKET, SO_ERROR, &iErr, (socklen_t*)&iLen); if(iErr) { //dbg(); dbgint(errno); //超时处理 iRet = ERR; goto EXIT; } } //套接字已经准备好 if(_ptNetWorkMsg->m_iSocket < 0) { dbg(); dbgint(errno); iRet = ERR; goto EXIT; } if(!FD_ISSET(_ptNetWorkMsg->m_iSocket, &rdevents) && !FD_ISSET(_ptNetWorkMsg->m_iSocket, &wrevents)) { dbg(); dbgint(errno); iRet = ERR; goto EXIT; } if (getsockopt(_ptNetWorkMsg->m_iSocket, SOL_SOCKET, SO_ERROR, &iRet, &sLen) < 0) { //perror("getsockopt "); dbg(); dbgint(errno); } #if 0 if (iRet != 0) { dbg(); } #endif if(2 == iRet) { dbg(); dbgint(errno); iRet = ERR; goto EXIT; } //到这里说明connect()正确返回 } } iRet = OK; set_socket_nonblock(_ptNetWorkMsg->m_iSocket); #if 0 iRet = epoll_add_connection(_ptConnection, 1); if(iRet!=0) { iRet = ERR; goto EXIT; } #endif EXIT: if(OK != iRet && INVALID_SOCKET != _ptNetWorkMsg->m_iSocket) { //dbg(); close(_ptNetWorkMsg->m_iSocket); _ptNetWorkMsg->m_iSocket = INVALID_SOCKET; } return iRet; }
/* * pconn: client --> proxy, its buffer isn't NULL */ int read_client_handle( conn_t *pconn ) { log_message( LOG_DEBUG, "in read_client_handle" ); int ret; char ip[100]; //有可能不是ip uint16_t port; if ( 1 == pconn->read_closed ) { //因为某种原因不想读取client数据了 log_message( LOG_WARNING, "try reading from client[%s], but it closed read", inet_ntoa( pconn->addr.sin_addr ) ); return -1; } ret = read_buffer( pconn->fd, pconn->read_buffer ); log_message( LOG_DEBUG, "read %d bytes from client[%s:%d].", ret, inet_ntoa(pconn->addr.sin_addr), ntohs(pconn->addr.sin_port) ); if ( g_errno <= 0 ) { //read occur error, or closed log_message( LOG_CONN, "read occur error, close read from client[%s:%d].", inet_ntoa(pconn->addr.sin_addr), ntohs(pconn->addr.sin_port) ); CONN_CLOSE_READ( pconn ); /** * client关闭写,并且buffer没有数据了,proxy也要关闭server的写 * write_server的事情 * 发现问题了,这里要判断是否删除pconn->server_conn */ if ( NULL != pconn->server_conn && 0 == buffer_size( pconn->read_buffer ) ) { CONN_CLOSE_WRITE( pconn->server_conn ); if ( 1 == pconn->server_conn->read_closed ) { //very important epoll_del_connection( pconn->server_conn ); release_conns_slot( pconn->server_conn ); } } /** * 当客户端关闭写,并且没有VM,(或者VM关闭写并且buffer空了,这时就该关闭连接)--write_client_handle有处理 */ if ( 1 == pconn->write_closed || NULL == pconn->server_conn ) return -1; //删除pconn } /** * 这个很重要,不然容易导致工作进程突然死掉 */ if ( /*1 == pconn->read_closed &&*/ 0 == buffer_size( pconn->read_buffer ) ) { //return 0; //没有数据,不需要进入下一步 goto CLIENT_EPOLLSET; } /** * 处理读取的数据 */ if ( NULL == pconn->server_conn || //the fd connection to server has been reused by another client. //maybe has some potential problem. pconn->server_conn->server_conn != pconn ) { memset( ip, 0, sizeof(ip) ); //抽取VM IP:port,并重写url 需要再次修改这段代码 ret = extract_ip_buffer(pconn->read_buffer, ip, sizeof(ip), &port); if ( ret < 0 ) { log_message( LOG_WARNING, "extract_ip_buffer not find vm ip:port" ); //return 0; //等待新的数据到来 goto CLIENT_EPOLLSET; } int fd; struct sockaddr_in addr; NEWCONN: fd = open_client_socket( &addr, ip, port ); if ( fd < 0 ) { //发送error.html log_message( LOG_WARNING, "conn to Vm[%s:%d] failed.", ip, port ); if ( '\0' == ip[0] || 0 == port ) { //just for test char tmp[1024]; memset( tmp, 0, sizeof(tmp) ); memcpy( tmp, BLOCK_SENDADDR(pconn->read_buffer->head), 100 ); log_message( LOG_ERROR, "ip error:%s", tmp ); } if ( send_error_html( pconn->write_buffer ) < 0 ) return -1; //需要修改epll goto CLIENT_EPOLLSET; } conn_t * server_conn; server_conn = get_conns_slot(); if ( NULL == server_conn ) { log_message( LOG_WARNING, "conn slot full." ); if ( send_slot_full( pconn->write_buffer ) < 0 ) return -1; //需要修改epll goto CLIENT_EPOLLSET; } server_conn->fd = fd; server_conn->read_handle = read_server_handle; server_conn->write_handle = write_server_handle; server_conn->type = C_SERVER; server_conn->server_conn = pconn; server_conn->read_buffer = pconn->write_buffer; server_conn->write_buffer = pconn->read_buffer; server_conn->addr = addr; pconn->server_conn = server_conn; log_message( LOG_CONN, "client[%s:%d] conn to Vm[%s:%d:%d]\n", inet_ntoa(pconn->addr.sin_addr), ntohs(pconn->addr.sin_port), ip, port, fd ); epoll_add_connection( server_conn, EPOLLIN|EPOLLOUT ); } else { //这里假设http请求可以一次读完,以后需要再次修改 //rewrite URL in request ret = extract_ip_buffer(pconn->read_buffer, ip, sizeof(ip), &port); if ( ret < 0 ) { //表示没有请求行或是格式出错 epoll_mod_connection( pconn->server_conn, EPOLLIN ); //等待server读事件 log_message( LOG_ERROR, "extract_ip_buffer error, just rewrite url." ); //return 0; //没有加入epollout中,因为需要等待更多数据的到来 goto CLIENT_EPOLLSET; } //判断当前server是否与url中的vm匹配,如果不匹配,则需要把整个连接删除 // ip=0, 表示符合格式,但是没有包含vm:port,有可能已经删除过了 if ( '\0' != ip[0] && 0 != strcasecmp( ip, inet_ntoa(pconn->server_conn->addr.sin_addr) ) ) { epoll_del_connection( pconn->server_conn ); release_conns_slot( pconn->server_conn ); pconn->server_conn = NULL; //log_message( LOG_ERROR, "hp, goto NEWCOM" ); goto NEWCONN; //与新的vm创建连接 } epoll_mod_connection( pconn->server_conn, EPOLLIN|EPOLLOUT ); } /* * it's very important */ uint32_t clientf = 0; CLIENT_EPOLLSET: if ( 0 == pconn->write_closed && buffer_size( pconn->write_buffer ) > 0 ) clientf |= EPOLLOUT; if ( 0 == pconn->read_closed && buffer_size( pconn->read_buffer ) < MAXBUFFSIZE ) clientf |= EPOLLIN; epoll_mod_connection( pconn, clientf ); return 0; }