예제 #1
0
DWORD WINAPI TcpServer::RecvThreadProc(LPVOID lpParameter)
{
	TcpServer* _this=(TcpServer*)lpParameter;
	TransparentWnd *win=(TransparentWnd *)_this->winHandler;
	int size=0;
	//std::stringstream ss;
	int count=0;
	char* s=NULL;
	bool startReceive=false;
	int retry=0;
	//开始接受数据,等待
	for(;;)
	{
		char recvBuf[40960] = {0};
		int l=recv(_this->curSocket,recvBuf,40960,0);
		if(l==0) {
			++retry;
			if(retry>3){
				if(!startReceive){
					size=0;
					if(s!=NULL){
						delete s;
						s=NULL;
					}
					count=0;
					waitForConnect(lpParameter);
					break;
					retry=0;
				}
			}
		}
		else{
			if(size==0&&l==4){
				int *b= (int*)recvBuf;
				size=(int)(*b);
				if(s!=NULL){
					delete s;
					s=NULL;
				}
				s=new char[size+1];
				s[size]=0;
			}
			else if(s!=NULL&&size>0){
				for(int i=count,j=0;i<count+l&&i<size;++i,++j){
					s[i]=recvBuf[j];
				}
				count+=l;
				if(count>=size){
					win->RecieveMessage(TCPMESSAGE,s,0,0);
					size=0;
					count=0;
				}
			}
		}

	}
	return 0;
}
예제 #2
0
int CCONV
stream_server_connect(const char *dest, const char *svcname, int *fdp, int *cancelSocket, char *errdesc, int errdesclen)
{
	struct addrinfo hints, *res, *res0 = NULL;
	int err, cancelled = 0;
	SOCKET s = INVALID_SOCKET;
	int tmpSock[2];
	int cancelRecvSocket = INVALID_SOCKET;
#ifdef _WINDOWS
	u_long nNonBlocking = TRUE;
#endif

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	
	if ((err = getaddrinfo(dest, svcname, &hints, &res0)) != 0) {
		if (errdesc)
			snprintf(errdesc, errdesclen, "getaddrinfo: %s", gai_strerror(err));
		freeaddrinfo(res0);
		return 0;
	}
	
	//setup cancel socket
	err = socketpair(AF_UNIX, SOCK_STREAM, 0, tmpSock);
	if (err < 0) {
		err = errno;
	} else {
		*cancelSocket = tmpSock[0];
		cancelRecvSocket = tmpSock[1];
	}
	
	for (res = res0; res; res = res->ai_next) {
		if(cancelled)
			break;
		
		// sometimes on mac, we get 0.0.0.0 ??!! - just ignore it
		if(((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr == 0) 
		{
			continue;
		}
		
		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
#ifndef _WINDOWS
		if (s < 0) {
#else
		if (s == INVALID_SOCKET) {
#endif
			SET_ERRDESC(errdesc, errdesclen);
			continue;
		}
			
		//Make the socket non-blocking
#ifndef _WINDOWS
		if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
			SET_ERRDESC(errdesc, errdesclen);
			s = INVALID_SOCKET;	
			continue;
		}
#else
		if (ioctlsocket(s, FIONBIO, (u_long FAR *) & nNonBlocking))
		{
			s = INVALID_SOCKET;	
			continue;
		}
#endif

		if((err = connect(s, res->ai_addr, (int) res->ai_addrlen)) != 0)
		{
			//Connection in progress - wait for completion or cancelation
#ifndef _WINDOWS
			if(errno == EINPROGRESS)
#else
			err = WSAGetLastError();
			if(err == WSAEINPROGRESS || err == WSAEWOULDBLOCK)
#endif
			{
				err = waitForConnect(s, cancelRecvSocket);
				
				// Not cancelled, so must have either connected or failed.  
				// Check to see if we're connected by calling getpeername.
				if (err == 0) {
					socklen_t 	len = sizeof(struct sockaddr);
					struct sockaddr name;
					err = getpeername(s, &name, &len);
					
					// The connection failed.  Get the error associated with 
					// the connection attempt.
					if (err < 0) {
						int tmpErr;
#ifdef _WINDOWS
						err = WSAGetLastError();
#endif
						len = sizeof(tmpErr);
						err = getsockopt(s, SOL_SOCKET, SO_ERROR, &tmpErr, &len);
						if (err < 0) {
#ifdef _WINDOWS
							err = WSAGetLastError();
#else
							err = errno;
#endif
						} else {
							assert(tmpErr != 0);
							err = tmpErr;
						}
					}
					//connection good
					else
						break;
				}
				//cancelled
				else if(err==ECANCELED)
				{
					cancelled = 1;
				}
				
#ifdef _WINDOWS
				WSASetLastError(err);
#else
				errno = err;
#endif
			}
			//Error
			SET_ERRDESC(errdesc, errdesclen);
#ifndef _WINDOWS
			close(s);
#else
			closesocket(s);
#endif
			s = INVALID_SOCKET;	
			continue;
		}
		break;
	}
		
	//cleanup cancel socket - not needed anymore
	if (tmpSock[0] != -1)
#ifndef _WINDOWS
		close(tmpSock[0]);
#else
		closesocket(tmpSock[0]);
#endif
	if (tmpSock[1] != -1)
#ifndef _WINDOWS
		close(tmpSock[1]);
#else
		closesocket(tmpSock[1]);
#endif
		*cancelSocket = INVALID_SOCKET;
		
#ifndef _WINDOWS
	if (s < 0) {
#else
	if (s == INVALID_SOCKET) {
#endif
		SET_ERRDESC(errdesc, errdesclen);
		freeaddrinfo(res0);
		return 0;
	}
	if (fdp)
		*fdp = s;
	freeaddrinfo(res0);
	return 1;
}

/*
 * Accepts a TCP connection on a given port and invokes the given
 * callback to handle it. This is where the main server thread sits.
 */
int
stream_server_accept(int port, void(*clfunc)(int fd, const char *addr,
    int port), char *errdesc, int errdesclen)
{
	struct sockaddr_in sin = { 0 };
	struct sockaddr_in cin = { 0 };
	const int opt = 1;
	socklen_t cl;
	char *addr;
	int fd;
	int s;

	if (!(s = (int)socket(PF_INET, SOCK_STREAM, 0))) {
		SET_ERRDESC(errdesc, errdesclen);
		return 0;
	}
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt));
#ifdef _MACOSX
	setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof (opt));
#endif
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = INADDR_ANY;
	if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
		SET_ERRDESC(errdesc, errdesclen);
		return 0;
	}
	if (listen(s, 5) != 0) {
		SET_ERRDESC(errdesc, errdesclen);
		return 0;
	}
	for (;;) {
		cl = sizeof(cin);
		while ((fd = (int)accept(s, (struct sockaddr *)&cin, &cl)) < 0 &&
		    errno == EAGAIN)
			;
		if (fd < 0) {
			SET_ERRDESC(errdesc, errdesclen);
			return 0;
		}
		setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&opt, sizeof (opt));
