2 * Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/types.h>
18 #include <sys/queue.h>
32 #include "got_error.h"
33 #include "got_serve.h"
35 #include "got_version.h"
36 #include "got_reference.h"
37 #include "got_object.h"
39 #include "got_lib_pkt.h"
40 #include "got_lib_dial.h"
41 #include "got_lib_gitproto.h"
42 #include "got_lib_hash.h"
43 #include "got_lib_poll.h"
48 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
51 static const struct got_capability read_capabilities
[] = {
52 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
53 { GOT_CAPA_OFS_DELTA
, NULL
},
54 { GOT_CAPA_SIDE_BAND_64K
, NULL
},
57 static const struct got_capability write_capabilities
[] = {
58 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
59 { GOT_CAPA_OFS_DELTA
, NULL
},
60 { GOT_CAPA_REPORT_STATUS
, NULL
},
61 { GOT_CAPA_NO_THIN
, NULL
},
62 { GOT_CAPA_DELETE_REFS
, NULL
},
65 static const struct got_error
*
66 append_read_capabilities(size_t *capalen
, size_t len
, const char *symrefstr
,
67 uint8_t *buf
, size_t bufsize
)
69 struct got_capability capa
[nitems(read_capabilities
) + 1];
72 memcpy(&capa
, read_capabilities
, sizeof(read_capabilities
));
74 capa
[nitems(read_capabilities
)].key
= "symref";
75 capa
[nitems(read_capabilities
)].value
= symrefstr
;
78 ncapa
= nitems(read_capabilities
);
80 return got_gitproto_append_capabilities(capalen
, buf
, len
,
81 bufsize
, capa
, ncapa
);
84 static const struct got_error
*
85 send_ref(int outfd
, uint8_t *id
, const char *refname
, int send_capabilities
,
86 int client_is_reading
, const char *symrefstr
, int chattygot
)
88 const struct got_error
*err
= NULL
;
89 char hex
[SHA1_DIGEST_STRING_LENGTH
];
90 char buf
[GOT_PKT_MAX
];
91 size_t len
, capalen
= 0;
93 if (got_sha1_digest_to_str(id
, hex
, sizeof(hex
)) == NULL
)
94 return got_error(GOT_ERR_BAD_OBJ_ID
);
96 len
= snprintf(buf
, sizeof(buf
), "%s %s", hex
, refname
);
97 if (len
>= sizeof(buf
))
98 return got_error(GOT_ERR_NO_SPACE
);
100 if (send_capabilities
) {
101 if (client_is_reading
) {
102 err
= append_read_capabilities(&capalen
, len
,
103 symrefstr
, buf
, sizeof(buf
));
105 err
= got_gitproto_append_capabilities(&capalen
,
106 buf
, len
, sizeof(buf
), write_capabilities
,
107 nitems(write_capabilities
));
114 if (len
+ 1 >= sizeof(buf
))
115 return got_error(GOT_ERR_NO_SPACE
);
120 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
123 static const struct got_error
*
124 send_zero_refs(int outfd
, int client_is_reading
, int chattygot
)
126 const struct got_error
*err
= NULL
;
127 const char *line
= GOT_SHA1_STRING_ZERO
" capabilities^{}";
128 char buf
[GOT_PKT_MAX
];
129 size_t len
, capalen
= 0;
131 len
= strlcpy(buf
, line
, sizeof(buf
));
132 if (len
>= sizeof(buf
))
133 return got_error(GOT_ERR_NO_SPACE
);
135 if (client_is_reading
) {
136 err
= got_gitproto_append_capabilities(&capalen
, buf
, len
,
137 sizeof(buf
), read_capabilities
, nitems(read_capabilities
));
141 err
= got_gitproto_append_capabilities(&capalen
, buf
, len
,
142 sizeof(buf
), write_capabilities
,
143 nitems(write_capabilities
));
148 return got_pkt_writepkt(outfd
, buf
, len
+ capalen
, chattygot
);
152 echo_error(const struct got_error
*err
, int outfd
, int chattygot
)
154 char buf
[4 + GOT_ERR_MAX_MSG_SIZE
];
158 * Echo the error to the client on a pkt-line.
159 * The client should then terminate its session.
161 buf
[0] = 'E'; buf
[1] = 'R'; buf
[2] = 'R'; buf
[3] = ' '; buf
[4] = '\0';
162 len
= strlcat(buf
, err
->msg
, sizeof(buf
));
163 got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
166 static const struct got_error
*
167 announce_refs(int outfd
, struct imsgbuf
*ibuf
, int client_is_reading
,
168 const char *repo_path
, int chattygot
)
170 const struct got_error
*err
= NULL
;
173 struct gotd_imsg_list_refs lsref
;
174 struct gotd_imsg_reflist ireflist
;
175 struct gotd_imsg_ref iref
;
176 struct gotd_imsg_symref isymref
;
178 int have_nrefs
= 0, sent_capabilities
= 0;
179 char *symrefname
= NULL
, *symreftarget
= NULL
, *symrefstr
= NULL
;
180 char *refname
= NULL
;
182 memset(&imsg
, 0, sizeof(imsg
));
183 memset(&lsref
, 0, sizeof(lsref
));
185 if (strlcpy(lsref
.repo_name
, repo_path
, sizeof(lsref
.repo_name
)) >=
186 sizeof(lsref
.repo_name
))
187 return got_error(GOT_ERR_NO_SPACE
);
188 lsref
.client_is_reading
= client_is_reading
;
190 if (imsg_compose(ibuf
, GOTD_IMSG_LIST_REFS
, 0, 0, -1,
191 &lsref
, sizeof(lsref
)) == -1)
192 return got_error_from_errno("imsg_compose LIST_REFS");
194 err
= gotd_imsg_flush(ibuf
);
198 while (!have_nrefs
|| nrefs
> 0) {
199 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
202 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
203 switch (imsg
.hdr
.type
) {
204 case GOTD_IMSG_ERROR
:
205 err
= gotd_imsg_recv_error(NULL
, &imsg
);
207 case GOTD_IMSG_REFLIST
:
208 if (have_nrefs
|| nrefs
> 0) {
209 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
212 if (datalen
!= sizeof(ireflist
)) {
213 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
216 memcpy(&ireflist
, imsg
.data
, sizeof(ireflist
));
217 nrefs
= ireflist
.nrefs
;
220 err
= send_zero_refs(outfd
, client_is_reading
,
224 if (!have_nrefs
|| nrefs
== 0) {
225 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
228 if (datalen
< sizeof(iref
)) {
229 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
232 memcpy(&iref
, imsg
.data
, sizeof(iref
));
233 if (datalen
!= sizeof(iref
) + iref
.name_len
) {
234 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
237 refname
= strndup(imsg
.data
+ sizeof(iref
),
239 if (refname
== NULL
) {
240 err
= got_error_from_errno("strndup");
243 err
= send_ref(outfd
, iref
.id
, refname
,
244 !sent_capabilities
, client_is_reading
,
250 sent_capabilities
= 1;
254 case GOTD_IMSG_SYMREF
:
255 if (!have_nrefs
|| nrefs
== 0) {
256 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
259 if (datalen
< sizeof(isymref
)) {
260 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
263 memcpy(&isymref
, imsg
.data
, sizeof(isymref
));
264 if (datalen
!= sizeof(isymref
) + isymref
.name_len
+
265 isymref
.target_len
) {
266 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
271 * For now, we only announce one symbolic ref,
272 * as part of our capability advertisement.
274 if (sent_capabilities
|| symrefstr
!= NULL
||
275 symrefname
!= NULL
|| symreftarget
!= NULL
)
278 symrefname
= strndup(imsg
.data
+ sizeof(isymref
),
280 if (symrefname
== NULL
) {
281 err
= got_error_from_errno("malloc");
285 symreftarget
= strndup(
286 imsg
.data
+ sizeof(isymref
) + isymref
.name_len
,
288 if (symreftarget
== NULL
) {
289 err
= got_error_from_errno("strndup");
293 if (asprintf(&symrefstr
, "%s:%s", symrefname
,
294 symreftarget
) == -1) {
295 err
= got_error_from_errno("asprintf");
298 err
= send_ref(outfd
, isymref
.target_id
, symrefname
,
299 !sent_capabilities
, client_is_reading
, symrefstr
,
305 sent_capabilities
= 1;
310 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
317 err
= got_pkt_flushpkt(outfd
, chattygot
);
327 static const struct got_error
*
328 parse_want_line(char **common_capabilities
, uint8_t *id
, char *buf
, size_t len
)
330 const struct got_error
*err
;
331 char *id_str
= NULL
, *client_capabilities
= NULL
;
333 err
= got_gitproto_parse_want_line(&id_str
,
334 &client_capabilities
, buf
, len
);
338 if (!got_parse_hash_digest(id
, id_str
, GOT_HASH_SHA1
)) {
339 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
340 "want-line with bad object ID");
344 if (client_capabilities
) {
345 err
= got_gitproto_match_capabilities(common_capabilities
,
346 NULL
, client_capabilities
, read_capabilities
,
347 nitems(read_capabilities
));
353 free(client_capabilities
);
357 static const struct got_error
*
358 parse_have_line(uint8_t *id
, char *buf
, size_t len
)
360 const struct got_error
*err
;
363 err
= got_gitproto_parse_have_line(&id_str
, buf
, len
);
367 if (!got_parse_hash_digest(id
, id_str
, GOT_HASH_SHA1
)) {
368 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
369 "have-line with bad object ID");
377 static const struct got_error
*
378 send_capability(struct got_capability
*capa
, struct imsgbuf
*ibuf
)
380 const struct got_error
*err
= NULL
;
381 struct gotd_imsg_capability icapa
;
385 memset(&icapa
, 0, sizeof(icapa
));
387 icapa
.key_len
= strlen(capa
->key
);
388 len
= sizeof(icapa
) + icapa
.key_len
;
390 icapa
.value_len
= strlen(capa
->value
);
391 len
+= icapa
.value_len
;
394 wbuf
= imsg_create(ibuf
, GOTD_IMSG_CAPABILITY
, 0, 0, len
);
396 err
= got_error_from_errno("imsg_create CAPABILITY");
400 if (imsg_add(wbuf
, &icapa
, sizeof(icapa
)) == -1)
401 return got_error_from_errno("imsg_add CAPABILITY");
402 if (imsg_add(wbuf
, capa
->key
, icapa
.key_len
) == -1)
403 return got_error_from_errno("imsg_add CAPABILITY");
405 if (imsg_add(wbuf
, capa
->value
, icapa
.value_len
) == -1)
406 return got_error_from_errno("imsg_add CAPABILITY");
410 imsg_close(ibuf
, wbuf
);
415 static const struct got_error
*
416 send_capabilities(int *use_sidebands
, int *report_status
,
417 char *capabilities_str
, struct imsgbuf
*ibuf
)
419 const struct got_error
*err
= NULL
;
420 struct gotd_imsg_capabilities icapas
;
421 struct got_capability
*capa
= NULL
;
424 err
= got_gitproto_split_capabilities_str(&capa
, &ncapa
,
429 icapas
.ncapabilities
= ncapa
;
430 if (imsg_compose(ibuf
, GOTD_IMSG_CAPABILITIES
, 0, 0, -1,
431 &icapas
, sizeof(icapas
)) == -1) {
432 err
= got_error_from_errno("imsg_compose IMSG_CAPABILITIES");
436 for (i
= 0; i
< ncapa
; i
++) {
437 err
= send_capability(&capa
[i
], ibuf
);
441 strcmp(capa
[i
].key
, GOT_CAPA_SIDE_BAND_64K
) == 0)
444 strcmp(capa
[i
].key
, GOT_CAPA_REPORT_STATUS
) == 0)
452 static const struct got_error
*
453 forward_flushpkt(struct imsgbuf
*ibuf
)
455 if (imsg_compose(ibuf
, GOTD_IMSG_FLUSH
, 0, 0, -1, NULL
, 0) == -1)
456 return got_error_from_errno("imsg_compose FLUSH");
458 return gotd_imsg_flush(ibuf
);
461 static const struct got_error
*
462 recv_ack(struct imsg
*imsg
, uint8_t *expected_id
)
464 struct gotd_imsg_ack iack
;
467 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
468 if (datalen
!= sizeof(iack
))
469 return got_error(GOT_ERR_PRIVSEP_LEN
);
471 memcpy(&iack
, imsg
->data
, sizeof(iack
));
472 if (memcmp(iack
.object_id
, expected_id
, SHA1_DIGEST_LENGTH
) != 0)
473 return got_error(GOT_ERR_BAD_OBJ_ID
);
478 static const struct got_error
*
479 recv_nak(struct imsg
*imsg
, uint8_t *expected_id
)
481 struct gotd_imsg_ack inak
;
484 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
485 if (datalen
!= sizeof(inak
))
486 return got_error(GOT_ERR_PRIVSEP_LEN
);
488 memcpy(&inak
, imsg
->data
, sizeof(inak
));
489 if (memcmp(inak
.object_id
, expected_id
, SHA1_DIGEST_LENGTH
) != 0)
490 return got_error(GOT_ERR_BAD_OBJ_ID
);
496 static const struct got_error
*
497 recv_want(int *use_sidebands
, int outfd
, struct imsgbuf
*ibuf
,
498 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
500 const struct got_error
*err
;
501 struct gotd_imsg_want iwant
;
502 char *capabilities_str
;
506 memset(&iwant
, 0, sizeof(iwant
));
507 memset(&imsg
, 0, sizeof(imsg
));
509 err
= parse_want_line(&capabilities_str
, iwant
.object_id
, buf
, len
);
513 if (capabilities_str
) {
514 if (!expect_capabilities
) {
515 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
516 "unexpected capability announcement received");
519 err
= send_capabilities(use_sidebands
, NULL
, capabilities_str
,
526 if (imsg_compose(ibuf
, GOTD_IMSG_WANT
, 0, 0, -1,
527 &iwant
, sizeof(iwant
)) == -1) {
528 err
= got_error_from_errno("imsg_compose WANT");
532 err
= gotd_imsg_flush(ibuf
);
537 * Wait for an ACK, or an error in case the desired object
540 while (!done
&& err
== NULL
) {
541 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
544 switch (imsg
.hdr
.type
) {
545 case GOTD_IMSG_ERROR
:
546 err
= gotd_imsg_recv_error(NULL
, &imsg
);
549 err
= recv_ack(&imsg
, iwant
.object_id
);
555 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
562 free(capabilities_str
);
566 static const struct got_error
*
567 send_ack(int outfd
, uint8_t *id
, int chattygot
)
569 char hex
[SHA1_DIGEST_STRING_LENGTH
];
570 char buf
[GOT_PKT_MAX
];
573 if (got_sha1_digest_to_str(id
, hex
, sizeof(hex
)) == NULL
)
574 return got_error(GOT_ERR_BAD_OBJ_ID
);
576 len
= snprintf(buf
, sizeof(buf
), "ACK %s\n", hex
);
577 if (len
>= sizeof(buf
))
578 return got_error(GOT_ERR_NO_SPACE
);
580 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
583 static const struct got_error
*
584 send_nak(int outfd
, int chattygot
)
589 len
= snprintf(buf
, sizeof(buf
), "NAK\n");
590 if (len
>= sizeof(buf
))
591 return got_error(GOT_ERR_NO_SPACE
);
593 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
596 static const struct got_error
*
597 recv_have(int *have_ack
, int outfd
, struct imsgbuf
*ibuf
, char *buf
,
598 size_t len
, int chattygot
)
600 const struct got_error
*err
;
601 struct gotd_imsg_have ihave
;
605 memset(&ihave
, 0, sizeof(ihave
));
606 memset(&imsg
, 0, sizeof(imsg
));
608 err
= parse_have_line(ihave
.object_id
, buf
, len
);
612 if (imsg_compose(ibuf
, GOTD_IMSG_HAVE
, 0, 0, -1,
613 &ihave
, sizeof(ihave
)) == -1)
614 return got_error_from_errno("imsg_compose HAVE");
616 err
= gotd_imsg_flush(ibuf
);
621 * Wait for an ACK or a NAK, indicating whether a common
622 * commit object has been found.
624 while (!done
&& err
== NULL
) {
625 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
628 switch (imsg
.hdr
.type
) {
629 case GOTD_IMSG_ERROR
:
630 err
= gotd_imsg_recv_error(NULL
, &imsg
);
633 err
= recv_ack(&imsg
, ihave
.object_id
);
637 err
= send_ack(outfd
, ihave
.object_id
,
646 err
= recv_nak(&imsg
, ihave
.object_id
);
652 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
662 static const struct got_error
*
663 recv_done(int *packfd
, int outfd
, struct imsgbuf
*ibuf
, int chattygot
)
665 const struct got_error
*err
;
670 if (imsg_compose(ibuf
, GOTD_IMSG_DONE
, 0, 0, -1, NULL
, 0) == -1)
671 return got_error_from_errno("imsg_compose DONE");
673 err
= gotd_imsg_flush(ibuf
);
677 while (*packfd
== -1 && err
== NULL
) {
678 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
682 switch (imsg
.hdr
.type
) {
683 case GOTD_IMSG_ERROR
:
684 err
= gotd_imsg_recv_error(NULL
, &imsg
);
686 case GOTD_IMSG_PACKFILE_PIPE
:
690 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
693 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
703 static const struct got_error
*
704 relay_progress_reports(struct imsgbuf
*ibuf
, int outfd
, int chattygot
)
706 const struct got_error
*err
= NULL
;
707 int pack_starting
= 0;
708 struct gotd_imsg_packfile_progress iprog
;
709 char buf
[GOT_PKT_MAX
];
712 int p_deltify
= 0, n
;
713 const char *eol
= "\r";
715 memset(&imsg
, 0, sizeof(imsg
));
717 while (!pack_starting
&& err
== NULL
) {
718 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
722 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
723 switch (imsg
.hdr
.type
) {
724 case GOTD_IMSG_ERROR
:
725 err
= gotd_imsg_recv_error(NULL
, &imsg
);
727 case GOTD_IMSG_PACKFILE_READY
:
731 case GOTD_IMSG_PACKFILE_PROGRESS
:
732 if (datalen
!= sizeof(iprog
)) {
733 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
736 memcpy(&iprog
, imsg
.data
, sizeof(iprog
));
737 if (iprog
.nobj_total
> 0) {
738 p_deltify
= (iprog
.nobj_deltify
* 100) /
741 buf
[0] = GOT_SIDEBAND_PROGRESS_INFO
;
742 n
= snprintf(&buf
[1], sizeof(buf
) - 1,
743 "%d commits colored, "
749 if (n
>= sizeof(buf
) - 1)
751 err
= got_pkt_writepkt(outfd
, buf
, 1 + n
, chattygot
);
754 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
764 static const struct got_error
*
765 serve_read(int infd
, int outfd
, int gotd_sock
, const char *repo_path
,
768 const struct got_error
*err
= NULL
;
769 char buf
[GOT_PKT_MAX
];
773 STATE_EXPECT_MORE_WANT
,
778 enum protostate curstate
= STATE_EXPECT_WANT
;
779 int have_ack
= 0, use_sidebands
= 0, seen_have
= 0;
781 size_t pack_chunksize
;
783 imsg_init(&ibuf
, gotd_sock
);
785 err
= announce_refs(outfd
, &ibuf
, 1, repo_path
, chattygot
);
789 while (curstate
!= STATE_DONE
) {
792 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
);
796 if (curstate
!= STATE_EXPECT_WANT
&&
797 curstate
!= STATE_EXPECT_MORE_WANT
&&
798 curstate
!= STATE_EXPECT_HAVE
&&
799 curstate
!= STATE_EXPECT_DONE
) {
800 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
801 "unexpected flush packet received");
805 if (curstate
== STATE_EXPECT_WANT
) {
808 * If the client does not want to fetch
809 * anything we should receive a flush
810 * packet followed by EOF.
812 r
= read(infd
, buf
, sizeof(buf
));
814 err
= got_error_from_errno("read");
817 if (r
== 0) /* EOF */
820 /* Zero-length field followed by payload. */
821 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
822 "unexpected flush packet received");
826 if (curstate
== STATE_EXPECT_WANT
||
827 curstate
== STATE_EXPECT_MORE_WANT
||
828 curstate
== STATE_EXPECT_HAVE
) {
829 err
= forward_flushpkt(&ibuf
);
833 if (curstate
== STATE_EXPECT_HAVE
&& !have_ack
) {
834 err
= send_nak(outfd
, chattygot
);
838 if (curstate
== STATE_EXPECT_MORE_WANT
)
839 curstate
= STATE_EXPECT_HAVE
;
841 curstate
= STATE_EXPECT_DONE
;
842 } else if (n
>= 5 && strncmp(buf
, "want ", 5) == 0) {
843 if (curstate
!= STATE_EXPECT_WANT
&&
844 curstate
!= STATE_EXPECT_MORE_WANT
) {
845 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
846 "unexpected 'want' packet");
849 err
= recv_want(&use_sidebands
, outfd
, &ibuf
, buf
, n
,
850 curstate
== STATE_EXPECT_WANT
? 1 : 0, chattygot
);
853 if (curstate
== STATE_EXPECT_WANT
)
854 curstate
= STATE_EXPECT_MORE_WANT
;
855 } else if (n
>= 5 && strncmp(buf
, "have ", 5) == 0) {
856 if (curstate
!= STATE_EXPECT_HAVE
&&
857 curstate
!= STATE_EXPECT_DONE
) {
858 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
859 "unexpected 'have' packet");
862 if (curstate
== STATE_EXPECT_HAVE
) {
863 err
= recv_have(&have_ack
, outfd
, &ibuf
,
869 } else if (n
== 5 && strncmp(buf
, "done\n", 5) == 0) {
870 if (curstate
!= STATE_EXPECT_HAVE
&&
871 curstate
!= STATE_EXPECT_DONE
) {
872 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
873 "unexpected 'done' packet");
876 err
= recv_done(&packfd
, outfd
, &ibuf
, chattygot
);
879 curstate
= STATE_DONE
;
882 err
= got_error(GOT_ERR_BAD_PACKET
);
888 err
= send_nak(outfd
, chattygot
);
894 err
= relay_progress_reports(&ibuf
, outfd
, chattygot
);
897 pack_chunksize
= GOT_SIDEBAND_64K_PACKFILE_DATA_MAX
;
899 pack_chunksize
= sizeof(buf
);
904 r
= read(packfd
, use_sidebands
? &buf
[1] : buf
,
907 err
= got_error_from_errno("read");
910 err
= got_pkt_flushpkt(outfd
, chattygot
);
915 buf
[0] = GOT_SIDEBAND_PACKFILE_DATA
;
916 err
= got_pkt_writepkt(outfd
, buf
, 1 + r
, chattygot
);
920 err
= got_poll_write_full(outfd
, buf
, r
);
922 if (err
->code
== GOT_ERR_EOF
)
930 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
931 err
= got_error_from_errno("close");
933 echo_error(err
, outfd
, chattygot
);
937 static const struct got_error
*
938 parse_ref_update_line(char **common_capabilities
, char **refname
,
939 uint8_t *old_id
, uint8_t *new_id
, char *buf
, size_t len
)
941 const struct got_error
*err
;
942 char *old_id_str
= NULL
, *new_id_str
= NULL
;
943 char *client_capabilities
= NULL
;
947 err
= got_gitproto_parse_ref_update_line(&old_id_str
, &new_id_str
,
948 refname
, &client_capabilities
, buf
, len
);
952 if (!got_parse_hash_digest(old_id
, old_id_str
, GOT_HASH_SHA1
) ||
953 !got_parse_hash_digest(new_id
, new_id_str
, GOT_HASH_SHA1
)) {
954 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
955 "ref-update with bad object ID");
958 if (!got_ref_name_is_valid(*refname
)) {
959 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
960 "ref-update with bad reference name");
964 if (client_capabilities
) {
965 err
= got_gitproto_match_capabilities(common_capabilities
,
966 NULL
, client_capabilities
, write_capabilities
,
967 nitems(write_capabilities
));
974 free(client_capabilities
);
982 static const struct got_error
*
983 recv_ref_update(int *report_status
, int outfd
, struct imsgbuf
*ibuf
,
984 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
986 const struct got_error
*err
;
987 struct gotd_imsg_ref_update iref
;
989 char *capabilities_str
= NULL
, *refname
= NULL
;
993 memset(&iref
, 0, sizeof(iref
));
994 memset(&imsg
, 0, sizeof(imsg
));
996 err
= parse_ref_update_line(&capabilities_str
, &refname
,
997 iref
.old_id
, iref
.new_id
, buf
, len
);
1001 if (capabilities_str
) {
1002 if (!expect_capabilities
) {
1003 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1004 "unexpected capability announcement received");
1007 err
= send_capabilities(NULL
, report_status
, capabilities_str
,
1013 iref
.name_len
= strlen(refname
);
1014 len
= sizeof(iref
) + iref
.name_len
;
1015 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF_UPDATE
, 0, 0, len
);
1017 err
= got_error_from_errno("imsg_create REF_UPDATE");
1021 if (imsg_add(wbuf
, &iref
, sizeof(iref
)) == -1)
1022 return got_error_from_errno("imsg_add REF_UPDATE");
1023 if (imsg_add(wbuf
, refname
, iref
.name_len
) == -1)
1024 return got_error_from_errno("imsg_add REF_UPDATE");
1026 imsg_close(ibuf
, wbuf
);
1028 err
= gotd_imsg_flush(ibuf
);
1032 /* Wait for ACK or an error. */
1033 while (!done
&& err
== NULL
) {
1034 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
1037 switch (imsg
.hdr
.type
) {
1038 case GOTD_IMSG_ERROR
:
1039 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1042 err
= recv_ack(&imsg
, iref
.new_id
);
1048 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1055 free(capabilities_str
);
1060 static const struct got_error
*
1061 recv_packfile(struct imsg
*imsg
, int infd
)
1063 const struct got_error
*err
= NULL
;
1066 char buf
[GOT_PKT_MAX
];
1069 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1071 return got_error(GOT_ERR_PRIVSEP_MSG
);
1074 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
1077 while (!pack_done
) {
1080 err
= got_poll_fd(infd
, POLLIN
, 1);
1082 if (err
->code
!= GOT_ERR_TIMEOUT
)
1086 r
= read(infd
, buf
, sizeof(buf
));
1088 err
= got_error_from_errno("read");
1093 * Git clients hang up their side of the
1094 * connection after sending the pack file.
1103 /* Detect gotd(8) closing the pack pipe when done. */
1104 err
= got_poll_fd(packfd
, POLLOUT
, 1);
1106 if (err
->code
!= GOT_ERR_EOF
)
1112 /* Write pack data and/or detect pipe being closed. */
1113 err
= got_poll_write_full(packfd
, buf
, r
);
1115 if (err
->code
== GOT_ERR_EOF
)
1126 static const struct got_error
*
1127 report_unpack_status(struct imsg
*imsg
, int outfd
, int chattygot
)
1129 const struct got_error
*err
= NULL
;
1130 struct gotd_imsg_packfile_status istatus
;
1131 char buf
[GOT_PKT_MAX
];
1132 size_t datalen
, len
;
1133 char *reason
= NULL
;
1135 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1136 if (datalen
< sizeof(istatus
))
1137 return got_error(GOT_ERR_PRIVSEP_LEN
);
1138 memcpy(&istatus
, imsg
->data
, sizeof(istatus
));
1139 if (datalen
!= sizeof(istatus
) + istatus
.reason_len
)
1140 return got_error(GOT_ERR_PRIVSEP_LEN
);
1142 reason
= strndup(imsg
->data
+ sizeof(istatus
), istatus
.reason_len
);
1143 if (reason
== NULL
) {
1144 err
= got_error_from_errno("strndup");
1149 len
= snprintf(buf
, sizeof(buf
), "unpack ok\n");
1151 len
= snprintf(buf
, sizeof(buf
), "unpack %s\n", reason
);
1152 if (len
>= sizeof(buf
)) {
1153 err
= got_error(GOT_ERR_NO_SPACE
);
1157 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1163 static const struct got_error
*
1164 recv_ref_update_ok(struct imsg
*imsg
, int outfd
, int chattygot
)
1166 const struct got_error
*err
= NULL
;
1167 struct gotd_imsg_ref_update_ok iok
;
1168 size_t datalen
, len
;
1169 char buf
[GOT_PKT_MAX
];
1170 char *refname
= NULL
;
1172 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1173 if (datalen
< sizeof(iok
))
1174 return got_error(GOT_ERR_PRIVSEP_LEN
);
1175 memcpy(&iok
, imsg
->data
, sizeof(iok
));
1176 if (datalen
!= sizeof(iok
) + iok
.name_len
)
1177 return got_error(GOT_ERR_PRIVSEP_LEN
);
1179 memcpy(&iok
, imsg
->data
, sizeof(iok
));
1181 refname
= strndup(imsg
->data
+ sizeof(iok
), iok
.name_len
);
1182 if (refname
== NULL
)
1183 return got_error_from_errno("strndup");
1185 len
= snprintf(buf
, sizeof(buf
), "ok %s\n", refname
);
1186 if (len
>= sizeof(buf
)) {
1187 err
= got_error(GOT_ERR_NO_SPACE
);
1191 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1197 static const struct got_error
*
1198 recv_ref_update_ng(struct imsg
*imsg
, int outfd
, int chattygot
)
1200 const struct got_error
*err
= NULL
;
1201 struct gotd_imsg_ref_update_ng ing
;
1202 size_t datalen
, len
;
1203 char buf
[GOT_PKT_MAX
];
1204 char *refname
= NULL
, *reason
= NULL
;
1206 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1207 if (datalen
< sizeof(ing
))
1208 return got_error(GOT_ERR_PRIVSEP_LEN
);
1209 memcpy(&ing
, imsg
->data
, sizeof(ing
));
1210 if (datalen
!= sizeof(ing
) + ing
.name_len
+ ing
.reason_len
)
1211 return got_error(GOT_ERR_PRIVSEP_LEN
);
1213 memcpy(&ing
, imsg
->data
, sizeof(ing
));
1215 refname
= strndup(imsg
->data
+ sizeof(ing
), ing
.name_len
);
1216 if (refname
== NULL
)
1217 return got_error_from_errno("strndup");
1219 reason
= strndup(imsg
->data
+ sizeof(ing
) + ing
.name_len
,
1221 if (reason
== NULL
) {
1222 err
= got_error_from_errno("strndup");
1226 len
= snprintf(buf
, sizeof(buf
), "ng %s %s\n", refname
, reason
);
1227 if (len
>= sizeof(buf
)) {
1228 err
= got_error(GOT_ERR_NO_SPACE
);
1232 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1239 static const struct got_error
*
1240 serve_write(int infd
, int outfd
, int gotd_sock
, const char *repo_path
,
1243 const struct got_error
*err
= NULL
;
1244 char buf
[GOT_PKT_MAX
];
1245 struct imsgbuf ibuf
;
1247 STATE_EXPECT_REF_UPDATE
,
1248 STATE_EXPECT_MORE_REF_UPDATES
,
1249 STATE_EXPECT_PACKFILE
,
1250 STATE_PACKFILE_RECEIVED
,
1253 enum protostate curstate
= STATE_EXPECT_REF_UPDATE
;
1255 int report_status
= 0;
1257 imsg_init(&ibuf
, gotd_sock
);
1258 memset(&imsg
, 0, sizeof(imsg
));
1260 err
= announce_refs(outfd
, &ibuf
, 0, repo_path
, chattygot
);
1264 while (curstate
!= STATE_EXPECT_PACKFILE
) {
1267 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
);
1271 if (curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1272 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1273 "unexpected flush packet received");
1276 err
= forward_flushpkt(&ibuf
);
1279 curstate
= STATE_EXPECT_PACKFILE
;
1280 } else if (n
>= (SHA1_DIGEST_STRING_LENGTH
* 2) + 2) {
1281 if (curstate
!= STATE_EXPECT_REF_UPDATE
&&
1282 curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1283 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1284 "unexpected ref-update packet");
1287 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1288 err
= recv_ref_update(&report_status
,
1289 outfd
, &ibuf
, buf
, n
, 1, chattygot
);
1291 err
= recv_ref_update(NULL
, outfd
, &ibuf
,
1292 buf
, n
, 0, chattygot
);
1296 curstate
= STATE_EXPECT_MORE_REF_UPDATES
;
1298 err
= got_error(GOT_ERR_BAD_PACKET
);
1303 while (curstate
!= STATE_PACKFILE_RECEIVED
) {
1304 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1307 switch (imsg
.hdr
.type
) {
1308 case GOTD_IMSG_ERROR
:
1309 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1311 case GOTD_IMSG_RECV_PACKFILE
:
1312 err
= recv_packfile(&imsg
, infd
);
1314 if (err
->code
!= GOT_ERR_EOF
)
1317 * EOF is reported when the client hangs up,
1318 * which can happen with Git clients.
1319 * The socket should stay half-open so we
1320 * can still send our reports if requested.
1324 curstate
= STATE_PACKFILE_RECEIVED
;
1327 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1336 while (curstate
!= STATE_REFS_UPDATED
&& err
== NULL
) {
1337 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1340 switch (imsg
.hdr
.type
) {
1341 case GOTD_IMSG_ERROR
:
1342 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1344 case GOTD_IMSG_PACKFILE_STATUS
:
1347 err
= report_unpack_status(&imsg
, outfd
, chattygot
);
1349 case GOTD_IMSG_REF_UPDATE_OK
:
1352 err
= recv_ref_update_ok(&imsg
, outfd
, chattygot
);
1354 case GOTD_IMSG_REF_UPDATE_NG
:
1357 err
= recv_ref_update_ng(&imsg
, outfd
, chattygot
);
1359 case GOTD_IMSG_REFS_UPDATED
:
1360 curstate
= STATE_REFS_UPDATED
;
1361 err
= got_pkt_flushpkt(outfd
, chattygot
);
1364 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1373 echo_error(err
, outfd
, chattygot
);
1377 const struct got_error
*
1378 got_serve(int infd
, int outfd
, const char *command
, const char *repo_path
,
1379 int gotd_sock
, int chattygot
)
1381 const struct got_error
*err
= NULL
;
1383 if (strcmp(command
, GOT_DIAL_CMD_FETCH
) == 0)
1384 err
= serve_read(infd
, outfd
, gotd_sock
, repo_path
, chattygot
);
1385 else if (strcmp(command
, GOT_DIAL_CMD_SEND
) == 0)
1386 err
= serve_write(infd
, outfd
, gotd_sock
, repo_path
,
1389 err
= got_error(GOT_ERR_BAD_PACKET
);