1 /* $NetBSD: sockin.c,v 1.63 2016/01/26 23:12:19 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2008, 2009 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: sockin.c,v 1.63 2016/01/26 23:12:19 pooka Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/condvar.h> 33 #include <sys/domain.h> 34 #include <sys/kmem.h> 35 #include <sys/kthread.h> 36 #include <sys/mbuf.h> 37 #include <sys/mutex.h> 38 #include <sys/once.h> 39 #include <sys/poll.h> 40 #include <sys/protosw.h> 41 #include <sys/queue.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/time.h> 45 46 #include <net/bpf.h> 47 #include <net/if.h> 48 #include <net/radix.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> 52 #include <netinet/ip.h> 53 54 #include <rump-sys/kern.h> 55 56 #include <rump/rumpuser.h> 57 58 #include "sockin_user.h" 59 60 /* 61 * An inet communication domain which uses the socket interface. 62 * Supports IPv4 & IPv6 UDP/TCP. 63 */ 64 65 DOMAIN_DEFINE(sockindomain); 66 DOMAIN_DEFINE(sockin6domain); 67 68 static int sockin_do_init(void); 69 static void sockin_init(void); 70 static int sockin_attach(struct socket *, int); 71 static void sockin_detach(struct socket *); 72 static int sockin_accept(struct socket *, struct sockaddr *); 73 static int sockin_connect2(struct socket *, struct socket *); 74 static int sockin_bind(struct socket *, struct sockaddr *, struct lwp *); 75 static int sockin_listen(struct socket *, struct lwp *); 76 static int sockin_connect(struct socket *, struct sockaddr *, struct lwp *); 77 static int sockin_disconnect(struct socket *); 78 static int sockin_shutdown(struct socket *); 79 static int sockin_abort(struct socket *); 80 static int sockin_ioctl(struct socket *, u_long, void *, struct ifnet *); 81 static int sockin_stat(struct socket *, struct stat *); 82 static int sockin_peeraddr(struct socket *, struct sockaddr *); 83 static int sockin_sockaddr(struct socket *, struct sockaddr *); 84 static int sockin_rcvd(struct socket *, int, struct lwp *); 85 static int sockin_recvoob(struct socket *, struct mbuf *, int); 86 static int sockin_send(struct socket *, struct mbuf *, struct sockaddr *, 87 struct mbuf *, struct lwp *); 88 static int sockin_sendoob(struct socket *, struct mbuf *, struct mbuf *); 89 static int sockin_purgeif(struct socket *, struct ifnet *); 90 static int sockin_ctloutput(int op, struct socket *, struct sockopt *); 91 92 static const struct pr_usrreqs sockin_usrreqs = { 93 .pr_attach = sockin_attach, 94 .pr_detach = sockin_detach, 95 .pr_accept = sockin_accept, 96 .pr_bind = sockin_bind, 97 .pr_listen = sockin_listen, 98 .pr_connect = sockin_connect, 99 .pr_connect2 = sockin_connect2, 100 .pr_disconnect = sockin_disconnect, 101 .pr_shutdown = sockin_shutdown, 102 .pr_abort = sockin_abort, 103 .pr_ioctl = sockin_ioctl, 104 .pr_stat = sockin_stat, 105 .pr_peeraddr = sockin_peeraddr, 106 .pr_sockaddr = sockin_sockaddr, 107 .pr_rcvd = sockin_rcvd, 108 .pr_recvoob = sockin_recvoob, 109 .pr_send = sockin_send, 110 .pr_sendoob = sockin_sendoob, 111 .pr_purgeif = sockin_purgeif, 112 }; 113 114 const struct protosw sockinsw[] = { 115 { 116 .pr_type = SOCK_DGRAM, 117 .pr_domain = &sockindomain, 118 .pr_protocol = IPPROTO_UDP, 119 .pr_flags = PR_ATOMIC|PR_ADDR, 120 .pr_usrreqs = &sockin_usrreqs, 121 .pr_ctloutput = sockin_ctloutput, 122 }, 123 { 124 .pr_type = SOCK_STREAM, 125 .pr_domain = &sockindomain, 126 .pr_protocol = IPPROTO_TCP, 127 .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS, 128 .pr_usrreqs = &sockin_usrreqs, 129 .pr_ctloutput = sockin_ctloutput, 130 }}; 131 const struct protosw sockin6sw[] = { 132 { 133 .pr_type = SOCK_DGRAM, 134 .pr_domain = &sockin6domain, 135 .pr_protocol = IPPROTO_UDP, 136 .pr_flags = PR_ATOMIC|PR_ADDR, 137 .pr_usrreqs = &sockin_usrreqs, 138 .pr_ctloutput = sockin_ctloutput, 139 }, 140 { 141 .pr_type = SOCK_STREAM, 142 .pr_domain = &sockin6domain, 143 .pr_protocol = IPPROTO_TCP, 144 .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS, 145 .pr_usrreqs = &sockin_usrreqs, 146 .pr_ctloutput = sockin_ctloutput, 147 }}; 148 149 struct domain sockindomain = { 150 .dom_family = PF_INET, 151 .dom_name = "socket_inet", 152 .dom_init = sockin_init, 153 .dom_externalize = NULL, 154 .dom_dispose = NULL, 155 .dom_protosw = sockinsw, 156 .dom_protoswNPROTOSW = &sockinsw[__arraycount(sockinsw)], 157 .dom_rtattach = rt_inithead, 158 .dom_rtoffset = 32, 159 .dom_maxrtkey = sizeof(struct sockaddr_in), 160 .dom_ifattach = NULL, 161 .dom_ifdetach = NULL, 162 .dom_ifqueues = { NULL }, 163 .dom_link = { NULL }, 164 .dom_mowner = MOWNER_INIT("",""), 165 .dom_rtcache = { NULL }, 166 .dom_sockaddr_cmp = NULL 167 }; 168 struct domain sockin6domain = { 169 .dom_family = PF_INET6, 170 .dom_name = "socket_inet6", 171 .dom_init = sockin_init, 172 .dom_externalize = NULL, 173 .dom_dispose = NULL, 174 .dom_protosw = sockin6sw, 175 .dom_protoswNPROTOSW = &sockin6sw[__arraycount(sockin6sw)], 176 .dom_rtattach = rt_inithead, 177 .dom_rtoffset = 32, 178 .dom_maxrtkey = sizeof(struct sockaddr_in6), 179 .dom_ifattach = NULL, 180 .dom_ifdetach = NULL, 181 .dom_ifqueues = { NULL }, 182 .dom_link = { NULL }, 183 .dom_mowner = MOWNER_INIT("",""), 184 .dom_rtcache = { NULL }, 185 .dom_sockaddr_cmp = NULL 186 }; 187 188 #define SO2S(so) ((intptr_t)(so->so_internal)) 189 #define SOCKIN_SBSIZE 65536 190 191 struct sockin_unit { 192 struct socket *su_so; 193 194 LIST_ENTRY(sockin_unit) su_entries; 195 }; 196 static LIST_HEAD(, sockin_unit) su_ent = LIST_HEAD_INITIALIZER(su_ent); 197 static kmutex_t su_mtx; 198 static bool rebuild; 199 static int nsock; 200 201 /* XXX: for the bpf hack */ 202 static struct ifnet sockin_if; 203 int ifpromisc(struct ifnet *ifp, int pswitch) { return 0; } 204 205 static int 206 registersock(struct socket *so, int news) 207 { 208 struct sockin_unit *su; 209 210 su = kmem_alloc(sizeof(*su), KM_NOSLEEP); 211 if (!su) 212 return ENOMEM; 213 214 so->so_internal = (void *)(intptr_t)news; 215 su->su_so = so; 216 217 mutex_enter(&su_mtx); 218 LIST_INSERT_HEAD(&su_ent, su, su_entries); 219 nsock++; 220 rebuild = true; 221 mutex_exit(&su_mtx); 222 223 return 0; 224 } 225 226 static void 227 removesock(struct socket *so) 228 { 229 struct sockin_unit *su_iter; 230 231 mutex_enter(&su_mtx); 232 LIST_FOREACH(su_iter, &su_ent, su_entries) { 233 if (su_iter->su_so == so) 234 break; 235 } 236 if (!su_iter) 237 panic("no such socket"); 238 239 LIST_REMOVE(su_iter, su_entries); 240 nsock--; 241 rebuild = true; 242 mutex_exit(&su_mtx); 243 244 rumpuser_close(SO2S(su_iter->su_so)); 245 kmem_free(su_iter, sizeof(*su_iter)); 246 } 247 248 static void 249 sockin_process(struct socket *so) 250 { 251 struct sockaddr_in6 from; 252 struct iovec io; 253 struct msghdr rmsg; 254 struct mbuf *m; 255 size_t n, plen; 256 int error; 257 258 m = m_gethdr(M_WAIT, MT_DATA); 259 if (so->so_proto->pr_type == SOCK_DGRAM) { 260 plen = IP_MAXPACKET; 261 MEXTMALLOC(m, plen, M_DONTWAIT); 262 } else { 263 plen = MCLBYTES; 264 MCLGET(m, M_DONTWAIT); 265 } 266 if ((m->m_flags & M_EXT) == 0) { 267 m_freem(m); 268 return; 269 } 270 271 memset(&rmsg, 0, sizeof(rmsg)); 272 io.iov_base = mtod(m, void *); 273 io.iov_len = plen; 274 rmsg.msg_iov = &io; 275 rmsg.msg_iovlen = 1; 276 rmsg.msg_name = (struct sockaddr *)&from; 277 rmsg.msg_namelen = sizeof(from); 278 279 error = rumpcomp_sockin_recvmsg(SO2S(so), &rmsg, 0, &n); 280 if (error || n == 0) { 281 m_freem(m); 282 283 /* Treat a TCP socket a goner */ 284 if (error != EAGAIN && so->so_proto->pr_type == SOCK_STREAM) { 285 mutex_enter(softnet_lock); 286 soisdisconnected(so); 287 mutex_exit(softnet_lock); 288 removesock(so); 289 } 290 return; 291 } 292 m->m_len = m->m_pkthdr.len = n; 293 294 bpf_mtap_af(&sockin_if, AF_UNSPEC, m); 295 296 mutex_enter(softnet_lock); 297 if (so->so_proto->pr_type == SOCK_DGRAM) { 298 if (!sbappendaddr(&so->so_rcv, rmsg.msg_name, m, NULL)) { 299 m_freem(m); 300 } 301 } else { 302 sbappendstream(&so->so_rcv, m); 303 } 304 305 sorwakeup(so); 306 mutex_exit(softnet_lock); 307 } 308 309 static void 310 sockin_waccept(struct socket *so) 311 { 312 struct socket *nso; 313 struct sockaddr_in6 sin; 314 int news, error, slen; 315 316 slen = sizeof(sin); 317 error = rumpcomp_sockin_accept(SO2S(so), (struct sockaddr *)&sin, 318 &slen, &news); 319 if (error) 320 return; 321 322 mutex_enter(softnet_lock); 323 nso = sonewconn(so, true); 324 if (nso == NULL) 325 goto errout; 326 if (registersock(nso, news) != 0) 327 goto errout; 328 mutex_exit(softnet_lock); 329 return; 330 331 errout: 332 rumpuser_close(news); 333 if (nso) 334 soclose(nso); 335 mutex_exit(softnet_lock); 336 } 337 338 #define POLLTIMEOUT 100 /* check for new entries every 100ms */ 339 340 /* XXX: doesn't handle socket (kernel) locking properly? */ 341 static void 342 sockinworker(void *arg) 343 { 344 struct pollfd *pfds = NULL, *npfds; 345 struct sockin_unit *su_iter; 346 struct socket *so; 347 int cursock = 0, i, rv, error; 348 349 /* 350 * Loop reading requests. Check for new sockets periodically 351 * (could be smarter, but I'm lazy). 352 */ 353 for (;;) { 354 if (rebuild) { 355 npfds = NULL; 356 mutex_enter(&su_mtx); 357 if (nsock) 358 npfds = kmem_alloc(nsock * sizeof(*npfds), 359 KM_NOSLEEP); 360 if (npfds || nsock == 0) { 361 if (pfds) 362 kmem_free(pfds, cursock*sizeof(*pfds)); 363 pfds = npfds; 364 cursock = nsock; 365 rebuild = false; 366 367 i = 0; 368 LIST_FOREACH(su_iter, &su_ent, su_entries) { 369 pfds[i].fd = SO2S(su_iter->su_so); 370 pfds[i].events = POLLIN; 371 pfds[i].revents = 0; 372 i++; 373 } 374 KASSERT(i == nsock); 375 } 376 mutex_exit(&su_mtx); 377 } 378 379 /* find affected sockets & process */ 380 error = rumpcomp_sockin_poll(pfds, cursock, POLLTIMEOUT, &rv); 381 for (i = 0; i < cursock && rv > 0 && error == 0; i++) { 382 if (pfds[i].revents & POLLIN) { 383 mutex_enter(&su_mtx); 384 LIST_FOREACH(su_iter, &su_ent, su_entries) { 385 if (SO2S(su_iter->su_so)==pfds[i].fd) { 386 so = su_iter->su_so; 387 mutex_exit(&su_mtx); 388 if(so->so_options&SO_ACCEPTCONN) 389 sockin_waccept(so); 390 else 391 sockin_process(so); 392 mutex_enter(&su_mtx); 393 break; 394 } 395 } 396 /* if we can't find it, just wing it */ 397 KASSERT(rebuild || su_iter); 398 mutex_exit(&su_mtx); 399 pfds[i].revents = 0; 400 rv--; 401 i = -1; 402 continue; 403 } 404 405 /* something else? ignore */ 406 if (pfds[i].revents) { 407 pfds[i].revents = 0; 408 rv--; 409 } 410 } 411 KASSERT(rv <= 0); 412 } 413 414 } 415 416 static int 417 sockin_do_init(void) 418 { 419 int rv; 420 421 if (rump_threads) { 422 if ((rv = kthread_create(PRI_NONE, 0, NULL, sockinworker, 423 NULL, NULL, "sockwork")) != 0) 424 panic("sockin_init: could not create worker thread\n"); 425 } else { 426 printf("sockin_init: no threads => no worker thread\n"); 427 } 428 mutex_init(&su_mtx, MUTEX_DEFAULT, IPL_NONE); 429 strlcpy(sockin_if.if_xname, "sockin0", sizeof(sockin_if.if_xname)); 430 bpf_attach(&sockin_if, DLT_NULL, 0); 431 return 0; 432 } 433 434 static void 435 sockin_init(void) 436 { 437 static ONCE_DECL(init); 438 439 RUN_ONCE(&init, sockin_do_init); 440 } 441 442 static int 443 sockin_attach(struct socket *so, int proto) 444 { 445 const int type = so->so_proto->pr_type; 446 int error, news, family; 447 448 sosetlock(so); 449 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 450 error = soreserve(so, SOCKIN_SBSIZE, SOCKIN_SBSIZE); 451 if (error) 452 return error; 453 } 454 455 family = so->so_proto->pr_domain->dom_family; 456 KASSERT(family == PF_INET || family == PF_INET6); 457 error = rumpcomp_sockin_socket(family, type, 0, &news); 458 if (error) 459 return error; 460 461 /* For UDP sockets, make sure we can send/recv maximum. */ 462 if (type == SOCK_DGRAM) { 463 int sbsize = SOCKIN_SBSIZE; 464 error = rumpcomp_sockin_setsockopt(news, 465 SOL_SOCKET, SO_SNDBUF, 466 &sbsize, sizeof(sbsize)); 467 sbsize = SOCKIN_SBSIZE; 468 error = rumpcomp_sockin_setsockopt(news, 469 SOL_SOCKET, SO_RCVBUF, 470 &sbsize, sizeof(sbsize)); 471 } 472 473 if ((error = registersock(so, news)) != 0) 474 rumpuser_close(news); 475 476 return error; 477 } 478 479 static void 480 sockin_detach(struct socket *so) 481 { 482 panic("sockin_detach: IMPLEMENT ME\n"); 483 } 484 485 static int 486 sockin_accept(struct socket *so, struct sockaddr *nam) 487 { 488 KASSERT(solocked(so)); 489 490 /* we do all the work in the worker thread */ 491 return 0; 492 } 493 494 static int 495 sockin_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 496 { 497 KASSERT(solocked(so)); 498 KASSERT(nam != NULL); 499 500 return rumpcomp_sockin_bind(SO2S(so), nam, nam->sa_len); 501 } 502 503 static int 504 sockin_listen(struct socket *so, struct lwp *l) 505 { 506 KASSERT(solocked(so)); 507 508 return rumpcomp_sockin_listen(SO2S(so), so->so_qlimit); 509 } 510 511 static int 512 sockin_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 513 { 514 int error = 0; 515 516 KASSERT(solocked(so)); 517 KASSERT(nam != NULL); 518 519 error = rumpcomp_sockin_connect(SO2S(so), nam, nam->sa_len); 520 if (error == 0) 521 soisconnected(so); 522 523 return error; 524 } 525 526 static int 527 sockin_connect2(struct socket *so, struct socket *so2) 528 { 529 KASSERT(solocked(so)); 530 531 panic("sockin_connect2: IMPLEMENT ME, connect2 not supported"); 532 } 533 534 static int 535 sockin_disconnect(struct socket *so) 536 { 537 KASSERT(solocked(so)); 538 539 panic("sockin_disconnect: IMPLEMENT ME, disconnect not supported"); 540 } 541 542 static int 543 sockin_shutdown(struct socket *so) 544 { 545 KASSERT(solocked(so)); 546 547 removesock(so); 548 return 0; 549 } 550 551 static int 552 sockin_abort(struct socket *so) 553 { 554 KASSERT(solocked(so)); 555 556 panic("sockin_abort: IMPLEMENT ME, abort not supported"); 557 } 558 559 static int 560 sockin_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 561 { 562 return ENOTTY; 563 } 564 565 static int 566 sockin_stat(struct socket *so, struct stat *ub) 567 { 568 KASSERT(solocked(so)); 569 570 return 0; 571 } 572 573 static int 574 sockin_peeraddr(struct socket *so, struct sockaddr *nam) 575 { 576 KASSERT(solocked(so)); 577 578 int error = 0; 579 int slen = nam->sa_len; 580 581 error = rumpcomp_sockin_getname(SO2S(so), 582 nam, &slen, RUMPCOMP_SOCKIN_PEERNAME); 583 if (error == 0) 584 nam->sa_len = slen; 585 return error; 586 } 587 588 static int 589 sockin_sockaddr(struct socket *so, struct sockaddr *nam) 590 { 591 KASSERT(solocked(so)); 592 593 int error = 0; 594 int slen = nam->sa_len; 595 596 error = rumpcomp_sockin_getname(SO2S(so), 597 nam, &slen, RUMPCOMP_SOCKIN_SOCKNAME); 598 if (error == 0) 599 nam->sa_len = slen; 600 return error; 601 } 602 603 static int 604 sockin_rcvd(struct socket *so, int flags, struct lwp *l) 605 { 606 KASSERT(solocked(so)); 607 608 panic("sockin_rcvd: IMPLEMENT ME, rcvd not supported"); 609 } 610 611 static int 612 sockin_recvoob(struct socket *so, struct mbuf *m, int flags) 613 { 614 KASSERT(solocked(so)); 615 616 panic("sockin_recvoob: IMPLEMENT ME, recvoob not supported"); 617 } 618 619 static int 620 sockin_send(struct socket *so, struct mbuf *m, struct sockaddr *saddr, 621 struct mbuf *control, struct lwp *l) 622 { 623 struct msghdr mhdr; 624 size_t iov_max, i; 625 struct iovec iov_buf[32], *iov; 626 struct mbuf *m2; 627 size_t tot, n; 628 int error = 0; 629 int s; 630 631 bpf_mtap_af(&sockin_if, AF_UNSPEC, m); 632 633 memset(&mhdr, 0, sizeof(mhdr)); 634 635 iov_max = 0; 636 for (m2 = m; m2 != NULL; m2 = m2->m_next) { 637 iov_max++; 638 } 639 640 if (iov_max <= __arraycount(iov_buf)) { 641 iov = iov_buf; 642 } else { 643 iov = kmem_alloc(sizeof(struct iovec) * iov_max, 644 KM_SLEEP); 645 } 646 647 tot = 0; 648 for (i = 0, m2 = m; m2 != NULL; m2 = m2->m_next, i++) { 649 iov[i].iov_base = m2->m_data; 650 iov[i].iov_len = m2->m_len; 651 tot += m2->m_len; 652 } 653 mhdr.msg_iov = iov; 654 mhdr.msg_iovlen = i; 655 s = SO2S(so); 656 657 if (saddr != NULL) { 658 mhdr.msg_name = saddr; 659 mhdr.msg_namelen = saddr->sa_len; 660 } 661 662 rumpcomp_sockin_sendmsg(s, &mhdr, 0, &n); 663 664 if (iov != iov_buf) 665 kmem_free(iov, sizeof(struct iovec) * iov_max); 666 667 m_freem(m); 668 m_freem(control); 669 670 /* this assumes too many things to list.. buthey, testing */ 671 if (!rump_threads) 672 sockin_process(so); 673 674 return error; 675 } 676 677 static int 678 sockin_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 679 { 680 KASSERT(solocked(so)); 681 682 panic("sockin_sendoob: IMPLEMENT ME, sendoob not supported"); 683 } 684 685 static int 686 sockin_purgeif(struct socket *so, struct ifnet *ifp) 687 { 688 689 panic("sockin_purgeif: IMPLEMENT ME, purgeif not supported"); 690 } 691 692 static int 693 sockin_ctloutput(int op, struct socket *so, struct sockopt *sopt) 694 { 695 696 return rumpcomp_sockin_setsockopt(SO2S(so), sopt->sopt_level, 697 sopt->sopt_name, sopt->sopt_data, sopt->sopt_size); 698 } 699 700 int sockin_unavailable(void); 701 int 702 sockin_unavailable(void) 703 { 704 705 panic("interface not available in with sockin"); 706 } 707 __strong_alias(rtrequest,sockin_unavailable); 708 __strong_alias(ifunit,sockin_unavailable); 709 __strong_alias(ifreq_setaddr,sockin_unavailable); 710