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