#ifdef _MACOSX
		setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof (opt));
#endif
		addr = strdup(inet_ntoa(cin.sin_addr));
		clfunc(fd, addr, ntohs(cin.sin_port));
		free(addr); addr = NULL;
	}
	/*NOTREACHED*/
}

int
pu_write(int fd, const void *buf, unsigned int len, char *errdesc, int edlen)
{
	static pthread_mutex_t *writelock = 0;
	int res = 0;
	int olen = len;

	if (fd == -1)
		return len;

	if (!writelock) {
		if (!(writelock = malloc(sizeof (*writelock))))
			return 0;
		pthread_mutex_init(writelock, NULL);
	}
	pthread_mutex_lock(writelock);
	do {
		if (res > 0) {
#ifdef _WINDOWS
			(unsigned char *)buf += res;
#else
			buf += res;
#endif
			len -= res;
		}
		if (len)
		{
		tryagain:
			res = send(fd, buf, len, MSG_NOSIGNAL);
			//Error
			if(res == -1)
			{
#ifdef _WINDOWS
				switch(WSAGetLastError())
				{
					//non-blocking, try again
					case WSAEWOULDBLOCK:
						SLEEP(10);
						goto tryagain;
					//any other error, don't try again
					default:
						break;
				}
#else
				switch(errno)
				{
					//Interrupted, try again
					case EINTR:
					//non-blocking, try again
					case EAGAIN:
						SLEEP(10);
						goto tryagain;
					//any other error, don't try again
					default:
						break;
				}
#endif
			}
		}
		else
			res = olen;
	} while (len && res >= 0);
	pthread_mutex_unlock(writelock);

	if (res != olen) {
		SET_ERRDESC(errdesc, edlen);
		return 0;
	} else
		return 1;
}

int
pu_read(int fd, void *buf, unsigned int len, char *errdesc, int edlen)
{
	int res=0, err=0;
	if (fd == -1)
		return 0;

tryagain:
	res = recv(fd, buf, len, 0);
	//Error
	if(res == -1)
	{
#ifdef _WINDOWS
		switch(WSAGetLastError())
		{
			//non-blocking, try again
			case WSAEWOULDBLOCK:
				SLEEP(10);
				goto tryagain;
			//any other error, don't try again
			default:
				err = WSAGetLastError();
				break;
		}
#else
		switch(errno)
		{
			//Interrupted, try again
			case EINTR:
			//non-blocking, try again
			case EAGAIN:
				SLEEP(10);
				goto tryagain;
			//any other error, don't try again
			default:
				err = errno;
				break;
		}
#endif
	}
	if (res <= 0) {
		SET_ERRDESC(errdesc, edlen);
		return 0;
	} else
		return res;
}

int
pu_close(int fd, char *errdesc, int edlen)
{
	int res=0;
	if(fd == -1) return 0;
#ifndef _WINDOWS
	res = close(fd);
#else
	res = closesocket(fd);
#endif
	SET_ERRDESC(errdesc, edlen);
	return res;
}