nbd: Permit simple error to NBD_CMD_BLOCK_STATUS
[qemu/ericb.git] / slirp / src / sbuf.c
blob9c0b31b513bd2bbf56c824f778224fdeb36448fa
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * Copyright (c) 1995 Danny Gasparovski.
4 */
6 #include "slirp.h"
8 static void sbappendsb(struct sbuf *sb, struct mbuf *m);
10 void
11 sbfree(struct sbuf *sb)
13 free(sb->sb_data);
16 bool
17 sbdrop(struct sbuf *sb, int num)
19 int limit = sb->sb_datalen / 2;
22 * We can only drop how much we have
23 * This should never succeed
25 if(num > sb->sb_cc)
26 num = sb->sb_cc;
27 sb->sb_cc -= num;
28 sb->sb_rptr += num;
29 if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
30 sb->sb_rptr -= sb->sb_datalen;
32 if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
33 return true;
36 return false;
39 void
40 sbreserve(struct sbuf *sb, int size)
42 if (sb->sb_data) {
43 /* Already alloced, realloc if necessary */
44 if (sb->sb_datalen != size) {
45 sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
46 sb->sb_cc = 0;
47 if (sb->sb_wptr)
48 sb->sb_datalen = size;
49 else
50 sb->sb_datalen = 0;
52 } else {
53 sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
54 sb->sb_cc = 0;
55 if (sb->sb_wptr)
56 sb->sb_datalen = size;
57 else
58 sb->sb_datalen = 0;
63 * Try and write() to the socket, whatever doesn't get written
64 * append to the buffer... for a host with a fast net connection,
65 * this prevents an unnecessary copy of the data
66 * (the socket is non-blocking, so we won't hang)
68 void
69 sbappend(struct socket *so, struct mbuf *m)
71 int ret = 0;
73 DEBUG_CALL("sbappend");
74 DEBUG_ARG("so = %p", so);
75 DEBUG_ARG("m = %p", m);
76 DEBUG_ARG("m->m_len = %d", m->m_len);
78 /* Shouldn't happen, but... e.g. foreign host closes connection */
79 if (m->m_len <= 0) {
80 m_free(m);
81 return;
85 * If there is urgent data, call sosendoob
86 * if not all was sent, sowrite will take care of the rest
87 * (The rest of this function is just an optimisation)
89 if (so->so_urgc) {
90 sbappendsb(&so->so_rcv, m);
91 m_free(m);
92 (void)sosendoob(so);
93 return;
97 * We only write if there's nothing in the buffer,
98 * ottherwise it'll arrive out of order, and hence corrupt
100 if (!so->so_rcv.sb_cc)
101 ret = slirp_send(so, m->m_data, m->m_len, 0);
103 if (ret <= 0) {
105 * Nothing was written
106 * It's possible that the socket has closed, but
107 * we don't need to check because if it has closed,
108 * it will be detected in the normal way by soread()
110 sbappendsb(&so->so_rcv, m);
111 } else if (ret != m->m_len) {
113 * Something was written, but not everything..
114 * sbappendsb the rest
116 m->m_len -= ret;
117 m->m_data += ret;
118 sbappendsb(&so->so_rcv, m);
119 } /* else */
120 /* Whatever happened, we free the mbuf */
121 m_free(m);
125 * Copy the data from m into sb
126 * The caller is responsible to make sure there's enough room
128 static void
129 sbappendsb(struct sbuf *sb, struct mbuf *m)
131 int len, n, nn;
133 len = m->m_len;
135 if (sb->sb_wptr < sb->sb_rptr) {
136 n = sb->sb_rptr - sb->sb_wptr;
137 if (n > len) n = len;
138 memcpy(sb->sb_wptr, m->m_data, n);
139 } else {
140 /* Do the right edge first */
141 n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
142 if (n > len) n = len;
143 memcpy(sb->sb_wptr, m->m_data, n);
144 len -= n;
145 if (len) {
146 /* Now the left edge */
147 nn = sb->sb_rptr - sb->sb_data;
148 if (nn > len) nn = len;
149 memcpy(sb->sb_data,m->m_data+n,nn);
150 n += nn;
154 sb->sb_cc += n;
155 sb->sb_wptr += n;
156 if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
157 sb->sb_wptr -= sb->sb_datalen;
161 * Copy data from sbuf to a normal, straight buffer
162 * Don't update the sbuf rptr, this will be
163 * done in sbdrop when the data is acked
165 void
166 sbcopy(struct sbuf *sb, int off, int len, char *to)
168 char *from;
170 from = sb->sb_rptr + off;
171 if (from >= sb->sb_data + sb->sb_datalen)
172 from -= sb->sb_datalen;
174 if (from < sb->sb_wptr) {
175 if (len > sb->sb_cc) len = sb->sb_cc;
176 memcpy(to,from,len);
177 } else {
178 /* re-use off */
179 off = (sb->sb_data + sb->sb_datalen) - from;
180 if (off > len) off = len;
181 memcpy(to,from,off);
182 len -= off;
183 if (len)
184 memcpy(to+off,sb->sb_data,len);