1 20 21 package org.jivesoftware.smack; 22 23 import org.jivesoftware.smack.filter.PacketFilter; 24 import org.jivesoftware.smack.packet.*; 25 import org.jivesoftware.smack.provider.IQProvider; 26 import org.jivesoftware.smack.provider.ProviderManager; 27 import org.jivesoftware.smack.util.PacketParserUtils; 28 import org.xmlpull.mxp1.MXParser; 29 import org.xmlpull.v1.XmlPullParser; 30 import org.xmlpull.v1.XmlPullParserException; 31 32 import java.util.*; 33 34 42 class PacketReader { 43 44 private Thread readerThread; 45 private Thread listenerThread; 46 47 private XMPPConnection connection; 48 private XmlPullParser parser; 49 private boolean done = false; 50 protected List collectors = new ArrayList(); 51 private List listeners = new ArrayList(); 52 protected List connectionListeners = new ArrayList(); 53 54 private String connectionID = null; 55 private Object connectionIDLock = new Object (); 56 57 protected PacketReader(XMPPConnection connection) { 58 this.connection = connection; 59 60 readerThread = new Thread () { 61 public void run() { 62 parsePackets(); 63 } 64 }; 65 readerThread.setName("Smack Packet Reader"); 66 readerThread.setDaemon(true); 67 68 listenerThread = new Thread () { 69 public void run() { 70 try { 71 processListeners(); 72 } 73 catch (Exception e) { 74 e.printStackTrace(); 75 } 76 } 77 }; 78 listenerThread.setName("Smack Listener Processor"); 79 listenerThread.setDaemon(true); 80 81 try { 82 parser = new MXParser(); 83 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); 84 parser.setInput(connection.reader); 85 } 86 catch (XmlPullParserException xppe) { 87 xppe.printStackTrace(); 88 } 89 } 90 91 98 public PacketCollector createPacketCollector(PacketFilter packetFilter) { 99 return new PacketCollector(this, packetFilter); 100 } 101 102 109 public void addPacketListener(PacketListener packetListener, PacketFilter packetFilter) { 110 ListenerWrapper wrapper = new ListenerWrapper(this, packetListener, 111 packetFilter); 112 synchronized (listeners) { 113 listeners.add(wrapper); 114 } 115 } 116 117 122 public void removePacketListener(PacketListener packetListener) { 123 synchronized (listeners) { 124 for (int i=0; i<listeners.size(); i++) { 125 ListenerWrapper wrapper = (ListenerWrapper)listeners.get(i); 126 if (wrapper != null && wrapper.packetListener.equals(packetListener)) { 127 listeners.set(i, null); 128 } 129 } 130 } 131 } 132 133 141 public void startup() throws XMPPException { 142 readerThread.start(); 143 listenerThread.start(); 144 try { 147 synchronized(connectionIDLock) { 148 if (connectionID == null) { 149 long waitTime = SmackConfiguration.getPacketReplyTimeout(); 154 long start = System.currentTimeMillis(); 155 while (connectionID == null && !done) { 156 if (waitTime <= 0) { 157 break; 158 } 159 connectionIDLock.wait(waitTime * 3); 161 long now = System.currentTimeMillis(); 162 waitTime -= now - start; 163 start = now; 164 } 165 } 166 } 167 } 168 catch (InterruptedException ie) { } 169 if (connectionID == null) { 170 throw new XMPPException("Connection failed. No response from server."); 171 } 172 else { 173 connection.connectionID = connectionID; 174 } 175 } 176 177 180 public void shutdown() { 181 if (!done) { 183 ArrayList listenersCopy; 184 synchronized (connectionListeners) { 185 listenersCopy = new ArrayList(connectionListeners); 187 for (Iterator i=listenersCopy.iterator(); i.hasNext(); ) { 188 ConnectionListener listener = (ConnectionListener)i.next(); 189 listener.connectionClosed(); 190 } 191 } 192 } 193 done = true; 194 } 195 196 202 void notifyConnectionError(Exception e) { 203 done = true; 204 connection.close(); 205 e.printStackTrace(); 207 ArrayList listenersCopy; 209 synchronized (connectionListeners) { 210 listenersCopy = new ArrayList(connectionListeners); 212 for (Iterator i=listenersCopy.iterator(); i.hasNext(); ) { 213 ConnectionListener listener = (ConnectionListener)i.next(); 214 listener.connectionClosedOnError(e); 215 } 216 } 217 } 218 219 224 private void resetParser() throws XmlPullParserException { 225 parser.setInput(connection.reader); 226 } 227 228 231 private void processListeners() { 232 boolean processedPacket = false; 233 while (!done) { 234 synchronized (listeners) { 235 if (listeners.size() > 0) { 236 for (int i=listeners.size()-1; i>=0; i--) { 237 if (listeners.get(i) == null) { 238 listeners.remove(i); 239 } 240 } 241 } 242 } 243 processedPacket = false; 244 int size = listeners.size(); 245 for (int i=0; i<size; i++) { 246 ListenerWrapper wrapper = (ListenerWrapper)listeners.get(i); 247 if (wrapper != null) { 248 processedPacket = processedPacket || wrapper.notifyListener(); 249 } 250 } 251 if (!processedPacket) { 252 try { 253 Thread.sleep(100); 254 } 255 catch (InterruptedException ie) { } 256 } 257 } 258 } 259 260 263 private void parsePackets() { 264 try { 265 int eventType = parser.getEventType(); 266 do { 267 if (eventType == XmlPullParser.START_TAG) { 268 if (parser.getName().equals("message")) { 269 processPacket(PacketParserUtils.parseMessage(parser)); 270 } 271 else if (parser.getName().equals("iq")) { 272 processPacket(parseIQ(parser)); 273 } 274 else if (parser.getName().equals("presence")) { 275 processPacket(PacketParserUtils.parsePresence(parser)); 276 } 277 else if (parser.getName().equals("stream")) { 280 if ("jabber:client".equals(parser.getNamespace(null))) { 282 for (int i=0; i<parser.getAttributeCount(); i++) { 284 if (parser.getAttributeName(i).equals("id")) { 285 if (("1.0".equals(parser.getAttributeValue("", "version")) && 286 connection.isUsingTLS()) || (!"1.0".equals( 287 parser.getAttributeValue("", "version")))) { 288 synchronized(connectionIDLock) { 292 connectionID = parser.getAttributeValue(i); 293 connectionIDLock.notifyAll(); 294 } 295 } 296 } 297 else if (parser.getAttributeName(i).equals("from")) { 298 connection.serviceName = parser.getAttributeValue(i); 300 } 301 } 302 } 303 } 304 else if (parser.getName().equals("features")) { 305 parseFeatures(parser); 306 } 307 else if (parser.getName().equals("proceed")) { 308 connection.proceedTLSReceived(); 310 resetParser(); 313 } 314 else if (parser.getName().equals("failure")) { 315 throw new Exception ("TLS negotiation has failed"); 317 } 318 else if (parser.getName().equals("challenge")) { 319 connection.getSASLAuthentication().challengeReceived(parser.nextText()); 321 } 322 else if (parser.getName().equals("success")) { 323 connection.getSASLAuthentication().authenticated(); 326 resetParser(); 329 } 330 } 331 else if (eventType == XmlPullParser.END_TAG) { 332 if (parser.getName().equals("stream")) { 333 connection.close(); 335 } 336 } 337 eventType = parser.next(); 338 } while (!done && eventType != XmlPullParser.END_DOCUMENT); 339 } 340 catch (Exception e) { 341 if (!done) { 342 notifyConnectionError(e); 345 } 346 } 347 } 348 349 356 private void processPacket(Packet packet) { 357 if (packet == null) { 358 return; 359 } 360 361 synchronized (collectors) { 363 for (int i=collectors.size()-1; i>=0; i--) { 364 if (collectors.get(i) == null) { 365 collectors.remove(i); 366 } 367 } 368 } 369 370 int size = collectors.size(); 372 for (int i=0; i<size; i++) { 373 PacketCollector collector = (PacketCollector)collectors.get(i); 374 if (collector != null) { 375 collector.processPacket(packet); 377 } 378 } 379 } 380 381 private void parseFeatures(XmlPullParser parser) throws Exception { 382 boolean done = false; 383 while (!done) { 384 int eventType = parser.next(); 385 386 if (eventType == XmlPullParser.START_TAG) { 387 if (parser.getName().equals("starttls")) { 388 connection.startTLSReceived(); 390 } 391 else if (parser.getName().equals("mechanisms") && connection.isUsingTLS()) { 392 connection.getSASLAuthentication() 396 .setAvailableSASLMethods(parseMechanisms(parser)); 397 } 398 else if (parser.getName().equals("bind")) { 399 connection.getSASLAuthentication().bindingRequired(); 401 } 402 else if (parser.getName().equals("session")) { 403 connection.getSASLAuthentication().sessionsSupported(); 405 } 406 } 407 else if (eventType == XmlPullParser.END_TAG) { 408 if (parser.getName().equals("features")) { 409 done = true; 410 } 411 } 412 } 413 } 414 415 422 private Collection parseMechanisms(XmlPullParser parser) throws Exception { 423 List mechanisms = new ArrayList(); 424 boolean done = false; 425 while (!done) { 426 int eventType = parser.next(); 427 428 if (eventType == XmlPullParser.START_TAG) { 429 String elementName = parser.getName(); 430 if (elementName.equals("mechanism")) { 431 mechanisms.add(parser.nextText()); 432 } 433 } 434 else if (eventType == XmlPullParser.END_TAG) { 435 if (parser.getName().equals("mechanisms")) { 436 done = true; 437 } 438 } 439 } 440 return mechanisms; 441 } 442 443 450 private IQ parseIQ(XmlPullParser parser) throws Exception { 451 IQ iqPacket = null; 452 453 String id = parser.getAttributeValue("", "id"); 454 String to = parser.getAttributeValue("", "to"); 455 String from = parser.getAttributeValue("", "from"); 456 IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type")); 457 XMPPError error = null; 458 459 boolean done = false; 460 while (!done) { 461 int eventType = parser.next(); 462 463 if (eventType == XmlPullParser.START_TAG) { 464 String elementName = parser.getName(); 465 String namespace = parser.getNamespace(); 466 if (elementName.equals("error")) { 467 error = PacketParserUtils.parseError(parser); 468 } 469 else if (elementName.equals("query") && namespace.equals("jabber:iq:auth")) { 470 iqPacket = parseAuthentication(parser); 471 } 472 else if (elementName.equals("query") && namespace.equals("jabber:iq:roster")) { 473 iqPacket = parseRoster(parser); 474 } 475 else if (elementName.equals("query") && namespace.equals("jabber:iq:register")) { 476 iqPacket = parseRegistration(parser); 477 } 478 else { 481 Object provider = ProviderManager.getIQProvider(elementName, namespace); 482 if (provider != null) { 483 if (provider instanceof IQProvider) { 484 iqPacket = ((IQProvider)provider).parseIQ(parser); 485 } 486 else if (provider instanceof Class ) { 487 iqPacket = (IQ)PacketParserUtils.parseWithIntrospection(elementName, 488 (Class )provider, parser); 489 } 490 } 491 } 492 } 493 else if (eventType == XmlPullParser.END_TAG) { 494 if (parser.getName().equals("iq")) { 495 done = true; 496 } 497 } 498 } 499 if (iqPacket == null) { 501 if (IQ.Type.GET == type || IQ.Type.SET == type ) { 502 iqPacket = new IQ() { 506 public String getChildElementXML() { 507 return null; 508 } 509 }; 510 iqPacket.setPacketID(id); 511 iqPacket.setTo(from); 512 iqPacket.setFrom(to); 513 iqPacket.setType(IQ.Type.ERROR); 514 iqPacket.setError(new XMPPError(501, "feature-not-implemented")); 515 connection.sendPacket(iqPacket); 516 return null; 517 } 518 else { 519 iqPacket = new IQ() { 521 public String getChildElementXML() { 522 return null; 523 } 524 }; 525 } 526 } 527 528 iqPacket.setPacketID(id); 530 iqPacket.setTo(to); 531 iqPacket.setFrom(from); 532 iqPacket.setType(type); 533 iqPacket.setError(error); 534 535 return iqPacket; 536 } 537 538 private Authentication parseAuthentication(XmlPullParser parser) throws Exception { 539 Authentication authentication = new Authentication(); 540 boolean done = false; 541 while (!done) { 542 int eventType = parser.next(); 543 if (eventType == XmlPullParser.START_TAG) { 544 if (parser.getName().equals("username")) { 545 authentication.setUsername(parser.nextText()); 546 } 547 else if (parser.getName().equals("password")) { 548 authentication.setPassword(parser.nextText()); 549 } 550 else if (parser.getName().equals("digest")) { 551 authentication.setDigest(parser.nextText()); 552 } 553 else if (parser.getName().equals("resource")) { 554 authentication.setResource(parser.nextText()); 555 } 556 } 557 else if (eventType == XmlPullParser.END_TAG) { 558 if (parser.getName().equals("query")) { 559 done = true; 560 } 561 } 562 } 563 return authentication; 564 } 565 566 private RosterPacket parseRoster(XmlPullParser parser) throws Exception { 567 RosterPacket roster = new RosterPacket(); 568 boolean done = false; 569 RosterPacket.Item item = null; 570 while (!done) { 571 int eventType = parser.next(); 572 if (eventType == XmlPullParser.START_TAG) { 573 if (parser.getName().equals("item")) { 574 String jid = parser.getAttributeValue("", "jid"); 575 String name = parser.getAttributeValue("", "name"); 576 item = new RosterPacket.Item(jid, name); 578 String ask = parser.getAttributeValue("", "ask"); 580 RosterPacket.ItemStatus status = RosterPacket.ItemStatus.fromString(ask); 581 item.setItemStatus(status); 582 String subscription = parser.getAttributeValue("", "subscription"); 584 RosterPacket.ItemType type = RosterPacket.ItemType.fromString(subscription); 585 item.setItemType(type); 586 } 587 if (parser.getName().equals("group")) { 588 String groupName = parser.nextText(); 589 item.addGroupName(groupName); 590 } 591 } 592 else if (eventType == XmlPullParser.END_TAG) { 593 if (parser.getName().equals("item")) { 594 roster.addRosterItem(item); 595 } 596 if (parser.getName().equals("query")) { 597 done = true; 598 } 599 } 600 } 601 return roster; 602 } 603 604 private Registration parseRegistration(XmlPullParser parser) throws Exception { 605 Registration registration = new Registration(); 606 Map fields = null; 607 boolean done = false; 608 while (!done) { 609 int eventType = parser.next(); 610 if (eventType == XmlPullParser.START_TAG) { 611 if (parser.getNamespace().equals("jabber:iq:register")) { 614 String name = parser.getName(); 615 String value = ""; 616 if (fields == null) { 617 fields = new HashMap(); 618 } 619 620 if (parser.next() == XmlPullParser.TEXT) { 621 value = parser.getText(); 622 } 623 if (!name.equals("instructions")) { 625 fields.put(name, value); 626 } 627 else { 628 registration.setInstructions(value); 629 } 630 } 631 else { 633 registration.addExtension( 634 PacketParserUtils.parsePacketExtension( 635 parser.getName(), 636 parser.getNamespace(), 637 parser)); 638 } 639 } 640 else if (eventType == XmlPullParser.END_TAG) { 641 if (parser.getName().equals("query")) { 642 done = true; 643 } 644 } 645 } 646 registration.setAttributes(fields); 647 return registration; 648 } 649 650 653 private static class ListenerWrapper { 654 655 private PacketListener packetListener; 656 private PacketCollector packetCollector; 657 658 public ListenerWrapper(PacketReader packetReader, PacketListener packetListener, 659 PacketFilter packetFilter) 660 { 661 this.packetListener = packetListener; 662 this.packetCollector = new PacketCollector(packetReader, packetFilter); 663 } 664 665 public boolean equals(Object object) { 666 if (object == null) { 667 return false; 668 } 669 if (object instanceof ListenerWrapper) { 670 return ((ListenerWrapper)object).packetListener.equals(this.packetListener); 671 } 672 else if (object instanceof PacketListener) { 673 return object.equals(this.packetListener); 674 } 675 return false; 676 } 677 678 public boolean notifyListener() { 679 Packet packet = packetCollector.pollResult(); 680 if (packet != null) { 681 packetListener.processPacket(packet); 682 return true; 683 } 684 else { 685 return false; 686 } 687 } 688 689 public void cancel() { 690 packetCollector.cancel(); 691 packetCollector = null; 692 packetListener = null; 693 } 694 } 695 } | Popular Tags |