package ejip123; /** UDP see RFC 768. */ public class Udp{ private static final Object mutex = new Object(); public static final int PROTOCOL = 17; /** @deprecated */ public static final int DATA = 7; // offset of data in words /** Offset of udp payload in ip packets w/o options (in 32b words). */ public static final int OFFSET = Ip.OFFSET + 2; private static int MAX_HANDLER = 0; private static UdpHandler[] list = null; private static int[] ports = null; private Udp(){ } public static void init(int handlerCnt){ MAX_HANDLER = handlerCnt <= 0 ? 4 : handlerCnt; list = new UdpHandler[MAX_HANDLER]; ports = new int[MAX_HANDLER]; } /** Adds a handler for UDP requests. @param port The port the handler wants to listens on. @param h The handler. @return true, if h gets added, false if the list is full or there is already one handler for that port. */ public static boolean addHandler(int port, UdpHandler h){ /* DONE should we check if there is already someone listening on the port? * According to the code, that calls the handler, we should. */ synchronized(mutex){ int n = -1; // search for a free place and check that the port is not taken yet for(int i = 0; i < MAX_HANDLER; ++i){ if(list[i] == null){ n = i; } else if(ports[i] == port){ return false; } } if(n >= 0){ ports[n] = port; list[n] = h; return true; } } return false; } /** Removes an UDP handler. @param port The port the handler is currently registered to. @return False, if there was no handler registered for that port. True, otherwise. */ public static boolean removeHandler(int port){ synchronized(mutex){ for(int i = 0; i < MAX_HANDLER; ++i){ if(list[i] != null){ if(ports[i] == port){ list[i] = null; return true; } } } } return false; } /* process packet and generate reply if necessary. */ static void process(Packet p, int off){ int[] buf = p.buf; int port = buf[off]; // int remPort = port>>>16; port &= 0xffff; synchronized(mutex){ for(int i = 0; i < MAX_HANDLER; ++i){ // searching for the handler registered at this port if(list[i] != null && ports[i] == port){ // a checksum of zero indicates disabled checksumming if((buf[off + 1]&0xffff) != 0){ // inject pseudo header for udp checksum into original packet // e.g. for packets w/o options: ttl, prot and ip checksum are overwritten buf[off - 1] = buf[4]; // dst ip buf[off - 2] = buf[3]; // src ip buf[off - 3] = (PROTOCOL<<16) + p.len() - (off<<2); if(Ip.chkSum(buf, off - 3, p.len() - ((off - 3)<<2)) != 0){ p.free(); // mark packet free return; } } p.setStatus(Packet.APP); list[i].request(p, off + 2); p.freeIfApp(); return; } } } Icmp.sendPortUnreachable(buf, off); p.free(); // mark packet free } /** Sends an UDP packet. Source IP and port will be chosen by the implementation. @param p The packet to be sent. The length of the packet needs to be set correctly. @param dstIp Destination IP. @param dstPort Destination port. @return true if a packet was sent to a link layer. */ public static boolean send(Packet p, int dstIp, int dstPort){ return send(p, 0, dstIp, dstPort, dstPort, true); } /** Sends an UDP packet. Source port will be chosen by the implementation. @param p The packet to be sent. The length of the packet needs to be set correctly. @param srcIp Source IP. If 0, the IP of the used interface will be used. @param dstIp Destination IP. @param dstPort Destination port. @return true if a packet was sent to a link layer. */ public static boolean send(Packet p, int srcIp, int dstIp, int dstPort){ return send(p, srcIp, dstIp, dstPort, dstPort, true); } /** Sends an UDP packet. @param p The packet to be sent. The length of the packet needs to be set correctly. @param srcIp Source IP. If 0, the IP of the used interface will be used. @param dstIp Destination IP. @param srcPort Source port. @param dstPort Destination port. @param calcChksum If true the UDP checksum will be calculated and stored in the packet, else the calculation will be skipped and the field be set to 0. @return true if a packet was sent to a link layer. */ public static boolean send(Packet p, int srcIp, int dstIp, int srcPort, int dstPort, boolean calcChksum){ if(p==null) return false; int off = Ip.OFFSET; // 1. UDP header int[] buf = p.buf; buf[off] = (srcPort<<16) + dstPort; buf[off + 1] = (p.len() - 20)<<16; if(calcChksum){ // (optional) 2. UDP pseudo header in front to calc UDP checksum if(srcIp == 0){ LinkLayer ll = Router.getIf(dstIp); if(ll == null){ p.free(); return false; } p.setLinkLayer(ll); srcIp = ll.getIp(); } buf[off - 1] = dstIp; buf[off - 2] = srcIp; buf[off - 3] = (PROTOCOL<<16) + p.len() - (off<<2); int i = Ip.chkSum(buf, off - 3, p.len() - ((off - 3)<<2)); buf[off + 1] |= (i == 0) ? 0xffff : i; // special case in UDP: no checksum -> 0, calculated checksum=0 -> 0xffff } // 3. remains of the IP header return Ip.send(p, srcIp, dstIp, PROTOCOL); } }