/** Adds a GGEP block with the specified alternate locations to the output stream. */ static void addGGEP(OutputStream out, GGEPContainer ggep) throws IOException { if (ggep == null || (ggep.locations.size() == 0 && ggep.createTime <= 0)) throw new NullPointerException("null or empty locations"); GGEP info = new GGEP(); if (ggep.locations.size() > 0) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { for (Iterator i = ggep.locations.iterator(); i.hasNext(); ) { try { Endpoint ep = (Endpoint) i.next(); baos.write(ep.getHostBytes()); ByteOrder.short2leb((short) ep.getPort(), baos); } catch (UnknownHostException uhe) { continue; } } } catch (IOException impossible) { ErrorService.error(impossible); } info.put(GGEP.GGEP_HEADER_ALTS, baos.toByteArray()); } if (ggep.createTime > 0) info.put(GGEP.GGEP_HEADER_CREATE_TIME, ggep.createTime / 1000); info.write(out); }
/** * @requires this and other have dotted-quad addresses, or names that can be resolved. * @effects Returns true if this is on the same subnet as 'other', i.e., if this and other are in * the same IP class and have the same network number. */ public boolean isSameSubnet(Endpoint other) { byte[] a; byte[] b; int first; try { a = getHostBytes(); first = ByteOrder.ubyte2int(a[0]); b = other.getHostBytes(); } catch (UnknownHostException e) { return false; } // See http://www.3com.com/nsc/501302.html // class A if (first <= 127) return a[0] == b[0]; // class B else if (first <= 191) return a[0] == b[0] && a[1] == b[1]; // class C else return a[0] == b[0] && a[1] == b[1] && a[2] == b[2]; }
/** * Parses a new ExtendedEndpoint. Strictly validates all data. For example, addresses MUST be in * dotted quad format. * * @param line a single line read from the stream * @return the endpoint constructed from the line * @exception IOException problem reading from in, e.g., EOF reached prematurely * @exception ParseException data not in proper format. Does NOT necessarily set the offset of the * exception properly. * @see write */ public static ExtendedEndpoint read(String line) throws ParseException { // Break the line into fields. Skip if badly formatted. Note that // subsequent delimiters are NOT coalesced. String[] linea = StringUtils.splitNoCoalesce(line, FIELD_SEPARATOR); if (linea.length == 0) throw new ParseException("Empty line", 0); // 1. Host and port. As a dirty trick, we use existing code in Endpoint. // Note that we strictly validate the address to work around corrupted // gnutella.net files from an earlier version boolean pureNumeric; String host; int port; try { Endpoint tmp = new Endpoint(linea[0], true); // require numeric. host = tmp.getAddress(); port = tmp.getPort(); pureNumeric = true; } catch (IllegalArgumentException e) { // Alright, pure numeric failed -- let's try constructing without // numeric & without requiring a DNS lookup. try { Endpoint tmp = new Endpoint(linea[0], false, false); host = tmp.getAddress(); port = tmp.getPort(); pureNumeric = false; } catch (IllegalArgumentException e2) { ParseException e3 = new ParseException("Couldn't extract address and port from: " + linea[0], 0); e3.initCause(e2); throw e3; } } // Build endpoint without any optional data. (We'll set it if possible // later.) ExtendedEndpoint ret = new ExtendedEndpoint(host, port, false); // 2. Average uptime (optional) if (linea.length >= 2) { try { ret.dailyUptime = Integer.parseInt(linea[1].trim()); } catch (NumberFormatException e) { } } // 3. Time of pong (optional). Do NOT use current system tome // if not set. ret.timeRecorded = DEFAULT_TIME_RECORDED; if (linea.length >= 3) { try { ret.timeRecorded = Long.parseLong(linea[2].trim()); } catch (NumberFormatException e) { } } // 4. Time of successful connects (optional) if (linea.length >= 4) { try { String times[] = StringUtils.split(linea[3], LIST_SEPARATOR); for (int i = times.length - 1; i >= 0; i--) ret.recordConnectionAttempt(ret.connectSuccesses, Long.parseLong(times[i].trim())); } catch (NumberFormatException e) { } } // 5. Time of failed connects (optional) if (linea.length >= 5) { try { String times[] = StringUtils.split(linea[4], LIST_SEPARATOR); for (int i = times.length - 1; i >= 0; i--) ret.recordConnectionAttempt(ret.connectFailures, Long.parseLong(times[i].trim())); } catch (NumberFormatException e) { } } // 6. locale of the connection (optional) if (linea.length >= 6) { ret.setClientLocale(linea[5]); } // 7. udp-host if (linea.length >= 7) { try { int i = Integer.parseInt(linea[6]); if (i >= 0) ret.udpHostCacheFailures = i; } catch (NumberFormatException nfe) { } } // validate address if numeric. if (pureNumeric && !NetworkUtils.isValidAddress(host)) throw new ParseException("invalid dotted addr: " + ret, 0); // validate that non UHC addresses were numeric. if (!ret.isUDPHostCache() && !pureNumeric) throw new ParseException("illegal non-UHC endpoint: " + ret, 0); return ret; }