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]))
53 static const struct got_capability read_capabilities
[] = {
54 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
55 { GOT_CAPA_OFS_DELTA
, NULL
},
56 { GOT_CAPA_SIDE_BAND_64K
, NULL
},
59 static const struct got_capability write_capabilities
[] = {
60 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
61 { GOT_CAPA_OFS_DELTA
, NULL
},
62 { GOT_CAPA_REPORT_STATUS
, NULL
},
63 { GOT_CAPA_NO_THIN
, NULL
},
64 { GOT_CAPA_DELETE_REFS
, NULL
},
67 static const struct got_error
*
68 append_read_capabilities(size_t *capalen
, size_t len
, const char *symrefstr
,
69 uint8_t *buf
, size_t bufsize
)
71 struct got_capability capa
[nitems(read_capabilities
) + 1];
74 memcpy(&capa
, read_capabilities
, sizeof(read_capabilities
));
76 capa
[nitems(read_capabilities
)].key
= "symref";
77 capa
[nitems(read_capabilities
)].value
= symrefstr
;
80 ncapa
= nitems(read_capabilities
);
82 return got_gitproto_append_capabilities(capalen
, buf
, len
,
83 bufsize
, capa
, ncapa
);
86 static const struct got_error
*
87 send_ref(int outfd
, uint8_t *id
, const char *refname
, int send_capabilities
,
88 int client_is_reading
, const char *symrefstr
, int chattygot
)
90 const struct got_error
*err
= NULL
;
91 char hex
[SHA1_DIGEST_STRING_LENGTH
];
92 char buf
[GOT_PKT_MAX
];
93 size_t len
, capalen
= 0;
95 if (got_sha1_digest_to_str(id
, hex
, sizeof(hex
)) == NULL
)
96 return got_error(GOT_ERR_BAD_OBJ_ID
);
98 len
= snprintf(buf
, sizeof(buf
), "%s %s", hex
, refname
);
99 if (len
>= sizeof(buf
))
100 return got_error(GOT_ERR_NO_SPACE
);
102 if (send_capabilities
) {
103 if (client_is_reading
) {
104 err
= append_read_capabilities(&capalen
, len
,
105 symrefstr
, buf
, sizeof(buf
));
107 err
= got_gitproto_append_capabilities(&capalen
,
108 buf
, len
, sizeof(buf
), write_capabilities
,
109 nitems(write_capabilities
));
116 if (len
+ 1 >= sizeof(buf
))
117 return got_error(GOT_ERR_NO_SPACE
);
122 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
125 static const struct got_error
*
126 send_zero_refs(int outfd
, int client_is_reading
, int chattygot
)
128 const struct got_error
*err
= NULL
;
129 const char *line
= GOT_SHA1_STRING_ZERO
" capabilities^{}";
130 char buf
[GOT_PKT_MAX
];
131 size_t len
, capalen
= 0;
133 len
= strlcpy(buf
, line
, sizeof(buf
));
134 if (len
>= sizeof(buf
))
135 return got_error(GOT_ERR_NO_SPACE
);
137 if (client_is_reading
) {
138 err
= got_gitproto_append_capabilities(&capalen
, buf
, len
,
139 sizeof(buf
), read_capabilities
, nitems(read_capabilities
));
143 err
= got_gitproto_append_capabilities(&capalen
, buf
, len
,
144 sizeof(buf
), write_capabilities
,
145 nitems(write_capabilities
));
150 return got_pkt_writepkt(outfd
, buf
, len
+ capalen
, chattygot
);
154 echo_error(const struct got_error
*err
, int outfd
, int chattygot
)
156 char buf
[4 + GOT_ERR_MAX_MSG_SIZE
];
160 * Echo the error to the client on a pkt-line.
161 * The client should then terminate its session.
163 buf
[0] = 'E'; buf
[1] = 'R'; buf
[2] = 'R'; buf
[3] = ' '; buf
[4] = '\0';
164 len
= strlcat(buf
, err
->msg
, sizeof(buf
));
165 got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
168 static const struct got_error
*
169 announce_refs(int outfd
, struct imsgbuf
*ibuf
, int client_is_reading
,
170 const char *repo_path
, int chattygot
)
172 const struct got_error
*err
= NULL
;
175 struct gotd_imsg_list_refs lsref
;
176 struct gotd_imsg_reflist ireflist
;
177 struct gotd_imsg_ref iref
;
178 struct gotd_imsg_symref isymref
;
180 int have_nrefs
= 0, sent_capabilities
= 0;
181 char *symrefname
= NULL
, *symreftarget
= NULL
, *symrefstr
= NULL
;
182 char *refname
= NULL
;
184 memset(&imsg
, 0, sizeof(imsg
));
185 memset(&lsref
, 0, sizeof(lsref
));
187 if (strlcpy(lsref
.repo_name
, repo_path
, sizeof(lsref
.repo_name
)) >=
188 sizeof(lsref
.repo_name
))
189 return got_error(GOT_ERR_NO_SPACE
);
190 lsref
.client_is_reading
= client_is_reading
;
192 if (imsg_compose(ibuf
, GOTD_IMSG_LIST_REFS
, 0, 0, -1,
193 &lsref
, sizeof(lsref
)) == -1)
194 return got_error_from_errno("imsg_compose LIST_REFS");
196 err
= gotd_imsg_flush(ibuf
);
200 while (!have_nrefs
|| nrefs
> 0) {
201 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
204 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
205 switch (imsg
.hdr
.type
) {
206 case GOTD_IMSG_ERROR
:
207 err
= gotd_imsg_recv_error(NULL
, &imsg
);
209 case GOTD_IMSG_REFLIST
:
210 if (have_nrefs
|| nrefs
> 0) {
211 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
214 if (datalen
!= sizeof(ireflist
)) {
215 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
218 memcpy(&ireflist
, imsg
.data
, sizeof(ireflist
));
219 nrefs
= ireflist
.nrefs
;
222 err
= send_zero_refs(outfd
, client_is_reading
,
226 if (!have_nrefs
|| nrefs
== 0) {
227 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
230 if (datalen
< sizeof(iref
)) {
231 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
234 memcpy(&iref
, imsg
.data
, sizeof(iref
));
235 if (datalen
!= sizeof(iref
) + iref
.name_len
) {
236 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
239 refname
= strndup(imsg
.data
+ sizeof(iref
),
241 if (refname
== NULL
) {
242 err
= got_error_from_errno("strndup");
245 err
= send_ref(outfd
, iref
.id
, refname
,
246 !sent_capabilities
, client_is_reading
,
252 sent_capabilities
= 1;
256 case GOTD_IMSG_SYMREF
:
257 if (!have_nrefs
|| nrefs
== 0) {
258 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
261 if (datalen
< sizeof(isymref
)) {
262 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
265 memcpy(&isymref
, imsg
.data
, sizeof(isymref
));
266 if (datalen
!= sizeof(isymref
) + isymref
.name_len
+
267 isymref
.target_len
) {
268 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
273 * For now, we only announce one symbolic ref,
274 * as part of our capability advertisement.
276 if (sent_capabilities
|| symrefstr
!= NULL
||
277 symrefname
!= NULL
|| symreftarget
!= NULL
)
280 symrefname
= strndup(imsg
.data
+ sizeof(isymref
),
282 if (symrefname
== NULL
) {
283 err
= got_error_from_errno("malloc");
287 symreftarget
= strndup(
288 imsg
.data
+ sizeof(isymref
) + isymref
.name_len
,
290 if (symreftarget
== NULL
) {
291 err
= got_error_from_errno("strndup");
295 if (asprintf(&symrefstr
, "%s:%s", symrefname
,
296 symreftarget
) == -1) {
297 err
= got_error_from_errno("asprintf");
300 err
= send_ref(outfd
, isymref
.target_id
, symrefname
,
301 !sent_capabilities
, client_is_reading
, symrefstr
,
307 sent_capabilities
= 1;
312 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
319 err
= got_pkt_flushpkt(outfd
, chattygot
);
329 static const struct got_error
*
330 parse_want_line(char **common_capabilities
, uint8_t *id
, char *buf
, size_t len
)
332 const struct got_error
*err
;
333 char *id_str
= NULL
, *client_capabilities
= NULL
;
335 err
= got_gitproto_parse_want_line(&id_str
,
336 &client_capabilities
, buf
, len
);
340 if (!got_parse_hash_digest(id
, id_str
, GOT_HASH_SHA1
)) {
341 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
342 "want-line with bad object ID");
346 if (client_capabilities
) {
347 err
= got_gitproto_match_capabilities(common_capabilities
,
348 NULL
, client_capabilities
, read_capabilities
,
349 nitems(read_capabilities
));
355 free(client_capabilities
);
359 static const struct got_error
*
360 parse_have_line(uint8_t *id
, char *buf
, size_t len
)
362 const struct got_error
*err
;
365 err
= got_gitproto_parse_have_line(&id_str
, buf
, len
);
369 if (!got_parse_hash_digest(id
, id_str
, GOT_HASH_SHA1
)) {
370 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
371 "have-line with bad object ID");
379 static const struct got_error
*
380 send_capability(struct got_capability
*capa
, struct imsgbuf
*ibuf
)
382 const struct got_error
*err
= NULL
;
383 struct gotd_imsg_capability icapa
;
387 memset(&icapa
, 0, sizeof(icapa
));
389 icapa
.key_len
= strlen(capa
->key
);
390 len
= sizeof(icapa
) + icapa
.key_len
;
392 icapa
.value_len
= strlen(capa
->value
);
393 len
+= icapa
.value_len
;
396 wbuf
= imsg_create(ibuf
, GOTD_IMSG_CAPABILITY
, 0, 0, len
);
398 err
= got_error_from_errno("imsg_create CAPABILITY");
402 if (imsg_add(wbuf
, &icapa
, sizeof(icapa
)) == -1)
403 return got_error_from_errno("imsg_add CAPABILITY");
404 if (imsg_add(wbuf
, capa
->key
, icapa
.key_len
) == -1)
405 return got_error_from_errno("imsg_add CAPABILITY");
407 if (imsg_add(wbuf
, capa
->value
, icapa
.value_len
) == -1)
408 return got_error_from_errno("imsg_add CAPABILITY");
412 imsg_close(ibuf
, wbuf
);
417 static const struct got_error
*
418 send_capabilities(int *use_sidebands
, int *report_status
,
419 char *capabilities_str
, struct imsgbuf
*ibuf
)
421 const struct got_error
*err
= NULL
;
422 struct gotd_imsg_capabilities icapas
;
423 struct got_capability
*capa
= NULL
;
426 err
= got_gitproto_split_capabilities_str(&capa
, &ncapa
,
431 icapas
.ncapabilities
= ncapa
;
432 if (imsg_compose(ibuf
, GOTD_IMSG_CAPABILITIES
, 0, 0, -1,
433 &icapas
, sizeof(icapas
)) == -1) {
434 err
= got_error_from_errno("imsg_compose IMSG_CAPABILITIES");
438 for (i
= 0; i
< ncapa
; i
++) {
439 err
= send_capability(&capa
[i
], ibuf
);
443 strcmp(capa
[i
].key
, GOT_CAPA_SIDE_BAND_64K
) == 0)
446 strcmp(capa
[i
].key
, GOT_CAPA_REPORT_STATUS
) == 0)
454 static const struct got_error
*
455 forward_flushpkt(struct imsgbuf
*ibuf
)
457 if (imsg_compose(ibuf
, GOTD_IMSG_FLUSH
, 0, 0, -1, NULL
, 0) == -1)
458 return got_error_from_errno("imsg_compose FLUSH");
460 return gotd_imsg_flush(ibuf
);
463 static const struct got_error
*
464 recv_ack(struct imsg
*imsg
, uint8_t *expected_id
)
466 struct gotd_imsg_ack iack
;
469 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
470 if (datalen
!= sizeof(iack
))
471 return got_error(GOT_ERR_PRIVSEP_LEN
);
473 memcpy(&iack
, imsg
->data
, sizeof(iack
));
474 if (memcmp(iack
.object_id
, expected_id
, SHA1_DIGEST_LENGTH
) != 0)
475 return got_error(GOT_ERR_BAD_OBJ_ID
);
480 static const struct got_error
*
481 recv_nak(struct imsg
*imsg
, uint8_t *expected_id
)
483 struct gotd_imsg_ack inak
;
486 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
487 if (datalen
!= sizeof(inak
))
488 return got_error(GOT_ERR_PRIVSEP_LEN
);
490 memcpy(&inak
, imsg
->data
, sizeof(inak
));
491 if (memcmp(inak
.object_id
, expected_id
, SHA1_DIGEST_LENGTH
) != 0)
492 return got_error(GOT_ERR_BAD_OBJ_ID
);
498 static const struct got_error
*
499 recv_want(int *use_sidebands
, int outfd
, struct imsgbuf
*ibuf
,
500 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
502 const struct got_error
*err
;
503 struct gotd_imsg_want iwant
;
504 char *capabilities_str
;
508 memset(&iwant
, 0, sizeof(iwant
));
509 memset(&imsg
, 0, sizeof(imsg
));
511 err
= parse_want_line(&capabilities_str
, iwant
.object_id
, buf
, len
);
515 if (capabilities_str
) {
516 if (!expect_capabilities
) {
517 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
518 "unexpected capability announcement received");
521 err
= send_capabilities(use_sidebands
, NULL
, capabilities_str
,
528 if (imsg_compose(ibuf
, GOTD_IMSG_WANT
, 0, 0, -1,
529 &iwant
, sizeof(iwant
)) == -1) {
530 err
= got_error_from_errno("imsg_compose WANT");
534 err
= gotd_imsg_flush(ibuf
);
539 * Wait for an ACK, or an error in case the desired object
542 while (!done
&& err
== NULL
) {
543 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
546 switch (imsg
.hdr
.type
) {
547 case GOTD_IMSG_ERROR
:
548 err
= gotd_imsg_recv_error(NULL
, &imsg
);
551 err
= recv_ack(&imsg
, iwant
.object_id
);
557 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
564 free(capabilities_str
);
568 static const struct got_error
*
569 send_ack(int outfd
, uint8_t *id
, int chattygot
)
571 char hex
[SHA1_DIGEST_STRING_LENGTH
];
572 char buf
[GOT_PKT_MAX
];
575 if (got_sha1_digest_to_str(id
, hex
, sizeof(hex
)) == NULL
)
576 return got_error(GOT_ERR_BAD_OBJ_ID
);
578 len
= snprintf(buf
, sizeof(buf
), "ACK %s\n", hex
);
579 if (len
>= sizeof(buf
))
580 return got_error(GOT_ERR_NO_SPACE
);
582 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
585 static const struct got_error
*
586 send_nak(int outfd
, int chattygot
)
591 len
= snprintf(buf
, sizeof(buf
), "NAK\n");
592 if (len
>= sizeof(buf
))
593 return got_error(GOT_ERR_NO_SPACE
);
595 return got_pkt_writepkt(outfd
, buf
, len
, chattygot
);
598 static const struct got_error
*
599 recv_have(int *have_ack
, int outfd
, struct imsgbuf
*ibuf
, char *buf
,
600 size_t len
, int chattygot
)
602 const struct got_error
*err
;
603 struct gotd_imsg_have ihave
;
607 memset(&ihave
, 0, sizeof(ihave
));
608 memset(&imsg
, 0, sizeof(imsg
));
610 err
= parse_have_line(ihave
.object_id
, buf
, len
);
614 if (imsg_compose(ibuf
, GOTD_IMSG_HAVE
, 0, 0, -1,
615 &ihave
, sizeof(ihave
)) == -1)
616 return got_error_from_errno("imsg_compose HAVE");
618 err
= gotd_imsg_flush(ibuf
);
623 * Wait for an ACK or a NAK, indicating whether a common
624 * commit object has been found.
626 while (!done
&& err
== NULL
) {
627 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
630 switch (imsg
.hdr
.type
) {
631 case GOTD_IMSG_ERROR
:
632 err
= gotd_imsg_recv_error(NULL
, &imsg
);
635 err
= recv_ack(&imsg
, ihave
.object_id
);
639 err
= send_ack(outfd
, ihave
.object_id
,
648 err
= recv_nak(&imsg
, ihave
.object_id
);
654 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
664 static const struct got_error
*
665 recv_done(int *packfd
, int outfd
, struct imsgbuf
*ibuf
, int chattygot
)
667 const struct got_error
*err
;
672 if (imsg_compose(ibuf
, GOTD_IMSG_DONE
, 0, 0, -1, NULL
, 0) == -1)
673 return got_error_from_errno("imsg_compose DONE");
675 err
= gotd_imsg_flush(ibuf
);
679 while (*packfd
== -1 && err
== NULL
) {
680 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
684 switch (imsg
.hdr
.type
) {
685 case GOTD_IMSG_ERROR
:
686 err
= gotd_imsg_recv_error(NULL
, &imsg
);
688 case GOTD_IMSG_PACKFILE_PIPE
:
692 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
695 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
705 static const struct got_error
*
706 relay_progress_reports(struct imsgbuf
*ibuf
, int outfd
, int chattygot
)
708 const struct got_error
*err
= NULL
;
709 int pack_starting
= 0;
710 struct gotd_imsg_packfile_progress iprog
;
711 char buf
[GOT_PKT_MAX
];
714 int p_deltify
= 0, n
;
715 const char *eol
= "\r";
717 memset(&imsg
, 0, sizeof(imsg
));
719 while (!pack_starting
&& err
== NULL
) {
720 err
= gotd_imsg_poll_recv(&imsg
, ibuf
, 0);
724 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
725 switch (imsg
.hdr
.type
) {
726 case GOTD_IMSG_ERROR
:
727 err
= gotd_imsg_recv_error(NULL
, &imsg
);
729 case GOTD_IMSG_PACKFILE_READY
:
733 case GOTD_IMSG_PACKFILE_PROGRESS
:
734 if (datalen
!= sizeof(iprog
)) {
735 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
738 memcpy(&iprog
, imsg
.data
, sizeof(iprog
));
739 if (iprog
.nobj_total
> 0) {
740 p_deltify
= (iprog
.nobj_deltify
* 100) /
743 buf
[0] = GOT_SIDEBAND_PROGRESS_INFO
;
744 n
= snprintf(&buf
[1], sizeof(buf
) - 1,
745 "%d commits colored, "
751 if (n
>= sizeof(buf
) - 1)
753 err
= got_pkt_writepkt(outfd
, buf
, 1 + n
, chattygot
);
756 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
766 static const struct got_error
*
767 serve_read(int infd
, int outfd
, int gotd_sock
, const char *repo_path
,
770 const struct got_error
*err
= NULL
;
771 char buf
[GOT_PKT_MAX
];
775 STATE_EXPECT_MORE_WANT
,
780 enum protostate curstate
= STATE_EXPECT_WANT
;
781 int have_ack
= 0, use_sidebands
= 0, seen_have
= 0;
783 size_t pack_chunksize
;
785 imsg_init(&ibuf
, gotd_sock
);
787 err
= announce_refs(outfd
, &ibuf
, 1, repo_path
, chattygot
);
791 while (curstate
!= STATE_DONE
) {
794 err
= got_pkt_readpkt(&n
, infd
, buf
, sizeof(buf
), chattygot
);
798 if (curstate
!= STATE_EXPECT_WANT
&&
799 curstate
!= STATE_EXPECT_MORE_WANT
&&
800 curstate
!= STATE_EXPECT_HAVE
&&
801 curstate
!= STATE_EXPECT_DONE
) {
802 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
803 "unexpected flush packet received");
807 if (curstate
== STATE_EXPECT_WANT
) {
810 * If the client does not want to fetch
811 * anything we should receive a flush
812 * packet followed by EOF.
814 r
= read(infd
, buf
, sizeof(buf
));
816 err
= got_error_from_errno("read");
819 if (r
== 0) /* EOF */
822 /* Zero-length field followed by payload. */
823 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
824 "unexpected flush packet received");
828 if (curstate
== STATE_EXPECT_WANT
||
829 curstate
== STATE_EXPECT_MORE_WANT
||
830 curstate
== STATE_EXPECT_HAVE
) {
831 err
= forward_flushpkt(&ibuf
);
835 if (curstate
== STATE_EXPECT_HAVE
&& !have_ack
) {
836 err
= send_nak(outfd
, chattygot
);
840 if (curstate
== STATE_EXPECT_MORE_WANT
)
841 curstate
= STATE_EXPECT_HAVE
;
843 curstate
= STATE_EXPECT_DONE
;
844 } else if (n
>= 5 && strncmp(buf
, "want ", 5) == 0) {
845 if (curstate
!= STATE_EXPECT_WANT
&&
846 curstate
!= STATE_EXPECT_MORE_WANT
) {
847 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
848 "unexpected 'want' packet");
851 err
= recv_want(&use_sidebands
, outfd
, &ibuf
, buf
, n
,
852 curstate
== STATE_EXPECT_WANT
? 1 : 0, chattygot
);
855 if (curstate
== STATE_EXPECT_WANT
)
856 curstate
= STATE_EXPECT_MORE_WANT
;
857 } else if (n
>= 5 && strncmp(buf
, "have ", 5) == 0) {
858 if (curstate
!= STATE_EXPECT_HAVE
&&
859 curstate
!= STATE_EXPECT_DONE
) {
860 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
861 "unexpected 'have' packet");
864 if (curstate
== STATE_EXPECT_HAVE
) {
865 err
= recv_have(&have_ack
, outfd
, &ibuf
,
871 } else if (n
== 5 && strncmp(buf
, "done\n", 5) == 0) {
872 if (curstate
!= STATE_EXPECT_HAVE
&&
873 curstate
!= STATE_EXPECT_DONE
) {
874 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
875 "unexpected 'done' packet");
878 err
= recv_done(&packfd
, outfd
, &ibuf
, chattygot
);
881 curstate
= STATE_DONE
;
884 err
= got_error(GOT_ERR_BAD_PACKET
);
890 err
= send_nak(outfd
, chattygot
);
896 err
= relay_progress_reports(&ibuf
, outfd
, chattygot
);
899 pack_chunksize
= GOT_SIDEBAND_64K_PACKFILE_DATA_MAX
;
901 pack_chunksize
= sizeof(buf
);
906 r
= read(packfd
, use_sidebands
? &buf
[1] : buf
,
909 err
= got_error_from_errno("read");
912 err
= got_pkt_flushpkt(outfd
, chattygot
);
917 buf
[0] = GOT_SIDEBAND_PACKFILE_DATA
;
918 err
= got_pkt_writepkt(outfd
, buf
, 1 + r
, chattygot
);
922 err
= got_poll_write_full(outfd
, buf
, r
);
924 if (err
->code
== GOT_ERR_EOF
)
932 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
933 err
= got_error_from_errno("close");
935 echo_error(err
, outfd
, chattygot
);
939 static const struct got_error
*
940 parse_ref_update_line(char **common_capabilities
, char **refname
,
941 uint8_t *old_id
, uint8_t *new_id
, char *buf
, size_t len
)
943 const struct got_error
*err
;
944 char *old_id_str
= NULL
, *new_id_str
= NULL
;
945 char *client_capabilities
= NULL
;
949 err
= got_gitproto_parse_ref_update_line(&old_id_str
, &new_id_str
,
950 refname
, &client_capabilities
, buf
, len
);
954 if (!got_parse_hash_digest(old_id
, old_id_str
, GOT_HASH_SHA1
) ||
955 !got_parse_hash_digest(new_id
, new_id_str
, GOT_HASH_SHA1
)) {
956 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
957 "ref-update with bad object ID");
960 if (!got_ref_name_is_valid(*refname
)) {
961 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
962 "ref-update with bad reference name");
966 if (client_capabilities
) {
967 err
= got_gitproto_match_capabilities(common_capabilities
,
968 NULL
, client_capabilities
, write_capabilities
,
969 nitems(write_capabilities
));
976 free(client_capabilities
);
984 static const struct got_error
*
985 recv_ref_update(int *report_status
, int outfd
, struct imsgbuf
*ibuf
,
986 char *buf
, size_t len
, int expect_capabilities
, int chattygot
)
988 const struct got_error
*err
;
989 struct gotd_imsg_ref_update iref
;
991 char *capabilities_str
= NULL
, *refname
= NULL
;
995 memset(&iref
, 0, sizeof(iref
));
996 memset(&imsg
, 0, sizeof(imsg
));
998 err
= parse_ref_update_line(&capabilities_str
, &refname
,
999 iref
.old_id
, iref
.new_id
, buf
, len
);
1003 if (capabilities_str
) {
1004 if (!expect_capabilities
) {
1005 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1006 "unexpected capability announcement received");
1009 err
= send_capabilities(NULL
, report_status
, capabilities_str
,
1015 iref
.name_len
= strlen(refname
);
1016 len
= sizeof(iref
) + iref
.name_len
;
1017 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF_UPDATE
, 0, 0, len
);
1019 err
= got_error_from_errno("imsg_create REF_UPDATE");
1023 if (imsg_add(wbuf
, &iref
, sizeof(iref
)) == -1)
1024 return got_error_from_errno("imsg_add REF_UPDATE");
1025 if (imsg_add(wbuf
, refname
, iref
.name_len
) == -1)
1026 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
);
1076 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
);
1275 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1276 /* The client will not send us anything. */
1278 } else if (curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1279 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1280 "unexpected flush packet received");
1283 err
= forward_flushpkt(&ibuf
);
1286 curstate
= STATE_EXPECT_PACKFILE
;
1287 } else if (n
>= (SHA1_DIGEST_STRING_LENGTH
* 2) + 2) {
1288 if (curstate
!= STATE_EXPECT_REF_UPDATE
&&
1289 curstate
!= STATE_EXPECT_MORE_REF_UPDATES
) {
1290 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
1291 "unexpected ref-update packet");
1294 if (curstate
== STATE_EXPECT_REF_UPDATE
) {
1295 err
= recv_ref_update(&report_status
,
1296 outfd
, &ibuf
, buf
, n
, 1, chattygot
);
1298 err
= recv_ref_update(NULL
, outfd
, &ibuf
,
1299 buf
, n
, 0, chattygot
);
1303 curstate
= STATE_EXPECT_MORE_REF_UPDATES
;
1305 err
= got_error(GOT_ERR_BAD_PACKET
);
1310 while (curstate
!= STATE_PACKFILE_RECEIVED
) {
1311 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1314 switch (imsg
.hdr
.type
) {
1315 case GOTD_IMSG_ERROR
:
1316 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1318 case GOTD_IMSG_PACKFILE_PIPE
:
1319 err
= recv_packfile(&imsg
, infd
);
1321 if (err
->code
!= GOT_ERR_EOF
)
1324 * EOF is reported when the client hangs up,
1325 * which can happen with Git clients.
1326 * The socket should stay half-open so we
1327 * can still send our reports if requested.
1331 curstate
= STATE_PACKFILE_RECEIVED
;
1334 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1343 while (curstate
!= STATE_REFS_UPDATED
&& err
== NULL
) {
1344 err
= gotd_imsg_poll_recv(&imsg
, &ibuf
, 0);
1347 switch (imsg
.hdr
.type
) {
1348 case GOTD_IMSG_ERROR
:
1349 err
= gotd_imsg_recv_error(NULL
, &imsg
);
1351 case GOTD_IMSG_PACKFILE_STATUS
:
1354 err
= report_unpack_status(&imsg
, outfd
, chattygot
);
1356 case GOTD_IMSG_REF_UPDATE_OK
:
1359 err
= recv_ref_update_ok(&imsg
, outfd
, chattygot
);
1361 case GOTD_IMSG_REF_UPDATE_NG
:
1364 err
= recv_ref_update_ng(&imsg
, outfd
, chattygot
);
1366 case GOTD_IMSG_REFS_UPDATED
:
1367 curstate
= STATE_REFS_UPDATED
;
1368 err
= got_pkt_flushpkt(outfd
, chattygot
);
1371 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1380 echo_error(err
, outfd
, chattygot
);
1384 const struct got_error
*
1385 got_serve(int infd
, int outfd
, const char *command
, const char *repo_path
,
1386 int gotd_sock
, int chattygot
)
1388 const struct got_error
*err
= NULL
;
1390 if (strcmp(command
, GOT_DIAL_CMD_FETCH
) == 0)
1391 err
= serve_read(infd
, outfd
, gotd_sock
, repo_path
, chattygot
);
1392 else if (strcmp(command
, GOT_DIAL_CMD_SEND
) == 0)
1393 err
= serve_write(infd
, outfd
, gotd_sock
, repo_path
,
1396 err
= got_error(GOT_ERR_BAD_PACKET
);