VirtualBox

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

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

ICMP part of sorecvfrom receives only ICMP_ECHOREPLY and ICMP_TIMXCEED messages,
the unnessary coping disabled for ICMP_ECHOREPLY messages

  • 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 *m;
455 struct icmp_msg *icm;
456
457 ip = (struct ip *)buff;
458 icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
459
460 Assert(icp->icmp_type == ICMP_ECHOREPLY || icp->icmp_type == ICMP_TIMXCEED);
461
462 if (icp->icmp_type == ICMP_TIMXCEED ) {
463 ip = &icp->icmp_ip;
464 }
465
466 icm = icmp_find_original_mbuf(pData, ip);
467
468 if (icm == NULL) {
469 LogRel(("Can't find the corresponding packet for the received ICMP\n"));
470 return;
471 }
472
473 m = icm->im_m;
474 Assert(m != NULL);
475
476 src = addr.sin_addr.s_addr;
477
478 ip = mtod(m, struct ip *);
479 /* Now ip is pointing on header we've sent from guest */
480 if (icp->icmp_type == ICMP_TIMXCEED) {
481 old_ip_len = (ip->ip_hl << 2) + 64;
482 memcpy(ip_copy, ip, old_ip_len);
483 }
484
485 /* source address from original IP packet*/
486 dst = ip->ip_src.s_addr;
487
488 /* overide ther tail of old packet */
489 memcpy(m->m_data, buff, len);
490 m->m_len = len;
491 ip = mtod(m, struct ip *); /* ip is from mbuf we've overrided */
492
493 icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
494 if (icp->icmp_type == ICMP_TIMXCEED) {
495 /* according RFC 793 error messages required copy of initial IP header + 64 bit */
496 memcpy(&icp->icmp_ip, ip_copy, old_ip_len);
497 ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
498 }
499
500 /* the low level expects fields to be in host format so let's convert them*/
501 NTOHS(ip->ip_len);
502 NTOHS(ip->ip_off);
503 NTOHS(ip->ip_id);
504 ip->ip_src.s_addr = src;
505 ip->ip_dst.s_addr = dst;
506 icmp_reflect(pData, m);
507 LIST_REMOVE(icm, im_list);
508 /* Don't call m_free here*/
509 free(icm);
510#else
511 icmp_reflect(pData, so->so_m);
512 so->so_m = 0; /* Don't m_free() it again! */
513#endif
514 }
515 /* No need for this socket anymore, udp_detach it */
516 udp_detach(pData, so);
517 } else { /* A "normal" UDP packet */
518 struct mbuf *m;
519 int len, n;
520
521 if (!(m = m_get(pData)))
522 return;
523 m->m_data += if_maxlinkhdr;
524
525 /*
526 * XXX Shouldn't FIONREAD packets destined for port 53,
527 * but I don't know the max packet size for DNS lookups
528 */
529 len = M_FREEROOM(m);
530 /* if (so->so_fport != htons(53)) */
531 {
532 ioctlsocket(so->s, FIONREAD, &n);
533
534 if (n > len)
535 {
536 n = (m->m_data - m->m_dat) + m->m_len + n + 1;
537 m_inc(m, n);
538 len = M_FREEROOM(m);
539 }
540 }
541
542 m->m_len = recvfrom(so->s, m->m_data, len, 0,
543 (struct sockaddr *)&addr, &addrlen);
544 DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
545 m->m_len, errno,strerror(errno)));
546 if(m->m_len < 0)
547 {
548 u_char code=ICMP_UNREACH_PORT;
549
550 if (errno == EHOSTUNREACH)
551 code=ICMP_UNREACH_HOST;
552 else if(errno == ENETUNREACH)
553 code=ICMP_UNREACH_NET;
554
555 DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
556 icmp_error(pData, so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
557 m_free(pData, m);
558 }
559 else
560 {
561 /*
562 * Hack: domain name lookup will be used the most for UDP,
563 * and since they'll only be used once there's no need
564 * for the 4 minute (or whatever) timeout... So we time them
565 * out much quicker (10 seconds for now...)
566 */
567 if (so->so_expire)
568 {
569 if (so->so_fport == htons(53))
570 so->so_expire = curtime + SO_EXPIREFAST;
571 else
572 so->so_expire = curtime + SO_EXPIRE;
573 }
574
575#if 0
576 if (m->m_len == len)
577 {
578 m_inc(m, MINCSIZE);
579 m->m_len = 0;
580 }
581#endif
582
583 /*
584 * If this packet was destined for CTL_ADDR,
585 * make it look like that's where it came from, done by udp_output
586 */
587 udp_output(pData, so, m, &addr);
588 } /* rx error */
589 } /* if ping packet */
590}
591
592/*
593 * sendto() a socket
594 */
595int
596sosendto(PNATState pData, struct socket *so, struct mbuf *m)
597{
598 int ret;
599 struct sockaddr_in addr;
600#if 0
601 struct sockaddr_in host_addr;
602#endif
603
604 DEBUG_CALL("sosendto");
605 DEBUG_ARG("so = %lx", (long)so);
606 DEBUG_ARG("m = %lx", (long)m);
607
608 addr.sin_family = AF_INET;
609 if ((so->so_faddr.s_addr & htonl(pData->netmask)) == special_addr.s_addr)
610 {
611 /* It's an alias */
612 uint32_t last_byte = ntohl(so->so_faddr.s_addr) & ~pData->netmask;
613 switch(last_byte)
614 {
615#if 0
616 /* handle this case at 'default:' */
617 case CTL_BROADCAST:
618 addr.sin_addr.s_addr = INADDR_BROADCAST;
619 /* Send the packet to host to fully emulate broadcast */
620 /** @todo r=klaus: on Linux host this causes the host to receive
621 * the packet twice for some reason. And I cannot find any place
622 * in the man pages which states that sending a broadcast does not
623 * reach the host itself. */
624 host_addr.sin_family = AF_INET;
625 host_addr.sin_port = so->so_fport;
626 host_addr.sin_addr = our_addr;
627 sendto(so->s, m->m_data, m->m_len, 0,
628 (struct sockaddr *)&host_addr, sizeof (struct sockaddr));
629 break;
630#endif
631 case CTL_DNS:
632 if (!get_dns_addr(pData, &dns_addr))
633 addr.sin_addr = dns_addr;
634 else
635 addr.sin_addr = loopback_addr;
636 break;
637 case CTL_ALIAS:
638 default:
639 if (last_byte == ~pData->netmask)
640 addr.sin_addr.s_addr = INADDR_BROADCAST;
641 else
642 addr.sin_addr = loopback_addr;
643 break;
644 }
645 }
646 else
647 addr.sin_addr = so->so_faddr;
648 addr.sin_port = so->so_fport;
649
650 DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n",
651 ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
652
653 /* Don't care what port we get */
654 ret = sendto(so->s, m->m_data, m->m_len, 0,
655 (struct sockaddr *)&addr, sizeof (struct sockaddr));
656 if (ret < 0)
657 return -1;
658
659 /*
660 * Kill the socket if there's no reply in 4 minutes,
661 * but only if it's an expirable socket
662 */
663 if (so->so_expire)
664 so->so_expire = curtime + SO_EXPIRE;
665 so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */
666 return 0;
667}
668
669/*
670 * XXX This should really be tcp_listen
671 */
672struct socket *
673solisten(PNATState pData, u_int port, u_int32_t laddr, u_int lport, int flags)
674{
675 struct sockaddr_in addr;
676 struct socket *so;
677 socklen_t addrlen = sizeof(addr);
678 int s, opt = 1;
679
680 DEBUG_CALL("solisten");
681 DEBUG_ARG("port = %d", port);
682 DEBUG_ARG("laddr = %x", laddr);
683 DEBUG_ARG("lport = %d", lport);
684 DEBUG_ARG("flags = %x", flags);
685
686 if ((so = socreate()) == NULL)
687 {
688 /* free(so); Not sofree() ??? free(NULL) == NOP */
689 return NULL;
690 }
691
692 /* Don't tcp_attach... we don't need so_snd nor so_rcv */
693 if ((so->so_tcpcb = tcp_newtcpcb(pData, so)) == NULL)
694 {
695 free(so);
696 return NULL;
697 }
698 insque(pData, so,&tcb);
699
700 /*
701 * SS_FACCEPTONCE sockets must time out.
702 */
703 if (flags & SS_FACCEPTONCE)
704 so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
705
706 so->so_state = (SS_FACCEPTCONN|flags);
707 so->so_lport = lport; /* Kept in network format */
708 so->so_laddr.s_addr = laddr; /* Ditto */
709
710 addr.sin_family = AF_INET;
711 addr.sin_addr.s_addr = INADDR_ANY;
712 addr.sin_port = port;
713
714 if ( ((s = socket(AF_INET,SOCK_STREAM,0)) < 0)
715 || (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0)
716 || (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0)
717 || (listen(s,1) < 0))
718 {
719#ifdef RT_OS_WINDOWS
720 int tmperrno = WSAGetLastError(); /* Don't clobber the real reason we failed */
721 closesocket(s);
722 sofree(pData, so);
723 /* Restore the real errno */
724 WSASetLastError(tmperrno);
725#else
726 int tmperrno = errno; /* Don't clobber the real reason we failed */
727 close(s);
728 sofree(pData, so);
729 /* Restore the real errno */
730 errno = tmperrno;
731#endif
732 return NULL;
733 }
734 setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
735
736 getsockname(s,(struct sockaddr *)&addr,&addrlen);
737 so->so_fport = addr.sin_port;
738 if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
739 so->so_faddr = alias_addr;
740 else
741 so->so_faddr = addr.sin_addr;
742
743 so->s = s;
744 return so;
745}
746
747/*
748 * Data is available in so_rcv
749 * Just write() the data to the socket
750 * XXX not yet...
751 */
752void
753sorwakeup(struct socket *so)
754{
755#if 0
756 sowrite(so);
757 FD_CLR(so->s,&writefds);
758#endif
759}
760
761/*
762 * Data has been freed in so_snd
763 * We have room for a read() if we want to
764 * For now, don't read, it'll be done in the main loop
765 */
766void
767sowwakeup(struct socket *so)
768{
769}
770
771/*
772 * Various session state calls
773 * XXX Should be #define's
774 * The socket state stuff needs work, these often get call 2 or 3
775 * times each when only 1 was needed
776 */
777void
778soisfconnecting(struct socket *so)
779{
780 so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE|
781 SS_FCANTSENDMORE|SS_FWDRAIN);
782 so->so_state |= SS_ISFCONNECTING; /* Clobber other states */
783}
784
785void
786soisfconnected(struct socket *so)
787{
788 so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF);
789 so->so_state |= SS_ISFCONNECTED; /* Clobber other states */
790}
791
792void
793sofcantrcvmore(struct socket *so)
794{
795 if ((so->so_state & SS_NOFDREF) == 0)
796 {
797 shutdown(so->s,0);
798 }
799 so->so_state &= ~(SS_ISFCONNECTING);
800 if (so->so_state & SS_FCANTSENDMORE)
801 so->so_state = SS_NOFDREF; /* Don't select it */
802 /* XXX close() here as well? */
803 else
804 so->so_state |= SS_FCANTRCVMORE;
805}
806
807void
808sofcantsendmore(struct socket *so)
809{
810 if ((so->so_state & SS_NOFDREF) == 0)
811 shutdown(so->s, 1); /* send FIN to fhost */
812
813 so->so_state &= ~(SS_ISFCONNECTING);
814 if (so->so_state & SS_FCANTRCVMORE)
815 so->so_state = SS_NOFDREF; /* as above */
816 else
817 so->so_state |= SS_FCANTSENDMORE;
818}
819
820void
821soisfdisconnected(struct socket *so)
822{
823#if 0
824 so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED);
825 close(so->s);
826 so->so_state = SS_ISFDISCONNECTED;
827 /*
828 * XXX Do nothing ... ?
829 */
830#endif
831}
832
833/*
834 * Set write drain mode
835 * Set CANTSENDMORE once all data has been write()n
836 */
837void
838sofwdrain(struct socket *so)
839{
840 if (so->so_rcv.sb_cc)
841 so->so_state |= SS_FWDRAIN;
842 else
843 sofcantsendmore(so);
844}
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