Statistics
| Branch: | Revision:

root / slirp / sbuf.c @ bb4ea393

History | View | Annotate | Download (3.8 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
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
}