<commit_before>-module(sipproxy).
-export([fork/8, generate_branch/0, get_branch/1]).

% This is the start() function of sipproxy. sipproxy can presently
% accomplish 'stateless forking'. It can follow an Actions list and
% fork a request to several Targets.
%
% You start it by calling the fork() method with a set of Actions. Currenly
% supported actions are a list of 'call' and 'wait'. You can mix calls and
% waits freely.

fork(BranchBase, Parent, OrigRequest, FromIP, Socket, Actions, Timeout, Targets) ->
    % XXX detect Max-Forwards: 1 here instead of when sending the requests
    % out since siprequest:send_proxy_request() would send the errors
    % right back to the caller
    {Method, ReqURI, Header, Body} = OrigRequest,
    case Actions of
	[{call, CallTimeout, CallURI} | Rest] ->
	    logger:log(debug, "sipproxy: calling ~s with timeout ~p",
		      [sipurl:print(CallURI), CallTimeout]),
	    Branch = BranchBase ++ "-UAC" ++ integer_to_list(length(Targets) + 1),
	    Request = {Method, CallURI, Header, Body},
	    BranchPid = clientbranch:start(Branch, Socket, FromIP, self(), OrigRequest, Request, CallTimeout),
	    NewTargets = targetlist:add_target(Branch, Request, BranchPid, calling, none, Targets),
	    fork(BranchBase, Parent, OrigRequest, FromIP, Socket, Rest, Timeout, NewTargets);
	[{wait, Time} | Rest] ->
	    logger:log(debug, "sipproxy: waiting ~p seconds", [Time]),
	    case process_wait(Parent, OrigRequest, Socket, Targets,
			      false, util:timestamp() + Time, calling) of
		{discontinue, NewTargets} ->
		    logger:log(debug, "sipproxy: discontinue processing"),
		    fork(BranchBase, Parent, OrigRequest, FromIP, Socket, [], Timeout, NewTargets);
		NewTargets ->
		    fork(BranchBase, Parent, OrigRequest, FromIP, Socket, Rest, Timeout, NewTargets)
	    end;
	[] ->
	    case allterminated(Targets) of
		true ->
		    logger:log(debug, "sipproxy: All targets are terminated, staying alive to handle resends");
		_ ->
		    logger:log(normal, "sipproxy: Reached end of Actions-list for ~s ~s, cancelling pending targets.",
		    		[Method, sipurl:print(ReqURI)]),
		    cancel_pending_targets(Targets),
		    Parent ! {no_more_actions}
	    end,
	    logger:log(debug, "sipproxy: waiting ~p seconds for final responses", [Timeout]),
	    process_wait(Parent, OrigRequest, Socket, Targets,
			 false, util:timestamp() + Timeout, stayalive),
	    Parent ! {callhandler_terminating, self()}
    end.

generate_branch() ->
    {Megasec, Sec, Microsec} = now(),
    "z9hG4bK-yxa-" ++ hex:to(Sec, 8) ++ hex:to(Microsec, 8).

get_branch(Header) ->
    case sipheader:via(keylist:fetch("Via", Header)) of
	[Via | _] ->
	    % XXX check that this is my Via
	    case dict:find("branch", sipheader:via_params(Via)) of
		error ->
		    none;
		{ok, Branch} ->
		    Branch
	    end;
	_ ->
	    none
    end.

cancel_pending_targets(Targets) ->
    % send {cancel} to all PIDs in states other than completed and terminated
    NewTargets1 = cancel_targets_state(Targets, calling),
    cancel_targets_state(NewTargets1, proceeding).

cancel_all_targets(Targets) ->
    % send {cancel} to all PIDs in states other than terminated<commit_msg>fork: bugfix: send no_more_actions to parent even if not all targets are terminated<commit_after>-module(sipproxy).
-export([fork/8, generate_branch/0, get_branch/1]).

% This is the start() function of sipproxy. sipproxy can presently
% accomplish 'stateless forking'. It can follow an Actions list and
% fork a request to several Targets.
%
% You start it by calling the fork() method with a set of Actions. Currenly
% supported actions are a list of 'call' and 'wait'. You can mix calls and
% waits freely.

fork(BranchBase, Parent, OrigRequest, FromIP, Socket, Actions, Timeout, Targets) ->
    % XXX detect Max-Forwards: 1 here instead of when sending the requests
    % out since siprequest:send_proxy_request() would send the errors
    % right back to the caller
    {Method, ReqURI, Header, Body} = OrigRequest,
    case Actions of
	[{call, CallTimeout, CallURI} | Rest] ->
	    logger:log(debug, "sipproxy: calling ~s with timeout ~p",
		      [sipurl:print(CallURI), CallTimeout]),
	    Branch = BranchBase ++ "-UAC" ++ integer_to_list(length(Targets) + 1),
	    Request = {Method, CallURI, Header, Body},
	    BranchPid = clientbranch:start(Branch, Socket, FromIP, self(), OrigRequest, Request, CallTimeout),
	    NewTargets = targetlist:add_target(Branch, Request, BranchPid, calling, none, Targets),
	    fork(BranchBase, Parent, OrigRequest, FromIP, Socket, Rest, Timeout, NewTargets);
	[{wait, Time} | Rest] ->
	    logger:log(debug, "sipproxy: waiting ~p seconds", [Time]),
	    case process_wait(Parent, OrigRequest, Socket, Targets,
			      false, util:timestamp() + Time, calling) of
		{discontinue, NewTargets} ->
		    logger:log(debug, "sipproxy: discontinue processing"),
		    fork(BranchBase, Parent, OrigRequest, FromIP, Socket, [], Timeout, NewTargets);
		NewTargets ->
		    fork(BranchBase, Parent, OrigRequest, FromIP, Socket, Rest, Timeout, NewTargets)
	    end;
	[] ->
	    case allterminated(Targets) of
		true ->
		    logger:log(debug, "sipproxy: All targets are terminated, staying alive to handle resends");
		_ ->
		    logger:log(normal, "sipproxy: Reached end of Actions-list for ~s ~s, cancelling pending targets.",
		    		[Method, sipurl:print(ReqURI)]),
		    cancel_pending_targets(Targets)
	    end,
	    Parent ! {no_more_actions},
	    logger:log(debug, "sipproxy: waiting ~p seconds for final responses", [Timeout]),
	    process_wait(Parent, OrigRequest, Socket, Targets,
			 false, util:timestamp() + Timeout, stayalive),
	    Parent ! {callhandler_terminating, self()}
    end.

generate_branch() ->
    {Megasec, Sec, Microsec} = now(),
    "z9hG4bK-yxa-" ++ hex:to(Sec, 8) ++ hex:to(Microsec, 8).

get_branch(Header) ->
    case sipheader:via(keylist:fetch("Via", Header)) of
	[Via | _] ->
	    % XXX check that this is my Via
	    case dict:find("branch", sipheader:via_params(Via)) of
		error ->
		    none;
		{ok, Branch} ->
		    Branch
	    end;
	_ ->
	    none
    end.

cancel_pending_targets(Targets) ->
    % send {cancel} to all PIDs in states other than completed and terminated
    NewTargets1 = cancel_targets_state(Targets, calling),
    cancel_targets_state(NewTargets1, proceeding).

cancel_all_targets(Targets) ->
    % send {cancel} to all PIDs in states other than terminated
{'fraction_non_alphanumeric': 0.120354532732079, 'fraction_numerical': 0.003420929870937646, 'mean_word_length': 3.9174311926605503, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '172009', 'n_tokens_mistral': 2177, 'n_tokens_neox': 2043, 'n_words': 621}