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