示例#1
0
void tcpsock_shutdown(Socket *sock, int shutflags)
{
	TCPSocket *tcpsock = (TCPSocket*) sock;
	
	semWait(&tcpsock->lock);
	
	if (shutflags & SHUT_RD)
	{
		if ((tcpsock->shutflags & SHUT_RD) == 0)
		{
			tcpsock->shutflags |= SHUT_RD;
			// do not terminate the receive semaphore. this should only happen
			// if we actually receive a FIN.
		};
	};
	
	if (shutflags & SHUT_WR)
	{
		if ((tcpsock->shutflags & SHUT_WR) == 0)
		{
			tcpsock->shutflags |= SHUT_WR;
			semTerminate(&tcpsock->semSendPut);
		};
	};
	
	semSignal(&tcpsock->lock);
};
示例#2
0
static void task_delete_hook(WIND_TCB * tcb) {
    if (tcb != main_thread && taskIdCurrent != main_thread) {
        EventInfo info;
        VX_COUNTING_SEMAPHORE(signal_mem);
        info.signal = semCInitialize(signal_mem, SEM_Q_FIFO, 0);
        info.pid = (UINT32)tcb;
        post_event(task_delete_event, &info);
        semTake(info.signal, WAIT_FOREVER);
        semTerminate(info.signal);
    }
}
示例#3
0
static void tcpsock_close(Socket *sock)
{
	TCPSocket *tcpsock = (TCPSocket*) sock;
	if (tcpsock->thread != NULL)
	{

		// terminate the semSendFetch semaphore, causing the handler thread to send a FIN and
		// later terminate.
		semTerminate(&tcpsock->semSendFetch);
	}
	else
	{
		FreeSocket(sock);
	};
};
示例#4
0
static int tcpsock_packet(Socket *sock, const struct sockaddr *src, const struct sockaddr *dest, size_t addrlen,
			const void *packet, size_t size, int proto)
{
	// TODO: 4-mapped-6 addresses
	if (src->sa_family != sock->domain)
	{
		return SOCK_CONT;
	};
	
	if (size < sizeof(TCPSegment))
	{
		return SOCK_CONT;
	};
	
	TCPSocket *tcpsock = (TCPSocket*) sock;
	if (tcpsock->state == TCP_CLOSED)
	{
		return SOCK_CONT;
	};
	
	if (proto == IPPROTO_TCP)
	{
		if (tcpsock->state == TCP_LISTENING)
		{
			TCPSegment *seg = (TCPSegment*) packet;
			uint16_t listenPort;
			static uint64_t zeroAddr[2] = {0, 0};
		
			if (sock->domain == AF_INET)
			{
				const struct sockaddr_in *inname = (const struct sockaddr_in*) &tcpsock->sockname;
			
				listenPort = inname->sin_port;
			
				const struct sockaddr_in *indst = (const struct sockaddr_in*) dest;
			
				if (memcmp(&indst->sin_addr, &inname->sin_addr, 4) != 0 && memcmp(&inname->sin_addr, zeroAddr, 4) != 0)
				{
					return SOCK_CONT;
				};
			}
			else
			{
				const struct sockaddr_in6 *inname = (const struct sockaddr_in6*) &tcpsock->sockname;
			
				listenPort = inname->sin6_port;

				const struct sockaddr_in6 *indst = (const struct sockaddr_in6*) dest;
			
				if (memcmp(&indst->sin6_addr, &inname->sin6_addr, 16) != 0 && memcmp(&inname->sin6_addr, zeroAddr, 16) != 0)
				{
					return SOCK_CONT;
				};
			};
		
			if (seg->dstport != listenPort)
			{
				return SOCK_CONT;
			};
		
			if ((seg->flags & TCP_SYN) == 0)
			{
				return SOCK_CONT;
			};
			
			struct sockaddr local;
			memset(&local, 0, sizeof(struct sockaddr));
			struct sockaddr peer;
			memset(&peer, 0, sizeof(struct sockaddr));
			memcpy(&local, dest, addrlen);
			memcpy(&peer, src, addrlen);
		
			if (sock->domain == AF_INET)
			{
				((struct sockaddr_in*)&local)->sin_port = seg->dstport;
				((struct sockaddr_in*)&peer)->sin_port = seg->srcport;
			}
			else
			{
				((struct sockaddr_in6*)&local)->sin6_port = seg->dstport;
				((struct sockaddr_in6*)&peer)->sin6_port = seg->srcport;
				((struct sockaddr_in6*)&local)->sin6_flowinfo = 0;
				((struct sockaddr_in6*)&peer)->sin6_flowinfo = 0;
			};
		
			// we just received a connection
			semWait(&tcpsock->lock);
		
			// first check if the connection is already pending
			int found = 0;
			TCPPending *pend;
			for (pend=tcpsock->firstPending; pend!=NULL; pend=pend->next)
			{
				if (memcmp(&pend->local, &local, sizeof(struct sockaddr)) == 0
					&& memcmp(&pend->peer, &peer, sizeof(struct sockaddr)) == 0)
				{
					found = 1;
					break;
				};
			};
		
			// if not yet on the pending list, add it
			if (!found)
			{
				pend = NEW(TCPPending);
				pend->next = NULL;
				memcpy(&pend->local, &local, sizeof(struct sockaddr));
				memcpy(&pend->peer, &peer, sizeof(struct sockaddr));
				pend->ackno = ntohl(seg->seqno)+1;
				
				if (tcpsock->firstPending == NULL)
				{
					tcpsock->firstPending = pend;
				}
				else
				{
					TCPPending *last = tcpsock->firstPending;
					while (last->next != NULL) last = last->next;
					last->next = pend;
				};
			};
		
			semSignal(&tcpsock->lock);
			semSignal(&tcpsock->semConnWaiting);
			return SOCK_STOP;
		};
	
		if (ValidateChecksum(src, dest, packet, size) != 0)
		{
			return SOCK_CONT;
		};
		
		uint16_t localPort, remotePort;
		if (sock->domain == AF_INET)
		{
			const struct sockaddr_in *inname = (const struct sockaddr_in*) &tcpsock->sockname;
			const struct sockaddr_in *inpeer = (const struct sockaddr_in*) &tcpsock->peername;
			
			localPort = inname->sin_port;
			remotePort = inpeer->sin_port;
			
			const struct sockaddr_in *insrc = (const struct sockaddr_in*) src;
			const struct sockaddr_in *indst = (const struct sockaddr_in*) dest;
			
			if (memcmp(&insrc->sin_addr, &inpeer->sin_addr, 4) != 0)
			{
				return SOCK_CONT;
			};
			
			if (memcmp(&indst->sin_addr, &inname->sin_addr, 4) != 0)
			{
				return SOCK_CONT;
			};
		}
		else
		{
			const struct sockaddr_in6 *inname = (const struct sockaddr_in6*) &tcpsock->sockname;
			const struct sockaddr_in6 *inpeer = (const struct sockaddr_in6*) &tcpsock->peername;
			
			localPort = inname->sin6_port;
			remotePort = inpeer->sin6_port;

			const struct sockaddr_in6 *insrc = (const struct sockaddr_in6*) src;
			const struct sockaddr_in6 *indst = (const struct sockaddr_in6*) dest;
			
			if (memcmp(&insrc->sin6_addr, &inpeer->sin6_addr, 16) != 0)
			{
				return SOCK_CONT;
			};
			
			if (memcmp(&indst->sin6_addr, &inname->sin6_addr, 16) != 0)
			{
				return SOCK_CONT;
			};
		};
		
		TCPSegment *seg = (TCPSegment*) packet;

		if ((seg->srcport != remotePort) || (seg->dstport != localPort))
		{
			return SOCK_CONT;
		};
		
		// at this point, we know that this packet is destined to this socket, so from now on return SOCK_STOP only,
		// to avoid it arriving at other sockets
		
		if (seg->flags & TCP_ACK)
		{
			uint64_t ackno = (uint64_t) ntohl(seg->ackno);
			if (atomic_compare_and_swap64(&tcpsock->expectedAck, ackno, (1UL << 32)) == ackno)
			{
				semSignal(&tcpsock->semAck);
			};
		};
		
		if (seg->flags & TCP_RST)
		{
			semWait(&tcpsock->lock);
			if (ntohl(seg->seqno) == tcpsock->nextAckNo)
			{
				tcpsock->sockErr = ECONNRESET;
				tcpsock->shutflags |= SHUT_WR | SHUT_RD;
				tcpsock->state = TCP_TERMINATED;
				semSignal(&tcpsock->semStop);
			};
			semSignal(&tcpsock->lock);
		};
		
		if (tcpsock->state == TCP_TERMINATED)
		{
			semSignal(&tcpsock->semAckOut);
			return SOCK_STOP;
		};
		
		size_t headerSize = (size_t)(seg->dataOffsetNS >> 4) * 4;
		if (seg->flags & TCP_SYN)
		{
			Semaphore *semConn = &tcpsock->semConnected;
			uint8_t bitmap = 0;
			semPoll(1, &semConn, &bitmap, SEM_W_NONBLOCK, 0);
			
			if (bitmap == 0)
			{
				tcpsock->nextAckNo = ntohl(seg->seqno)+1;
				semSignal(&tcpsock->semConnected);
			};

			semSignal(&tcpsock->semAckOut);
		}
		else if (seg->flags & TCP_FIN)
		{
			uint32_t seqno = ntohl(seg->seqno);
			semWait(&tcpsock->lock);
			
			if (seqno == tcpsock->nextAckNo)
			{
				tcpsock->shutflags |= SHUT_RD;
				tcpsock->nextAckNo = seqno+1;
				semTerminate(&tcpsock->semRecvFetch);
				semSignal(&tcpsock->semAckOut);
			};

			semSignal(&tcpsock->lock);
		}
		else if (seg->flags & TCP_PSH || size > headerSize)
		{
			size_t payloadSize = size - headerSize;
			const uint8_t *scan = (const uint8_t*)seg + headerSize;
			
			uint32_t seqno = ntohl(seg->seqno);
			semWait(&tcpsock->lock);
			if (seqno == tcpsock->nextAckNo)
			{
				if (tcpsock->cntRecvPut < payloadSize)
				{
					// we can't fit this payload in our buffer! drop it as it will
					// be re-transmitted soon
					semSignal(&tcpsock->lock);
					return SOCK_STOP;
				};
				
				tcpsock->cntRecvPut -= payloadSize;
				
				size_t count = payloadSize;
				while (count--)
				{
					tcpsock->bufRecv[tcpsock->idxRecvPut] = *scan++;
					tcpsock->idxRecvPut = (tcpsock->idxRecvPut+1) % TCP_BUFFER_SIZE;
				};
				
				semSignal2(&tcpsock->semRecvFetch, (int)payloadSize);
				
				tcpsock->nextAckNo += (uint32_t)payloadSize;
			};

			semSignal(&tcpsock->semAckOut);
			semSignal(&tcpsock->lock);
		};
		
		return SOCK_STOP;
	};
	// TODO: ICMP messages relating to TCP
	
	return SOCK_CONT;
};