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 if (imsgbuf_init(&ibuf
, gotd_sock
) == -1)
792 return got_error_from_errno("imsgbuf_init");
793 imsgbuf_allow_fdpass(&ibuf
);
795 err
= announce_refs(outfd
, &ibuf
, 1, repo_path
, chattygot
);
799 while (curstate
!= STATE_DONE
) {
802 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
,
807 if (curstate
!= STATE_EXPECT_WANT
&&
808 curstate
!= STATE_EXPECT_MORE_WANT
&&
809 curstate
!= STATE_EXPECT_HAVE_OR_DONE
) {
810 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
811 "unexpected flush packet received");
815 if (curstate
== STATE_EXPECT_WANT
) {
818 * If the client does not want to fetch
819 * anything we should receive a flush
820 * packet followed by EOF.
822 r
= read(infd
, buf
, sizeof(buf
));
824 err
= got_error_from_errno("read");
827 if (r
== 0) /* EOF */
830 /* Zero-length field followed by payload. */
831 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
832 "unexpected flush packet received");
836 if (curstate
== STATE_EXPECT_WANT
||
837 curstate
== STATE_EXPECT_MORE_WANT
||
838 curstate
== STATE_EXPECT_HAVE_OR_DONE
) {
839 err
= forward_flushpkt(&ibuf
);
843 if (curstate
== STATE_EXPECT_HAVE_OR_DONE
&&
845 err
= send_nak(outfd
, chattygot
);
849 if (curstate
== STATE_EXPECT_MORE_WANT
)
850 curstate
= STATE_EXPECT_HAVE_OR_DONE
;
851 } else if (n
>= 5 && strncmp(buf
, "want ", 5) == 0) {
852 if (curstate
!= STATE_EXPECT_WANT
&&
853 curstate
!= STATE_EXPECT_MORE_WANT
) {
854 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
855 "unexpected 'want' packet");
858 err
= recv_want(&use_sidebands
, outfd
, &ibuf
, buf
, n
,
859 curstate
== STATE_EXPECT_WANT
? 1 : 0, chattygot
);
862 if (curstate
== STATE_EXPECT_WANT
)
863 curstate
= STATE_EXPECT_MORE_WANT
;
864 } else if (n
>= 5 && strncmp(buf
, "have ", 5) == 0) {
865 if (curstate
!= STATE_EXPECT_HAVE_OR_DONE
) {
866 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
867 "unexpected 'have' packet");
870 err
= recv_have(&have_ack
, outfd
, &ibuf
,
875 } else if (n
== 5 && strncmp(buf
, "done\n", 5) == 0) {
876 if (curstate
!= STATE_EXPECT_HAVE_OR_DONE
) {
877 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
878 "unexpected 'done' packet");
881 err
= recv_done(&packfd
, outfd
, &ibuf
, chattygot
);
884 curstate
= STATE_DONE
;
887 err
= got_error(GOT_ERR_BAD_PACKET
);
893 err
= send_nak(outfd
, chattygot
);
899 err
= relay_progress_reports(&ibuf
, outfd
, chattygot
);
902 pack_chunksize
= GOT_SIDEBAND_64K_PACKFILE_DATA_MAX
;
904 pack_chunksize
= sizeof(buf
);
909 r
= read(packfd
, use_sidebands
? &buf
[1] : buf
,
912 err
= got_error_from_errno("read");
915 err
= got_pkt_flushpkt(outfd
, chattygot
);
920 buf
[0] = GOT_SIDEBAND_PACKFILE_DATA
;
921 err
= got_pkt_writepkt(outfd
, buf
, 1 + r
, chattygot
);
925 err
= got_poll_write_full(outfd
, buf
, r
);
927 if (err
->code
== GOT_ERR_EOF
)
934 imsgbuf_clear(&ibuf
);
935 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
936 err
= got_error_from_errno("close");
938 echo_error(err
, outfd
, chattygot
);
942 static const struct got_error
*
943 parse_ref_update_line(char **common_capabilities
, char **refname
,
944 uint8_t *old_id
, uint8_t *new_id
, char *buf
, size_t len
)
946 const struct got_error
*err
;
947 char *old_id_str
= NULL
, *new_id_str
= NULL
;
948 char *client_capabilities
= NULL
;
952 err
= got_gitproto_parse_ref_update_line(&old_id_str
, &new_id_str
,
953 refname
, &client_capabilities
, buf
, len
);
957 if (!got_parse_hash_digest(old_id
, old_id_str
, GOT_HASH_SHA1
) ||
958 !got_parse_hash_digest(new_id
, new_id_str
, GOT_HASH_SHA1
)) {
959 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
960 "ref-update with bad object ID");
963 if (!got_ref_name_is_valid(*refname
)) {
964 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
965 "ref-update with bad reference name");
969 if (client_capabilities
) {
970 err
= got_gitproto_match_capabilities(common_capabilities
,
971 NULL
, client_capabilities
, write_capabilities
,
972 nitems(write_capabilities
));
979 free(client_capabilities
);
987 static const struct got_error
*
988 recv_ref_update(int *report_status
, int outfd
, struct imsgbuf
*ibuf
,
989 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
991 const struct got_error
*err
;
992 struct gotd_imsg_ref_update iref
;
994 char *capabilities_str
= NULL
, *refname
= NULL
;
998 memset(&iref
, 0, sizeof(iref
));
999 memset(&imsg
, 0, sizeof(imsg
));
1001 err
= parse_ref_update_line(&capabilities_str
, &refname
,
1002 iref
.old_id
, iref
.new_id
, buf
, len
);
1006 if (capabilities_str
) {
1007 if (!expect_capabilities
) {
1008 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1009 "unexpected capability announcement received");
1012 err
= send_capabilities(NULL
, report_status
, capabilities_str
,
1018 iref
.name_len
= strlen(refname
);
1019 len
= sizeof(iref
) + iref
.name_len
;
1020 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF_UPDATE
, 0, 0, len
);
1022 err
= got_error_from_errno("imsg_create REF_UPDATE");
1026 if (imsg_add(wbuf
, &iref
, sizeof(iref
)) == -1)
1027 return got_error_from_errno("imsg_add REF_UPDATE");
1028 if (imsg_add(wbuf
, refname
, iref
.name_len
) == -1)
1029 return got_error_from_errno("imsg_add REF_UPDATE");
1030 imsg_close(ibuf
, wbuf
);
1032 err
= gotd_imsg_flush(ibuf
);
1036 /* Wait for ACK or an error. */
1037 while (!done
&& err
== NULL
) {
1038 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
1041 switch (imsg
.hdr
.type
) {
1042 case GOTD_IMSG_ERROR
:
1043 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1046 err
= recv_ack(&imsg
, iref
.new_id
);
1052 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1059 free(capabilities_str
);
1064 static const struct got_error
*
1065 recv_packfile(struct imsg
*imsg
, int infd
)
1067 const struct got_error
*err
= NULL
;
1070 char buf
[GOT_PKT_MAX
];
1073 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1075 return got_error(GOT_ERR_PRIVSEP_MSG
);
1077 packfd
= imsg_get_fd(imsg
);
1079 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
1081 while (!pack_done
) {
1084 err
= got_poll_fd(infd
, POLLIN
, 1);
1086 if (err
->code
!= GOT_ERR_TIMEOUT
)
1090 r
= read(infd
, buf
, sizeof(buf
));
1092 err
= got_error_from_errno("read");
1097 * Git clients hang up their side of the
1098 * connection after sending the pack file.
1107 /* Detect gotd(8) closing the pack pipe when done. */
1108 err
= got_poll_fd(packfd
, 0, 1);
1110 if (err
->code
!= GOT_ERR_TIMEOUT
&&
1111 err
->code
!= GOT_ERR_EOF
)
1113 if (err
->code
== GOT_ERR_EOF
)
1118 /* Write pack data and/or detect pipe being closed. */
1119 err
= got_poll_write_full(packfd
, buf
, r
);
1121 if (err
->code
== GOT_ERR_EOF
)
1132 static const struct got_error
*
1133 report_unpack_status(struct imsg
*imsg
, int outfd
, int chattygot
)
1135 const struct got_error
*err
= NULL
;
1136 struct gotd_imsg_packfile_status istatus
;
1137 char buf
[GOT_PKT_MAX
];
1138 size_t datalen
, len
;
1139 char *reason
= NULL
;
1141 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1142 if (datalen
< sizeof(istatus
))
1143 return got_error(GOT_ERR_PRIVSEP_LEN
);
1144 memcpy(&istatus
, imsg
->data
, sizeof(istatus
));
1145 if (datalen
!= sizeof(istatus
) + istatus
.reason_len
)
1146 return got_error(GOT_ERR_PRIVSEP_LEN
);
1148 reason
= strndup(imsg
->data
+ sizeof(istatus
), istatus
.reason_len
);
1149 if (reason
== NULL
) {
1150 err
= got_error_from_errno("strndup");
1155 len
= snprintf(buf
, sizeof(buf
), "unpack ok\n");
1157 len
= snprintf(buf
, sizeof(buf
), "unpack %s\n", reason
);
1158 if (len
>= sizeof(buf
)) {
1159 err
= got_error(GOT_ERR_NO_SPACE
);
1163 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1169 static const struct got_error
*
1170 recv_ref_update_ok(struct imsg
*imsg
, int outfd
, int chattygot
)
1172 const struct got_error
*err
= NULL
;
1173 struct gotd_imsg_ref_update_ok iok
;
1174 size_t datalen
, len
;
1175 char buf
[GOT_PKT_MAX
];
1176 char *refname
= NULL
;
1178 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1179 if (datalen
< sizeof(iok
))
1180 return got_error(GOT_ERR_PRIVSEP_LEN
);
1181 memcpy(&iok
, imsg
->data
, sizeof(iok
));
1182 if (datalen
!= sizeof(iok
) + iok
.name_len
)
1183 return got_error(GOT_ERR_PRIVSEP_LEN
);
1185 memcpy(&iok
, imsg
->data
, sizeof(iok
));
1187 refname
= strndup(imsg
->data
+ sizeof(iok
), iok
.name_len
);
1188 if (refname
== NULL
)
1189 return got_error_from_errno("strndup");
1191 len
= snprintf(buf
, sizeof(buf
), "ok %s\n", refname
);
1192 if (len
>= sizeof(buf
)) {
1193 err
= got_error(GOT_ERR_NO_SPACE
);
1197 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1203 static const struct got_error
*
1204 recv_ref_update_ng(struct imsg
*imsg
, int outfd
, int chattygot
)
1206 const struct got_error
*err
= NULL
;
1207 struct gotd_imsg_ref_update_ng ing
;
1208 size_t datalen
, len
;
1209 char buf
[GOT_PKT_MAX
];
1210 char *refname
= NULL
, *reason
= NULL
;
1212 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1213 if (datalen
< sizeof(ing
))
1214 return got_error(GOT_ERR_PRIVSEP_LEN
);
1215 memcpy(&ing
, imsg
->data
, sizeof(ing
));
1216 if (datalen
!= sizeof(ing
) + ing
.name_len
+ ing
.reason_len
)
1217 return got_error(GOT_ERR_PRIVSEP_LEN
);
1219 memcpy(&ing
, imsg
->data
, sizeof(ing
));
1221 refname
= strndup(imsg
->data
+ sizeof(ing
), ing
.name_len
);
1222 if (refname
== NULL
)
1223 return got_error_from_errno("strndup");
1225 reason
= strndup(imsg
->data
+ sizeof(ing
) + ing
.name_len
,
1227 if (reason
== NULL
) {
1228 err
= got_error_from_errno("strndup");
1232 len
= snprintf(buf
, sizeof(buf
), "ng %s %s\n", refname
, reason
);
1233 if (len
>= sizeof(buf
)) {
1234 err
= got_error(GOT_ERR_NO_SPACE
);
1238 err
= got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
1245 static const struct got_error
*
1246 serve_write(int infd
, int outfd
, int gotd_sock
, const char *repo_path
,
1249 const struct got_error
*err
= NULL
;
1250 char buf
[GOT_PKT_MAX
];
1251 struct imsgbuf ibuf
;
1253 STATE_EXPECT_REF_UPDATE
,
1254 STATE_EXPECT_MORE_REF_UPDATES
,
1255 STATE_EXPECT_PACKFILE
,
1256 STATE_PACKFILE_RECEIVED
,
1259 enum protostate curstate
= STATE_EXPECT_REF_UPDATE
;
1261 int report_status
= 0;
1263 if (imsgbuf_init(&ibuf
, gotd_sock
) == -1)
1264 return got_error_from_errno("imsgbuf_init");
1265 imsgbuf_allow_fdpass(&ibuf
);
1267 memset(&imsg
, 0, sizeof(imsg
));
1269 err
= announce_refs(outfd
, &ibuf
, 0, repo_path
, chattygot
);
1273 while (curstate
!= STATE_EXPECT_PACKFILE
) {
1276 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
,
1281 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1282 /* The client will not send us anything. */
1284 } else if (curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1285 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1286 "unexpected flush packet received");
1289 err
= forward_flushpkt(&ibuf
);
1292 curstate
= STATE_EXPECT_PACKFILE
;
1293 } else if (n
>= (SHA1_DIGEST_STRING_LENGTH
* 2) + 2) {
1294 if (curstate
!= STATE_EXPECT_REF_UPDATE
&&
1295 curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1296 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1297 "unexpected ref-update packet");
1300 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1301 err
= recv_ref_update(&report_status
,
1302 outfd
, &ibuf
, buf
, n
, 1, chattygot
);
1304 err
= recv_ref_update(NULL
, outfd
, &ibuf
,
1305 buf
, n
, 0, chattygot
);
1309 curstate
= STATE_EXPECT_MORE_REF_UPDATES
;
1311 err
= got_error(GOT_ERR_BAD_PACKET
);
1316 while (curstate
!= STATE_PACKFILE_RECEIVED
) {
1317 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1320 switch (imsg
.hdr
.type
) {
1321 case GOTD_IMSG_ERROR
:
1322 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1324 case GOTD_IMSG_PACKFILE_PIPE
:
1325 err
= recv_packfile(&imsg
, infd
);
1327 if (err
->code
!= GOT_ERR_EOF
)
1330 * EOF is reported when the client hangs up,
1331 * which can happen with Git clients.
1332 * The socket should stay half-open so we
1333 * can still send our reports if requested.
1337 curstate
= STATE_PACKFILE_RECEIVED
;
1340 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1349 while (curstate
!= STATE_REFS_UPDATED
&& err
== NULL
) {
1350 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1353 switch (imsg
.hdr
.type
) {
1354 case GOTD_IMSG_ERROR
:
1355 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1357 case GOTD_IMSG_PACKFILE_STATUS
:
1360 err
= report_unpack_status(&imsg
, outfd
, chattygot
);
1362 case GOTD_IMSG_REF_UPDATE_OK
:
1365 err
= recv_ref_update_ok(&imsg
, outfd
, chattygot
);
1367 case GOTD_IMSG_REF_UPDATE_NG
:
1370 err
= recv_ref_update_ng(&imsg
, outfd
, chattygot
);
1372 case GOTD_IMSG_REFS_UPDATED
:
1373 curstate
= STATE_REFS_UPDATED
;
1374 err
= got_pkt_flushpkt(outfd
, chattygot
);
1377 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1384 imsgbuf_clear(&ibuf
);
1386 echo_error(err
, outfd
, chattygot
);
1390 const struct got_error
*
1391 got_serve(int infd
, int outfd
, const char *command
, const char *repo_path
,
1392 int gotd_sock
, int chattygot
)
1394 const struct got_error
*err
= NULL
;
1396 if (strcmp(command
, GOT_DIAL_CMD_FETCH
) == 0)
1397 err
= serve_read(infd
, outfd
, gotd_sock
, repo_path
, chattygot
);
1398 else if (strcmp(command
, GOT_DIAL_CMD_SEND
) == 0)
1399 err
= serve_write(infd
, outfd
, gotd_sock
, repo_path
,
1402 err
= got_error(GOT_ERR_BAD_PACKET
);