Skip to content

Commit d60ddcc

Browse files
committed
Fix s2s labeled-response batches
Previously, batches would end prematurely if they traveled through an intermediate server before reaching their destination because the intermediate server would send ENCAP ACK multiple times, causing the pending server count to go down way too fast. Solve this by introducing two things: - Check that the direction of the incoming command matches the direction we'd be sending the ACK to (avoids sending additional ACKs for replies from remote servers that we pass along) - Add a mask parameter to the tracking metadata for remote responses and only send an ACK if we match the mask. this way things like remote WHOIS don't generate ACKs from intermediate servers
1 parent 362b336 commit d60ddcc

10 files changed

Lines changed: 44 additions & 30 deletions

File tree

include/response.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ struct ResponseInfo
4242
bool sent;
4343
/* while this is >0, outgoing messages will not be tagged with label/batch even if they otherwise would */
4444
int skip_tags;
45+
/* for remote batches, the server mask dictating which servers we are expecting responses from */
46+
char mask[HOSTLEN + 1];
4547
};
4648

4749
/* state of an outgoing labeled-response */
@@ -57,9 +59,11 @@ void begin_local_response_batch(void);
5759

5860
/* send a labeled-response BATCH to the incoming client for replies that will be generated at least partially
5961
* by remote servers. server_count must be the number of servers expected to send responses back.
60-
* If a batch is already opened, adds server_count to the number of servers we're expecting responses from.
62+
* mask must be a string (potentially containing * and ? wildcards) that matches servers we need responses from.
63+
* If a local batch is already opened, transforms it into a remote batch.
64+
* Calling on an existing remote batch is an error.
6165
*/
62-
void begin_remote_response_batch(int server_count);
66+
void begin_remote_response_batch(int server_count, const char *mask);
6367

6468
/* Get details for a labeled-response batch with the specified batch ID */
6569
struct ResponseInfo *get_remote_response_batch(const char *batch);

ircd/response.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "client.h"
2626
#include "response.h"
2727
#include "send.h"
28+
#include "s_assert.h"
2829
#include "s_serv.h"
2930

3031
/* number of seconds we'll wait for remote servers to finish sending their responses
@@ -93,7 +94,7 @@ begin_local_response_batch(void)
9394
}
9495

9596
void
96-
begin_remote_response_batch(int server_count)
97+
begin_remote_response_batch(int server_count, const char *mask)
9798
{
9899
if (outgoing_response_info == NULL || !MyConnect(outgoing_response_info->source_p))
99100
return;
@@ -103,6 +104,7 @@ begin_remote_response_batch(int server_count)
103104
/* creating a new remote response batch */
104105
generate_batch_id(outgoing_response_info->batch, sizeof(outgoing_response_info->batch));
105106
outgoing_response_info->remote_response = server_count;
107+
rb_strlcpy(outgoing_response_info->mask, mask, sizeof(outgoing_response_info->mask));
106108
outgoing_response_info->expires = rb_current_time() + RESPONSE_EXPIRY;
107109
rb_dlinkAddAlloc(outgoing_response_info, &outgoing_response_info->source_p->localClient->pending_remote_responses);
108110
rb_dictionary_add(pending_responses, outgoing_response_info->batch, outgoing_response_info);
@@ -111,16 +113,14 @@ begin_remote_response_batch(int server_count)
111113
}
112114
else
113115
{
114-
/* increase the number of servers we're expecting responses from */
115-
outgoing_response_info->remote_response += server_count;
116+
/* can only upgrade local batches to remote */
117+
s_assert(outgoing_response_info->remote_response == 0);
116118

117-
/* if we're upgrading a local batch to a remote batch, add it to tracking places */
118-
if (outgoing_response_info->expires == 0)
119-
{
120-
outgoing_response_info->expires = rb_current_time() + RESPONSE_EXPIRY;
121-
rb_dlinkAddAlloc(outgoing_response_info, &outgoing_response_info->source_p->localClient->pending_remote_responses);
122-
rb_dictionary_add(pending_responses, outgoing_response_info->batch, outgoing_response_info);
123-
}
119+
outgoing_response_info->remote_response += server_count;
120+
rb_strlcpy(outgoing_response_info->mask, mask, sizeof(outgoing_response_info->mask));
121+
outgoing_response_info->expires = rb_current_time() + RESPONSE_EXPIRY;
122+
rb_dlinkAddAlloc(outgoing_response_info, &outgoing_response_info->source_p->localClient->pending_remote_responses);
123+
rb_dictionary_add(pending_responses, outgoing_response_info->batch, outgoing_response_info);
124124
}
125125
}
126126

