anchor.diff:  		       _ ->
   			   ""
   		   end,
  -	    logger:log(debug, "Packet from ~s ~s:~n~s", [S, RStr, Packet])
  +	    logger:log_iolist(debug, [<<"Packet from ">>, OriginStr, 32, RStr, $:, 10, Packet, 10]);
  +	true ->
  +	    %% This is not our final parse attempt, don't log
  +	    true
       end,
  -    Packetfixed = siputil:linefix(Packet),
  -    case string:str(Packetfixed, "\n\n") of
  -	0 ->
  -	    {Packetfixed, ""};
  -	Headerlen ->
  -	    HeaderStr = string:substr(Packetfixed, 1, Headerlen),
  -	    BodyStr = string:substr(Packetfixed, Headerlen + 2),
  -	    {HeaderStr, BodyStr}
  +    {FirstLine, HeaderOffset} = parse_firstline(Packet, 0),
  +    {Header, BodyOffset} = parse_headers(Packet, HeaderOffset),
  +    {FirstLine, Header, BodyOffset}.
  +
  +%%--------------------------------------------------------------------
  +%% Function: parse_headers(Bin, Offset)
  +%%           Bin    = binary(), the complete SIP message
  +%%           Offset = integer(), headers start offset
  +%% Descrip.: Get all headers, and a new offset pointing at whatever
  +%%           is after the header-body separator (body or nothing).
  +%% Returns : {Headers, BodyOffset}
  +%%           Headers    = keylist record()
  +%%           BodyOffset = integer()
  +%%--------------------------------------------------------------------
  +parse_headers(Bin, Offset) ->
  +    parse_headers(Bin, Offset, []).
  +
  +parse_headers(Bin, Offset, Res) ->
  +    case Bin of
  +	<<_:Offset/binary, ?CR, ?LF, _/binary>> ->
  +	    %% CRLF, must be header-body separator. We are finished.
  +	    {make_keylist(Bin, lists:reverse(Res)), Offset + 2};
  +	<<_:Offset/binary, N:8, _/binary>> when N == ?CR; N == ?LF ->
  +	    %% CR or LF, must be header-body separator (albeit broken). We are finished.
  +	    {make_keylist(Bin, lists:reverse(Res)), Offset + 1};
  +	<<_:Offset/binary, _, _/binary>> ->
  +	    {ok, This, NextOffset} = parse_one_header(Bin, Offset),
  +	    parse_headers(Bin, NextOffset, [This | Res]);
  +	_ ->
  +	    throw({error, no_header_body_separator_found})
       end.
   
   %%--------------------------------------------------------------------
  -%% Function: parseheader(Message)
  -%%           Message = string()
  -%% Descrip.: Parse from the start of a SIP message up to the header-
  -%%           body separator. Return the first line as it was given to
  -%%           us, and a created keylist of all the headers.
  -%% Returns : {FirstLine, Header}
  -%%           FirstLine = string()
  -%%           Header    = keylist record()
  -%%--------------------------------------------------------------------
  -parseheader(Message) ->
  -    [FirstLine | Rest] = string:tokens(Message, "\n"),
  -    Parseheader = fun(Line) ->
  -			  Index = string:chr(Line, $:),
  -			  Name = string:strip(string:substr(Line, 1, Index - 1), right),
  -			  Value = string:strip(string:substr(Line, Index + 1),
  -					       left),
  -			  Key = keylist:normalize(Name),
  -			  {Key, Name, split_header_value(Key, Value)}
  -		  end,
  -    Headerlist = lists:map(Parseheader, Rest),
  -    Header = keylist:from_list(Headerlist),
  -    {FirstLine, Header}.
  +%% Function: parse_one_header(Bin, Offset)
  +%%           Bin    = binary(), the complete SIP message
  +%%           Offset = integer(), this headers start offset
  +%% Descrip.: Get the offsets for all elements in the header starting
  +%%           at Offset. This is a tuple containing the offset and
  +%%           length of the header name, and one or more tuples with
  +%%           start offset and length of value elements. This is a list
  +%%           since header values can span over multiple lines.
  +%% Returns : {ok, HData, NextLineOffset}
  +%%           HData          = header record()
  +%%           NextLineOffset = integer()
  +%%--------------------------------------------------------------------
  +parse_one_header(Bin, Offset) ->
  +    {KeyLength, ColonOffset} = parse_one_header_key(Bin, Offset),
  +    Key = #ptr{offset=Offset, length=KeyLength},
  +    {Comma, ValuePtrs, NextLineOffset} = parse_one_header_values(Bin, ColonOffset + 1),
  +    This = #header{key=Key, valueptrs=ValuePtrs, comma=Comma},
  +    {ok, This, NextLineOffset}.
  +
  +%%--------------------------------------------------------------------
  +%% Function: parse_one_header_key(Bin, Offset)
  +%%           Bin    = binary(), the complete SIP message
  +%%           Offset = integer(), this headers start offset
  +%% Descrip.: Get the offset and length of the key for this header.
  +%%           Return an offset to the first byte after the colon
  +%%           separating key and values.
  +%% Returns : {Length, AfterColonOffset}
  +%%           Length           = integer()
  +%%           AfterColonOffset = integer()
  +%%--------------------------------------------------------------------
  +parse_one_header_key(Bin, Offset) ->
  +    parse_one_header_key2(Bin, Offset, 0, false).
  +
  +parse_one_header_key2(Bin, Offset, KeyLen, RequireColon) ->
  +    case Bin of
  +	<<_:Offset/binary, N, _/binary>> when N == ?SP; N == ?HTAB ->
  +	    %% RFC3261 BNF for headers :
  +	    %% To separate the header name from the rest of value,
  +	    %% a colon is used, which, by the above rule, allows whitespace before,
  +	    %% but no line break, and whitespace after, including a linebreak.
  +	    case (KeyLen >= 0) of
  +		false ->
  +		    throw({error, whitespace_where_header_name_was_expected});
  +		true ->
  +		    %% KeyLen is non-zero, so tab and space are OK - don't increase
  +		    %% KeyLen for spaces though, and set RequireColon to true
  +		    parse_one_header_key2(Bin, Offset + 1, KeyLen, true)
  +	    end;
  +	<<_:Offset/binary, $:, _/binary>> ->
  +	    %% Colon spotted
  +	    case (KeyLen >= 0) of
  +		true ->
  +		    %% KeyLen >= 0. We are finished.
  +		    {KeyLen, Offset};
  +		false ->
  +		    throw({error, colon_where_header_name_was_expected})
  +	    end;
  +	<<_:Offset/binary, _:8, _/binary>> ->
  +	    %% anything else, make sure we don't have RequireColon set
  +	    case RequireColon of
  +		true ->
  +		    throw({error, non_colon_when_colon_was_required});
  +		false ->
  +		    parse_one_header_key2(Bin, Offset + 1, KeyLen + 1, false)
  +	    end;
  +	_ ->
  +	    throw({error, no_end_of_key_or_no_header_body_separator})
  +    end.
  +
  +%%--------------------------------------------------------------------
  +%% Function: parse_one_header_values(Bin, Offset)
  +%%           Bin    = binary(), the complete SIP message
  +%%           Offset = integer(), this headers start offset
  +%% Descrip.: Locate all value elements for this header. This is a list
  +%%           of tuples consisting of start offset and length, since
  +%%           header values can span over multiple lines.
  +%% Returns : {Comma, ValuePtrs, NextOffset}
  +%%           Comma      = true | false, comma seen or not?
  +%%           ValuePtrs  = ptr record()
  +%%           NextOffset = integer(), offset of whatever is after this
  +%%                        header's value(s)
  +%%--------------------------------------------------------------------
  +parse_one_header_values(Bin, Offset) ->
  +    parse_one_header_values2(Bin, false, Offset, Offset, 0, []).
  +
  +parse_one_header_values2(Bin, Comma, Offset, StartOffset, Len, Res) ->
  +    case Bin of
  +	<<_:Offset/binary, N:8, _/binary>> when Len == 0, Res == [], N == ?SP; N == ?HTAB ->
  +	    %% space / tab after colon, just ignore
  +	    parse_one_header_values2(Bin, Comma, Offset + 1, StartOffset + 1, Len, Res);
  +	<<_:Offset/binary, ?CR, ?LF, N:8, _/binary>> when N == ?SP; N == ?HTAB ->
  +	    %% CRLF followed by space / tab, this header continues on the next line.
  +	    %% Make a ptr record() for what we have this far, and then start over (set
  +	    %% a new StartOffset and set Len to 0)
  +	    This = #ptr{offset=StartOffset, length=Len},
  +	    NextOffset = Offset + 3,
  +	    parse_one_header_values2(Bin, Comma, NextOffset, NextOffset, 0, [This | Res]);
  +	<<_:Offset/binary, ?LF, N:8, _/binary>> when N == ?SP; N == ?HTAB ->
  +	    %% LF followed by space / tab, this header continues on the next line.
  +	    %% Make a ptr record() for what we have this far, and then start over (set
  +	    %% a new StartOffset and set Len to 0)
  +	    This = #ptr{offset=StartOffset, length=Len},
  +	    NextOffset = Offset + 2,
  +	    parse_one_header_values2(Bin, Comma, NextOffset, NextOffset, 0, [This | Res]);
  +	<<_:Offset/binary, ?CR, ?LF, _/binary>> ->
  +	    %% CRLF (not followed by space or tab (checked above)), we are done
  +	    This = #ptr{offset=StartOffset, length=Len},
  +	    {Comma, lists:reverse([This | Res]), Offset + 2};
  +	<<_:Offset/binary, ?LF, _/binary>> ->
  +	    %% LF (not followed by space or tab (checked above)), we are done
  +	    This = #ptr{offset=StartOffset, length=Len},
  +	    {Comma, lists:reverse([This | Res]), Offset + 1};
  +	<<_:Offset/binary, 44, _/binary>> ->	%% 44 is comma
  +	    %% comma, part of value but remember we saw a comma (by setting Comma to true)
  +	    parse_one_header_values2(Bin, true, Offset + 1, StartOffset, Len + 1, Res);
  +	<<_:Offset/binary, _:8, _/binary>> ->
  +	    %% something else, must be part of value
  +	    parse_one_header_values2(Bin, Comma, Offset + 1, StartOffset, Len + 1, Res);
  +	_ ->
  +	    throw({error, no_end_of_header})
  +    end.
  +
   
   %%====================================================================
   %% Internal functions
   %%====================================================================
   
   %%--------------------------------------------------------------------
  -%% Function: split_header_value(Key, Value)
  -%%           Key   = string()
  -%%           Value = string()
  +%% Function: make_keylist(Bin, Headers)
  +%%           Bin     = binary(), the complete SIP message
  +%%           Headers = list() of header record()
  +%% Descrip.: Turn every element of Offsets into a {Key, Name, Values}
  +%%           tuple and then hand all those tuples to
  +%%           keylist:from_list() to get a keylist record.
  +%% Returns : Keylist = keylist record()
  +%%--------------------------------------------------------------------
  +make_keylist(Bin, Headers) ->
  +    Headerlist = make_keylist2(Bin, Headers, []),
  +    Keylist = keylist:from_list(Headerlist),
  +    Keylist.
  +
  +make_keylist2(Bin, [#header{key=HKey, valueptrs=ValuePtrs, comma=Comma} | T], Res) ->
  +    #ptr{offset=KeyOffset, length=KeyLen} = HKey,
  +
  +    %% Extract key
  +    <<_:KeyOffset/binary, NameBin:KeyLen/binary-unit:8, _/binary>> = Bin,
  +    Name = binary_to_list(NameBin),
  +    Key = keylist:normalize(Name),
  +
  +    %% Extract values
  +    Values = split_header_value(Key, ValuePtrs, Bin, Comma),
  +    This = {Key, Name, Values},
  +
  +    make_keylist2(Bin, T, [This | Res]);
  +make_keylist2(_Bin, [], Res) ->
  +    %% No more input
  +    lists:reverse(Res).
  +
  +%%--------------------------------------------------------------------
  +%% Function: split_header_value(Key, ValuePtrs, Bin, Comma)
  +%%           Key       = atom() | string()
  +%%           ValuePtrs = list() of ptr record()
  +%%           Bin       = binary(), the complete SIP message
  +%%           Comma     = true | false, wether there is a comma in
  +%%                       the values or not
   %% Descrip.: Look at Key and decide whether Value is a header that
  -%%           should be splitted on comma, or if it is in fact just a
  -%%           single value that should be returned as a single list
  -%%           element.
  +%%           should be splitted on comma or not. Then look at Comma to
  +%%           see if there is a comma in the values at all. If it is,
  +%%           then do the expensive sipheader:comma() on the values,
  +%%           otherwise just return it as [Value].
   %% Returns : ValueList, list() of string() or just [Value]
   %%--------------------------------------------------------------------
  -split_header_value(_Key, []) ->
  +split_header_value(_Key, [], _Bin, _Comma) ->
       [];
  -split_header_value(Key, Value) ->
  -    case lists:member(Key, ['www-authenticate', authorization,
  -			    'proxy-authenticate', 'proxy-authorization',
  -			    date]) of
  -	true ->
  -	    %% Except the headers listed in RFC3261 7.3.1 and some other that needs
  -	    %% to be excepted from standard header comma splitting
  -	    [Value];
  -	_ ->
  -	    Res = sipheader:comma(Value),
  -	    %% Remove leading and trailing white space
  -	    lists:map(fun(V) ->
  -			      string:strip(V)
  -		      end, Res)
  -    end.
  +%% Except the headers listed in RFC3261 7.3.1 and some other that needs
  +%% to be excepted from standard header comma splitting
  +split_header_value('www-authenticate', ValuePtrs, Bin, _Comma) ->
  +    extract_value_s(ValuePtrs, Bin);
  +split_header_value('authorization', ValuePtrs, Bin, _Comma) ->
  +    extract_value_s(ValuePtrs, Bin);
  +split_header_value('proxy-authenticate', ValuePtrs, Bin, _Comma) ->
  +    extract_value_s(ValuePtrs, Bin);
  +split_header_value('proxy-authorization', ValuePtrs, Bin, _Comma) ->
  +    extract_value_s(ValuePtrs, Bin);
  +split_header_value('date', ValuePtrs, Bin, _Comma) ->
  +    extract_value_s(ValuePtrs, Bin);
  +split_header_value(_Key, ValuePtrs, Bin, false) ->
  +    %% An ordinary header, but we haven't seen a comma in it so we don't
  +    %% have to try and split on comma
  +    extract_value_s(ValuePtrs, Bin);
  +split_header_value(_Key, ValuePtrs, Bin, true) ->
  +    Value = extract_value(ValuePtrs, Bin),
  +    Splitted = sipheader:comma(Value),
  +    %% Remove leading and trailing white space from all the values
  +    Res = lists:map(fun(V) ->
  +			    string:strip(V, both)
  +		    end, Splitted),
  +    Res.
  +
  +%% part of split_header_value(), extract all value parts from the
  +%% original SIP message and turn them into a list()
  +%% Returns : string()
  +extract_value(ValuePtrs, Bin) ->
  +    extract_value2(ValuePtrs, Bin, []).
  +
  +%% part of split_header_value(), extract all value parts, strip leading
  +%% and trailing whitespace and return it as a list containing a string
  +%% Returns : [string()]
  +extract_value_s(ValuePtrs, Bin) ->
  +    V = extract_value2(ValuePtrs, Bin, []),
  +    [string:strip(V, both)].
  +
  +extract_value2([H | T], Bin, Res) ->
  +    #ptr{offset=VOffset, length=VLen} = H,
  +    <<_:VOffset/binary, ValueBin:VLen/binary-unit:8, _/binary>> = Bin,
  +    extract_value2(T, Bin, [ValueBin | Res]);
  +extract_value2([], _Bin, Res) ->
  +    %% No more input
  +    All = concat_binary(lists:reverse(Res)),
  +    binary_to_list(All).
   
   %%--------------------------------------------------------------------
   %% Function: parse_firstline(FirstLine)
  
positive.code:     io:format("test: parse/1 request - 10.1~n"),
      %% make sure we can handle message where body is not yet fully received
      %% (also test \n instead of \r\n throughout the message)
      {request, "INVITE", _, Header10, "partial"} = parse(Message10, none),
  
      io:format("test: parse/1 request - 10.2~n"),
      %% verify the Content-Length is untouched (to not re-introduce bug)
      ["20"] = keylist:fetch('content-length', Header10),
  
      Message11 =
  	"INVITE sip:a@example.org SIP/2.0\r"
  	"Via: SIP/2.0/TLS 192.0.2.1\r"
  	"\r"
  	"body",
  
      io:format("test: parse/1 request - 11.1~n"),
      %% verify that we can parse message with broken line endings (\r)
      {request, "INVITE", _, Header11, "body"} = parse(Message11, none),
  
      io:format("test: parse/1 request - 11.2~n"),
      %% verify the only header
      ["SIP/2.0/TLS 192.0.2.1"] = keylist:fetch('via', Header11),
  
  
      %% RESPONSES
  
      RMessage1 = "SIP/2.0 100 Trying\r\n"
  	"Via: SIP/2.0/TLS 192.0.2.78   \r\n",
      io:format("test: parse/1 response - 1.1~n"),
      {response, 100, "Trying", RHeader1, ""} = parse(RMessage1, none),
  
      %% verify the Via header so we know keylist is created as it should
      io:format("test: parse/1 response - 1.2~n"),
      ["SIP/2.0/TLS 192.0.2.78"] = keylist:fetch('via', RHeader1),
  
      RMessage2 =
          "SIP/2.0 100 \r\n"
          "Via: SIP/2.0/TLS 192.0.2.78\r\n",
      io:format("test: parse/1 response - 2.1~n"),
      {response, 100, "", RHeader2, ""} = parse(RMessage2, none),
  
      %% verify the Via header so we know keylist is created as it should
      io:format("test: parse/1 response - 2.2~n"),
      ["SIP/2.0/TLS 192.0.2.78"] = keylist:fetch('via', RHeader2),
  
      %% '3.1.2.19  Overlarge response code' from draft-ietf-sipping-torture-tests-04.txt
      %% (in a shorter form) - the draft says you should just ignore responses with
      %% too large response codes, so we can do that here already.
      _RMessage3 =
  	"SIP/2.0 4294967301 better not break the receiver\r\n"
          "Via: SIP/2.0/TLS 192.0.2.78\r\n",
      io:format("test: parse/1 response - 3~n"),
      %%    invalid = parse(RMessage3, none),
  
  
  
      ok.
  
negative.code: %%           {response, {Status, Reason}
  %%           Method = string(), e.g. "INVITE"
  %%           URIstr = string(), e.g. "sip:user@example.org"
  %%           Status = integer(), e.g. 100
  %%           Reason = string(), e.g. "Trying"
  %%--------------------------------------------------------------------
  parse_firstline(Bin, Offset) ->
      case Bin of
  	<<"SIP/2.0 ", _/binary>> ->
  	    %% is response
  	    {Parsed, NextLineOffset} = parse_firstline_response(Bin, Offset + 8),
  	    {{response, Parsed}, NextLineOffset};
  	_ ->
  	    %% is (hopefully) request
  	    {Parsed, NextLineOffset} = parse_firstline_request(Bin, Offset),
  	    {{request, Parsed}, NextLineOffset}
      end.
  
  %% part of parse_firstline(), try to parse data at offset MethodOffset
  %% as a Request-Line.
  parse_firstline_request(Bin, MethodOffset) ->
      {Method, MethodEOffset} = extract_token(Bin, MethodOffset, ?SP),
      {URI, URIEOffset} = extract_token(Bin, MethodEOffset + 1, ?SP),
      VerOffset = URIEOffset + 1,
      case Bin of
  	<<_:VerOffset/binary, "SIP/2.0", _/binary>> ->
  	    %% Ok, the URI had " SIP/2.0" after it - now verify that
  	    %% the " SIP/2.0" is the last thing on this line
  	    VerEOffset = URIEOffset + 8,
  	    case Bin of
  		<<_:VerEOffset/binary, ?CR, ?LF, _/binary>> ->
  		    {{Method, URI}, VerEOffset + 2};
  		<<_:VerEOffset/binary, ?LF, _/binary>> ->
  		    {{Method, URI}, VerEOffset + 1};
  		_ ->
  		%% uh oh, there is something other than a linefeed there
  		%% (or nothing more at all)
  		throw({error, garbage_after_sip_version})
  	    end;
  	_ ->
  	    throw({error, invalid_sip_version})
      end.
  
  %% Get everything up until Sep (Sep is a byte)
  extract_token(Bin, Offset, Sep) ->
      extract_token(Bin, Offset, Sep, []).
  
  extract_token(Bin, Offset, Sep, Res) ->
      case Bin of
  	<<_:Offset/binary, Sep:8, _/binary>> ->
  	    %% Separator found
  	    {lists:reverse(Res), Offset};
  	<<_:Offset/binary, N:8, _/binary>> ->
  	    extract_token(Bin, Offset + 1, Sep, [N | Res]);
  	_ ->
  	    %% end of binary
  	    {lists:reverse(Res), Offset}
      end.
  
  %% part of parse_firstline(), this should be a Status-Line
  parse_firstline_response(Bin, StatusOffset) ->
      {Status, StatusEOffset} = extract_integer(Bin, StatusOffset),
      {Reason, NextLineOffset} = extract_eol(Bin, StatusEOffset + 1),
      {{Status, Reason}, NextLineOffset}.
  
  %% Get an integer starting at Offset
  extract_integer(Bin, Offset) ->
      extract_integer(Bin, Offset, []).
  
  extract_integer(Bin, Offset, Res) ->
      case Bin of
  	<<_:Offset/binary, N:8, _/binary>> when N >= $0, N =< $9 ->
  	    %% a digit
  	    extract_integer(Bin, Offset + 1, [N | Res]);
  	_ ->
  	    %% not a digit, we are finished
  	    L = lists:reverse(Res),
  	    Int = try list_to_integer(L) of
  		      N -> N
  		  catch
  		      error: _ ->
  			  throw({error, non_integer_where_integer_expected})
  		  end,
  	    {Int, Offset}
      end.
  
  %% extract up to the next end-of-line (CR or LF)
  extract_eol(Bin, Offset) ->
      extract_eol(Bin, Offset, false, []).
  
  extract_eol(Bin, Offset, CRLFseen, Res) ->
      case Bin of
  	<<_:Offset/binary, N, _/binary>> when N == ?CR; N == ?LF ->
  	    %% CR or LF, advance to next position
  	    extract_eol(Bin, Offset + 1, true, Res);
  	<<_:Offset/binary, N, _/binary>> when CRLFseen == false ->
  	    %% non-CR/LF, add to front of Res
  	    extract_eol(Bin, Offset + 1, false, [N | Res]);
  	_ ->
  	    %% we are finished, peel of spaces and then return
  	    Str = lists:reverse(string:strip(Res, left)),
  	    {Str, Offset}
      end.
  
  %%--------------------------------------------------------------------
  