001: /*
002: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
003: * Reserved. Use is subject to license terms.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: /*
026: */
027: package gov.nist.siplite.header;
028:
029: import gov.nist.siplite.parser.*;
030: import gov.nist.core.*;
031:
032: /**
033: * Via Header (these are strung together in a ViaList).
034: *
035: * @version JAIN-SIP-1.1
036: *
037: *
038: * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
039: *
040: */
041: public class ViaHeader extends gov.nist.siplite.header.ParametersHeader {
042: /** Class handle. */
043: public static Class clazz;
044: /** Via header field label. */
045: public static final String NAME = Header.VIA;
046:
047: /**
048: * The branch parameter is included by every forking proxy.
049: */
050: public static final String BRANCH = "branch";
051:
052: /**
053: * The "hidden" paramter is included if this header field
054: * was hidden by the upstream proxy.
055: */
056: public static final String HIDDEN = "hidden";
057:
058: /**
059: * The "received" parameter is added only for receiver-added Via Fields.
060: */
061: public static final String RECEIVED = "received";
062:
063: /**
064: * The "maddr" parameter is designating the multicast address.
065: */
066: public static final String MADDR = "maddr";
067:
068: /**
069: * The "TTL" parameter is designating the time-to-live value.
070: */
071: public static final String TTL = "ttl";
072:
073: /**
074: * Sent protocol field.
075: */
076: protected Protocol sentProtocol;
077:
078: /**
079: * Sent by field.
080: */
081: protected HostPort sentBy;
082:
083: /**
084: * Comment field.
085: */
086: protected String comment;
087:
088: static {
089: clazz = new ViaHeader().getClass();
090: }
091:
092: /**
093: * Default constructor.
094: */
095: public ViaHeader() {
096: super (VIA);
097: this .sentBy = new HostPort();
098:
099: sentProtocol = new Protocol();
100: }
101:
102: /**
103: * Compares two via headers for equaltiy.
104: * @param other Object to set.
105: * @return true if the two via headers are the same.
106: */
107: public boolean equals(Object other) {
108: if (!this .getClass().equals(other.getClass())) {
109: return false;
110: }
111:
112: ViaHeader that = (ViaHeader) other;
113:
114: if (!this .sentProtocol.equals(that.sentProtocol)) {
115: return false;
116: }
117:
118: if (!this .parameters.equals(that.parameters)) {
119: return false;
120: }
121:
122: if (!this .sentBy.equals(that.sentBy)) {
123: return false;
124: }
125:
126: return true;
127: }
128:
129: /**
130: * Encodes the via header into a cannonical string.
131: * @return String containing cannonical encoding of via header.
132: */
133: public String encodeBody() {
134: String encoding = "";
135: encoding += sentProtocol.encode() + Separators.SP
136: + sentBy.encode();
137:
138: // Add the default port if there is no port specified.
139: if (!sentBy.hasPort())
140: encoding += Separators.COLON + "5060";
141:
142: if (comment != null) {
143: encoding += Separators.LPAREN + comment + Separators.RPAREN;
144: }
145:
146: encoding += encodeWithSep();
147:
148: return encoding;
149: }
150:
151: /**
152: * Gets the Protocol Version.
153: * @return String
154: */
155: public String getProtocolVersion() {
156: if (sentProtocol == null)
157: return null;
158: else
159: return sentProtocol.getProtocolVersion();
160: }
161:
162: /**
163: * Accessor for the sentProtocol field.
164: * @return Protocol field
165: */
166: public Protocol getSentProtocol() {
167:
168: return sentProtocol;
169: }
170:
171: /**
172: * Accessor for the sentBy field
173: * @return SentBy field
174: */
175: public HostPort getSentBy() {
176: return sentBy;
177: }
178:
179: /**
180: * Gest the host name. (null if not yet set).
181: * @return host name from the via header.
182: */
183: public String getHost() {
184: if (sentBy == null)
185: return null;
186: else {
187: Host host = sentBy.getHost();
188: if (host == null)
189: return null;
190: else
191: return host.getHostname();
192: }
193: }
194:
195: /**
196: * Port of the Via header.
197: * @return port field.
198: */
199: public int getPort() {
200: if (sentBy == null)
201: return -1;
202: return sentBy.getPort();
203: }
204:
205: /**
206: * Port of the Via Header.
207: * @return true if Port exists.
208: */
209: public boolean hasPort() {
210: if (sentBy == null)
211: return false;
212: return (getSentBy()).hasPort();
213: }
214:
215: /**
216: * Accessor for the comment field.
217: * @return comment field.
218: */
219: public String getComment() {
220: return comment;
221: }
222:
223: /**
224: * Gets the Branch parameter if it exists.
225: * @return Branch field.
226: */
227: public String getBranch() {
228: return super .getParameter(ViaHeader.BRANCH);
229: }
230:
231: /**
232: * Gets the received parameter if it exists.
233: * @return received parameter.
234: */
235: public String getReceived() {
236: return super .getParameter(ViaHeader.RECEIVED);
237:
238: }
239:
240: /**
241: * Gets the maddr parameter if it exists.
242: * @return maddr parameter.
243: */
244: public String getMaddr() {
245: return super .getParameter(ViaHeader.MADDR);
246:
247: }
248:
249: /**
250: * get the ttl parameter if it exists.
251: * @return ttl parameter.
252: */
253: public String getTTL() {
254: return super .getParameter(ViaHeader.TTL);
255: }
256:
257: /**
258: * Comment of the Via Header.
259: *
260: * @return false if comment does not exist and true otherwise.
261: */
262: public boolean hasComment() {
263: return comment != null;
264: }
265:
266: /**
267: * Removes the comment field.
268: */
269: public void removeComment() {
270: comment = null;
271: }
272:
273: /**
274: * Sets the Protocol Version.
275: *
276: * BNF (RFC3261, p. 222, 232):
277: * protocol-version = token
278: *
279: * @param protocolVersion String to set
280: */
281: public void setProtocolVersion(String protocolVersion) {
282: if (sentProtocol == null)
283: sentProtocol = new Protocol();
284: sentProtocol.setProtocolVersion(protocolVersion);
285: }
286:
287: /**
288: * Sets the sentProtocol member
289: * @param s Protocol to set.
290: */
291: public void setSentProtocol(Protocol s) {
292: sentProtocol = s;
293: }
294:
295: /**
296: * Sets the transport string.
297: *
298: * BNF (RFC3261, p. 222, 232):
299: * transport = "UDP" / "TCP" / "TLS" / "SCTP" / other-transport
300: *
301: * @param transport String to set
302: */
303: public void setTransport(String transport) {
304: if (sentProtocol == null)
305: sentProtocol = new Protocol();
306: sentProtocol.setTransport(transport);
307: }
308:
309: /**
310: * Sets the sentBy member
311: * @param s HostPort to set.
312: */
313: public void setSentBy(HostPort s) {
314: sentBy = s;
315: }
316:
317: /**
318: * Sets the comment member
319: * @param c String to set.
320: */
321: public void setComment(String c) {
322: comment = c;
323: }
324:
325: /**
326: * Clone - do a deep copy.
327: * @return Object Via
328: */
329: public Object clone() {
330: ViaHeader retval = new ViaHeader();
331:
332: if (this .comment != null)
333: retval.comment = new String(this .comment);
334: if (this .parameters != null)
335: retval.parameters = (NameValueList) parameters.clone();
336: if (this .sentBy != null)
337: retval.sentBy = (HostPort) sentBy.clone();
338: if (this .sentProtocol != null)
339: retval.sentProtocol = (Protocol) sentProtocol.clone();
340: return retval;
341: }
342:
343: /**
344: * Gets the value portion of this header (does nto include the parameters).
345: * @return the via header field value
346: */
347: public Object getValue() {
348: return sentProtocol.encode() + " " + sentBy.encode();
349:
350: }
351:
352: /**
353: * Sets the header value field (without parameters).
354: * @param value is the value field to set.
355: * @throws IllegalArgumentException if the value is invalid.
356: */
357: public void setHeaderValue(String value)
358: throws IllegalArgumentException {
359:
360: StringMsgParser smp = new StringMsgParser();
361: ViaList hl = null;
362: String strNewHeader = NAME + Separators.COLON + value;
363:
364: try {
365: hl = (ViaList) smp.parseHeader(strNewHeader);
366: } catch (ParseException e) {
367: throw new IllegalArgumentException(e.toString());
368: }
369:
370: if (hl.size() > 1) {
371: throw new IllegalArgumentException("Ivalid Via header "
372: + "value: " + value);
373: }
374:
375: ViaHeader header = (ViaHeader) hl.elementAt(0);
376:
377: // Copy the values from the header created from the parsed value
378: setSentBy(header.getSentBy());
379: setSentProtocol(header.getSentProtocol());
380:
381: if (sentProtocol != null) {
382: setProtocolVersion(header.getProtocolVersion());
383: setTransport(header.getTransport());
384: }
385:
386: if (sentBy != null) {
387: setHost(header.getHost());
388: setPort(header.getPort());
389: }
390:
391: // IMPL_NOTE:
392: // System.out.println("new: '" + strNewHeader + "'");
393: // System.out.println("this: '" + strNewHeader + "'");
394: }
395:
396: /**
397: * This function is overloaded in order to validate the parameters.
398: * Sets the value of the specified parameter. If the parameter already
399: * had a value it will be overwritten. A zero-length String indicates flag
400: * parameter.
401: *
402: * IMPL_NOTE: add a support for all parameters that are stored as
403: * members of this class.
404: *
405: * @param name a String specifying the parameter name
406: * @param value a String specifying the parameter value
407: * @throws IllegalArgumentException if the parameter's name or its value
408: * is invalid.
409: */
410: public void setParameter(String name, String value)
411: throws IllegalArgumentException {
412: if (name.equalsIgnoreCase(ViaHeader.TTL)) {
413: setTTL(value);
414: } else if (name.equalsIgnoreCase(ViaHeader.RECEIVED)) {
415: setReceived(value);
416: } else {
417: super .setParameter(name, value);
418: }
419: }
420:
421: /**
422: * Sets the 'received' parameter.
423: *
424: * BNF (RFC3261, p. 223, 232):
425: * via-received = "received" EQUAL (IPv4address / IPv6address)
426: * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
427: * IPv6address = hexpart [ ":" IPv4address ]
428: * hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
429: * hexseq = hex4 *( ":" hex4)
430: * hex4 = 1*4HEXDIG
431: *
432: * @param received the new 'received' value.
433: * @throws IllegalArgumentException if the new 'received' value is invalid.
434: */
435: public void setReceived(String received)
436: throws IllegalArgumentException {
437: if (!Lexer.isValidIpv4Address(received)
438: && !Lexer.isValidIpv6Address(received)) {
439: throw new IllegalArgumentException("Invalid IP address");
440: }
441:
442: super .setParameter(RECEIVED, received);
443: }
444:
445: /**
446: * Sets the maddr parameter.
447: *
448: * BNF (RFC3261, p. 222, 232):
449: * via-maddr = "maddr" EQUAL host
450: * host = hostname / IPv4address / IPv6reference
451: * hostname = *( domainlabel "." ) toplabel [ "." ]
452: * domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum
453: * toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum
454: *
455: * IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
456: * IPv6reference = "[" IPv6address "]"
457: * IPv6address = hexpart [ ":" IPv4address ]
458: * hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
459: * hexseq = hex4 *( ":" hex4)
460: * hex4 = 1*4HEXDIG
461: *
462: * IMPL_NOTE: check maddr for validity.
463: * @param maddr the new maddr value.
464: * @throws IllegalArgumentException if the new maddr value is invalid.
465: */
466: public void setMaddr(String maddr) throws IllegalArgumentException {
467: super .setParameter(MADDR, maddr);
468: }
469:
470: /**
471: * Sets the ttl parameter.
472: *
473: * BNF (RFC3261, p. 232):
474: * ttl = 1*3DIGIT ; 0 to 255
475: *
476: * @param strTTL the new ttl value given in a string form.
477: * @throws IllegalArgumentException if the new ttl value is invalid.
478: */
479: public void setTTL(String strTTL) throws IllegalArgumentException {
480: int ttl = 0;
481:
482: try {
483: ttl = Integer.parseInt(strTTL);
484: } catch (NumberFormatException e) {
485: throw new IllegalArgumentException("Cannot parse TTL '"
486: + strTTL + "': " + e);
487: }
488:
489: if (ttl < 0 || ttl > 255) {
490: throw new IllegalArgumentException("Invalid TTL: " + strTTL);
491: }
492:
493: super .setParameter(TTL, strTTL);
494: }
495:
496: /**
497: * Sets the branch field.
498: *
499: * BNF (RFC3261, p. 232):
500: * via-branch = "branch" EQUAL token
501: *
502: * @param branch the new branch value
503: */
504: public void setBranch(String branch) {
505: super .setParameter(BRANCH, branch);
506: }
507:
508: /**
509: * Sets the host field.
510: *
511: * BNF (RFC3261, p. 222):
512: * host = hostname / IPv4address / IPv6reference
513: * See setMaddr() for the full BNF.
514: *
515: * @param host the new host value
516: */
517: public void setHost(String host) {
518: this .sentBy.setHost(new Host(host));
519: }
520:
521: /**
522: * Sets the host field.
523: * @param host the new host value
524: */
525: public void setHost(Host host) {
526: this .sentBy.setHost(host);
527: }
528:
529: /**
530: * Sets the port field.
531: *
532: * BNF (RFC3261, p. 232):
533: * port = 1*DIGIT
534: *
535: * @param port the new port value
536: */
537: public void setPort(int port) {
538: this .sentBy.setPort(port);
539: }
540:
541: /**
542: * Gets the current transport.
543: * @return the current transport
544: */
545: public String getTransport() {
546: if (this.sentProtocol == null)
547: return null;
548: else
549: return this.sentProtocol.getTransport();
550: }
551:
552: }
|