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"
28 const struct got_error *
29 got_pkt_readn(ssize_t *off, int fd, void *buf, size_t n)
30 {
31 ssize_t r;
33 *off = 0;
34 while (*off != n) {
35 r = read(fd, buf + *off, n - *off);
36 if (r == -1)
37 return got_error_from_errno("read");
38 if (r == 0)
39 return got_error(GOT_ERR_EOF);
40 *off += r;
41 }
42 return NULL;
43 }
45 const struct got_error *
46 got_pkt_flushpkt(int fd, int chattygot)
47 {
48 ssize_t w;
50 if (chattygot > 1)
51 fprintf(stderr, "%s: writepkt: 0000\n", getprogname());
53 w = write(fd, "0000", 4);
54 if (w == -1)
55 return got_error_from_errno("write");
56 if (w != 4)
57 return got_error(GOT_ERR_IO);
58 return NULL;
59 }
61 /*
62 * Packet header contains a 4-byte hexstring which specifies the length
63 * of data which follows.
64 */
65 const struct got_error *
66 got_pkt_readhdr(int *datalen, int fd, int chattygot)
67 {
68 static const struct got_error *err = NULL;
69 char lenstr[5];
70 long len;
71 char *e;
72 int n, i;
73 ssize_t r;
75 *datalen = 0;
77 err = got_pkt_readn(&r, fd, lenstr, 4);
78 if (err)
79 return err;
80 if (r == 0) {
81 /* implicit "0000" */
82 if (chattygot > 1)
83 fprintf(stderr, "%s: readpkt: 0000\n", getprogname());
84 return NULL;
85 }
86 if (r != 4)
87 return got_error_msg(GOT_ERR_BAD_PACKET,
88 "wrong packet header length");
90 lenstr[4] = '\0';
91 for (i = 0; i < 4; i++) {
92 if (!isprint((unsigned char)lenstr[i]))
93 return got_error_msg(GOT_ERR_BAD_PACKET,
94 "unprintable character in packet length field");
95 }
96 for (i = 0; i < 4; i++) {
97 if (!isxdigit((unsigned char)lenstr[i])) {
98 if (chattygot)
99 fprintf(stderr, "%s: bad length: '%s'\n",
100 getprogname(), lenstr);
101 return got_error_msg(GOT_ERR_BAD_PACKET,
102 "packet length not specified in hex");
105 errno = 0;
106 len = strtol(lenstr, &e, 16);
107 if (lenstr[0] == '\0' || *e != '\0')
108 return got_error(GOT_ERR_BAD_PACKET);
109 if (errno == ERANGE && (len == LONG_MAX || len == LONG_MIN))
110 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
111 if (len > INT_MAX || len < INT_MIN)
112 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
113 n = len;
114 if (n == 0)
115 return NULL;
116 if (n <= 4)
117 return got_error_msg(GOT_ERR_BAD_PACKET, "packet too short");
118 n -= 4;
120 *datalen = n;
121 return NULL;
124 const struct got_error *
125 got_pkt_readpkt(int *outlen, int fd, char *buf, int buflen, int chattygot)
127 const struct got_error *err = NULL;
128 int datalen, i;
129 ssize_t n;
131 err = got_pkt_readhdr(&datalen, fd, chattygot);
132 if (err)
133 return err;
135 if (datalen > buflen)
136 return got_error(GOT_ERR_NO_SPACE);
138 err = got_pkt_readn(&n, fd, buf, datalen);
139 if (err)
140 return err;
141 if (n != datalen)
142 return got_error_msg(GOT_ERR_BAD_PACKET, "short packet");
144 if (chattygot > 1) {
145 fprintf(stderr, "%s: readpkt: %zd:\t", getprogname(), n);
146 for (i = 0; i < n; i++) {
147 if (isprint((unsigned char)buf[i]))
148 fputc(buf[i], stderr);
149 else
150 fprintf(stderr, "[0x%.2x]", buf[i]);
152 fputc('\n', stderr);
155 *outlen = n;
156 return NULL;
159 const struct got_error *
160 got_pkt_writepkt(int fd, char *buf, int nbuf, int chattygot)
162 char len[5];
163 int i, ret;
164 ssize_t w;
166 ret = snprintf(len, sizeof(len), "%04x", nbuf + 4);
167 if (ret < 0 || (size_t)ret >= sizeof(len))
168 return got_error(GOT_ERR_NO_SPACE);
169 w = write(fd, len, 4);
170 if (w == -1)
171 return got_error_from_errno("write");
172 if (w != 4)
173 return got_error(GOT_ERR_IO);
174 w = write(fd, buf, nbuf);
175 if (w == -1)
176 return got_error_from_errno("write");
177 if (w != nbuf)
178 return got_error(GOT_ERR_IO);
179 if (chattygot > 1) {
180 fprintf(stderr, "%s: writepkt: %s:\t", getprogname(), len);
181 for (i = 0; i < nbuf; i++) {
182 if (isprint((unsigned char)buf[i]))
183 fputc(buf[i], stderr);
184 else
185 fprintf(stderr, "[0x%.2x]", buf[i]);
187 fputc('\n', stderr);
189 return NULL;