@@ -167,7 +167,7 @@ count_match_servs(struct Client *one, const char *mask, uint64_t cap, uint64_t n
167167
RB_DLINK_FOREACH(ptr, global_serv_list.head)
168168
{
169169
struct Client *target_p = ptr->data;
170-
if (target_p == &me)
170+
if (IsMe(target_p))
171171
continue;
172172

173173
if (target_p->from == one->from)

ircd/s_serv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ hunt_server(struct Client *client_p, struct Client *source_p,
246246
old = parv[server];
247247
parv[server] = get_id(target_p, target_p);
248248

249-
begin_remote_response_batch(1);
249+
begin_remote_response_batch(1, target_p->servptr->name);
250250
sendto_one(target_p, command, get_id(source_p, target_p),
251251
parv[1], parv[2], parv[3], parv[4], parv[5], parv[6], parv[7], parv[8]);
252252
parv[server] = old;

modules/cap_labeled_response.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,25 @@ cap_labeled_response_incoming(void *data_)
9999
}
100100
else if (IsServer(data->client) && !strcmp(serv_response_tag, data->key) && !EmptyString(data->value))
101101
{
102-
/* tag value should be UID,batch_id */
103-
char uid[IDLEN] = { 0 };
104-
const char *batch_id = strchr(data->value, ',');
105-
if (batch_id == NULL)
102+
/* tag value should be UID,batch_id,mask */
103+
char *buf = rb_strdup(data->value);
104+
char *p;
105+
const char *uid = rb_strtok_r(buf, ",", &p);
106+
const char *batch_id = rb_strtok_r(NULL, ",", &p);
107+
const char *mask = rb_strtok_r(NULL, ",", &p);
108+
109+
if (uid == NULL || batch_id == NULL || mask == NULL)
110+
{
111+
rb_free(buf);
106112
return;
113+
}
107114

108-
++batch_id;
109-
memcpy(uid, data->value, sizeof(uid) - 1);
110115
struct Client *client = find_id(uid);
111116
if (client == NULL)
117+
{
118+
rb_free(buf);
112119
return;
120+
}
113121

114122
if (MyConnect(client))
115123
{
@@ -120,15 +128,17 @@ cap_labeled_response_incoming(void *data_)
120128
SetClientCap(outgoing_response_info->source_p, CLICAP_RECEIVE_LABEL);
121129
}
122130
}
123-
else
131+
else if (data->client == client->from && match(mask, me.name))
124132
{
125133
outgoing_response_info = rb_malloc(sizeof(struct ResponseInfo));
126134
outgoing_response_info->source_p = client;
127135
outgoing_response_info->client_p = client->from;
128136
rb_strlcpy(outgoing_response_info->batch, batch_id, sizeof(outgoing_response_info->batch));
137+
rb_strlcpy(outgoing_response_info->mask, mask, sizeof(outgoing_response_info->mask));
129138
outgoing_response_info->sent = true;
130139
}
131140

141+
rb_free(buf);
132142
data->approved = MESSAGE_TAG_ALLOW;
133143
data->capmask = CLICAP_SERVONLY;
134144
}
@@ -174,8 +184,8 @@ cap_labeled_response_process(void *data_)
174184
}
175185
else if (outgoing_response_info != NULL && outgoing_response_info->remote_response > 0)
176186
{
177-
snprintf(response_tag_buf, sizeof(response_tag_buf), "%s,%s",
178-
outgoing_response_info->source_p->id, outgoing_response_info->batch);
187+
snprintf(response_tag_buf, sizeof(response_tag_buf), "%s,%s,%s",
188+
outgoing_response_info->source_p->id, outgoing_response_info->batch, outgoing_response_info->mask);
179189
msgbuf_append_tag(msgbuf, serv_response_tag, response_tag_buf, CLICAP_SERVONLY);
180190
}
181191
}

modules/core/m_message.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ msg_client(enum message_type msgtype,
10741074
}
10751075
else
10761076
{
1077-
begin_remote_response_batch(1);
1077+
begin_remote_response_batch(1, target_p->servptr->name);
10781078
sendto_anywhere_tags(target_p, source_p, cmdname[msgtype],
10791079
msgtype == MESSAGE_TYPE_TAGMSG ? CAP_STAG : NOCAPS,
10801080
NOCAPS, msgbuf_p->n_tags, msgbuf_p->tags,
@@ -1094,7 +1094,7 @@ msg_client_targeted(enum message_type msgtype,
10941094
{
10951095
s_assert(!IsMe(target_p) && IsServer(target_p));
10961096

1097-
begin_remote_response_batch(1);
1097+
begin_remote_response_batch(1, target_p->servptr->name);
10981098
sendto_one_tags(target_p,
10991099
msgtype == MESSAGE_TYPE_TAGMSG ? CAP_STAG : NOCAPS,
11001100
NOCAPS, msgbuf_p->n_tags, msgbuf_p->tags,

modules/core/m_modules.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sour
185185

186186
if(parc > 2)
187187
{
188-
begin_remote_response_batch(count_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS));
188+
begin_remote_response_batch(count_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS), parv[2]);
189189
sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
190190
"ENCAP %s MODLIST %s", parv[2], parv[1]);
191191
if(match(parv[2], me.name) == 0)

modules/m_etrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ mo_etrace(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *sourc
129129
{
130130
if (!MyClient(target_p))
131131
{
132-
begin_remote_response_batch(1);
132+
begin_remote_response_batch(1, target_p->servptr->name);
133133
sendto_one(target_p, ":%s ENCAP %s ETRACE %s",
134134
get_id(source_p, target_p),
135135
target_p->servptr->name,

modules/m_grant.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ mo_grant(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
5858
}
5959
else
6060
{
61-
begin_remote_response_batch(1);
61+
begin_remote_response_batch(1, target_p->servptr->name);
6262
sendto_one(target_p, ":%s ENCAP %s GRANT %s %s",
6363
get_id(source_p, target_p), target_p->servptr->name,
6464
get_id(target_p, target_p), parv[2]);

modules/m_list.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ mo_list(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
310310
}
311311

312312
/* mark it as a "remote" response so we don't terminate the batch at the end of the command handler */
313-
begin_remote_response_batch(1);
313+
begin_remote_response_batch(1, "");
314314
params->response_info = outgoing_response_info;
315315

316316
safelist_client_instantiate(source_p, params);

modules/m_privs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ mo_privs(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
182182
}
183183
else
184184
{
185-
begin_remote_response_batch(1);
185+
begin_remote_response_batch(1, server_p->name);
186186
sendto_one(server_p, ":%s ENCAP %s PRIVS %s",
187187
get_id(source_p, server_p),
188188
server_p->name,

0 commit comments

Comments
 (0)