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 "got_compat.h"
19 #include <sys/types.h>
20 #include <sys/queue.h>
34 #include "got_error.h"
35 #include "got_serve.h"
37 #include "got_version.h"
38 #include "got_reference.h"
39 #include "got_object.h"
41 #include "got_lib_pkt.h"
42 #include "got_lib_dial.h"
43 #include "got_lib_gitproto.h"
44 #include "got_lib_hash.h"
45 #include "got_lib_poll.h"
50 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
54 * Number of seconds until we give up trying to read more
55 * data from the client connection.
57 static const int timeout
= 60;
59 static const struct got_capability read_capabilities
[] = {
60 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
61 { GOT_CAPA_OFS_DELTA
, NULL
},
62 { GOT_CAPA_SIDE_BAND_64K
, NULL
},
65 static const struct got_capability write_capabilities
[] = {
66 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
67 { GOT_CAPA_OFS_DELTA
, NULL
},
68 { GOT_CAPA_REPORT_STATUS
, NULL
},
69 { GOT_CAPA_NO_THIN
, NULL
},
70 { GOT_CAPA_DELETE_REFS
, NULL
},
73 static const struct got_error
*
74 append_read_capabilities(size_t *capalen
, size_t len
, const char *symrefstr
,
75 uint8_t *buf
, size_t bufsize
)
77 struct got_capability capa
[nitems(read_capabilities
) + 1];
80 memcpy(&capa
, read_capabilities
, sizeof(read_capabilities
));
82 capa
[nitems(read_capabilities
)].key
= "symref";
83 capa
[nitems(read_capabilities
)].value
= symrefstr
;
86 ncapa
= nitems(read_capabilities
);
88 return got_gitproto_append_capabilities(capalen
, buf
, len
,
89 bufsize
, capa
, ncapa
);
92 static const struct got_error
*
93 send_ref(int outfd
, uint8_t *id
, const char *refname
, int send_capabilities
,
94 int client_is_reading
, const char *symrefstr
, int chattygot
)
96 const struct got_error
*err
= NULL
;
97 char hex
[SHA1_DIGEST_STRING_LENGTH
];
98 char buf
[GOT_PKT_MAX
];
99 size_t len
, capalen
= 0;
101 if (got_sha1_digest_to_str(id
, hex
, sizeof(hex
)) == NULL
)
102 return got_error(GOT_ERR_BAD_OBJ_ID
);
104 len
= snprintf(buf
, sizeof(buf
), "%s %s", hex
, refname
);
105 if (len
>= sizeof(buf
))
106 return got_error(GOT_ERR_NO_SPACE
);
108 if (send_capabilities
) {
109 if (client_is_reading
) {
110 err
= append_read_capabilities(&capalen
, len
,
111 symrefstr
, buf
, sizeof(buf
));
113 err
= got_gitproto_append_capabilities(&capalen
,
114 buf
, len
, sizeof(buf
), write_capabilities
,
115 nitems(write_capabilities
));
122 if (len
+ 1 >= sizeof(buf
))
123 return got_error(GOT_ERR_NO_SPACE
);
128 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
131 static const struct got_error
*
132 send_zero_refs(int outfd
, int client_is_reading
, int chattygot
)
134 const struct got_error
*err
= NULL
;
135 const char *line
= GOT_SHA1_STRING_ZERO
" capabilities^{}";
136 char buf
[GOT_PKT_MAX
];
137 size_t len
, capalen
= 0;
139 len
= strlcpy(buf
, line
, sizeof(buf
));
140 if (len
>= sizeof(buf
))
141 return got_error(GOT_ERR_NO_SPACE
);
143 if (client_is_reading
) {
144 err
= got_gitproto_append_capabilities(&capalen
, buf
, len
,
145 sizeof(buf
), read_capabilities
, nitems(read_capabilities
));
149 err
= got_gitproto_append_capabilities(&capalen
, buf
, len
,
150 sizeof(buf
), write_capabilities
,
151 nitems(write_capabilities
));
156 return got_pkt_writepkt(outfd
, buf
, len
+ capalen
, chattygot
);
160 echo_error(const struct got_error
*err
, int outfd
, int chattygot
)
162 char buf
[4 + GOT_ERR_MAX_MSG_SIZE
];
166 * Echo the error to the client on a pkt-line.
167 * The client should then terminate its session.
169 buf
[0] = 'E'; buf
[1] = 'R'; buf
[2] = 'R'; buf
[3] = ' '; buf
[4] = '\0';
170 len
= strlcat(buf
, err
->msg
, sizeof(buf
));
171 got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
174 static const struct got_error
*
175 announce_refs(int outfd
, struct imsgbuf
*ibuf
, int client_is_reading
,
176 const char *repo_path
, int chattygot
)
178 const struct got_error
*err
= NULL
;
181 struct gotd_imsg_list_refs lsref
;
182 struct gotd_imsg_reflist ireflist
;
183 struct gotd_imsg_ref iref
;
184 struct gotd_imsg_symref isymref
;
186 int have_nrefs
= 0, sent_capabilities
= 0;
187 char *symrefname
= NULL
, *symreftarget
= NULL
, *symrefstr
= NULL
;
188 char *refname
= NULL
;
190 memset(&imsg
, 0, sizeof(imsg
));
191 memset(&lsref
, 0, sizeof(lsref
));
193 if (strlcpy(lsref
.repo_name
, repo_path
, sizeof(lsref
.repo_name
)) >=
194 sizeof(lsref
.repo_name
))
195 return got_error(GOT_ERR_NO_SPACE
);
196 lsref
.client_is_reading
= client_is_reading
;
198 if (imsg_compose(ibuf
, GOTD_IMSG_LIST_REFS
, 0, 0, -1,
199 &lsref
, sizeof(lsref
)) == -1)
200 return got_error_from_errno("imsg_compose LIST_REFS");
202 err
= gotd_imsg_flush(ibuf
);
206 while (!have_nrefs
|| nrefs
> 0) {
207 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
210 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
211 switch (imsg
.hdr
.type
) {
212 case GOTD_IMSG_ERROR
:
213 err
= gotd_imsg_recv_error(NULL
, &imsg
);
215 case GOTD_IMSG_REFLIST
:
216 if (have_nrefs
|| nrefs
> 0) {
217 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
220 if (datalen
!= sizeof(ireflist
)) {
221 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
224 memcpy(&ireflist
, imsg
.data
, sizeof(ireflist
));
225 nrefs
= ireflist
.nrefs
;
228 err
= send_zero_refs(outfd
, client_is_reading
,
232 if (!have_nrefs
|| nrefs
== 0) {
233 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
236 if (datalen
< sizeof(iref
)) {
237 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
240 memcpy(&iref
, imsg
.data
, sizeof(iref
));
241 if (datalen
!= sizeof(iref
) + iref
.name_len
) {
242 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
245 refname
= strndup(imsg
.data
+ sizeof(iref
),
247 if (refname
== NULL
) {
248 err
= got_error_from_errno("strndup");
251 err
= send_ref(outfd
, iref
.id
, refname
,
252 !sent_capabilities
, client_is_reading
,
258 sent_capabilities
= 1;
262 case GOTD_IMSG_SYMREF
:
263 if (!have_nrefs
|| nrefs
== 0) {
264 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
267 if (datalen
< sizeof(isymref
)) {
268 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
271 memcpy(&isymref
, imsg
.data
, sizeof(isymref
));
272 if (datalen
!= sizeof(isymref
) + isymref
.name_len
+
273 isymref
.target_len
) {
274 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
279 * For now, we only announce one symbolic ref,
280 * as part of our capability advertisement.
282 if (sent_capabilities
|| symrefstr
!= NULL
||
283 symrefname
!= NULL
|| symreftarget
!= NULL
)
286 symrefname
= strndup(imsg
.data
+ sizeof(isymref
),
288 if (symrefname
== NULL
) {
289 err
= got_error_from_errno("malloc");
293 symreftarget
= strndup(
294 imsg
.data
+ sizeof(isymref
) + isymref
.name_len
,
296 if (symreftarget
== NULL
) {
297 err
= got_error_from_errno("strndup");
301 if (asprintf(&symrefstr
, "%s:%s", symrefname
,
302 symreftarget
) == -1) {
303 err
= got_error_from_errno("asprintf");
306 err
= send_ref(outfd
, isymref
.target_id
, symrefname
,
307 !sent_capabilities
, client_is_reading
, symrefstr
,
313 sent_capabilities
= 1;
318 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
325 err
= got_pkt_flushpkt(outfd
, chattygot
);
335 static const struct got_error
*
336 parse_want_line(char **common_capabilities
, uint8_t *id
, char *buf
, size_t len
)
338 const struct got_error
*err
;
339 char *id_str
= NULL
, *client_capabilities
= NULL
;
341 err
= got_gitproto_parse_want_line(&id_str
,
342 &client_capabilities
, buf
, len
);
346 if (!got_parse_hash_digest(id
, id_str
, GOT_HASH_SHA1
)) {
347 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
348 "want-line with bad object ID");
352 if (client_capabilities
) {
353 err
= got_gitproto_match_capabilities(common_capabilities
,
354 NULL
, client_capabilities
, read_capabilities
,
355 nitems(read_capabilities
));
361 free(client_capabilities
);
365 static const struct got_error
*
366 parse_have_line(uint8_t *id
, char *buf
, size_t len
)
368 const struct got_error
*err
;
371 err
= got_gitproto_parse_have_line(&id_str
, buf
, len
);
375 if (!got_parse_hash_digest(id
, id_str
, GOT_HASH_SHA1
)) {
376 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
377 "have-line with bad object ID");
385 static const struct got_error
*
386 send_capability(struct got_capability
*capa
, struct imsgbuf
*ibuf
)
388 const struct got_error
*err
= NULL
;
389 struct gotd_imsg_capability icapa
;
393 memset(&icapa
, 0, sizeof(icapa
));
395 icapa
.key_len
= strlen(capa
->key
);
396 len
= sizeof(icapa
) + icapa
.key_len
;
398 icapa
.value_len
= strlen(capa
->value
);
399 len
+= icapa
.value_len
;
402 wbuf
= imsg_create(ibuf
, GOTD_IMSG_CAPABILITY
, 0, 0, len
);
404 err
= got_error_from_errno("imsg_create CAPABILITY");
408 if (imsg_add(wbuf
, &icapa
, sizeof(icapa
)) == -1)
409 return got_error_from_errno("imsg_add CAPABILITY");
410 if (imsg_add(wbuf
, capa
->key
, icapa
.key_len
) == -1)
411 return got_error_from_errno("imsg_add CAPABILITY");
413 if (imsg_add(wbuf
, capa
->value
, icapa
.value_len
) == -1)
414 return got_error_from_errno("imsg_add CAPABILITY");
417 imsg_close(ibuf
, wbuf
);
422 static const struct got_error
*
423 send_capabilities(int *use_sidebands
, int *report_status
,
424 char *capabilities_str
, struct imsgbuf
*ibuf
)
426 const struct got_error
*err
= NULL
;
427 struct gotd_imsg_capabilities icapas
;
428 struct got_capability
*capa
= NULL
;
431 err
= got_gitproto_split_capabilities_str(&capa
, &ncapa
,
436 icapas
.ncapabilities
= ncapa
;
437 if (imsg_compose(ibuf
, GOTD_IMSG_CAPABILITIES
, 0, 0, -1,
438 &icapas
, sizeof(icapas
)) == -1) {
439 err
= got_error_from_errno("imsg_compose IMSG_CAPABILITIES");
443 for (i
= 0; i
< ncapa
; i
++) {
444 err
= send_capability(&capa
[i
], ibuf
);
448 strcmp(capa
[i
].key
, GOT_CAPA_SIDE_BAND_64K
) == 0)
451 strcmp(capa
[i
].key
, GOT_CAPA_REPORT_STATUS
) == 0)
459 static const struct got_error
*
460 forward_flushpkt(struct imsgbuf
*ibuf
)
462 if (imsg_compose(ibuf
, GOTD_IMSG_FLUSH
, 0, 0, -1, NULL
, 0) == -1)
463 return got_error_from_errno("imsg_compose FLUSH");
465 return gotd_imsg_flush(ibuf
);
468 static const struct got_error
*
469 recv_ack(struct imsg
*imsg
, uint8_t *expected_id
)
471 struct gotd_imsg_ack iack
;
474 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
475 if (datalen
!= sizeof(iack
))
476 return got_error(GOT_ERR_PRIVSEP_LEN
);
478 memcpy(&iack
, imsg
->data
, sizeof(iack
));
479 if (memcmp(iack
.object_id
, expected_id
, SHA1_DIGEST_LENGTH
) != 0)
480 return got_error(GOT_ERR_BAD_OBJ_ID
);
485 static const struct got_error
*
486 recv_nak(struct imsg
*imsg
, uint8_t *expected_id
)
488 struct gotd_imsg_ack inak
;
491 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
492 if (datalen
!= sizeof(inak
))
493 return got_error(GOT_ERR_PRIVSEP_LEN
);
495 memcpy(&inak
, imsg
->data
, sizeof(inak
));
496 if (memcmp(inak
.object_id
, expected_id
, SHA1_DIGEST_LENGTH
) != 0)
497 return got_error(GOT_ERR_BAD_OBJ_ID
);
503 static const struct got_error
*
504 recv_want(int *use_sidebands
, int outfd
, struct imsgbuf
*ibuf
,
505 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
507 const struct got_error
*err
;
508 struct gotd_imsg_want iwant
;
509 char *capabilities_str
;
513 memset(&iwant
, 0, sizeof(iwant
));
514 memset(&imsg
, 0, sizeof(imsg
));
516 err
= parse_want_line(&capabilities_str
, iwant
.object_id
, buf
, len
);
520 if (capabilities_str
) {
521 if (!expect_capabilities
) {
522 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
523 "unexpected capability announcement received");
526 err
= send_capabilities(use_sidebands
, NULL
, capabilities_str
,
533 if (imsg_compose(ibuf
, GOTD_IMSG_WANT
, 0, 0, -1,
534 &iwant
, sizeof(iwant
)) == -1) {
535 err
= got_error_from_errno("imsg_compose WANT");
539 err
= gotd_imsg_flush(ibuf
);
544 * Wait for an ACK, or an error in case the desired object
547 while (!done
&& err
== NULL
) {
548 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
551 switch (imsg
.hdr
.type
) {
552 case GOTD_IMSG_ERROR
:
553 err
= gotd_imsg_recv_error(NULL
, &imsg
);
556 err
= recv_ack(&imsg
, iwant
.object_id
);
562 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
569 free(capabilities_str
);
573 static const struct got_error
*
574 send_ack(int outfd
, uint8_t *id
, int chattygot
)
576 char hex
[SHA1_DIGEST_STRING_LENGTH
];
577 char buf
[GOT_PKT_MAX
];
580 if (got_sha1_digest_to_str(id
, hex
, sizeof(hex
)) == NULL
)
581 return got_error(GOT_ERR_BAD_OBJ_ID
);
583 len
= snprintf(buf
, sizeof(buf
), "ACK %s\n", hex
);
584 if (len
>= sizeof(buf
))
585 return got_error(GOT_ERR_NO_SPACE
);
587 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
590 static const struct got_error
*
591 send_nak(int outfd
, int chattygot
)
596 len
= snprintf(buf
, sizeof(buf
), "NAK\n");
597 if (len
>= sizeof(buf
))
598 return got_error(GOT_ERR_NO_SPACE
);
600 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
603 static const struct got_error
*
604 recv_have(int *have_ack
, int outfd
, struct imsgbuf
*ibuf
, char *buf
,
605 size_t len
, int chattygot
)
607 const struct got_error
*err
;
608 struct gotd_imsg_have ihave
;
612 memset(&ihave
, 0, sizeof(ihave
));
613 memset(&imsg
, 0, sizeof(imsg
));
615 err
= parse_have_line(ihave
.object_id
, buf
, len
);
619 if (imsg_compose(ibuf
, GOTD_IMSG_HAVE
, 0, 0, -1,
620 &ihave
, sizeof(ihave
)) == -1)
621 return got_error_from_errno("imsg_compose HAVE");
623 err
= gotd_imsg_flush(ibuf
);
628 * Wait for an ACK or a NAK, indicating whether a common
629 * commit object has been found.
631 while (!done
&& err
== NULL
) {
632 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
635 switch (imsg
.hdr
.type
) {
636 case GOTD_IMSG_ERROR
:
637 err
= gotd_imsg_recv_error(NULL
, &imsg
);
640 err
= recv_ack(&imsg
, ihave
.object_id
);
644 err
= send_ack(outfd
, ihave
.object_id
,
653 err
= recv_nak(&imsg
, ihave
.object_id
);
659 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
669 static const struct got_error
*
670 recv_done(int *packfd
, int outfd
, struct imsgbuf
*ibuf
, int chattygot
)
672 const struct got_error
*err
;
678 if (imsg_compose(ibuf
, GOTD_IMSG_DONE
, 0, 0, -1, NULL
, 0) == -1)
679 return got_error_from_errno("imsg_compose DONE");
681 err
= gotd_imsg_flush(ibuf
);
685 while (*packfd
== -1 && err
== NULL
) {
686 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
690 switch (imsg
.hdr
.type
) {
691 case GOTD_IMSG_ERROR
:
692 err
= gotd_imsg_recv_error(NULL
, &imsg
);
694 case GOTD_IMSG_PACKFILE_PIPE
:
695 fd
= imsg_get_fd(&imsg
);
699 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
702 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
712 static const struct got_error
*
713 relay_progress_reports(struct imsgbuf
*ibuf
, int outfd
, int chattygot
)
715 const struct got_error
*err
= NULL
;
716 int pack_starting
= 0;
717 struct gotd_imsg_packfile_progress iprog
;
718 char buf
[GOT_PKT_MAX
];
721 int p_deltify
= 0, n
;
722 const char *eol
= "\r";
724 memset(&imsg
, 0, sizeof(imsg
));
726 while (!pack_starting
&& err
== NULL
) {
727 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
731 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
732 switch (imsg
.hdr
.type
) {
733 case GOTD_IMSG_ERROR
:
734 err
= gotd_imsg_recv_error(NULL
, &imsg
);
736 case GOTD_IMSG_PACKFILE_READY
:
740 case GOTD_IMSG_PACKFILE_PROGRESS
:
741 if (datalen
!= sizeof(iprog
)) {
742 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
745 memcpy(&iprog
, imsg
.data
, sizeof(iprog
));
746 if (iprog
.nobj_total
> 0) {
747 p_deltify
= (iprog
.nobj_deltify
* 100) /
750 buf
[0] = GOT_SIDEBAND_PROGRESS_INFO
;
751 n
= snprintf(&buf
[1], sizeof(buf
) - 1,
752 "%d commits colored, "
758 if (n
>= sizeof(buf
) - 1)
760 err
= got_pkt_writepkt(outfd
, buf
, 1 + n
, chattygot
);
763 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
773 static const struct got_error
*
774 serve_read(int infd
, int outfd
, int gotd_sock
, const char *repo_path
,
777 const struct got_error
*err
= NULL
;
778 char buf
[GOT_PKT_MAX
];
782 STATE_EXPECT_MORE_WANT
,
783 STATE_EXPECT_HAVE_OR_DONE
,
786 enum protostate curstate
= STATE_EXPECT_WANT
;
787 int have_ack
= 0, use_sidebands
= 0, seen_have
= 0;
789 size_t pack_chunksize
;
791 imsg_init(&ibuf
, gotd_sock
);
793 err
= announce_refs(outfd
, &ibuf
, 1, repo_path
, chattygot
);
797 while (curstate
!= STATE_DONE
) {
800 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
,
805 if (curstate
!= STATE_EXPECT_WANT
&&
806 curstate
!= STATE_EXPECT_MORE_WANT
&&
807 curstate
!= STATE_EXPECT_HAVE_OR_DONE
) {
808 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
809 "unexpected flush packet received");
813 if (curstate
== STATE_EXPECT_WANT
) {
816 * If the client does not want to fetch
817 * anything we should receive a flush
818 * packet followed by EOF.
820 r
= read(infd
, buf
, sizeof(buf
));
822 err
= got_error_from_errno("read");
825 if (r
== 0) /* EOF */
828 /* Zero-length field followed by payload. */
829 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
830 "unexpected flush packet received");
834 if (curstate
== STATE_EXPECT_WANT
||
835 curstate
== STATE_EXPECT_MORE_WANT
||
836 curstate
== STATE_EXPECT_HAVE_OR_DONE
) {
837 err
= forward_flushpkt(&ibuf
);
841 if (curstate
== STATE_EXPECT_HAVE_OR_DONE
&&
843 err
= send_nak(outfd
, chattygot
);
847 if (curstate
== STATE_EXPECT_MORE_WANT
)
848 curstate
= STATE_EXPECT_HAVE_OR_DONE
;
849 } else if (n
>= 5 && strncmp(buf
, "want ", 5) == 0) {
850 if (curstate
!= STATE_EXPECT_WANT
&&
851 curstate
!= STATE_EXPECT_MORE_WANT
) {
852 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
853 "unexpected 'want' packet");
856 err
= recv_want(&use_sidebands
, outfd
, &ibuf
, buf
, n
,
857 curstate
== STATE_EXPECT_WANT
? 1 : 0, chattygot
);
860 if (curstate
== STATE_EXPECT_WANT
)
861 curstate
= STATE_EXPECT_MORE_WANT
;
862 } else if (n
>= 5 && strncmp(buf
, "have ", 5) == 0) {
863 if (curstate
!= STATE_EXPECT_HAVE_OR_DONE
) {
864 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
865 "unexpected 'have' packet");
868 err
= recv_have(&have_ack
, outfd
, &ibuf
,
873 } else if (n
== 5 && strncmp(buf
, "done\n", 5) == 0) {
874 if (curstate
!= STATE_EXPECT_HAVE_OR_DONE
) {
875 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
876 "unexpected 'done' packet");
879 err
= recv_done(&packfd
, outfd
, &ibuf
, chattygot
);
882 curstate
= STATE_DONE
;
885 err
= got_error(GOT_ERR_BAD_PACKET
);
891 err
= send_nak(outfd
, chattygot
);
897 err
= relay_progress_reports(&ibuf
, outfd
, chattygot
);
900 pack_chunksize
= GOT_SIDEBAND_64K_PACKFILE_DATA_MAX
;
902 pack_chunksize
= sizeof(buf
);
907 r
= read(packfd
, use_sidebands
? &buf
[1] : buf
,
910 err
= got_error_from_errno("read");
913 err
= got_pkt_flushpkt(outfd
, chattygot
);
918 buf
[0] = GOT_SIDEBAND_PACKFILE_DATA
;
919 err
= got_pkt_writepkt(outfd
, buf
, 1 + r
, chattygot
);
923 err
= got_poll_write_full(outfd
, buf
, r
);
925 if (err
->code
== GOT_ERR_EOF
)
933 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
934 err
= got_error_from_errno("close");
936 echo_error(err
, outfd
, chattygot
);
940 static const struct got_error
*
941 parse_ref_update_line(char **common_capabilities
, char **refname
,
942 uint8_t *old_id
, uint8_t *new_id
, char *buf
, size_t len
)
944 const struct got_error
*err
;
945 char *old_id_str
= NULL
, *new_id_str
= NULL
;
946 char *client_capabilities
= NULL
;
950 err
= got_gitproto_parse_ref_update_line(&old_id_str
, &new_id_str
,
951 refname
, &client_capabilities
, buf
, len
);
955 if (!got_parse_hash_digest(old_id
, old_id_str
, GOT_HASH_SHA1
) ||
956 !got_parse_hash_digest(new_id
, new_id_str
, GOT_HASH_SHA1
)) {
957 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
958 "ref-update with bad object ID");
961 if (!got_ref_name_is_valid(*refname
)) {
962 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
963 "ref-update with bad reference name");
967 if (client_capabilities
) {
968 err
= got_gitproto_match_capabilities(common_capabilities
,
969 NULL
, client_capabilities
, write_capabilities
,
970 nitems(write_capabilities
));
977 free(client_capabilities
);
985 static const struct got_error
*
986 recv_ref_update(int *report_status
, int outfd
, struct imsgbuf
*ibuf
,
987 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
989 const struct got_error
*err
;
990 struct gotd_imsg_ref_update iref
;
992 char *capabilities_str
= NULL
, *refname
= NULL
;
996 memset(&iref
, 0, sizeof(iref
));
997 memset(&imsg
, 0, sizeof(imsg
));
999 err
= parse_ref_update_line(&capabilities_str
, &refname
,
1000 iref
.old_id
, iref
.new_id
, buf
, len
);
1004 if (capabilities_str
) {
1005 if (!expect_capabilities
) {
1006 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1007 "unexpected capability announcement received");
1010 err
= send_capabilities(NULL
, report_status
, capabilities_str
,
1016 iref
.name_len
= strlen(refname
);
1017 len
= sizeof(iref
) + iref
.name_len
;
1018 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF_UPDATE
, 0, 0, len
);
1020 err
= got_error_from_errno("imsg_create REF_UPDATE");
1024 if (imsg_add(wbuf
, &iref
, sizeof(iref
)) == -1)
1025 return got_error_from_errno("imsg_add REF_UPDATE");
1026 if (imsg_add(wbuf
, refname
, iref
.name_len
) == -1)
1027 return got_error_from_errno("imsg_add REF_UPDATE");
1028 imsg_close(ibuf
, wbuf
);
1030 err
= gotd_imsg_flush(ibuf
);
1034 /* Wait for ACK or an error. */
1035 while (!done
&& err
== NULL
) {
1036 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
1039 switch (imsg
.hdr
.type
) {
1040 case GOTD_IMSG_ERROR
:
1041 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1044 err
= recv_ack(&imsg
, iref
.new_id
);
1050 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1057 free(capabilities_str
);
1062 static const struct got_error
*
1063 recv_packfile(struct imsg
*imsg
, int infd
)
1065 const struct got_error
*err
= NULL
;
1068 char buf
[GOT_PKT_MAX
];
1071 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1073 return got_error(GOT_ERR_PRIVSEP_MSG
);
1075 packfd
= imsg_get_fd(imsg
);
1077 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
1079 while (!pack_done
) {
1082 err
= got_poll_fd(infd
, POLLIN
, 1);
1084 if (err
->code
!= GOT_ERR_TIMEOUT
)
1088 r
= read(infd
, buf
, sizeof(buf
));
1090 err
= got_error_from_errno("read");
1095 * Git clients hang up their side of the
1096 * connection after sending the pack file.
1105 /* Detect gotd(8) closing the pack pipe when done. */
1106 err
= got_poll_fd(packfd
, 0, 1);
1108 if (err
->code
!= GOT_ERR_TIMEOUT
&&
1109 err
->code
!= GOT_ERR_EOF
)
1111 if (err
->code
== GOT_ERR_EOF
)
1116 /* Write pack data and/or detect pipe being closed. */
1117 err
= got_poll_write_full(packfd
, buf
, r
);
1119 if (err
->code
== GOT_ERR_EOF
)
1130 static const struct got_error
*
1131 report_unpack_status(struct imsg
*imsg
, int outfd
, int chattygot
)
1133 const struct got_error
*err
= NULL
;
1134 struct gotd_imsg_packfile_status istatus
;
1135 char buf
[GOT_PKT_MAX
];
1136 size_t datalen
, len
;
1137 char *reason
= NULL
;
1139 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1140 if (datalen
< sizeof(istatus
))
1141 return got_error(GOT_ERR_PRIVSEP_LEN
);
1142 memcpy(&istatus
, imsg
->data
, sizeof(istatus
));
1143 if (datalen
!= sizeof(istatus
) + istatus
.reason_len
)
1144 return got_error(GOT_ERR_PRIVSEP_LEN
);
1146 reason
= strndup(imsg
->data
+ sizeof(istatus
), istatus
.reason_len
);
1147 if (reason
== NULL
) {
1148 err
= got_error_from_errno("strndup");
1153 len
= snprintf(buf
, sizeof(buf
), "unpack ok\n");
1155 len
= snprintf(buf
, sizeof(buf
), "unpack %s\n", reason
);
1156 if (len
>= sizeof(buf
)) {
1157 err
= got_error(GOT_ERR_NO_SPACE
);
1161 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1167 static const struct got_error
*
1168 recv_ref_update_ok(struct imsg
*imsg
, int outfd
, int chattygot
)
1170 const struct got_error
*err
= NULL
;
1171 struct gotd_imsg_ref_update_ok iok
;
1172 size_t datalen
, len
;
1173 char buf
[GOT_PKT_MAX
];
1174 char *refname
= NULL
;
1176 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1177 if (datalen
< sizeof(iok
))
1178 return got_error(GOT_ERR_PRIVSEP_LEN
);
1179 memcpy(&iok
, imsg
->data
, sizeof(iok
));
1180 if (datalen
!= sizeof(iok
) + iok
.name_len
)
1181 return got_error(GOT_ERR_PRIVSEP_LEN
);
1183 memcpy(&iok
, imsg
->data
, sizeof(iok
));
1185 refname
= strndup(imsg
->data
+ sizeof(iok
), iok
.name_len
);
1186 if (refname
== NULL
)
1187 return got_error_from_errno("strndup");
1189 len
= snprintf(buf
, sizeof(buf
), "ok %s\n", refname
);
1190 if (len
>= sizeof(buf
)) {
1191 err
= got_error(GOT_ERR_NO_SPACE
);
1195 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1201 static const struct got_error
*
1202 recv_ref_update_ng(struct imsg
*imsg
, int outfd
, int chattygot
)
1204 const struct got_error
*err
= NULL
;
1205 struct gotd_imsg_ref_update_ng ing
;
1206 size_t datalen
, len
;
1207 char buf
[GOT_PKT_MAX
];
1208 char *refname
= NULL
, *reason
= NULL
;
1210 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1211 if (datalen
< sizeof(ing
))
1212 return got_error(GOT_ERR_PRIVSEP_LEN
);
1213 memcpy(&ing
, imsg
->data
, sizeof(ing
));
1214 if (datalen
!= sizeof(ing
) + ing
.name_len
+ ing
.reason_len
)
1215 return got_error(GOT_ERR_PRIVSEP_LEN
);
1217 memcpy(&ing
, imsg
->data
, sizeof(ing
));
1219 refname
= strndup(imsg
->data
+ sizeof(ing
), ing
.name_len
);
1220 if (refname
== NULL
)
1221 return got_error_from_errno("strndup");
1223 reason
= strndup(imsg
->data
+ sizeof(ing
) + ing
.name_len
,
1225 if (reason
== NULL
) {
1226 err
= got_error_from_errno("strndup");
1230 len
= snprintf(buf
, sizeof(buf
), "ng %s %s\n", refname
, reason
);
1231 if (len
>= sizeof(buf
)) {
1232 err
= got_error(GOT_ERR_NO_SPACE
);
1236 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1243 static const struct got_error
*
1244 serve_write(int infd
, int outfd
, int gotd_sock
, const char *repo_path
,
1247 const struct got_error
*err
= NULL
;
1248 char buf
[GOT_PKT_MAX
];
1249 struct imsgbuf ibuf
;
1251 STATE_EXPECT_REF_UPDATE
,
1252 STATE_EXPECT_MORE_REF_UPDATES
,
1253 STATE_EXPECT_PACKFILE
,
1254 STATE_PACKFILE_RECEIVED
,
1257 enum protostate curstate
= STATE_EXPECT_REF_UPDATE
;
1259 int report_status
= 0;
1261 imsg_init(&ibuf
, gotd_sock
);
1262 memset(&imsg
, 0, sizeof(imsg
));
1264 err
= announce_refs(outfd
, &ibuf
, 0, repo_path
, chattygot
);
1268 while (curstate
!= STATE_EXPECT_PACKFILE
) {
1271 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
,
1276 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1277 /* The client will not send us anything. */
1279 } else if (curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1280 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1281 "unexpected flush packet received");
1284 err
= forward_flushpkt(&ibuf
);
1287 curstate
= STATE_EXPECT_PACKFILE
;
1288 } else if (n
>= (SHA1_DIGEST_STRING_LENGTH
* 2) + 2) {
1289 if (curstate
!= STATE_EXPECT_REF_UPDATE
&&
1290 curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1291 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1292 "unexpected ref-update packet");
1295 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1296 err
= recv_ref_update(&report_status
,
1297 outfd
, &ibuf
, buf
, n
, 1, chattygot
);
1299 err
= recv_ref_update(NULL
, outfd
, &ibuf
,
1300 buf
, n
, 0, chattygot
);
1304 curstate
= STATE_EXPECT_MORE_REF_UPDATES
;
1306 err
= got_error(GOT_ERR_BAD_PACKET
);
1311 while (curstate
!= STATE_PACKFILE_RECEIVED
) {
1312 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1315 switch (imsg
.hdr
.type
) {
1316 case GOTD_IMSG_ERROR
:
1317 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1319 case GOTD_IMSG_PACKFILE_PIPE
:
1320 err
= recv_packfile(&imsg
, infd
);
1322 if (err
->code
!= GOT_ERR_EOF
)
1325 * EOF is reported when the client hangs up,
1326 * which can happen with Git clients.
1327 * The socket should stay half-open so we
1328 * can still send our reports if requested.
1332 curstate
= STATE_PACKFILE_RECEIVED
;
1335 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1344 while (curstate
!= STATE_REFS_UPDATED
&& err
== NULL
) {
1345 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1348 switch (imsg
.hdr
.type
) {
1349 case GOTD_IMSG_ERROR
:
1350 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1352 case GOTD_IMSG_PACKFILE_STATUS
:
1355 err
= report_unpack_status(&imsg
, outfd
, chattygot
);
1357 case GOTD_IMSG_REF_UPDATE_OK
:
1360 err
= recv_ref_update_ok(&imsg
, outfd
, chattygot
);
1362 case GOTD_IMSG_REF_UPDATE_NG
:
1365 err
= recv_ref_update_ng(&imsg
, outfd
, chattygot
);
1367 case GOTD_IMSG_REFS_UPDATED
:
1368 curstate
= STATE_REFS_UPDATED
;
1369 err
= got_pkt_flushpkt(outfd
, chattygot
);
1372 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1381 echo_error(err
, outfd
, chattygot
);
1385 const struct got_error
*
1386 got_serve(int infd
, int outfd
, const char *command
, const char *repo_path
,
1387 int gotd_sock
, int chattygot
)
1389 const struct got_error
*err
= NULL
;
1391 if (strcmp(command
, GOT_DIAL_CMD_FETCH
) == 0)
1392 err
= serve_read(infd
, outfd
, gotd_sock
, repo_path
, chattygot
);
1393 else if (strcmp(command
, GOT_DIAL_CMD_SEND
) == 0)
1394 err
= serve_write(infd
, outfd
, gotd_sock
, repo_path
,
1397 err
= got_error(GOT_ERR_BAD_PACKET
);