• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define WANT_SYS_IOCTL_H
9 #include "qemu-common.h"
10 #include <slirp.h>
11 #include "ip_icmp.h"
12 #include "main.h"
13 #ifdef __sun__
14 #include <sys/filio.h>
15 #endif
16 #define  SLIRP_COMPILATION 1
17 #include "sockets.h"
18 #include "proxy_common.h"
19 
20 static void sofcantrcvmore(struct socket *so);
21 static void sofcantsendmore(struct socket *so);
22 
23 #if 0
24 static void
25 so_init()
26 {
27 	/* Nothing yet */
28 }
29 #endif
30 
31 struct socket *
solookup(struct socket * head,uint32_t laddr,u_int lport,uint32_t faddr,u_int fport)32 solookup(struct socket *head, uint32_t laddr, u_int lport,
33          uint32_t faddr, u_int fport)
34 {
35 	struct socket *so;
36 
37 	for (so = head->so_next; so != head; so = so->so_next) {
38 		if (so->so_laddr_port == lport &&
39 		    so->so_laddr_ip   == laddr &&
40 		    so->so_faddr_ip   == faddr &&
41 		    so->so_faddr_port == fport)
42 		   break;
43 	}
44 
45 	if (so == head)
46 	   return (struct socket *)NULL;
47 	return so;
48 
49 }
50 
51 /*
52  * Create a new socket, initialise the fields
53  * It is the responsibility of the caller to
54  * insque() it into the correct linked-list
55  */
56 struct socket *
socreate(void)57 socreate(void)
58 {
59   struct socket *so;
60 
61   so = (struct socket *)malloc(sizeof(struct socket));
62   if(so) {
63     memset(so, 0, sizeof(struct socket));
64     so->so_state = SS_NOFDREF;
65     so->s = -1;
66   }
67   return(so);
68 }
69 
70 /*
71  * remque and free a socket, clobber cache
72  */
73 void
sofree(struct socket * so)74 sofree(struct socket *so)
75 {
76   if (so->so_state & SS_PROXIFIED)
77     proxy_manager_del(so);
78 
79   if (so->so_emu==EMU_RSH && so->extra) {
80 	sofree(so->extra);
81 	so->extra=NULL;
82   }
83   if (so == tcp_last_so)
84     tcp_last_so = &tcb;
85   else if (so == udp_last_so)
86     udp_last_so = &udb;
87 
88   m_free(so->so_m);
89 
90   if(so->so_next && so->so_prev)
91     remque(so);  /* crashes if so is not in a queue */
92 
93   free(so);
94 }
95 
sopreprbuf(struct socket * so,struct iovec * iov,int * np)96 size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np)
97 {
98 	int n, lss, total;
99 	struct sbuf *sb = &so->so_snd;
100 	int len = sb->sb_datalen - sb->sb_cc;
101 	int mss = so->so_tcpcb->t_maxseg;
102 
103 	DEBUG_CALL("sopreprbuf");
104 	DEBUG_ARG("so = %lx", (long )so);
105 
106 	len = sb->sb_datalen - sb->sb_cc;
107 
108 	if (len <= 0)
109 		return 0;
110 
111 	iov[0].iov_base = sb->sb_wptr;
112         iov[1].iov_base = NULL;
113         iov[1].iov_len = 0;
114 	if (sb->sb_wptr < sb->sb_rptr) {
115 		iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
116 		/* Should never succeed, but... */
117 		if (iov[0].iov_len > len)
118 		   iov[0].iov_len = len;
119 		if (iov[0].iov_len > mss)
120 		   iov[0].iov_len -= iov[0].iov_len%mss;
121 		n = 1;
122 	} else {
123 		iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr;
124 		/* Should never succeed, but... */
125 		if (iov[0].iov_len > len) iov[0].iov_len = len;
126 		len -= iov[0].iov_len;
127 		if (len) {
128 			iov[1].iov_base = sb->sb_data;
129 			iov[1].iov_len = sb->sb_rptr - sb->sb_data;
130 			if(iov[1].iov_len > len)
131 			   iov[1].iov_len = len;
132 			total = iov[0].iov_len + iov[1].iov_len;
133 			if (total > mss) {
134 				lss = total%mss;
135 				if (iov[1].iov_len > lss) {
136 					iov[1].iov_len -= lss;
137 					n = 2;
138 				} else {
139 					lss -= iov[1].iov_len;
140 					iov[0].iov_len -= lss;
141 					n = 1;
142 				}
143 			} else
144 				n = 2;
145 		} else {
146 			if (iov[0].iov_len > mss)
147 			   iov[0].iov_len -= iov[0].iov_len%mss;
148 			n = 1;
149 		}
150 	}
151 	if (np)
152 		*np = n;
153 
154 	return iov[0].iov_len + (n - 1) * iov[1].iov_len;
155 }
156 
157 /*
158  * Read from so's socket into sb_snd, updating all relevant sbuf fields
159  * NOTE: This will only be called if it is select()ed for reading, so
160  * a read() of 0 (or less) means it's disconnected
161  */
162 int
soread(struct socket * so)163 soread(struct socket *so)
164 {
165 	int n, nn;
166 	struct sbuf *sb = &so->so_snd;
167 	struct iovec iov[2];
168 
169 	DEBUG_CALL("soread");
170 	DEBUG_ARG("so = %lx", (long )so);
171 
172 	/*
173 	 * No need to check if there's enough room to read.
174 	 * soread wouldn't have been called if there weren't
175 	 */
176 	sopreprbuf(so, iov, &n);
177 
178 #ifdef HAVE_READV
179 	nn = readv(so->s, (struct iovec *)iov, n);
180 	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
181 #else
182 	nn = socket_recv(so->s, iov[0].iov_base, iov[0].iov_len);
183 #endif
184 	if (nn <= 0) {
185 		if (nn < 0 && (errno == EINTR || errno == EAGAIN))
186 			return 0;
187 		else {
188 			DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,errno_str));
189 			sofcantrcvmore(so);
190 			tcp_sockclosed(sototcpcb(so));
191 			return -1;
192 		}
193 	}
194 
195 #ifndef HAVE_READV
196 	/*
197 	 * If there was no error, try and read the second time round
198 	 * We read again if n = 2 (ie, there's another part of the buffer)
199 	 * and we read as much as we could in the first read
200 	 * We don't test for <= 0 this time, because there legitimately
201 	 * might not be any more data (since the socket is non-blocking),
202 	 * a close will be detected on next iteration.
203 	 * A return of -1 wont (shouldn't) happen, since it didn't happen above
204 	 */
205 	if (n == 2 && nn == iov[0].iov_len) {
206             int ret;
207             ret = socket_recv(so->s, iov[1].iov_base, iov[1].iov_len);
208             if (ret > 0)
209                 nn += ret;
210         }
211 
212 	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
213 #endif
214 
215 	/* Update fields */
216 	sb->sb_cc += nn;
217 	sb->sb_wptr += nn;
218 	if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
219 		sb->sb_wptr -= sb->sb_datalen;
220 	return nn;
221 }
222 
soreadbuf(struct socket * so,const char * buf,int size)223 int soreadbuf(struct socket *so, const char *buf, int size)
224 {
225     int n, nn, copy = size;
226 	struct sbuf *sb = &so->so_snd;
227 	struct iovec iov[2];
228 
229 	DEBUG_CALL("soreadbuf");
230 	DEBUG_ARG("so = %lx", (long )so);
231 
232 	/*
233 	 * No need to check if there's enough room to read.
234 	 * soread wouldn't have been called if there weren't
235 	 */
236 	if (sopreprbuf(so, iov, &n) < size)
237         goto err;
238 
239     nn = MIN(iov[0].iov_len, copy);
240     memcpy(iov[0].iov_base, buf, nn);
241 
242     copy -= nn;
243     buf += nn;
244 
245     if (copy == 0)
246         goto done;
247 
248     memcpy(iov[1].iov_base, buf, copy);
249 
250 done:
251     /* Update fields */
252 	sb->sb_cc += size;
253 	sb->sb_wptr += size;
254 	if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen))
255 		sb->sb_wptr -= sb->sb_datalen;
256     return size;
257 err:
258 
259     sofcantrcvmore(so);
260     tcp_sockclosed(sototcpcb(so));
261     fprintf(stderr, "soreadbuf buffer to small");
262     return -1;
263 }
264 
265 /*
266  * Get urgent data
267  *
268  * When the socket is created, we set it SO_OOBINLINE,
269  * so when OOB data arrives, we soread() it and everything
270  * in the send buffer is sent as urgent data
271  */
272 void
sorecvoob(struct socket * so)273 sorecvoob(struct socket *so)
274 {
275 	struct tcpcb *tp = sototcpcb(so);
276 
277 	DEBUG_CALL("sorecvoob");
278 	DEBUG_ARG("so = %lx", (long)so);
279 
280 	/*
281 	 * We take a guess at how much urgent data has arrived.
282 	 * In most situations, when urgent data arrives, the next
283 	 * read() should get all the urgent data.  This guess will
284 	 * be wrong however if more data arrives just after the
285 	 * urgent data, or the read() doesn't return all the
286 	 * urgent data.
287 	 */
288 	soread(so);
289 	tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
290 	tp->t_force = 1;
291 	tcp_output(tp);
292 	tp->t_force = 0;
293 }
294 
295 /*
296  * Send urgent data
297  * There's a lot duplicated code here, but...
298  */
299 int
sosendoob(struct socket * so)300 sosendoob(struct socket *so)
301 {
302 	struct sbuf *sb = &so->so_rcv;
303 	char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
304 
305 	int n, len;
306 
307 	DEBUG_CALL("sosendoob");
308 	DEBUG_ARG("so = %lx", (long)so);
309 	DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
310 
311 	if (so->so_urgc > 2048)
312 	   so->so_urgc = 2048; /* XXXX */
313 
314 	if (sb->sb_rptr < sb->sb_wptr) {
315 		/* We can send it directly */
316 		n = socket_send_oob(so->s, sb->sb_rptr, so->so_urgc); /* |MSG_DONTWAIT)); */
317 		so->so_urgc -= n;
318 
319 		DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
320 	} else {
321 		/*
322 		 * Since there's no sendv or sendtov like writev,
323 		 * we must copy all data to a linear buffer then
324 		 * send it all
325 		 */
326 		len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
327 		if (len > so->so_urgc) len = so->so_urgc;
328 		memcpy(buff, sb->sb_rptr, len);
329 		so->so_urgc -= len;
330 		if (so->so_urgc) {
331 			n = sb->sb_wptr - sb->sb_data;
332 			if (n > so->so_urgc) n = so->so_urgc;
333 			memcpy((buff + len), sb->sb_data, n);
334 			so->so_urgc -= n;
335 			len += n;
336 		}
337 		n = socket_send_oob(so->s, buff, len); /* |MSG_DONTWAIT)); */
338 #ifdef DEBUG
339 		if (n != len)
340 		   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
341 #endif
342 		DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
343 	}
344 
345 	sb->sb_cc -= n;
346 	sb->sb_rptr += n;
347 	if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
348 		sb->sb_rptr -= sb->sb_datalen;
349 
350 	return n;
351 }
352 
353 /*
354  * Write data from so_rcv to so's socket,
355  * updating all sbuf field as necessary
356  */
357 int
sowrite(struct socket * so)358 sowrite(struct socket *so)
359 {
360 	int  n,nn;
361 	struct sbuf *sb = &so->so_rcv;
362 	int len = sb->sb_cc;
363 	struct iovec iov[2];
364 
365 	DEBUG_CALL("sowrite");
366 	DEBUG_ARG("so = %lx", (long)so);
367 
368 	if (so->so_urgc) {
369 		sosendoob(so);
370 		if (sb->sb_cc == 0)
371 			return 0;
372 	}
373 
374 	/*
375 	 * No need to check if there's something to write,
376 	 * sowrite wouldn't have been called otherwise
377 	 */
378 
379         len = sb->sb_cc;
380 
381 	iov[0].iov_base = sb->sb_rptr;
382         iov[1].iov_base = NULL;
383         iov[1].iov_len = 0;
384 	if (sb->sb_rptr < sb->sb_wptr) {
385 		iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
386 		/* Should never succeed, but... */
387 		if (iov[0].iov_len > len) iov[0].iov_len = len;
388 		n = 1;
389 	} else {
390 		iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr;
391 		if (iov[0].iov_len > len) iov[0].iov_len = len;
392 		len -= iov[0].iov_len;
393 		if (len) {
394 			iov[1].iov_base = sb->sb_data;
395 			iov[1].iov_len = sb->sb_wptr - sb->sb_data;
396 			if (iov[1].iov_len > len) iov[1].iov_len = len;
397 			n = 2;
398 		} else
399 			n = 1;
400 	}
401 	/* Check if there's urgent data to send, and if so, send it */
402 
403 #ifdef HAVE_READV
404 	nn = writev(so->s, (const struct iovec *)iov, n);
405 
406 	DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
407 #else
408 	nn = socket_send(so->s, iov[0].iov_base, iov[0].iov_len);
409 #endif
410 	/* This should never happen, but people tell me it does *shrug* */
411 	if (nn < 0 && (errno == EAGAIN || errno == EINTR))
412 		return 0;
413 
414 	if (nn <= 0) {
415 		DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
416 			so->so_state, errno));
417 		sofcantsendmore(so);
418 		tcp_sockclosed(sototcpcb(so));
419 		return -1;
420 	}
421 
422 #ifndef HAVE_READV
423 	if (n == 2 && nn == iov[0].iov_len) {
424             int ret;
425             ret = socket_send(so->s, iov[1].iov_base, iov[1].iov_len);
426             if (ret > 0)
427                 nn += ret;
428         }
429         DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
430 #endif
431 
432 	/* Update sbuf */
433 	sb->sb_cc -= nn;
434 	sb->sb_rptr += nn;
435 	if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
436 		sb->sb_rptr -= sb->sb_datalen;
437 
438 	/*
439 	 * If in DRAIN mode, and there's no more data, set
440 	 * it CANTSENDMORE
441 	 */
442 	if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
443 		sofcantsendmore(so);
444 
445 	return nn;
446 }
447 
448 /*
449  * recvfrom() a UDP socket
450  */
451 void
sorecvfrom(struct socket * so)452 sorecvfrom(struct socket *so)
453 {
454         SockAddress  addr;
455 
456 	DEBUG_CALL("sorecvfrom");
457 	DEBUG_ARG("so = %lx", (long)so);
458 
459 	if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
460 	  char buff[256];
461 	  int len;
462 
463 	  len = socket_recvfrom(so->s, buff, 256, &addr);
464 	  /* XXX Check if reply is "correct"? */
465 
466 	  if(len == -1 || len == 0) {
467 	    u_char code=ICMP_UNREACH_PORT;
468 
469 	    if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
470 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
471 
472 	    DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
473 			errno,errno_str));
474 	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,errno_str);
475 	  } else {
476 	    icmp_reflect(so->so_m);
477 	    so->so_m = 0; /* Don't mbuf_free() it again! */
478 	  }
479 	  /* No need for this socket anymore, udp_detach it */
480 	  udp_detach(so);
481 	} else {                            	/* A "normal" UDP packet */
482 	  struct mbuf *m;
483           int len;
484 		  int n;
485 
486 	  if (!(m = m_get())) return;
487 	  m->m_data += IF_MAXLINKHDR;
488 
489 	  /*
490 	   * XXX Shouldn't FIONREAD packets destined for port 53,
491 	   * but I don't know the max packet size for DNS lookups
492 	   */
493 	  len = M_FREEROOM(m);
494 	  /* if (so->so_fport != htons(53)) { */
495 	  n = socket_can_read(so->s);
496 
497 	  if (n > len) {
498 	    n = (m->m_data - m->m_dat) + m->m_len + n + 1;
499 	    m_inc(m, n);
500 	    len = M_FREEROOM(m);
501 	  }
502 	  /* } */
503 
504 	  m->m_len = socket_recvfrom(so->s, m->m_data, len, &addr);
505 	  DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
506 		      m->m_len, errno,errno_str));
507 	  if(m->m_len<0) {
508 	    u_char code=ICMP_UNREACH_PORT;
509 
510 	    if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
511 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
512 
513 	    DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
514 	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,errno_str);
515 	    m_free(m);
516 	  } else {
517 	  /*
518 	   * Hack: domain name lookup will be used the most for UDP,
519 	   * and since they'll only be used once there's no need
520 	   * for the 4 minute (or whatever) timeout... So we time them
521 	   * out much quicker (10 seconds  for now...)
522 	   */
523 	    if (so->so_expire) {
524 	      if (so->so_faddr_port == 53)
525 		so->so_expire = curtime + SO_EXPIREFAST;
526 	      else
527 		so->so_expire = curtime + SO_EXPIRE;
528 	    }
529 
530 	    /*		if (m->m_len == len) {
531 	     *			m_inc(m, MINCSIZE);
532 	     *			m->m_len = 0;
533 	     *		}
534 	     */
535 
536 	    /*
537 	     * If this packet was destined for CTL_ADDR,
538 	     * make it look like that's where it came from, done by udp_output
539 	     */
540 	    udp_output_(so, m, &addr);
541 	  } /* rx error */
542 	} /* if ping packet */
543 }
544 
545 /*
546  * sendto() a socket
547  */
548 int
sosendto(struct socket * so,struct mbuf * m)549 sosendto(struct socket *so, struct mbuf *m)
550 {
551 	int ret;
552     SockAddress   addr;
553     uint32_t      addr_ip;
554     uint16_t      addr_port;
555 
556 	DEBUG_CALL("sosendto");
557 	DEBUG_ARG("so = %lx", (long)so);
558 	DEBUG_ARG("m = %lx", (long)m);
559 
560 	if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
561         /* It's an alias */
562       	int  low = so->so_faddr_ip & 0xff;
563 
564         if ( CTL_IS_DNS(low) )
565             addr_ip = dns_addr[low - CTL_DNS];
566         else
567             addr_ip = loopback_addr_ip;
568 	} else
569 	    addr_ip = so->so_faddr_ip;
570 
571 	addr_port = so->so_faddr_port;
572 
573 	/*
574 	 * test for generic forwarding; this function replaces the arguments
575 	 * only on success
576 	 */
577 	unsigned long faddr = addr_ip;
578         int fport = addr_port;
579 
580 	if (slirp_should_net_forward(faddr, fport, &faddr, &fport)) {
581       time_t timestamp = time(NULL);
582       slirp_drop_log(
583 	       "Redirected UDP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x "
584 	       "new dst: 0x%08lx:0x%04x %ld\n",
585 	        so->so_laddr_ip, so->so_laddr_port,
586 	        addr_ip, addr_port,
587 	        faddr, fport, timestamp
588 	    );
589 	}
590 	addr_ip = faddr;
591 	addr_port = fport;
592 
593 
594         sock_address_init_inet(&addr, addr_ip, addr_port);
595 
596 	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%08x\n", addr_port, addr_ip));
597 
598 	/* Don't care what port we get */
599 	ret = socket_sendto(so->s, m->m_data, m->m_len,&addr);
600 	if (ret < 0)
601 		return -1;
602 
603 	/*
604 	 * Kill the socket if there's no reply in 4 minutes,
605 	 * but only if it's an expirable socket
606 	 */
607 	if (so->so_expire)
608 		so->so_expire = curtime + SO_EXPIRE;
609 	so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */
610 	return 0;
611 }
612 
613 /*
614  * XXX This should really be tcp_listen
615  */
616 struct socket *
solisten(u_int port,u_int32_t laddr,u_int lport,int flags)617 solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
618 {
619 	SockAddress  addr;
620 	uint32_t     addr_ip;
621 	struct socket *so;
622 	int s;
623 
624 	DEBUG_CALL("solisten");
625 	DEBUG_ARG("port = %d", port);
626 	DEBUG_ARG("laddr = %x", laddr);
627 	DEBUG_ARG("lport = %d", lport);
628 	DEBUG_ARG("flags = %x", flags);
629 
630 	if ((so = socreate()) == NULL) {
631 	  /* free(so);      Not sofree() ??? free(NULL) == NOP */
632 	  return NULL;
633 	}
634 
635 	/* Don't tcp_attach... we don't need so_snd nor so_rcv */
636 	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
637 		free(so);
638 		return NULL;
639 	}
640 	insque(so,&tcb);
641 
642 	/*
643 	 * SS_FACCEPTONCE sockets must time out.
644 	 */
645 	if (flags & SS_FACCEPTONCE)
646 	   so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
647 
648 	so->so_state      = (SS_FACCEPTCONN|flags);
649 	so->so_laddr_port = lport; /* Kept in host format */
650     so->so_laddr_ip   = laddr; /* Ditto */
651     so->so_haddr_port = port;
652 
653     s = socket_loopback_server( port, SOCKET_STREAM );
654     if (s < 0)
655         return NULL;
656 
657     socket_get_address(s, &addr);
658 
659 	so->so_faddr_port = sock_address_get_port(&addr);
660 
661     addr_ip = (uint32_t) sock_address_get_ip(&addr);
662 
663     if (addr_ip == 0 || addr_ip == loopback_addr_ip)
664         so->so_faddr_ip = alias_addr_ip;
665     else
666         so->so_faddr_ip = addr_ip;
667 
668 	so->s = s;
669 	return so;
670 }
671 
672 
673 int
sounlisten(u_int port)674 sounlisten(u_int  port)
675 {
676     struct socket *so;
677 
678     for (so = tcb.so_next; so != &tcb; so = so->so_next) {
679         if (so->so_haddr_port == port) {
680             break;
681         }
682     }
683 
684     if (so == &tcb) {
685         return -1;
686     }
687 
688     sofcantrcvmore( so );
689     sofcantsendmore( so );
690     close( so->s );
691     so->s = -1;
692     sofree( so );
693     return 0;
694 }
695 
696 
697 #if 0
698 /*
699  * Data is available in so_rcv
700  * Just write() the data to the socket
701  * XXX not yet...
702  */
703 static void
704 sorwakeup(so)
705 	struct socket *so;
706 {
707 /*	sowrite(so); */
708 /*	FD_CLR(so->s,&writefds); */
709 }
710 
711 /*
712  * Data has been freed in so_snd
713  * We have room for a read() if we want to
714  * For now, don't read, it'll be done in the main loop
715  */
716 static void
717 sowwakeup(so)
718 	struct socket *so;
719 {
720 	/* Nothing, yet */
721 }
722 #endif
723 
724 /*
725  * Various session state calls
726  * XXX Should be #define's
727  * The socket state stuff needs work, these often get call 2 or 3
728  * times each when only 1 was needed
729  */
730 void
soisfconnecting(struct socket * so)731 soisfconnecting(struct socket *so)
732 {
733 	so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
734 			  SS_FCANTSENDMORE|SS_FWDRAIN);
735 	so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
736 }
737 
738 void
soisfconnected(struct socket * so)739 soisfconnected(struct socket *so)
740 {
741 	so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
742 	so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
743 }
744 
745 static void
sofcantrcvmore(struct socket * so)746 sofcantrcvmore(struct socket *so)
747 {
748 	if ((so->so_state & SS_NOFDREF) == 0) {
749 		shutdown(so->s,0);
750 		if(global_writefds) {
751 		  FD_CLR(so->s,global_writefds);
752 		}
753 	}
754 	so->so_state &= ~(SS_ISFCONNECTING);
755 	if (so->so_state & SS_FCANTSENDMORE)
756 	   so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */
757 	else
758 	   so->so_state |= SS_FCANTRCVMORE;
759 }
760 
761 static void
sofcantsendmore(struct socket * so)762 sofcantsendmore(struct socket *so)
763 {
764 	if ((so->so_state & SS_NOFDREF) == 0) {
765             shutdown(so->s,1);           /* send FIN to fhost */
766             if (global_readfds) {
767                 FD_CLR(so->s,global_readfds);
768             }
769             if (global_xfds) {
770                 FD_CLR(so->s,global_xfds);
771             }
772 	}
773 	so->so_state &= ~(SS_ISFCONNECTING);
774 	if (so->so_state & SS_FCANTRCVMORE)
775 	   so->so_state = SS_NOFDREF; /* as above */
776 	else
777 	   so->so_state |= SS_FCANTSENDMORE;
778 }
779 
780 void
soisfdisconnected(struct socket * so)781 soisfdisconnected(struct socket *so)
782 {
783 /*	so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */
784 /*	close(so->s); */
785 /*	so->so_state = SS_ISFDISCONNECTED; */
786 	/*
787 	 * XXX Do nothing ... ?
788 	 */
789 }
790 
791 /*
792  * Set write drain mode
793  * Set CANTSENDMORE once all data has been write()n
794  */
795 void
sofwdrain(struct socket * so)796 sofwdrain(struct socket *so)
797 {
798 	if (so->so_rcv.sb_cc)
799 		so->so_state |= SS_FWDRAIN;
800 	else
801 		sofcantsendmore(so);
802 }
803