📄 ppg.java
字号:
package push;import javax.servlet.*;import javax.servlet.http.*;import java.net.*;import java.io.*;import java.util.StringTokenizer;/** * <code>PPG</code> class implements some push proxy gateway (PPG) functionality for * the purposes of this example only. This simple PPG is targeted to be used in * conjunction with WAP toolkit, and IPv4 type client addressing. * */public final class PPG extends HttpServlet { /* xml version */ private final static String XML_VERSION = "<?xml version=\"1.0\"?>"; /* Push Access Protocol (PAP) document type */ private final static String PAP_DOCTYPE = "<!DOCTYPE pap PUBLIC \"-//WAPFORUM//DTD PAP 1.0//EN\" \"http://www.wapforum.org/DTD/pap_1.0.dtd\" >"; /* content type of the push request multipart body */ private final static String CONTENT_TYPE = "multipart/related; boundary=multipart-boundary; type=\"application/xml\""; /* WAP Push connection less service (client side). The registered port number. */ private static final int connectionlessPushPort = 2948; private static int transactionId = 0; /** * <code>doPost</code> * * @param request a <code>HttpServletRequest</code> value * @param response a <code>HttpServletResponse</code> value * @exception ServletException if an error occurs * @exception IOException if an error occurs */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String clientAddress = null; String pushId = null; int resultCode = 1001; // accepted for processing try { // first, check the content type which should be "multipart/related" String contentType = request.getHeader("content-type"); StringTokenizer st = new StringTokenizer(contentType, ";"); String token = st.nextToken(); String boundary = null; if(!token.equalsIgnoreCase("multipart/related")) throw new Exception("wrong content type"); // finds the boundary string while(st.hasMoreTokens()) { token = st.nextToken().trim(); if(token.startsWith("boundary=")) { boundary = token.substring(9); break; } } if(boundary == null) throw new Exception("no multipart boundary"); boundary = "--" + boundary; String endBoundary = boundary + "--"; StringBuffer messageContent = new StringBuffer(); BufferedReader in = request.getReader(); String line; int i=0; boolean startContent = false; System.out.println("boundary=" + boundary); // extract message content part while((line = in.readLine()) != null) { if(line.equals(boundary)) ++i; else if(line.equals(endBoundary)) break; if(i == 1) { // PAP control entity int j = line.indexOf("address-value="); if(j >= 0) { clientAddress = line.substring(j+15, line.indexOf('"', j+17)); } j = line.indexOf("push-id="); if(j >= 0) { pushId = line.substring(j+9, line.indexOf('"', j+11)); } } else if(i == 2) { // PAP content entity if(startContent) messageContent.append(line); else if(line.trim().equals("")) // end of headers startContent = true; else if(line.toLowerCase().startsWith("content-type:")) contentType = line.substring(13).trim(); } } if((i = clientAddress.indexOf("/TYPE=IPv4")) == -1) { resultCode = 2002; // address error throw new Exception("This PPG can handle only IPv4 type addresses"); } clientAddress = clientAddress.substring(clientAddress.indexOf("WAPPUSH=")+8, i); if(clientAddress == null) { resultCode = 2002; // address error throw new Exception("Client address is not known"); } System.out.println("clientAddress: " + clientAddress); System.out.println("pushId: " + pushId); System.out.println("message content: " + messageContent); unitPushRequest(clientAddress, messageContent.toString().trim(), contentType); } catch (Exception e) { System.err.println(e); if(resultCode < 2000) resultCode = 2000; // bad message } // start writing the result response.setStatus(202); // accepted response.setContentType("application/xml"); PrintWriter out = response.getWriter(); out.println(XML_VERSION); out.println(PAP_DOCTYPE); out.println("<pap product-name=\"MobileZoo PPG\">"); out.println(" <push-response push-id=\"" + pushId + "\">"); out.println(" <response result"); out.println(" code=\"" + resultCode + "\""); out.println(" desc=\"" + resultCodeDesc(resultCode) + "\">"); out.println(" </response-result>"); out.println(" </push-response>"); out.println("</pap>"); } /** * Returns description of a PAP result response code * * @param code an <code>int</code> value * @return a <code>String</code> value */ private static String resultCodeDesc(int code) { switch(code) { case 1001: return "Accepted for Processing"; case 2000: return "Bad Request"; case 2002: return "Address Error"; } return "Unknown result code"; } /** * <code>unitPushRequest</code> generates a connectionless mode Push request * * @param clientAddress a <code>String</code> value * @param messageContent a <code>String</code> value * @param contentType a <code>String</code> value * @exception Exception if an error occurs */ private void unitPushRequest(String clientAddress, String messageContent, String contentType) throws Exception { ByteArrayOutputStream content = new ByteArrayOutputStream(); contentType = encodeContent(messageContent, content, contentType); int wspContentType = encodeContentType(contentType); transactionId %= 127; byte[] wspPdu = wspPduPUSH(transactionId++, wspContentType, content.toByteArray()); sendData(clientAddress, connectionlessPushPort, wspPdu, wspPdu.length); } /** * A simplified "WBXML encoder". * It handles only SI content type, and only href attribute within * SI content (others ignored). * No well-formedness nor validity checks are performed during the encoding. * * @param messageContent a <code>String</code> value * @param content a <code>ByteArrayOutputStream</code> value * @param contentType a <code>String</code> value * @return a <code>String</code> value */ private static String encodeContent(String messageContent, ByteArrayOutputStream content, String contentType) throws Exception { if(contentType.startsWith("text/vnd.wap.si")) { int i = messageContent.indexOf("href=\"http://"); if(i > 0) { try { final byte[] bytes1 = { 0x0, 0x5, 0x4, 0x0, 0x45, (byte)0xc6, 0xc, 0x3 }; final byte[] bytes2 = { 0x0, 0x7, 0x1, 0x3 }; final byte[] bytes3 = { 0x0, 0x1, 0x1}; String href = messageContent.substring(i+13, messageContent.indexOf("\"", i+14)); String message = messageContent.substring(messageContent.indexOf(">", i+15)+1, messageContent.indexOf("</indication>", i+16)); content.write(bytes1); content.write(href.getBytes()); content.write(bytes2); content.write(message.trim().getBytes()); content.write(bytes3); return "application/vnd.wap.sic"; } catch (Exception e) { content.reset(); } } } content.write(messageContent.getBytes()); return contentType; } /** * <code>encodeContentType</code> encodes mime type (cf. WSP specification WAP-203-WSP 4-May-2000) * * @param contentType a <code>String</code> value * @return an <code>int</code> value */ private static int encodeContentType(String contentType) throws Exception { contentType = contentType.toLowerCase(); if(contentType.startsWith("text/vnd.wap.wml")) return 0x88; else if(contentType.startsWith("text/vnd.wap.si")) return 0xAD; else if(contentType.startsWith("text/vnd.wap.sl")) return 0xAF; else if(contentType.startsWith("application/vnd.wap.wmlc")) return 0x94; else if(contentType.startsWith("application/vnd.wap.sic")) return 0xAE; else if(contentType.startsWith("applicavtion/vnd.wap.slc")) return 0xB0; throw new Exception("unsupported content type:" + contentType); } // WSP PDU Type Assigments // Table 34 (page 94) in WSP specification WAP-203-WSP 4-May-2000 private static final int WSP_PUSH = 0x06; /** * Generate WSP PUSH PDU (note: only partial functionality provided) * * @param tid an <code>int</code> value * @param contentType an <code>int</code> value * @param content a <code>byte[]</code> value * @return a <code>byte[]</code> value * @exception Exception if an error occurs */ private static byte[] wspPduPUSH(int tid, int contentType, byte[] content) throws Exception { ByteArrayOutputStream data = new ByteArrayOutputStream(); data.write(tid); data.write(WSP_PUSH); data.write(1); // contenttype size + headers size data.write(contentType); data.write(content); return data.toByteArray(); } /** * <code>sendData</code> sends data to given address and port using UDP datagram socket * * @param addressStr a <code>String</code> value * @param port an <code>int</code> value * @param data a <code>byte[]</code> value * @param dataSize an <code>int</code> value * @return an <code>int</code> value * @exception Exception if an error occurs */ private static int sendData(String addressStr, int port, final byte[] data, int dataSize) throws Exception { if(dataSize <= 0) return 0; InetAddress addr = InetAddress.getByName(addressStr); System.out.println("sendData addr = " + addr.getHostAddress() + "; port = " + port + "; data_size = " + dataSize); DatagramSocket s = new DatagramSocket(); // s.setSoTimeout(1000); DatagramPacket packet = new DatagramPacket(data, dataSize, addr, port); s.send(packet); int nBytes = packet.getLength(); if(dataSize != nBytes) System.err.println("warning: not all bytes of a datagram are sent to socket!?"); s.close(); return nBytes; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -