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