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