vmstate: port pckbd device
[qemu] / slirp / sbuf.c
1 /*
2  * Copyright (c) 1995 Danny Gasparovski.
3  *
4  * Please read the file COPYRIGHT for the
5  * terms and conditions of the copyright.
6  */
7
8 #include <slirp.h>
9
10 static void sbappendsb(struct sbuf *sb, struct mbuf *m);
11
12 void
13 sbfree(struct sbuf *sb)
14 {
15         free(sb->sb_data);
16 }
17
18 void
19 sbdrop(struct sbuf *sb, int num)
20 {
21         /*
22          * We can only drop how much we have
23          * This should never succeed
24          */
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;
31
32 }
33
34 void
35 sbreserve(struct sbuf *sb, int size)
36 {
37         if (sb->sb_data) {
38                 /* Already alloced, realloc if necessary */
39                 if (sb->sb_datalen != size) {
40                         sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
41                         sb->sb_cc = 0;
42                         if (sb->sb_wptr)
43                            sb->sb_datalen = size;
44                         else
45                            sb->sb_datalen = 0;
46                 }
47         } else {
48                 sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
49                 sb->sb_cc = 0;
50                 if (sb->sb_wptr)
51                    sb->sb_datalen = size;
52                 else
53                    sb->sb_datalen = 0;
54         }
55 }
56
57 /*
58  * Try and write() to the socket, whatever doesn't get written
59  * append to the buffer... for a host with a fast net connection,
60  * this prevents an unnecessary copy of the data
61  * (the socket is non-blocking, so we won't hang)
62  */
63 void
64 sbappend(struct socket *so, struct mbuf *m)
65 {
66         int ret = 0;
67
68         DEBUG_CALL("sbappend");
69         DEBUG_ARG("so = %lx", (long)so);
70         DEBUG_ARG("m = %lx", (long)m);
71         DEBUG_ARG("m->m_len = %d", m->m_len);
72
73         /* Shouldn't happen, but...  e.g. foreign host closes connection */
74         if (m->m_len <= 0) {
75                 m_free(m);
76                 return;
77         }
78
79         /*
80          * If there is urgent data, call sosendoob
81          * if not all was sent, sowrite will take care of the rest
82          * (The rest of this function is just an optimisation)
83          */
84         if (so->so_urgc) {
85                 sbappendsb(&so->so_rcv, m);
86                 m_free(m);
87                 sosendoob(so);
88                 return;
89         }
90
91         /*
92          * We only write if there's nothing in the buffer,
93          * ottherwise it'll arrive out of order, and hence corrupt
94          */
95         if (!so->so_rcv.sb_cc)
96            ret = slirp_send(so, m->m_data, m->m_len, 0);
97
98         if (ret <= 0) {
99                 /*
100                  * Nothing was written
101                  * It's possible that the socket has closed, but
102                  * we don't need to check because if it has closed,
103                  * it will be detected in the normal way by soread()
104                  */
105                 sbappendsb(&so->so_rcv, m);
106         } else if (ret != m->m_len) {
107                 /*
108                  * Something was written, but not everything..
109                  * sbappendsb the rest
110                  */
111                 m->m_len -= ret;
112                 m->m_data += ret;
113                 sbappendsb(&so->so_rcv, m);
114         } /* else */
115         /* Whatever happened, we free the mbuf */
116         m_free(m);
117 }
118
119 /*
120  * Copy the data from m into sb
121  * The caller is responsible to make sure there's enough room
122  */
123 static void
124 sbappendsb(struct sbuf *sb, struct mbuf *m)
125 {
126         int len, n,  nn;
127
128         len = m->m_len;
129
130         if (sb->sb_wptr < sb->sb_rptr) {
131                 n = sb->sb_rptr - sb->sb_wptr;
132                 if (n > len) n = len;
133                 memcpy(sb->sb_wptr, m->m_data, n);
134         } else {
135                 /* Do the right edge first */
136                 n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
137                 if (n > len) n = len;
138                 memcpy(sb->sb_wptr, m->m_data, n);
139                 len -= n;
140                 if (len) {
141                         /* Now the left edge */
142                         nn = sb->sb_rptr - sb->sb_data;
143                         if (nn > len) nn = len;
144                         memcpy(sb->sb_data,m->m_data+n,nn);
145                         n += nn;
146                 }
147         }
148
149         sb->sb_cc += n;
150         sb->sb_wptr += n;
151         if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
152                 sb->sb_wptr -= sb->sb_datalen;
153 }
154
155 /*
156  * Copy data from sbuf to a normal, straight buffer
157  * Don't update the sbuf rptr, this will be
158  * done in sbdrop when the data is acked
159  */
160 void
161 sbcopy(struct sbuf *sb, int off, int len, char *to)
162 {
163         char *from;
164
165         from = sb->sb_rptr + off;
166         if (from >= sb->sb_data + sb->sb_datalen)
167                 from -= sb->sb_datalen;
168
169         if (from < sb->sb_wptr) {
170                 if (len > sb->sb_cc) len = sb->sb_cc;
171                 memcpy(to,from,len);
172         } else {
173                 /* re-use off */
174                 off = (sb->sb_data + sb->sb_datalen) - from;
175                 if (off > len) off = len;
176                 memcpy(to,from,off);
177                 len -= off;
178                 if (len)
179                    memcpy(to+off,sb->sb_data,len);
180         }
181 }