105
hashmap_add(hashmap, entry);
106
return 0;
107
}
108
+
109
+static int handshake_version(struct child_process *process,
110
+ const char *welcome_prefix, int *versions,
111
+ int *chosen_version)
112
+{
113
+ int version_scratch;
114
+ int i;
115
+ char *line;
116
+ const char *p;
117
+
118
+ if (!chosen_version)
119
+ chosen_version = &version_scratch;
120
+
121
+ if (packet_write_fmt_gently(process->in, "%s-client\n",
122
+ welcome_prefix))
123
+ return error("Could not write client identification");
124
+ for (i = 0; versions[i]; i++) {
125
+ if (packet_write_fmt_gently(process->in, "version=%d\n",
126
+ versions[i]))
127
+ return error("Could not write requested version");
128
+ }
129
+ if (packet_flush_gently(process->in))
130
+ return error("Could not write flush packet");
131
+
132
+ if (!(line = packet_read_line(process->out, NULL)) ||
133
+ !skip_prefix(line, welcome_prefix, &p) ||
134
+ strcmp(p, "-server"))
135
+ return error("Unexpected line '%s', expected %s-server",
136
+ line ? line : "<flush packet>", welcome_prefix);
137
+ if (!(line = packet_read_line(process->out, NULL)) ||
138
+ !skip_prefix(line, "version=", &p) ||
139
+ strtol_i(p, 10, chosen_version))
140
+ return error("Unexpected line '%s', expected version",
141
+ line ? line : "<flush packet>");
142
+ if ((line = packet_read_line(process->out, NULL)))
143
+ return error("Unexpected line '%s', expected flush", line);
144
+
145
+ /* Check to make sure that the version received is supported */
146
+ for (i = 0; versions[i]; i++) {
147
+ if (versions[i] == *chosen_version)
148
+ break;
149
+ }
150
+ if (!versions[i])
151
+ return error("Version %d not supported", *chosen_version);
152
+
153
+ return 0;
154
+}
155
+
156
+static int handshake_capabilities(struct child_process *process,
157
+ struct subprocess_capability *capabilities,
158
+ unsigned int *supported_capabilities)
159
+{
160
+ int i;
161
+ char *line;
162
+
163
+ for (i = 0; capabilities[i].name; i++) {
164
+ if (packet_write_fmt_gently(process->in, "capability=%s\n",
165
+ capabilities[i].name))
166
+ return error("Could not write requested capability");
167
+ }
168
+ if (packet_flush_gently(process->in))
169
+ return error("Could not write flush packet");
170
+
171
+ while ((line = packet_read_line(process->out, NULL))) {
172
+ const char *p;
173
+ if (!skip_prefix(line, "capability=", &p))
174
+ continue;
175
+
176
+ for (i = 0;
177
+ capabilities[i].name && strcmp(p, capabilities[i].name);
178
+ i++)
179
+ ;
180
+ if (capabilities[i].name) {
181
+ if (supported_capabilities)
182
+ *supported_capabilities |= capabilities[i].flag;
183
+ } else {
184
+ warning("external filter requested unsupported filter capability '%s'",
185
+ p);
186
+ }
187
+ }
188
+
189
+ return 0;
190
+}
191
+
192
+int subprocess_handshake(struct subprocess_entry *entry,
193
+ const char *welcome_prefix,
194
+ int *versions,
195
+ int *chosen_version,
196
+ struct subprocess_capability *capabilities,
197
+ unsigned int *supported_capabilities)
198
+{
199
+ int retval;
200
+ struct child_process *process = &entry->process;
201
+
202
+ sigchain_push(SIGPIPE, SIG_IGN);
203
+
204
+ retval = handshake_version(process, welcome_prefix, versions,
205
+ chosen_version) ||
206
+ handshake_capabilities(process, capabilities,
207
+ supported_capabilities);
208
+
209
+ sigchain_pop(SIGPIPE);
210
+ return retval;
211
+}