VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/socket.c@ 15035

Last change on this file since 15035 was 15035, checked in by vboxsync, 16 years ago

ICMP: support storaging and searching of sent packet.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette