Blob


1 /*
2 * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
18 #include <ctype.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
25 #include "got_error.h"
26 #include "got_lib_pkt.h"
27 #include "got_lib_poll.h"
29 #define GOT_PKT_TIMEOUT 30
31 const struct got_error *
32 got_pkt_readn(ssize_t *off, int fd, void *buf, size_t n)
33 {
34 const struct got_error *err;
35 size_t len;
37 err = got_poll_read_full_timeout(fd, &len, buf, n, n,
38 GOT_PKT_TIMEOUT);
39 if (err)
40 return err;
42 /* XXX size_t -> ssize_t */
43 if (len > SSIZE_MAX)
44 return got_error(GOT_ERR_RANGE);
45 *off = len;
46 return NULL;
47 }
49 const struct got_error *
50 got_pkt_flushpkt(int fd, int chattygot)
51 {
52 ssize_t w;
54 if (chattygot > 1)
55 fprintf(stderr, "%s: writepkt: 0000\n", getprogname());
57 w = write(fd, "0000", 4);
58 if (w == -1)
59 return got_error_from_errno("write");
60 if (w != 4)
61 return got_error(GOT_ERR_IO);
62 return NULL;
63 }
65 const struct got_error *
66 got_pkt_readlen(int *len, const char *str, int chattygot)
67 {
68 int i;
70 *len = 0;
71 for (i = 0; i < 4; i++) {
72 if ('0' <= str[i] && str[i] <= '9') {
73 *len *= 16;
74 *len += str[i] - '0';
75 } else if ('a' <= str[i] && str[i] <= 'f') {
76 *len *= 16;
77 *len += str[i] - 'a' + 10;
78 } else {
79 if (chattygot)
80 fprintf(stderr, "%s: bad length: '.4%s'\n",
81 getprogname(), str);
82 return got_error_msg(GOT_ERR_BAD_PACKET,
83 "packet length has invalid format");
84 }
85 }
86 return NULL;
87 }
89 /*
90 * Packet header contains a 4-byte hexstring which specifies the length
91 * of data which follows.
92 */
93 const struct got_error *
94 got_pkt_readhdr(int *datalen, int fd, int chattygot)
95 {
96 static const struct got_error *err;
97 char lenstr[4];
98 ssize_t r;
99 int n;
101 *datalen = 0;
103 err = got_pkt_readn(&r, fd, lenstr, 4);
104 if (err)
105 return err;
106 if (r == 0) {
107 /* implicit "0000" */
108 if (chattygot > 1)
109 fprintf(stderr, "%s: readpkt: 0000\n", getprogname());
110 return NULL;
112 if (r != 4)
113 return got_error_msg(GOT_ERR_BAD_PACKET,
114 "wrong packet header length");
116 err = got_pkt_readlen(&n, lenstr, chattygot);
117 if (n == 0)
118 return err;
119 if (n <= 4)
120 return got_error_msg(GOT_ERR_BAD_PACKET, "packet too short");
121 n -= 4;
123 *datalen = n;
124 return NULL;
127 const struct got_error *
128 got_pkt_readpkt(int *outlen, int fd, char *buf, int buflen, int chattygot)
130 const struct got_error *err = NULL;
131 int datalen, i;
132 ssize_t n;
134 err = got_pkt_readhdr(&datalen, fd, chattygot);
135 if (err)
136 return err;
138 if (datalen > buflen)
139 return got_error(GOT_ERR_NO_SPACE);
141 err = got_pkt_readn(&n, fd, buf, datalen);
142 if (err)
143 return err;
144 if (n != datalen)
145 return got_error_msg(GOT_ERR_BAD_PACKET, "short packet");
147 if (chattygot > 1) {
148 fprintf(stderr, "%s: readpkt: %zd:\t", getprogname(), n);
149 for (i = 0; i < n; i++) {
150 if (isprint((unsigned char)buf[i]))
151 fputc(buf[i], stderr);
152 else
153 fprintf(stderr, "[0x%.2x]", buf[i]);
155 fputc('\n', stderr);
158 *outlen = n;
159 return NULL;
162 const struct got_error *
163 got_pkt_writepkt(int fd, char *buf, int nbuf, int chattygot)
165 char len[5];
166 int i, ret;
167 ssize_t w;
169 ret = snprintf(len, sizeof(len), "%04x", nbuf + 4);
170 if (ret < 0 || (size_t)ret >= sizeof(len))
171 return got_error(GOT_ERR_NO_SPACE);
172 w = write(fd, len, 4);
173 if (w == -1)
174 return got_error_from_errno("write");
175 if (w != 4)
176 return got_error(GOT_ERR_IO);
177 w = write(fd, buf, nbuf);
178 if (w == -1)
179 return got_error_from_errno("write");
180 if (w != nbuf)
181 return got_error(GOT_ERR_IO);
182 if (chattygot > 1) {
183 fprintf(stderr, "%s: writepkt: %s:\t", getprogname(), len);
184 for (i = 0; i < nbuf; i++) {
185 if (isprint((unsigned char)buf[i]))
186 fputc(buf[i], stderr);
187 else
188 fprintf(stderr, "[0x%.2x]", buf[i]);
190 fputc('\n', stderr);
192 return NULL;