Home | History | Annotate | Download | only in slirp
      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