18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 1995 Danny Gasparovski.
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Please read the file COPYRIGHT for the
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * terms and conditions of the copyright.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <slirp.h>
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void sbappendsb(struct sbuf *sb, struct mbuf *m);
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Done as a macro in socket.h */
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* int
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * sbspace(struct sockbuff *sb)
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * {
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *	return SB_DATALEN - sb->sb_cc;
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * }
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersbfree(struct sbuf *sb)
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	free(sb->sb_data);
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersbdrop(struct sbuf *sb, int num)
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/*
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * We can only drop how much we have
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	 * This should never succeed
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 */
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(num > sb->sb_cc)
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		num = sb->sb_cc;
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	sb->sb_cc -= num;
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	sb->sb_rptr += num;
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		sb->sb_rptr -= sb->sb_datalen;
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersbreserve(struct sbuf *sb, int size)
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (sb->sb_data) {
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/* Already alloced, realloc if necessary */
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (sb->sb_datalen != size) {
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sb->sb_cc = 0;
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			if (sb->sb_wptr)
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   sb->sb_datalen = size;
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			else
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			   sb->sb_datalen = 0;
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		}
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	} else {
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sb->sb_cc = 0;
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		if (sb->sb_wptr)
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		   sb->sb_datalen = size;
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		else
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		   sb->sb_datalen = 0;
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Try and write() to the socket, whatever doesn't get written
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * append to the buffer... for a host with a fast net connection,
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * this prevents an unnecessary copy of the data
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * (the socket is non-blocking, so we won't hang)
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersbappend(struct socket *so, struct mbuf *m)
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int ret = 0;
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	DEBUG_CALL("sbappend");
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	DEBUG_ARG("so = %lx", (long)so);
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	DEBUG_ARG("m = %lx", (long)m);
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	DEBUG_ARG("m->m_len = %d", m->m_len);
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* Shouldn't happen, but...  e.g. foreign host closes connection */
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (m->m_len <= 0) {
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		m_free(m);
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return;
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/*
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * If there is urgent data, call sosendoob
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * if not all was sent, sowrite will take care of the rest
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * (The rest of this function is just an optimisation)
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 */
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (so->so_urgc) {
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sbappendsb(&so->so_rcv, m);
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		m_free(m);
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		sosendoob(so);
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		return;
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/*
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * We only write if there's nothing in the buffer,
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 * ottherwise it'll arrive out of order, and hence corrupt
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	 */
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (!so->so_rcv.sb_cc)
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   ret = slirp_send(so, m->m_data, m->m_len, 0);
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (ret <= 0) {
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/*
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * Nothing was written
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * It's possible that the socket has closed, but
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * we don't need to check because if it has closed,
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * it will be detected in the normal way by soread()
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 */
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sbappendsb(&so->so_rcv, m);
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else if (ret != m->m_len) {
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/*
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 * Something was written, but not everything..
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		 * sbappendsb the rest
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		 */
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		m->m_len -= ret;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		m->m_data += ret;
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		sbappendsb(&so->so_rcv, m);
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} /* else */
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	/* Whatever happened, we free the mbuf */
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	m_free(m);
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copy the data from m into sb
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The caller is responsible to make sure there's enough room
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersbappendsb(struct sbuf *sb, struct mbuf *m)
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	int len, n,  nn;
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	len = m->m_len;
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (sb->sb_wptr < sb->sb_rptr) {
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		n = sb->sb_rptr - sb->sb_wptr;
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (n > len) n = len;
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(sb->sb_wptr, m->m_data, n);
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else {
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/* Do the right edge first */
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		n = sb->sb_data + sb->sb_datalen - sb->sb_wptr;
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (n > len) n = len;
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(sb->sb_wptr, m->m_data, n);
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		len -= n;
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (len) {
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			/* Now the left edge */
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			nn = sb->sb_rptr - sb->sb_data;
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			if (nn > len) nn = len;
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			memcpy(sb->sb_data,m->m_data+n,nn);
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project			n += nn;
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		}
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	sb->sb_cc += n;
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	sb->sb_wptr += n;
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		sb->sb_wptr -= sb->sb_datalen;
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copy data from sbuf to a normal, straight buffer
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Don't update the sbuf rptr, this will be
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * done in sbdrop when the data is acked
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnersbcopy(struct sbuf *sb, int off, int len, char *to)
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	char *from;
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	from = sb->sb_rptr + off;
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (from >= sb->sb_data + sb->sb_datalen)
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		from -= sb->sb_datalen;
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	if (from < sb->sb_wptr) {
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (len > sb->sb_cc) len = sb->sb_cc;
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(to,from,len);
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	} else {
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		/* re-use off */
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		off = (sb->sb_data + sb->sb_datalen) - from;
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (off > len) off = len;
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		memcpy(to,from,off);
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		len -= off;
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		if (len)
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project		   memcpy(to+off,sb->sb_data,len);
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	}
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
190