return(so);
}
+/*
+ * Remove references to so from the given message queue.
+ */
+static void
+soqfree(struct socket *so, struct quehead *qh)
+{
+ struct mbuf *ifq;
+
+ for (ifq = (struct mbuf *) qh->qh_link;
+ (struct quehead *) ifq != qh;
+ ifq = ifq->ifq_next) {
+ if (ifq->ifq_so == so) {
+ struct mbuf *ifm;
+ ifq->ifq_so = NULL;
+ for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) {
+ ifm->ifq_so = NULL;
+ }
+ }
+ }
+}
+
/*
* remque and free a socket, clobber cache
*/
sofree(struct socket *so)
{
Slirp *slirp = so->slirp;
- struct mbuf *ifm;
- for (ifm = (struct mbuf *) slirp->if_fastq.qh_link;
- (struct quehead *) ifm != &slirp->if_fastq;
- ifm = ifm->ifq_next) {
- if (ifm->ifq_so == so) {
- ifm->ifq_so = NULL;
- }
- }
-
- for (ifm = (struct mbuf *) slirp->if_batchq.qh_link;
- (struct quehead *) ifm != &slirp->if_batchq;
- ifm = ifm->ifq_next) {
- if (ifm->ifq_so == so) {
- ifm->ifq_so = NULL;
- }
- }
+ soqfree(so, &slirp->if_fastq);
+ soqfree(so, &slirp->if_batchq);
if (so->so_emu==EMU_RSH && so->extra) {
sofree(so->extra);
if(so->so_next && so->so_prev)
remque(so); /* crashes if so is not in a queue */
+ if (so->so_tcpcb) {
+ free(so->so_tcpcb);
+ }
free(so);
}
return 0;
else {
int err;
- socklen_t slen = sizeof err;
+ socklen_t elen = sizeof err;
+ struct sockaddr_storage addr;
+ struct sockaddr *paddr = (struct sockaddr *) &addr;
+ socklen_t alen = sizeof addr;
err = errno;
if (nn == 0) {
- getsockopt(so->s, SOL_SOCKET, SO_ERROR,
- &err, &slen);
+ if (getpeername(so->s, paddr, &alen) < 0) {
+ err = errno;
+ } else {
+ getsockopt(so->s, SOL_SOCKET, SO_ERROR,
+ &err, &elen);
+ }
}
DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
struct sbuf *sb = &so->so_rcv;
char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
- int n, len;
+ int n;
DEBUG_CALL("sosendoob");
DEBUG_ARG("so = %p", so);
if (sb->sb_rptr < sb->sb_wptr) {
/* We can send it directly */
n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
- so->so_urgc -= n;
-
- DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
} else {
/*
* Since there's no sendv or sendtov like writev,
* we must copy all data to a linear buffer then
* send it all
*/
- len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
- if (len > so->so_urgc) len = so->so_urgc;
+ uint32_t urgc = so->so_urgc;
+ int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
+ if (len > urgc) {
+ len = urgc;
+ }
memcpy(buff, sb->sb_rptr, len);
- so->so_urgc -= len;
- if (so->so_urgc) {
+ urgc -= len;
+ if (urgc) {
n = sb->sb_wptr - sb->sb_data;
- if (n > so->so_urgc) n = so->so_urgc;
+ if (n > urgc) {
+ n = urgc;
+ }
memcpy((buff + len), sb->sb_data, n);
- so->so_urgc -= n;
len += n;
}
n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
#ifdef DEBUG
- if (n != len)
- DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+ if (n != len) {
+ DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+ }
#endif
- DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
}
+ if (n < 0) {
+ return n;
+ }
+ so->so_urgc -= n;
+ DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
+
sb->sb_cc -= n;
sb->sb_rptr += n;
if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
DEBUG_ARG("so = %p", so);
if (so->so_urgc) {
- sosendoob(so);
+ uint32_t expected = so->so_urgc;
+ if (sosendoob(so) < expected) {
+ /* Treat a short write as a fatal error too,
+ * rather than continuing on and sending the urgent
+ * data as if it were non-urgent and leaving the
+ * so_urgc count wrong.
+ */
+ goto err_disconnected;
+ }
if (sb->sb_cc == 0)
return 0;
}
return 0;
if (nn <= 0) {
- DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
- so->so_state, errno));
- sofcantsendmore(so);
- tcp_sockclosed(sototcpcb(so));
- return -1;
+ goto err_disconnected;
}
#ifndef HAVE_READV
sofcantsendmore(so);
return nn;
+
+err_disconnected:
+ DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
+ so->so_state, errno));
+ sofcantsendmore(so);
+ tcp_sockclosed(sototcpcb(so));
+ return -1;
}
/*
memset(&addr, 0, addrlen);
DEBUG_CALL("tcp_listen");
- DEBUG_ARG("haddr = %x", haddr);
- DEBUG_ARG("hport = %d", hport);
- DEBUG_ARG("laddr = %x", laddr);
- DEBUG_ARG("lport = %d", lport);
+ DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr}));
+ DEBUG_ARG("hport = %d", ntohs(hport));
+ DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr}));
+ DEBUG_ARG("lport = %d", ntohs(lport));
DEBUG_ARG("flags = %x", flags);
so = socreate(slirp);
return NULL;
}
qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ opt = 1;
+ qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
getsockname(s,(struct sockaddr *)&addr,&addrlen);
so->so_ffamily = AF_INET;