Statistics
| Branch: | Revision:

root / slirp / sbuf.c @ 9634d903

History | View | Annotate | Download (4 kB)

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
}
201