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