Statistics
| Branch: | Revision:

root / slirp / sbuf.c @ 511d2b14

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(struct sbuf *sb)
22
{
23
        free(sb->sb_data);
24
}
25

    
26
void
27
sbdrop(struct sbuf *sb, int num)
28
{
29
        /*
30
         * We can only drop how much we have
31
         * This should never succeed
32
         */
33
        if(num > sb->sb_cc)
34
                num = sb->sb_cc;
35
        sb->sb_cc -= num;
36
        sb->sb_rptr += num;
37
        if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
38
                sb->sb_rptr -= sb->sb_datalen;
39

    
40
}
41

    
42
void
43
sbreserve(struct sbuf *sb, int size)
44
{
45
        if (sb->sb_data) {
46
                /* Already alloced, realloc if necessary */
47
                if (sb->sb_datalen != size) {
48
                        sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, 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
        } else {
56
                sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
57
                sb->sb_cc = 0;
58
                if (sb->sb_wptr)
59
                   sb->sb_datalen = size;
60
                else
61
                   sb->sb_datalen = 0;
62
        }
63
}
64

    
65
/*
66
 * Try and write() to the socket, whatever doesn't get written
67
 * append to the buffer... for a host with a fast net connection,
68
 * this prevents an unnecessary copy of the data
69
 * (the socket is non-blocking, so we won't hang)
70
 */
71
void
72
sbappend(struct socket *so, struct mbuf *m)
73
{
74
        int ret = 0;
75

    
76
        DEBUG_CALL("sbappend");
77
        DEBUG_ARG("so = %lx", (long)so);
78
        DEBUG_ARG("m = %lx", (long)m);
79
        DEBUG_ARG("m->m_len = %d", m->m_len);
80

    
81
        /* Shouldn't happen, but...  e.g. foreign host closes connection */
82
        if (m->m_len <= 0) {
83
                m_free(m);
84
                return;
85
        }
86

    
87
        /*
88
         * If there is urgent data, call sosendoob
89
         * if not all was sent, sowrite will take care of the rest
90
         * (The rest of this function is just an optimisation)
91
         */
92
        if (so->so_urgc) {
93
                sbappendsb(&so->so_rcv, m);
94
                m_free(m);
95
                sosendoob(so);
96
                return;
97
        }
98

    
99
        /*
100
         * We only write if there's nothing in the buffer,
101
         * ottherwise it'll arrive out of order, and hence corrupt
102
         */
103
        if (!so->so_rcv.sb_cc)
104
           ret = slirp_send(so, m->m_data, m->m_len, 0);
105

    
106
        if (ret <= 0) {
107
                /*
108
                 * Nothing was written
109
                 * It's possible that the socket has closed, but
110
                 * we don't need to check because if it has closed,
111
                 * it will be detected in the normal way by soread()
112
                 */
113
                sbappendsb(&so->so_rcv, m);
114
        } else if (ret != m->m_len) {
115
                /*
116
                 * Something was written, but not everything..
117
                 * sbappendsb the rest
118
                 */
119
                m->m_len -= ret;
120
                m->m_data += ret;
121
                sbappendsb(&so->so_rcv, m);
122
        } /* else */
123
        /* Whatever happened, we free the mbuf */
124
        m_free(m);
125
}
126

    
127
/*
128
 * Copy the data from m into sb
129
 * The caller is responsible to make sure there's enough room
130
 */
131
static void
132
sbappendsb(struct sbuf *sb, struct mbuf *m)
133
{
134
        int len, n,  nn;
135

    
136
        len = m->m_len;
137

    
138
        if (sb->sb_wptr < sb->sb_rptr) {
139
                n = sb->sb_rptr - sb->sb_wptr;
140
                if (n > len) n = len;
141
                memcpy(sb->sb_wptr, m->m_data, n);
142
        } else {
143
                /* Do the right edge first */
144
                n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
145
                if (n > len) n = len;
146
                memcpy(sb->sb_wptr, m->m_data, n);
147
                len -= n;
148
                if (len) {
149
                        /* Now the left edge */
150
                        nn = sb->sb_rptr - sb->sb_data;
151
                        if (nn > len) nn = len;
152
                        memcpy(sb->sb_data,m->m_data+n,nn);
153
                        n += nn;
154
                }
155
        }
156

    
157
        sb->sb_cc += n;
158
        sb->sb_wptr += n;
159
        if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
160
                sb->sb_wptr -= sb->sb_datalen;
161
}
162

    
163
/*
164
 * Copy data from sbuf to a normal, straight buffer
165
 * Don't update the sbuf rptr, this will be
166
 * done in sbdrop when the data is acked
167
 */
168
void
169
sbcopy(struct sbuf *sb, int off, int len, char *to)
170
{
171
        char *from;
172

    
173
        from = sb->sb_rptr + off;
174
        if (from >= sb->sb_data + sb->sb_datalen)
175
                from -= sb->sb_datalen;
176

    
177
        if (from < sb->sb_wptr) {
178
                if (len > sb->sb_cc) len = sb->sb_cc;
179
                memcpy(to,from,len);
180
        } else {
181
                /* re-use off */
182
                off = (sb->sb_data + sb->sb_datalen) - from;
183
                if (off > len) off = len;
184
                memcpy(to,from,off);
185
                len -= off;
186
                if (len)
187
                   memcpy(to+off,sb->sb_data,len);
188
        }
189
}