Exemple #1
0
void Account::SetType(int32 type)
{
	if (type < INBOUND_TYPE || type > IN_AND_OUTBOUND_TYPE)
		return;

	int32 index = gListView->IndexOf(fAccountItem) + 1;

	// missing inbound
	if ((type == INBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE) && !Inbound())
	{
		if (!fInbound)
			CreateInbound();

		if (fInbound)
			gListView->AddItem(fInboundItem,index);
	}
	if (Inbound())
		index++;

	// missing outbound
	if ((type == OUTBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE) && !Outbound())
	{
		if (!fOutbound)
			CreateOutbound();

		if (fOutbound)
			gListView->AddItem(fOutboundItem,index);
	}
	if (Outbound())
		index++;

	// missing filter
	if (!gListView->HasItem(fFilterItem))
		gListView->AddItem(fFilterItem,index);

	// remove inbound
	if (type == OUTBOUND_TYPE && Inbound())
		gListView->RemoveItem(fInboundItem);

	// remove outbound
	if (type == INBOUND_TYPE && Outbound())
		gListView->RemoveItem(fOutboundItem);
}
Exemple #2
0
static void tcpThread(void *context)
{
	Socket *sock = (Socket*) context;
	TCPSocket *tcpsock = (TCPSocket*) context;
	Semaphore *sems[4] = {&tcpsock->semConnected, &tcpsock->semStop, &tcpsock->semAck, &tcpsock->semAckOut};
	Semaphore *semsOut[3] = {&tcpsock->semStop, &tcpsock->semAckOut, &tcpsock->semSendFetch};

	detachMe();
	
	uint16_t srcport, dstport;
	if (sock->domain == AF_INET)
	{
		const struct sockaddr_in *inaddr = (const struct sockaddr_in*) &tcpsock->peername;
		struct sockaddr_in *inname = (struct sockaddr_in*) &tcpsock->sockname;
		srcport = inname->sin_port;
		dstport = inaddr->sin_port;
	}
	else
	{
		const struct sockaddr_in6 *inaddr = (const struct sockaddr_in6*) &tcpsock->peername;
		struct sockaddr_in6 *inname = (struct sockaddr_in6*) &tcpsock->sockname;
		inname->sin6_family = AF_INET6;
		srcport = inname->sin6_port;
		dstport = inaddr->sin6_port;
	};

	int connectDone = 0;
	if (tcpsock->state == TCP_ESTABLISHED)
	{
		sems[0] = NULL;
		connectDone = 1;
	};
	int wantExit = 0;
	while (1)
	{
		if (wantExit) break;
		
		uint64_t deadline = getNanotime() + sock->options[GSO_SNDTIMEO];
		if (sock->options[GSO_SNDTIMEO] == 0)
		{
			deadline = 0;
		};
		
		int sendOK = 0;
		int retransCount = 16;
		while (((getNanotime() < deadline) || (deadline == 0)) && (retransCount--))
		{
			tcpsock->currentOut->segment->ackno = htonl(tcpsock->nextAckNo);
			ChecksumOutbound(tcpsock->currentOut);
			
			int status = sendPacketEx(&tcpsock->sockname, &tcpsock->peername,
							tcpsock->currentOut->segment, tcpsock->currentOut->size,
							IPPROTO_TCP, sock->options, sock->ifname);

			if (status != 0)
			{
				tcpsock->sockErr = -status;

				if (tcpsock->state == TCP_CONNECTING)
				{
					semSignal(&tcpsock->semConnected);
				};
			
				tcpsock->state = TCP_TERMINATED;
				kfree(tcpsock->currentOut);
				wantExit = 1;
				break;
			};
			
			uint8_t bitmap = 0;
			if (semPoll(4, sems, &bitmap, 0, TCP_RETRANS_TIMEOUT) == 0)
			{
				continue;
			};
			
			if (bitmap & (1 << 1))
			{
				kfree(tcpsock->currentOut);
				tcpsock->state = TCP_TERMINATED;
				wantExit = 1;
				break;
			};
			
			if (bitmap & (1 << 2))
			{
				semWait(&tcpsock->semAck);
				sendOK = 1;
				break;
			};
			
			if (bitmap & (1 << 3))
			{
				semWaitGen(&tcpsock->semAckOut, -1, 0, 0);
			};
		};
		
		if (wantExit) break;
		
		int wasFin = tcpsock->currentOut->segment->flags & TCP_FIN;
		kfree(tcpsock->currentOut);
		
		if (!sendOK)
		{
			tcpsock->sockErr = ETIMEDOUT;
			
			if (tcpsock->state == TCP_CONNECTING)
			{
				semSignal(&tcpsock->semConnected);
			};
			
			tcpsock->state = TCP_TERMINATED;
			return;
		};
		
		if (!connectDone)
		{
			while ((getNanotime() < deadline) || (deadline == 0))
			{
				uint8_t bitmap = 0;
				semPoll(3, sems, &bitmap, 0, sock->options[GSO_SNDTIMEO]);
			
				if (bitmap & (1 << 1))
				{
					tcpsock->state = TCP_TERMINATED;
					return;
				};
				
				if (bitmap & (1 << 0))
				{
					connectDone = 1;
					break;
				};
			};

			if (!connectDone)
			{
				tcpsock->sockErr = ETIMEDOUT;
				semSignal(&tcpsock->semConnected);
				tcpsock->state = TCP_TERMINATED;
				return;
			};

			sems[0] = NULL;
			tcpsock->state = TCP_ESTABLISHED;
		};
		
		if (wasFin) break;
		
		while (1)
		{
			uint8_t bitmap = 0;
			semPoll(3, semsOut, &bitmap, 0, 0);
		
			if (bitmap & (1 << 2))
			{
				if (bitmap & (1 << 1))
				{
					semWaitGen(&tcpsock->semAckOut, -1, 0, 0);
				};
				
				int count = semWaitGen(&tcpsock->semSendFetch, 512, 0, 0);
				
				TCPOutbound *ob = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, (size_t)count);
				ob->segment->srcport = srcport;
				ob->segment->dstport = dstport;
				ob->segment->seqno = htonl(tcpsock->nextSeqNo);
				// ackno filled in at the start of the loop iteration
				ob->segment->dataOffsetNS = 0x50;
				ob->segment->flags = TCP_PSH | TCP_ACK;
				// a count of zero means end of data, so send FIN.
				if (count == 0)
				{
					ob->segment->flags = TCP_FIN | TCP_ACK;
					tcpsock->nextSeqNo++;
				};
				ob->segment->winsz = htons(TCP_BUFFER_SIZE);
				uint8_t *put = (uint8_t*) &ob->segment[1];
				uint32_t size = (uint32_t)count;
				while (count--)
				{
					*put++ = tcpsock->bufSend[tcpsock->idxSendFetch];
					tcpsock->idxSendFetch = (tcpsock->idxSendFetch+1) % TCP_BUFFER_SIZE;
				};

				tcpsock->nextSeqNo += size;
				tcpsock->expectedAck = tcpsock->nextSeqNo;
				tcpsock->currentOut = ob;
				semSignal2(&tcpsock->semSendPut, (int)size);
				break;		// continues the outer loop
			};
			
			if (bitmap & (1 << 1))
			{
				semWaitGen(&tcpsock->semAckOut, -1, 0, 0);
			
				TCPOutbound *ob = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, 0);
				TCPSegment *ack = ob->segment;
				
				ack->srcport = srcport;
				ack->dstport = dstport;
				ack->seqno = htonl(tcpsock->nextSeqNo);
				ack->ackno = htonl(tcpsock->nextAckNo);
				ack->dataOffsetNS = 0x50;
				ack->flags = TCP_ACK;
				ack->winsz = htons(TCP_BUFFER_SIZE);
				ChecksumOutbound(ob);
				
				sendPacketEx(&tcpsock->sockname, &tcpsock->peername,
						ob->segment, ob->size,
						IPPROTO_TCP, sock->options, sock->ifname);
				
				kfree(ob);
			};

			if (bitmap & (1 << 0))
			{
				tcpsock->state = TCP_TERMINATED;
				wantExit = 1;
				break;
			};
		};
	};

	// wait up to 4 minutes, acknowledging any packets if necessary (during a clean exit)
	uint64_t deadline = getNanotime() + 4UL * 60UL * 1000000000UL;
	uint64_t currentTime;
	Semaphore *semsClosing[2] = {&tcpsock->semStop, &tcpsock->semAckOut};
	while ((currentTime = getNanotime()) < deadline)
	{
		uint8_t bitmap = 0;
		semPoll(2, semsClosing, &bitmap, 0, deadline - currentTime);

		if (bitmap & (1 << 0))
		{
			wantExit = 1;
			semsClosing[0] = NULL;
		};
		
		if (bitmap & (1 << 1))
		{
			if (!wantExit)
			{
				semWaitGen(&tcpsock->semAckOut, -1, 0, 0);
	
				TCPOutbound *ob = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, 0);
				TCPSegment *ack = ob->segment;
		
				ack->srcport = srcport;
				ack->dstport = dstport;
				ack->seqno = htonl(tcpsock->nextSeqNo);
				ack->ackno = htonl(tcpsock->nextAckNo);
				ack->dataOffsetNS = 0x50;
				ack->flags = TCP_FIN | TCP_ACK;
				ack->winsz = htons(TCP_BUFFER_SIZE);
				ChecksumOutbound(ob);
		
				sendPacketEx(&tcpsock->sockname, &tcpsock->peername,
						ob->segment, ob->size,
						IPPROTO_TCP, sock->options, sock->ifname);
		
				kfree(ob);
			};
		};
	};

	// wait for the socket to actually be closed by the application (in case it wasn't already)
	while (semWaitGen(&tcpsock->semSendFetch, 512, 0, 0) != 0);
	
	// free the port and socket
	FreePort(srcport);
	FreeSocket(sock);
};
Exemple #3
0
static int tcpsock_connect(Socket *sock, const struct sockaddr *addr, size_t size)
{
	TCPSocket *tcpsock = (TCPSocket*) sock;
	if (addr->sa_family != sock->domain)
	{
		ERRNO = EAFNOSUPPORT;
		return -1;
	};
	
	if (size != INET_SOCKADDR_LEN)
	{
		ERRNO = EAFNOSUPPORT;
		return -1;
	};
	
	semWait(&tcpsock->lock);
	if (tcpsock->state == TCP_CONNECTING)
	{
		semSignal(&tcpsock->lock);
		ERRNO = EALREADY;
		return -1;
	};
	
	if (tcpsock->state != TCP_CLOSED)
	{
		semSignal(&tcpsock->lock);
		ERRNO = EISCONN;
		return -1;
	};
	
	uint16_t srcport, dstport;
	if (sock->domain == AF_INET)
	{
		const struct sockaddr_in *inaddr = (const struct sockaddr_in*) addr;
		struct sockaddr_in *inname = (struct sockaddr_in*) &tcpsock->sockname;
		if (inname->sin_family == AF_UNSPEC)
		{
			inname->sin_family = AF_INET;
			getDefaultAddr4(&inname->sin_addr, &inaddr->sin_addr, sock->ifname);
			inname->sin_port = AllocPort();
			srcport = inname->sin_port;
		}
		else
		{
			srcport = inname->sin_port;
		};
		
		dstport = inaddr->sin_port;
	}
	else
	{
		const struct sockaddr_in6 *inaddr = (const struct sockaddr_in6*) addr;
		struct sockaddr_in6 *inname = (struct sockaddr_in6*) &tcpsock->sockname;
		if (inname->sin6_family == AF_UNSPEC)
		{
			inname->sin6_family = AF_INET6;
			getDefaultAddr6(&inname->sin6_addr, &inaddr->sin6_addr, sock->ifname);
			inname->sin6_port = AllocPort();
			srcport = inname->sin6_port;
		}
		else
		{
			srcport = inname->sin6_port;
		}
		dstport = inaddr->sin6_port;
	};
	
	memcpy(&tcpsock->peername, addr, INET_SOCKADDR_LEN);
	tcpsock->state = TCP_CONNECTING;
	
	tcpsock->nextSeqNo = (uint32_t) getRandom();
	
	tcpsock->currentOut = CreateOutbound(&tcpsock->sockname, &tcpsock->peername, 0);
	tcpsock->expectedAck = tcpsock->nextSeqNo;
	TCPSegment *syn = tcpsock->currentOut->segment;
	syn->srcport = srcport;
	syn->dstport = dstport;
	syn->seqno = htonl(tcpsock->nextSeqNo-1);
	syn->dataOffsetNS = 0x50;
	syn->flags = TCP_SYN;
	syn->winsz = htons(TCP_BUFFER_SIZE);
	ChecksumOutbound(tcpsock->currentOut);
	
	KernelThreadParams pars;
	memset(&pars, 0, sizeof(KernelThreadParams));
	pars.stackSize = DEFAULT_STACK_SIZE;
	pars.name = "TCP Thread";
	tcpsock->thread = CreateKernelThread(tcpThread, &pars, tcpsock);
	
	semSignal(&tcpsock->lock);
	
	uint8_t bitmap = 0;
	Semaphore *semConn = &tcpsock->semConnected;
	if (semPoll(1, &semConn, &bitmap, SEM_W_FILE(sock->fp->oflags), 0) == 0)
	{
		// we caught an interrupt before the connection was completed
		ERRNO = EINPROGRESS;
		return -1;
	}
	else
	{
		// report the error synchronously if there is one; otherwise success
		if (tcpsock->sockErr == 0)
		{
			return 0;
		}
		else
		{
			ERRNO = tcpsock->sockErr;
			return -1;
		};
	};
};
Exemple #4
0
static Socket* tcpsock_accept(Socket *sock, struct sockaddr *addr, size_t *addrlenptr)
{
	TCPSocket *tcpsock = (TCPSocket*) sock;
	if (tcpsock->state != TCP_LISTENING)
	{
		ERRNO = EINVAL;
		return NULL;
	};
	
	if (addrlenptr != NULL)
	{
		if ((*addrlenptr) < INET_SOCKADDR_LEN)
		{
			ERRNO = EINVAL;
			return NULL;
		};
	};
	
	int count = semWaitGen(&tcpsock->semConnWaiting, 1, SEM_W_FILE(sock->fp->oflags), sock->options[GSO_RCVTIMEO]);
	if (count < 0)
	{
		ERRNO = -count;
		return NULL;
	};
	
	// a connection is pending, create the socket.
	// TODO: there is a race condition where we remove the pending connection from the list,
	// and another SYN arrives before we add the socket to the list, causing another connection
	// request to be created. We must work on that somehow.
	Socket *client = CreateTCPSocket();
	client->domain = sock->domain;
	client->type = SOCK_STREAM;
	client->proto = IPPROTO_TCP;
	memset(client->options, 0, 8*GSO_COUNT);
	
	TCPSocket *tcpclient = (TCPSocket*) client;
	
	semWait(&tcpsock->lock);
	TCPPending *pend = tcpsock->firstPending;
	tcpsock->firstPending = pend->next;
	semSignal(&tcpsock->lock);
	
	semWait(&tcpclient->lock);
	memcpy(&tcpclient->sockname, &pend->local, sizeof(struct sockaddr));
	memcpy(&tcpclient->peername, &pend->peer, sizeof(struct sockaddr));
	
	tcpclient->state = TCP_ESTABLISHED;
	tcpclient->nextSeqNo = (uint32_t) getRandom();
	tcpclient->nextAckNo = pend->ackno;
	
	tcpclient->currentOut = CreateOutbound(&tcpclient->sockname, &tcpclient->peername, 0);
	tcpclient->expectedAck = tcpclient->nextSeqNo;
	TCPSegment *syn = tcpclient->currentOut->segment;
	if (sock->domain == AF_INET)
	{
		syn->srcport = ((struct sockaddr_in*)&pend->local)->sin_port;
		syn->dstport = ((struct sockaddr_in*)&pend->peer)->sin_port;
	}
	else
	{
		syn->srcport = ((struct sockaddr_in6*)&pend->local)->sin6_port;
		syn->dstport = ((struct sockaddr_in6*)&pend->peer)->sin6_port;
	};
	syn->seqno = htonl(tcpclient->nextSeqNo-1);
	syn->ackno = htonl(pend->ackno);
	syn->dataOffsetNS = 0x50;
	syn->flags = TCP_SYN | TCP_ACK;
	syn->winsz = htons(TCP_BUFFER_SIZE);
	ChecksumOutbound(tcpclient->currentOut);
	
	KernelThreadParams pars;
	memset(&pars, 0, sizeof(KernelThreadParams));
	pars.stackSize = DEFAULT_STACK_SIZE;
	pars.name = "TCP Thread";
	tcpclient->thread = CreateKernelThread(tcpThread, &pars, tcpclient);
	
	semSignal(&tcpclient->lock);
	semSignal(&tcpclient->semConnected);
	
	if (addrlenptr != NULL) *addrlenptr = INET_SOCKADDR_LEN;
	if (addr != NULL)
	{
		memcpy(addr, &pend->peer, INET_SOCKADDR_LEN);
	};
	
	kfree(pend);
	return client;
};