File:  [Qemu by Fabrice Bellard] / qemu / slirp / sbuf.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:51:34 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, HEAD
qemu 1.1.1

    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: #include <main-loop.h>
   10: 
   11: static void sbappendsb(struct sbuf *sb, struct mbuf *m);
   12: 
   13: void
   14: sbfree(struct sbuf *sb)
   15: {
   16: 	free(sb->sb_data);
   17: }
   18: 
   19: void
   20: sbdrop(struct sbuf *sb, int num)
   21: {
   22:     int limit = sb->sb_datalen / 2;
   23: 
   24: 	/*
   25: 	 * We can only drop how much we have
   26: 	 * This should never succeed
   27: 	 */
   28: 	if(num > sb->sb_cc)
   29: 		num = sb->sb_cc;
   30: 	sb->sb_cc -= num;
   31: 	sb->sb_rptr += num;
   32: 	if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
   33: 		sb->sb_rptr -= sb->sb_datalen;
   34: 
   35:     if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
   36:         qemu_notify_event();
   37:     }
   38: }
   39: 
   40: void
   41: sbreserve(struct sbuf *sb, int size)
   42: {
   43: 	if (sb->sb_data) {
   44: 		/* Already alloced, realloc if necessary */
   45: 		if (sb->sb_datalen != size) {
   46: 			sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
   47: 			sb->sb_cc = 0;
   48: 			if (sb->sb_wptr)
   49: 			   sb->sb_datalen = size;
   50: 			else
   51: 			   sb->sb_datalen = 0;
   52: 		}
   53: 	} else {
   54: 		sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
   55: 		sb->sb_cc = 0;
   56: 		if (sb->sb_wptr)
   57: 		   sb->sb_datalen = size;
   58: 		else
   59: 		   sb->sb_datalen = 0;
   60: 	}
   61: }
   62: 
   63: /*
   64:  * Try and write() to the socket, whatever doesn't get written
   65:  * append to the buffer... for a host with a fast net connection,
   66:  * this prevents an unnecessary copy of the data
   67:  * (the socket is non-blocking, so we won't hang)
   68:  */
   69: void
   70: sbappend(struct socket *so, struct mbuf *m)
   71: {
   72: 	int ret = 0;
   73: 
   74: 	DEBUG_CALL("sbappend");
   75: 	DEBUG_ARG("so = %lx", (long)so);
   76: 	DEBUG_ARG("m = %lx", (long)m);
   77: 	DEBUG_ARG("m->m_len = %d", m->m_len);
   78: 
   79: 	/* Shouldn't happen, but...  e.g. foreign host closes connection */
   80: 	if (m->m_len <= 0) {
   81: 		m_free(m);
   82: 		return;
   83: 	}
   84: 
   85: 	/*
   86: 	 * If there is urgent data, call sosendoob
   87: 	 * if not all was sent, sowrite will take care of the rest
   88: 	 * (The rest of this function is just an optimisation)
   89: 	 */
   90: 	if (so->so_urgc) {
   91: 		sbappendsb(&so->so_rcv, m);
   92: 		m_free(m);
   93: 		sosendoob(so);
   94: 		return;
   95: 	}
   96: 
   97: 	/*
   98: 	 * We only write if there's nothing in the buffer,
   99: 	 * ottherwise it'll arrive out of order, and hence corrupt
  100: 	 */
  101: 	if (!so->so_rcv.sb_cc)
  102: 	   ret = slirp_send(so, m->m_data, m->m_len, 0);
  103: 
  104: 	if (ret <= 0) {
  105: 		/*
  106: 		 * Nothing was written
  107: 		 * It's possible that the socket has closed, but
  108: 		 * we don't need to check because if it has closed,
  109: 		 * it will be detected in the normal way by soread()
  110: 		 */
  111: 		sbappendsb(&so->so_rcv, m);
  112: 	} else if (ret != m->m_len) {
  113: 		/*
  114: 		 * Something was written, but not everything..
  115: 		 * sbappendsb the rest
  116: 		 */
  117: 		m->m_len -= ret;
  118: 		m->m_data += ret;
  119: 		sbappendsb(&so->so_rcv, m);
  120: 	} /* else */
  121: 	/* Whatever happened, we free the mbuf */
  122: 	m_free(m);
  123: }
  124: 
  125: /*
  126:  * Copy the data from m into sb
  127:  * The caller is responsible to make sure there's enough room
  128:  */
  129: static void
  130: sbappendsb(struct sbuf *sb, struct mbuf *m)
  131: {
  132: 	int len, n,  nn;
  133: 
  134: 	len = m->m_len;
  135: 
  136: 	if (sb->sb_wptr < sb->sb_rptr) {
  137: 		n = sb->sb_rptr - sb->sb_wptr;
  138: 		if (n > len) n = len;
  139: 		memcpy(sb->sb_wptr, m->m_data, n);
  140: 	} else {
  141: 		/* Do the right edge first */
  142: 		n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
  143: 		if (n > len) n = len;
  144: 		memcpy(sb->sb_wptr, m->m_data, n);
  145: 		len -= n;
  146: 		if (len) {
  147: 			/* Now the left edge */
  148: 			nn = sb->sb_rptr - sb->sb_data;
  149: 			if (nn > len) nn = len;
  150: 			memcpy(sb->sb_data,m->m_data+n,nn);
  151: 			n += nn;
  152: 		}
  153: 	}
  154: 
  155: 	sb->sb_cc += n;
  156: 	sb->sb_wptr += n;
  157: 	if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
  158: 		sb->sb_wptr -= sb->sb_datalen;
  159: }
  160: 
  161: /*
  162:  * Copy data from sbuf to a normal, straight buffer
  163:  * Don't update the sbuf rptr, this will be
  164:  * done in sbdrop when the data is acked
  165:  */
  166: void
  167: sbcopy(struct sbuf *sb, int off, int len, char *to)
  168: {
  169: 	char *from;
  170: 
  171: 	from = sb->sb_rptr + off;
  172: 	if (from >= sb->sb_data + sb->sb_datalen)
  173: 		from -= sb->sb_datalen;
  174: 
  175: 	if (from < sb->sb_wptr) {
  176: 		if (len > sb->sb_cc) len = sb->sb_cc;
  177: 		memcpy(to,from,len);
  178: 	} else {
  179: 		/* re-use off */
  180: 		off = (sb->sb_data + sb->sb_datalen) - from;
  181: 		if (off > len) off = len;
  182: 		memcpy(to,from,off);
  183: 		len -= off;
  184: 		if (len)
  185: 		   memcpy(to+off,sb->sb_data,len);
  186: 	}
  187: }

unix.superglobalmegacorp.com