X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Fudp.c;h=c1dbe9240d8f899a6f5240f676fd0a60185177ca;hb=b1873b4cff47aae8ada8cc303ea01b475cc7ccc8;hp=fe13a3e167d60f70810c289f1b253ec3bbff1e83;hpb=59a434cdeaf3b3bb2aeb0b93816abfef43cbcac7;p=tpg%2Facess2.git diff --git a/Modules/IPStack/udp.c b/Modules/IPStack/udp.c index fe13a3e1..c1dbe924 100644 --- a/Modules/IPStack/udp.c +++ b/Modules/IPStack/udp.c @@ -11,10 +11,12 @@ // === PROTOTYPES === void UDP_Initialise(); void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer); +void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer); +void UDP_SendPacket(tUDPChannel *Channel, void *Data, size_t Length); // --- Listening Server tVFS_Node *UDP_Server_Init(tInterface *Interface); char *UDP_Server_ReadDir(tVFS_Node *Node, int ID); -tVFS_Node UDP_Server_FindDir(tVFS_Node *Node, char *Name); +tVFS_Node *UDP_Server_FindDir(tVFS_Node *Node, const char *Name); int UDP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data); void UDP_Server_Close(tVFS_Node *Node); // --- Client Channels @@ -29,11 +31,16 @@ Uint16 UDP_int_AllocatePort(); void UDP_int_FreePort(Uint16 Port); // === GLOBALS === -tSpinlock glUDP_Channels; +tMutex glUDP_Servers; +tUDPServer *gpUDP_Servers; + +tMutex glUDP_Channels; tUDPChannel *gpUDP_Channels; -tSpinlock glUDP_Ports; + +tMutex glUDP_Ports; Uint32 gUDP_Ports[0x10000/32]; -//tSocketFile gUDP_ServerFile = {NULL, "udps", UDP_Server_Init}; + +tSocketFile gUDP_ServerFile = {NULL, "udps", UDP_Server_Init}; tSocketFile gUDP_ClientFile = {NULL, "udpc", UDP_Channel_Init}; // === CODE === @@ -43,29 +50,24 @@ tSocketFile gUDP_ClientFile = {NULL, "udpc", UDP_Channel_Init}; */ void UDP_Initialise() { + IPStack_AddFile(&gUDP_ServerFile); IPStack_AddFile(&gUDP_ClientFile); + //IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_Unreachable); IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket); } /** - * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer) - * \brief Handles a packet from the IP Layer + * \brief Scan a list of tUDPChannels and find process the first match + * \return 0 if no match was found, -1 on error and 1 if a match was found */ -void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer) +int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer) { tUDPHeader *hdr = Buffer; tUDPChannel *chan; tUDPPacket *pack; int len; - Log("[UDP ] hdr->SourcePort = %i", ntohs(hdr->SourcePort)); - Log("[UDP ] hdr->DestPort = %i", ntohs(hdr->DestPort)); - Log("[UDP ] hdr->Length = %i", ntohs(hdr->Length)); - Log("[UDP ] hdr->Checksum = 0x%x", ntohs(hdr->Checksum)); - - // Check registered connections - LOCK(&glUDP_Channels); - for(chan = gpUDP_Channels; + for(chan = List; chan; chan = chan->Next) { @@ -74,17 +76,18 @@ void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe if(chan->RemotePort != ntohs(hdr->SourcePort)) continue; if(Interface->Type == 4) { - if(IP4_EQU(chan->RemoteAddr.v4, *(tIPv4*)Address)) continue; + if(!IP4_EQU(chan->RemoteAddr.v4, *(tIPv4*)Address)) continue; } else if(Interface->Type == 6) { - if(IP6_EQU(chan->RemoteAddr.v6, *(tIPv6*)Address)) continue; + if(!IP6_EQU(chan->RemoteAddr.v6, *(tIPv6*)Address)) continue; } else { Warning("[UDP ] Address type %i unknown", Interface->Type); - RELEASE(&glUDP_Channels); - return ; + Mutex_Release(&glUDP_Channels); + return -1; } + Log("[UDP ] Recieved packet for %p", chan); // Create the cached packet len = ntohs(hdr->Length); pack = malloc(sizeof(tUDPPacket) + len); @@ -93,19 +96,65 @@ void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffe memcpy(pack->Data, hdr->Data, len); // Add the packet to the channel's queue - LOCK(&chan->lQueue); + SHORTLOCK(&chan->lQueue); if(chan->Queue) chan->QueueEnd->Next = pack; else chan->QueueEnd = chan->Queue = pack; - RELEASE(&chan->lQueue); - RELEASE(&glUDP_Channels); - return ; + SHORTREL(&chan->lQueue); + Mutex_Release(&glUDP_Channels); + return 1; } + return 0; +} + +/** + * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer) + * \brief Handles a packet from the IP Layer + */ +void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer) +{ + tUDPHeader *hdr = Buffer; + tUDPServer *srv; + int ret; + + Log("[UDP ] hdr->SourcePort = %i", ntohs(hdr->SourcePort)); + Log("[UDP ] hdr->DestPort = %i", ntohs(hdr->DestPort)); + Log("[UDP ] hdr->Length = %i", ntohs(hdr->Length)); + Log("[UDP ] hdr->Checksum = 0x%x", ntohs(hdr->Checksum)); + + // Check registered connections + Mutex_Acquire(&glUDP_Channels); + ret = UDP_int_ScanList(gpUDP_Channels, Interface, Address, Length, Buffer); + Mutex_Release(&glUDP_Channels); + if(ret != 0) return ; + // TODO: Server/Listener + Mutex_Acquire(&glUDP_Servers); + for(srv = gpUDP_Servers; + srv; + srv = srv->Next) + { + if(srv->Interface != Interface) continue; + if(srv->ListenPort != ntohs(hdr->DestPort)) continue; + ret = UDP_int_ScanList(srv->Channels, Interface, Address, Length, Buffer); + if(ret != 0) break; + + // Add connection + Warning("[UDP ] TODO - Add channel on connection"); + //TODO + } + Mutex_Release(&glUDP_Servers); + +} + +/** + * \brief Handle an ICMP Unrechable Error + */ +void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer) +{ - RELEASE(&glUDP_Channels); } /** @@ -136,6 +185,184 @@ void UDP_SendPacket(tUDPChannel *Channel, void *Data, size_t Length) } } +// --- Listening Server +tVFS_Node *UDP_Server_Init(tInterface *Interface) +{ + tUDPServer *new; + new = calloc( sizeof(tUDPServer), 1 ); + if(!new) return NULL; + + new->Node.ImplPtr = new; + new->Node.Flags = VFS_FFLAG_DIRECTORY; + new->Node.NumACLs = 1; + new->Node.ACLs = &gVFS_ACL_EveryoneRX; + new->Node.ReadDir = UDP_Server_ReadDir; + new->Node.FindDir = UDP_Server_FindDir; + new->Node.IOCtl = UDP_Server_IOCtl; + new->Node.Close = UDP_Server_Close; + + Mutex_Acquire(&glUDP_Servers); + new->Next = gpUDP_Servers; + gpUDP_Servers = new; + Mutex_Release(&glUDP_Servers); + + return &new->Node; +} + +/** + * \brief Wait for a connection and return its ID in a string + */ +char *UDP_Server_ReadDir(tVFS_Node *Node, int ID) +{ + tUDPServer *srv = Node->ImplPtr; + tUDPChannel *chan; + char *ret; + + if( srv->ListenPort == 0 ) return NULL; + + // Lock (so another thread can't collide with us here) and wait for a connection + Mutex_Acquire( &srv->Lock ); + while( srv->NewChannels == NULL ) Threads_Yield(); + // Pop the connection off the new list + chan = srv->NewChannels; + srv->NewChannels = chan->Next; + // Release the lock + Mutex_Release( &srv->Lock ); + + // Create the ID string and return it + ret = malloc(11+1); + sprintf(ret, "%i", chan->Node.ImplInt); + + return ret; +} + +/** + * \brief Take a string and find the channel + */ +tVFS_Node *UDP_Server_FindDir(tVFS_Node *Node, const char *Name) +{ + tUDPServer *srv = Node->ImplPtr; + tUDPChannel *chan; + int id = atoi(Name); + + for(chan = srv->Channels; + chan; + chan = chan->Next) + { + if( chan->Node.ImplInt < id ) continue; + if( chan->Node.ImplInt > id ) break; // Go sorted lists! + + return &chan->Node; + } + + return NULL; +} + +/** + * \brief Names for server IOCtl Calls + */ +static const char *casIOCtls_Server[] = { + DRV_IOCTLNAMES, + "getset_listenport", + NULL + }; +/** + * \brief Channel IOCtls + */ +int UDP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data) +{ + tUDPServer *srv = Node->ImplPtr; + + ENTER("pNode iID pData", Node, ID, Data); + switch(ID) + { + BASE_IOCTLS(DRV_TYPE_MISC, "UDP Server", 0x100, casIOCtls_Server); + + case 4: // getset_localport (returns bool success) + if(!Data) LEAVE_RET('i', srv->ListenPort); + if(!CheckMem( Data, sizeof(Uint16) ) ) { + LOG("Invalid pointer %p", Data); + LEAVE_RET('i', -1); + } + // Set port + srv->ListenPort = *(Uint16*)Data; + // Permissions check (Ports lower than 1024 are root-only) + if(srv->ListenPort != 0 && srv->ListenPort < 1024) { + if( Threads_GetUID() != 0 ) { + LOG("Attempt by non-superuser to listen on port %i", srv->ListenPort); + srv->ListenPort = 0; + LEAVE_RET('i', -1); + } + } + // Allocate a random port if requested + if( srv->ListenPort == 0 ) + srv->ListenPort = UDP_int_AllocatePort(); + else + { + // Else, mark the requested port as used + if( UDP_int_MarkPortAsUsed(srv->ListenPort) == 0 ) { + LOG("Port %i us currently in use", srv->ListenPort); + srv->ListenPort = 0; + LEAVE_RET('i', -1); + } + LEAVE_RET('i', 1); + } + LEAVE_RET('i', 1); + + default: + LEAVE_RET('i', -1); + } + LEAVE_RET('i', 0); +} + +void UDP_Server_Close(tVFS_Node *Node) +{ + tUDPServer *srv = Node->ImplPtr; + tUDPServer *prev; + tUDPChannel *chan; + tUDPPacket *tmp; + + + // Remove from the main list first + Mutex_Acquire(&glUDP_Servers); + if(gpUDP_Servers == srv) + gpUDP_Servers = gpUDP_Servers->Next; + else + { + for(prev = gpUDP_Servers; + prev->Next && prev->Next != srv; + prev = prev->Next); + if(!prev->Next) + Warning("[UDP ] Bookeeping Fail, server %p is not in main list", srv); + else + prev->Next = prev->Next->Next; + } + Mutex_Release(&glUDP_Servers); + + + Mutex_Acquire(&srv->Lock); + for(chan = srv->Channels; + chan; + chan = chan->Next) + { + // Clear Queue + SHORTLOCK(&chan->lQueue); + while(chan->Queue) + { + tmp = chan->Queue; + chan->Queue = tmp->Next; + free(tmp); + } + SHORTREL(&chan->lQueue); + + // Free channel structure + free(chan); + } + Mutex_Release(&srv->Lock); + + free(srv); +} + // --- Client Channels tVFS_Node *UDP_Channel_Init(tInterface *Interface) { @@ -150,10 +377,10 @@ tVFS_Node *UDP_Channel_Init(tInterface *Interface) new->Node.IOCtl = UDP_Channel_IOCtl; new->Node.Close = UDP_Channel_Close; - LOCK(&glUDP_Channels); + Mutex_Acquire(&glUDP_Channels); new->Next = gpUDP_Channels; gpUDP_Channels = new; - RELEASE(&glUDP_Channels); + Mutex_Release(&glUDP_Channels); return &new->Node; } @@ -173,15 +400,19 @@ Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buf for(;;) { - LOCK(&chan->lQueue); + VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "UDP_Channel_Read"); + SHORTLOCK(&chan->lQueue); if(chan->Queue == NULL) { - RELEASE(&chan->lQueue); + SHORTREL(&chan->lQueue); continue; } pack = chan->Queue; chan->Queue = pack->Next; - if(!chan->Queue) chan->QueueEnd = NULL; - RELEASE(&chan->lQueue); + if(!chan->Queue) { + chan->QueueEnd = NULL; + VFS_MarkAvaliable(Node, 0); // Nothing left + } + SHORTREL(&chan->lQueue); break; } @@ -294,7 +525,7 @@ void UDP_Channel_Close(tVFS_Node *Node) tUDPChannel *prev; // Remove from the main list first - LOCK(&glUDP_Channels); + Mutex_Acquire(&glUDP_Channels); if(gpUDP_Channels == chan) gpUDP_Channels = gpUDP_Channels->Next; else @@ -307,10 +538,10 @@ void UDP_Channel_Close(tVFS_Node *Node) else prev->Next = prev->Next->Next; } - RELEASE(&glUDP_Channels); + Mutex_Release(&glUDP_Channels); // Clear Queue - LOCK(&chan->lQueue); + SHORTLOCK(&chan->lQueue); while(chan->Queue) { tUDPPacket *tmp; @@ -318,7 +549,7 @@ void UDP_Channel_Close(tVFS_Node *Node) chan->Queue = tmp->Next; free(tmp); } - RELEASE(&chan->lQueue); + SHORTREL(&chan->lQueue); // Free channel structure free(chan); @@ -330,7 +561,7 @@ void UDP_Channel_Close(tVFS_Node *Node) Uint16 UDP_int_AllocatePort() { int i; - LOCK(&glUDP_Ports); + Mutex_Acquire(&glUDP_Ports); // Fast Search for( i = UDP_ALLOC_BASE; i < 0x10000; i += 32 ) if( gUDP_Ports[i/32] != 0xFFFFFFFF ) @@ -341,7 +572,7 @@ Uint16 UDP_int_AllocatePort() if( !(gUDP_Ports[i/32] & (1 << (i%32))) ) return i; } - RELEASE(&glUDP_Ports); + Mutex_Release(&glUDP_Ports); } /** @@ -350,13 +581,13 @@ Uint16 UDP_int_AllocatePort() */ int UDP_int_MarkPortAsUsed(Uint16 Port) { - LOCK(&glUDP_Ports); + Mutex_Acquire(&glUDP_Ports); if( gUDP_Ports[Port/32] & (1 << (Port%32)) ) { return 0; - RELEASE(&glUDP_Ports); + Mutex_Release(&glUDP_Ports); } gUDP_Ports[Port/32] |= 1 << (Port%32); - RELEASE(&glUDP_Ports); + Mutex_Release(&glUDP_Ports); return 1; } @@ -365,7 +596,7 @@ int UDP_int_MarkPortAsUsed(Uint16 Port) */ void UDP_int_FreePort(Uint16 Port) { - LOCK(&glUDP_Ports); + Mutex_Acquire(&glUDP_Ports); gUDP_Ports[Port/32] &= ~(1 << (Port%32)); - RELEASE(&glUDP_Ports); + Mutex_Release(&glUDP_Ports); }