-
Notifications
You must be signed in to change notification settings - Fork 40
[Reviewer: AJH] Sproutlet API change #1754
base: dev
Are you sure you want to change the base?
Conversation
Conflicts: modules/pjsip src/scscfsproutlet.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reviewed. Unfortunately I think there are a few high level issues with the code.
- The wrappers behave differently depending on whether they're at the start or end of the sproutlet graph. This bound to give inconsistent behavior. Each wrapper should behave the same way, and the UASTsx should be responsible for dealing with the ends of the graph.
- In one place you've got the wrappers driving the scheduling, which is backwards because the wrappers are the things that get scheduled.
- You've got the absorb ACKs flag in the wrong place IMO.
Let me know if you'd like to discuss any of these issues further.
A few other minor comments inline.
include/basicproxy.h
Outdated
/// If flag is set, any ACKs generated in the sproutlet wrapper will be | ||
/// absorbed. This is so that we do not send ACKs to negative responses off | ||
/// the box. | ||
bool _absorb_acks; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't live in the basic proxy. It is only a problem because the sproutlet proxy is generating ACKs to negative responses itself.
include/sproutlet.h
Outdated
virtual void on_rx_response(pjsip_msg* rsp, int fork_id) { send_response(rsp); } | ||
|
||
/// Called when a response has been transmitted on the transaction. | ||
/// Called if a 100 Trying response is received on the transaction. If the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing sentence.
include/sproutlet.h
Outdated
/// Called when a response has been transmitted on the transaction. | ||
/// Called if a 100 Trying response is received on the transaction. If the | ||
/// These responses are only sent by the wrappers, so we shouldn't call | ||
/// ever call send_response on them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an API, so you need to talk in terms that the API user will understand. The concept of the wrapper is not exposed on the API so you shouldn't talk about it. I would say something like "This is a notification that a 100 trying has been received. The sproutlet proxy handles these automatically. The Sproutlet Tsx should not forward the response on (i.e. should not call send_request
).
src/basicproxy.cpp
Outdated
pjsip_endpt_schedule_timer(stack_data.endpt, &(_trying_timer), &delay); | ||
} | ||
|
||
// Sproutlets may generate local ACKs to negative responses, we should not |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't be talking about sproutlets in the basic proxy.
src/basicproxy.cpp
Outdated
enter_context(); | ||
|
||
// For ACK transactions, we should not absorb ACKS that are generated by | ||
// the sproutlets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
src/sproutletproxy.cpp
Outdated
rsp->msg); | ||
++_pending_sends; | ||
tx_request(ack, fork_id); | ||
_proxy_tsx->schedule_requests(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's right for the wrapper to tell the UASTsx
when to schedule requests. In fact, rx_response
can be called from schedule_requests
so this can cause arbitrary levels of recursion so this is definitely wrong.
src/sproutletproxy.cpp
Outdated
// do this id this response has been passed to us directly from a UACTsx since | ||
// PJSIP will have sent and ACK already. | ||
if ((rsp->msg->line.status.code >= 300) && | ||
(!client_rsp)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if we only do this on a non-client response, doesn't think mean that the last sproutlet in the chain doesn't observe a -ve ACK being sent? If that's true, that's a problem.
src/sproutletproxy.cpp
Outdated
{ | ||
TRC_VERBOSE("%s received CANCEL request", _id.c_str()); | ||
|
||
// If this isn't the root sproutlet, send an immediate 200 OK to the CANCEL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, the fact we're doing something different at the end of the chain is wrong.
src/sproutletproxy.cpp
Outdated
} | ||
|
||
// LCOV_EXCL_START - Sproutlets don't forward 100 Trying responses so we | ||
// should never hit this code. But let's keep it here just in case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if we hit this code it implies a sproutlet is misusing the API. That is something that could totally happen, so let's add a UT for it and remove the coverage exclusions.
src/ut/mock_sproutlet.h
Outdated
MOCK_METHOD2(obs_tx_request, void(pjsip_msg*, int)); | ||
MOCK_METHOD2(on_rx_response, void(pjsip_msg*, int)); | ||
MOCK_METHOD1(on_tx_response, void(pjsip_msg*)); | ||
MOCK_METHOD1(obs_tx_response, void(pjsip_msg*)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well add mocks for the other new methods you've added at the same time.
I've applied all the markups - the only outstanding issue is the one about ACRs which I've emailed you about separately. Please could you re-review? On the max-forwards question - I changed the ordering to store the received request without decrementing the max-forwards because the upstream sproutlet uses the same pointer to see the request that it sent downstream. If we decrement max-forwards on receiving a request then the ACK generated to any negative responses will have the wrong mf header. This becomes a problem if the upstream sproutlet sends a request with mf=1 and we decrement it to 0 on receiving it downstream. Then any ACK to a negative response that is generated upstream will have mf=0 and will be dropped. |
A few more changes. I have:
I've done some initial testing for LI and all the messages we need seem to be available. Please review. |
Conflicts: src/scscfsproutlet.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good - nice one. A few comments inline.
include/sproutlet.h
Outdated
/// | ||
/// @param req - The received request. | ||
/// @param tsx_mgmt - Whether this is a transaction management message | ||
/// e.g. CANCEL, 200 OK to CANCEL, 100 Trying, ACK to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's occurred to me that a really nice way of expressing this is that the flag is set to true
when observing
- a received message that will not be passed to
on_rx_*
- a transmitted message that was not generated by the sproutlet tsx calling
send_*
Then say that this covers CANCEL, CANCEL 200, 100, and -ve ACK. I would probably put that in a separate comment before any of these methods.
include/sproutlet.h
Outdated
/// was triggered by an error or timeout. | ||
virtual void on_rx_cancel(int status_code, pjsip_msg* cancel_req) {} | ||
|
||
/// Called when a request is received by the sproutlet wrapper. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dude, avoid talking about the sproutlet wrapper! You could say something like "Called when a request is received at this sproutlet Tsx".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment on the rest of the obs_
methods too.
pjsip_tx_data* tdata, | ||
int reason_code); | ||
|
||
pjsip_tx_data* create_ack(pjsip_endpoint* endpt, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally you should be adding Doxygen comments to any new functions you add (these are the comments that start with a ///
and have the @params
and @return
handles in them).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important here because it's not clear whether this function can create any ACK, or just a -ve ACK (I thought it was the latter, but I might be wrong).
src/ut/mock_sproutlet.h
Outdated
MOCK_METHOD2(on_rx_response, void(pjsip_msg*, int)); | ||
MOCK_METHOD1(on_tx_response, void(pjsip_msg*)); | ||
MOCK_METHOD1(obs_rx_response, void(pjsip_msg*, int)); | ||
MOCK_METHOD1(obs_tx_response, void(pjsip_msg*)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These mock signatures look wrong to me.
src/scscfsproutlet.cpp
Outdated
return reason; | ||
} | ||
|
||
<<<<<<< HEAD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conflict marker?? How does this code compile?
// This is an ACK to a final response so disconnect the sproutlets. | ||
_dmap_sproutlet.erase(std::make_pair(upstream, fork_id)); | ||
UMap::iterator j = _umap.find((void*)downstream); | ||
_umap.erase(j); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth commonalizing this code?
src/sproutletproxy.cpp
Outdated
{ | ||
--mf_hdr->ivalue; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. When do we add the message to the list of messages that the wrapper owns? If we make any changes to it between storing it and passing it into the on_rx_*
methods then the message passed to on_rx_*
is different from messages returned by original_request
, which feels like an issue.
src/sproutletproxy.cpp
Outdated
(_forks[fork_id].state.tsx_state == PJSIP_TSX_STATE_CALLING)) | ||
|
||
int status_code = rsp->msg->line.status.code; | ||
if (status_code == PJSIP_SC_TRYING) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this need to cover CANCEL 200s as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see you handle this below. It would be clearer to put all the observation stuff in one place, even if it means repeating some if tests.
if (PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_CANCEL_METHOD) | ||
{ | ||
_sproutlet_tsx->obs_rx_response(rsp->msg, fork_id, true); | ||
pjsip_tx_data_dec_ref(rsp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we also need to drop our reference to a 100 trying?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you need to do this further down for 100 tryings. But in that case I would move both the 100 and 200 CANCEL processing further down.
src/sproutletproxy.cpp
Outdated
} | ||
|
||
// Sproutlets don't forward 100 Trying responses so we should never hit this | ||
// code. But let's keep it here just in case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've missed the point. even though they shouldn't, sproutlet's can forward 100 trying responses (there is nothing stopping them) so we need to keep this code.
This PR implements the Sproutlet API change that I sent you an email about.
The changes: