1*16695Smckusick /* uipc_usrreq.c 6.5 84/07/08 */ 28925Sroot 38925Sroot #include "../h/param.h" 48925Sroot #include "../h/dir.h" 58925Sroot #include "../h/user.h" 68925Sroot #include "../h/mbuf.h" 78925Sroot #include "../h/protosw.h" 88925Sroot #include "../h/socket.h" 98925Sroot #include "../h/socketvar.h" 108925Sroot #include "../h/unpcb.h" 118925Sroot #include "../h/un.h" 128925Sroot #include "../h/inode.h" 1312760Ssam #include "../h/file.h" 148925Sroot 158925Sroot /* 168925Sroot * Unix communications domain. 1712760Ssam * 1812760Ssam * TODO: 1912760Ssam * SEQPACKET, RDM 2013119Ssam * rethink name space problems 2112760Ssam * need a proper out-of-band 228925Sroot */ 2313119Ssam struct sockaddr sun_noname = { AF_UNIX }; 248925Sroot 258925Sroot /*ARGSUSED*/ 2612760Ssam uipc_usrreq(so, req, m, nam, rights) 278925Sroot struct socket *so; 288925Sroot int req; 2912760Ssam struct mbuf *m, *nam, *rights; 308925Sroot { 318925Sroot struct unpcb *unp = sotounpcb(so); 328925Sroot register struct socket *so2; 338925Sroot int error = 0; 348925Sroot 3512760Ssam if (req != PRU_SEND && rights && rights->m_len) { 3612760Ssam error = EOPNOTSUPP; 3712760Ssam goto release; 3812760Ssam } 3912760Ssam if (unp == 0 && req != PRU_ATTACH) { 4012760Ssam error = EINVAL; 4112760Ssam goto release; 4212760Ssam } 438925Sroot switch (req) { 448925Sroot 458925Sroot case PRU_ATTACH: 468925Sroot if (unp) { 479169Ssam error = EISCONN; 488925Sroot break; 498925Sroot } 509028Sroot error = unp_attach(so); 518925Sroot break; 528925Sroot 538925Sroot case PRU_DETACH: 548925Sroot unp_detach(unp); 558925Sroot break; 568925Sroot 579169Ssam case PRU_BIND: 589169Ssam error = unp_bind(unp, nam); 599169Ssam break; 609169Ssam 619169Ssam case PRU_LISTEN: 629169Ssam if (unp->unp_inode == 0) 639169Ssam error = EINVAL; 649169Ssam break; 659169Ssam 668925Sroot case PRU_CONNECT: 679028Sroot error = unp_connect(so, nam); 688925Sroot break; 698925Sroot 7012760Ssam case PRU_CONNECT2: 7113115Ssam error = unp_connect2(so, (struct mbuf *)0, 7213115Ssam (struct socket *)nam); 7312760Ssam break; 7412760Ssam 758925Sroot case PRU_DISCONNECT: 768925Sroot unp_disconnect(unp); 778925Sroot break; 788925Sroot 799169Ssam case PRU_ACCEPT: 809169Ssam nam->m_len = unp->unp_remaddr->m_len; 819169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 829169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 838925Sroot break; 848925Sroot 858925Sroot case PRU_SHUTDOWN: 868925Sroot socantsendmore(so); 878925Sroot unp_usrclosed(unp); 888925Sroot break; 898925Sroot 908925Sroot case PRU_RCVD: 918925Sroot switch (so->so_type) { 928925Sroot 938925Sroot case SOCK_DGRAM: 948925Sroot panic("uipc 1"); 9510139Ssam /*NOTREACHED*/ 968925Sroot 9710139Ssam case SOCK_STREAM: 988925Sroot #define rcv (&so->so_rcv) 998925Sroot #define snd (&so2->so_snd) 1008925Sroot if (unp->unp_conn == 0) 1018925Sroot break; 1028925Sroot so2 = unp->unp_conn->unp_socket; 1038925Sroot /* 1048925Sroot * Transfer resources back to send port 1058925Sroot * and wakeup any waiting to write. 1068925Sroot */ 1078925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 1088925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1098925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 1108925Sroot rcv->sb_hiwat = rcv->sb_cc; 1118925Sroot sbwakeup(snd); 1128925Sroot #undef snd 1138925Sroot #undef rcv 1148925Sroot break; 1158925Sroot 1168925Sroot default: 1178925Sroot panic("uipc 2"); 1188925Sroot } 1198925Sroot break; 1208925Sroot 1218925Sroot case PRU_SEND: 1228925Sroot switch (so->so_type) { 1238925Sroot 1248925Sroot case SOCK_DGRAM: 1259028Sroot if (nam) { 1268925Sroot if (unp->unp_conn) { 1278925Sroot error = EISCONN; 1288925Sroot break; 1298925Sroot } 1309028Sroot error = unp_connect(so, nam); 1318925Sroot if (error) 1328925Sroot break; 1338925Sroot } else { 1348925Sroot if (unp->unp_conn == 0) { 1358925Sroot error = ENOTCONN; 1368925Sroot break; 1378925Sroot } 1388925Sroot } 1398925Sroot so2 = unp->unp_conn->unp_socket; 1409169Ssam /* BEGIN XXX */ 14112760Ssam if (rights) { 14212760Ssam error = unp_internalize(rights); 14312760Ssam if (error) 14412760Ssam break; 14512760Ssam } 14612760Ssam if (sbspace(&so2->so_rcv) > 0) { 14713119Ssam /* 14813119Ssam * There's no record of source socket's 14913119Ssam * name, so send null name for the moment. 15013119Ssam */ 1519169Ssam (void) sbappendaddr(&so2->so_rcv, 15213119Ssam &sun_noname, m, rights); 15312760Ssam sbwakeup(&so2->so_rcv); 15412760Ssam m = 0; 15512760Ssam } 1569169Ssam /* END XXX */ 1579028Sroot if (nam) 1589169Ssam unp_disconnect(unp); 1598925Sroot break; 1608925Sroot 1618925Sroot case SOCK_STREAM: 1628925Sroot #define rcv (&so2->so_rcv) 1638925Sroot #define snd (&so->so_snd) 16412760Ssam if (rights && rights->m_len) { 16512760Ssam error = EOPNOTSUPP; 16612760Ssam break; 16712760Ssam } 1688925Sroot if (unp->unp_conn == 0) 1698925Sroot panic("uipc 3"); 1708925Sroot so2 = unp->unp_conn->unp_socket; 1718925Sroot /* 1728925Sroot * Send to paired receive port, and then 1738925Sroot * give it enough resources to hold what it already has. 1748925Sroot * Wake up readers. 1758925Sroot */ 1768925Sroot sbappend(rcv, m); 1778925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1788925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1798925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1808925Sroot rcv->sb_hiwat = rcv->sb_cc; 1818925Sroot sbwakeup(rcv); 1828925Sroot #undef snd 1838925Sroot #undef rcv 1848925Sroot break; 1858925Sroot 1868925Sroot default: 1878925Sroot panic("uipc 4"); 1888925Sroot } 18912760Ssam m = 0; 1908925Sroot break; 1918925Sroot 1928925Sroot case PRU_ABORT: 1938925Sroot unp_drop(unp, ECONNABORTED); 1948925Sroot break; 1958925Sroot 1968925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 1978925Sroot case PRU_CONTROL: 19813050Ssam return (EOPNOTSUPP); 1998925Sroot 2008925Sroot case PRU_SENSE: 2018925Sroot error = EOPNOTSUPP; 2028925Sroot break; 2038925Sroot /* END UNIMPLEMENTED HOOKS */ 2048925Sroot 2058925Sroot case PRU_RCVOOB: 2068925Sroot break; 2078925Sroot 2088925Sroot case PRU_SENDOOB: 2098925Sroot break; 2108925Sroot 2118925Sroot case PRU_SOCKADDR: 2128925Sroot break; 2138925Sroot 21414121Ssam case PRU_PEERADDR: 21514121Ssam break; 21614121Ssam 2178925Sroot case PRU_SLOWTIMO: 2188925Sroot break; 2198925Sroot 2208925Sroot default: 2218925Sroot panic("piusrreq"); 2228925Sroot } 22312760Ssam release: 22412760Ssam if (m) 22512760Ssam m_freem(m); 22611709Ssam return (error); 2278925Sroot } 2288925Sroot 22912760Ssam /* SHOULD BE PIPSIZ and 0 */ 2308925Sroot int unp_sendspace = 1024*2; 23116054Skarels int unp_recvspace = 1024*2 + sizeof(struct sockaddr); 2328925Sroot 2339169Ssam unp_attach(so) 2348925Sroot struct socket *so; 2358925Sroot { 2369169Ssam register struct mbuf *m; 2378925Sroot register struct unpcb *unp; 2388925Sroot int error; 2398925Sroot 2408925Sroot error = soreserve(so, unp_sendspace, unp_recvspace); 2418925Sroot if (error) 24210139Ssam return (error); 2439637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 24410139Ssam if (m == NULL) 24510139Ssam return (ENOBUFS); 2468925Sroot unp = mtod(m, struct unpcb *); 2478925Sroot so->so_pcb = (caddr_t)unp; 2488925Sroot unp->unp_socket = so; 2498925Sroot return (0); 2508925Sroot } 2518925Sroot 2528925Sroot unp_detach(unp) 2539169Ssam register struct unpcb *unp; 2548925Sroot { 2558925Sroot 2568925Sroot if (unp->unp_inode) { 2578925Sroot irele(unp->unp_inode); 2588925Sroot unp->unp_inode = 0; 2598925Sroot } 2608925Sroot if (unp->unp_conn) 2618925Sroot unp_disconnect(unp); 2628925Sroot while (unp->unp_refs) 2638925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2648925Sroot soisdisconnected(unp->unp_socket); 2658925Sroot unp->unp_socket->so_pcb = 0; 2669169Ssam m_freem(unp->unp_remaddr); 2679169Ssam (void) m_free(dtom(unp)); 2688925Sroot } 2698925Sroot 2709169Ssam unp_bind(unp, nam) 2718925Sroot struct unpcb *unp; 2729169Ssam struct mbuf *nam; 2738925Sroot { 2749169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2758925Sroot register struct inode *ip; 276*16695Smckusick register struct nameidata *ndp = &u.u_nd; 2778925Sroot int error; 2788925Sroot 279*16695Smckusick ndp->ni_dirp = soun->sun_path; 28012760Ssam if (nam->m_len == MLEN) 28112760Ssam return (EINVAL); 28212760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 28312760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 284*16695Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 285*16695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 286*16695Smckusick ip = namei(ndp); 2878925Sroot if (ip) { 2888925Sroot iput(ip); 28910139Ssam return (EADDRINUSE); 2908925Sroot } 29111828Ssam if (error = u.u_error) { 29211828Ssam u.u_error = 0; /* XXX */ 29311828Ssam return (error); 29411828Ssam } 295*16695Smckusick ip = maknode(IFSOCK | 0777, ndp); 2968925Sroot if (ip == NULL) { 2978925Sroot error = u.u_error; /* XXX */ 2988925Sroot u.u_error = 0; /* XXX */ 2998925Sroot return (error); 3008925Sroot } 3018925Sroot ip->i_socket = unp->unp_socket; 3028925Sroot unp->unp_inode = ip; 3038925Sroot iunlock(ip); /* but keep reference */ 3048925Sroot return (0); 3058925Sroot } 3068925Sroot 3079169Ssam unp_connect(so, nam) 3088925Sroot struct socket *so; 3099169Ssam struct mbuf *nam; 3108925Sroot { 3119169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3129169Ssam register struct inode *ip; 3138925Sroot int error; 31412760Ssam register struct socket *so2; 315*16695Smckusick register struct nameidata *ndp = &u.u_nd; 3168925Sroot 317*16695Smckusick ndp->ni_dirp = soun->sun_path; 31812760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 31912760Ssam return (EMSGSIZE); 32012760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 321*16695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 322*16695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 323*16695Smckusick ip = namei(ndp); 3248925Sroot if (ip == 0) { 3258925Sroot error = u.u_error; 3268925Sroot u.u_error = 0; 32710139Ssam return (error); /* XXX */ 3288925Sroot } 3298925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3308925Sroot error = ENOTSOCK; 3318925Sroot goto bad; 3328925Sroot } 3338925Sroot so2 = ip->i_socket; 3348925Sroot if (so2 == 0) { 3358925Sroot error = ECONNREFUSED; 3368925Sroot goto bad; 3378925Sroot } 33813115Ssam if (so->so_type != so2->so_type) { 33913115Ssam error = EPROTOTYPE; 34013115Ssam goto bad; 34113115Ssam } 34213115Ssam if (so->so_proto->pr_flags & PR_CONNREQUIRED && 34313115Ssam ((so2->so_options&SO_ACCEPTCONN) == 0 || 34413115Ssam (so2 = sonewconn(so2)) == 0)) { 34513115Ssam error = ECONNREFUSED; 34613115Ssam goto bad; 34713115Ssam } 34812760Ssam error = unp_connect2(so, nam, so2); 34912760Ssam bad: 35012760Ssam iput(ip); 35112760Ssam return (error); 35212760Ssam } 35312760Ssam 35412760Ssam unp_connect2(so, sonam, so2) 35512760Ssam register struct socket *so; 35612760Ssam struct mbuf *sonam; 35712760Ssam register struct socket *so2; 35812760Ssam { 35912760Ssam register struct unpcb *unp = sotounpcb(so); 36012760Ssam register struct unpcb *unp2; 36112760Ssam 36212760Ssam if (so2->so_type != so->so_type) 36312760Ssam return (EPROTOTYPE); 36414049Ssam unp2 = sotounpcb(so2); 36514049Ssam unp->unp_conn = unp2; 3668925Sroot switch (so->so_type) { 3678925Sroot 3688925Sroot case SOCK_DGRAM: 3698925Sroot unp->unp_nextref = unp2->unp_refs; 3708925Sroot unp2->unp_refs = unp; 3718925Sroot break; 3728925Sroot 3738925Sroot case SOCK_STREAM: 3749169Ssam unp2->unp_conn = unp; 37512760Ssam if (sonam) 37612760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 37714049Ssam soisconnected(so2); 37814049Ssam soisconnected(so); 3798925Sroot break; 3808925Sroot 3818925Sroot default: 38212760Ssam panic("unp_connect2"); 3838925Sroot } 3848925Sroot return (0); 3858925Sroot } 3869169Ssam 3879169Ssam unp_disconnect(unp) 3889169Ssam struct unpcb *unp; 3899169Ssam { 3909169Ssam register struct unpcb *unp2 = unp->unp_conn; 3919169Ssam 3929169Ssam if (unp2 == 0) 3939169Ssam return; 3949169Ssam unp->unp_conn = 0; 3959169Ssam switch (unp->unp_socket->so_type) { 3969169Ssam 3979169Ssam case SOCK_DGRAM: 3989169Ssam if (unp2->unp_refs == unp) 3999169Ssam unp2->unp_refs = unp->unp_nextref; 4009169Ssam else { 4019169Ssam unp2 = unp2->unp_refs; 4029169Ssam for (;;) { 4039169Ssam if (unp2 == 0) 4049169Ssam panic("unp_disconnect"); 4059169Ssam if (unp2->unp_nextref == unp) 4069169Ssam break; 4079169Ssam unp2 = unp2->unp_nextref; 4089169Ssam } 4099169Ssam unp2->unp_nextref = unp->unp_nextref; 4109169Ssam } 4119169Ssam unp->unp_nextref = 0; 4129169Ssam break; 4139169Ssam 4149169Ssam case SOCK_STREAM: 41514049Ssam soisdisconnected(unp->unp_socket); 4169169Ssam unp2->unp_conn = 0; 4179169Ssam soisdisconnected(unp2->unp_socket); 4189169Ssam break; 4199169Ssam } 4209169Ssam } 4219169Ssam 42212760Ssam #ifdef notdef 4239169Ssam unp_abort(unp) 4249169Ssam struct unpcb *unp; 4259169Ssam { 4269169Ssam 4279169Ssam unp_detach(unp); 4289169Ssam } 42912760Ssam #endif 4309169Ssam 4319169Ssam /*ARGSUSED*/ 4329169Ssam unp_usrclosed(unp) 4339169Ssam struct unpcb *unp; 4349169Ssam { 4359169Ssam 4369169Ssam } 4379169Ssam 4389169Ssam unp_drop(unp, errno) 4399169Ssam struct unpcb *unp; 4409169Ssam int errno; 4419169Ssam { 44216054Skarels struct socket *so = unp->unp_socket; 4439169Ssam 44416054Skarels so->so_error = errno; 4459169Ssam unp_disconnect(unp); 44616054Skarels if (so->so_head) { 44716054Skarels so->so_pcb = (caddr_t) 0; 44816431Skarels m_freem(unp->unp_remaddr); 44916054Skarels (void) m_free(dtom(unp)); 45016054Skarels sofree(so); 45116054Skarels } 4529169Ssam } 4539169Ssam 45412760Ssam #ifdef notdef 4559169Ssam unp_drain() 4569169Ssam { 4579169Ssam 4589169Ssam } 45912760Ssam #endif 46012760Ssam 46112760Ssam unp_externalize(rights) 46212760Ssam struct mbuf *rights; 46312760Ssam { 46412760Ssam int newfds = rights->m_len / sizeof (int); 46512760Ssam register int i; 46612760Ssam register struct file **rp = mtod(rights, struct file **); 46712760Ssam register struct file *fp; 46812760Ssam int f; 46912760Ssam 47012760Ssam if (newfds > ufavail()) { 47112760Ssam for (i = 0; i < newfds; i++) { 47212760Ssam fp = *rp; 47312760Ssam unp_discard(fp); 47412760Ssam *rp++ = 0; 47512760Ssam } 47612760Ssam return (EMSGSIZE); 47712760Ssam } 47812760Ssam for (i = 0; i < newfds; i++) { 47912760Ssam f = ufalloc(0); 48012760Ssam if (f < 0) 48112760Ssam panic("unp_externalize"); 48212760Ssam fp = *rp; 48312760Ssam u.u_ofile[f] = fp; 48412760Ssam fp->f_msgcount--; 48514927Smckusick *(int *)rp++ = f; 48612760Ssam } 48712760Ssam return (0); 48812760Ssam } 48912760Ssam 49012760Ssam unp_internalize(rights) 49112760Ssam struct mbuf *rights; 49212760Ssam { 49312760Ssam register struct file **rp; 49412760Ssam int oldfds = rights->m_len / sizeof (int); 49512760Ssam register int i; 49612760Ssam register struct file *fp; 49712760Ssam 49812760Ssam rp = mtod(rights, struct file **); 49913084Ssam for (i = 0; i < oldfds; i++) 50012760Ssam if (getf(*(int *)rp++) == 0) 50112760Ssam return (EBADF); 50212760Ssam rp = mtod(rights, struct file **); 50313084Ssam for (i = 0; i < oldfds; i++) { 50412760Ssam fp = getf(*(int *)rp); 50512760Ssam *rp++ = fp; 50612760Ssam fp->f_count++; 50712760Ssam fp->f_msgcount++; 50812760Ssam } 50912760Ssam return (0); 51012760Ssam } 51112760Ssam 51212760Ssam int unp_defer, unp_gcing; 51312760Ssam int unp_mark(); 51412760Ssam 51512760Ssam unp_gc() 51612760Ssam { 51712760Ssam register struct file *fp; 51812760Ssam register struct socket *so; 51912760Ssam 52012760Ssam if (unp_gcing) 52112760Ssam return; 52212760Ssam unp_gcing = 1; 52312760Ssam restart: 52412760Ssam unp_defer = 0; 52512760Ssam for (fp = file; fp < fileNFILE; fp++) 52612760Ssam fp->f_flag &= ~(FMARK|FDEFER); 52712760Ssam do { 52812760Ssam for (fp = file; fp < fileNFILE; fp++) { 52912760Ssam if (fp->f_count == 0) 53012760Ssam continue; 53112760Ssam if (fp->f_flag & FDEFER) { 53212760Ssam fp->f_flag &= ~FDEFER; 53312760Ssam unp_defer--; 53412760Ssam } else { 53512760Ssam if (fp->f_flag & FMARK) 53612760Ssam continue; 53712760Ssam if (fp->f_count == fp->f_msgcount) 53812760Ssam continue; 53912760Ssam fp->f_flag |= FMARK; 54012760Ssam } 54112760Ssam if (fp->f_type != DTYPE_SOCKET) 54212760Ssam continue; 54312760Ssam so = (struct socket *)fp->f_data; 54412760Ssam if (so->so_proto->pr_family != AF_UNIX || 54512760Ssam (so->so_proto->pr_flags&PR_ADDR) == 0) 54612760Ssam continue; 54712760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 54812760Ssam sbwait(&so->so_rcv); 54912760Ssam goto restart; 55012760Ssam } 55112760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 55212760Ssam } 55312760Ssam } while (unp_defer); 55412760Ssam for (fp = file; fp < fileNFILE; fp++) { 55512760Ssam if (fp->f_count == 0) 55612760Ssam continue; 55712760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 55812760Ssam if (fp->f_type != DTYPE_SOCKET) 55912760Ssam panic("unp_gc"); 56012760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 56112760Ssam } 56212760Ssam } 56312760Ssam unp_gcing = 0; 56412760Ssam } 56512760Ssam 56612760Ssam unp_scan(m, op) 56712760Ssam register struct mbuf *m; 56812760Ssam int (*op)(); 56912760Ssam { 57012760Ssam register struct file **rp; 57112760Ssam register int i; 57212760Ssam int qfds; 57312760Ssam 57412760Ssam while (m) { 57512760Ssam m = m->m_next; 57612760Ssam if (m == 0) 57712760Ssam goto bad; 57812760Ssam if (m->m_len) { 57912760Ssam qfds = m->m_len / sizeof (struct file *); 58012760Ssam rp = mtod(m, struct file **); 58112760Ssam for (i = 0; i < qfds; i++) 58212760Ssam (*op)(*rp++); 58312760Ssam } 58412760Ssam do { 58512760Ssam m = m->m_next; 58612760Ssam if (m == 0) 58712760Ssam goto bad; 58812760Ssam } while (m->m_act == 0); 58912760Ssam m = m->m_next; 59012760Ssam } 59112760Ssam return; 59212760Ssam bad: 59312760Ssam panic("unp_gcscan"); 59412760Ssam } 59512760Ssam 59612760Ssam unp_mark(fp) 59712760Ssam struct file *fp; 59812760Ssam { 59912760Ssam 60012760Ssam if (fp->f_flag & FMARK) 60112760Ssam return; 60212760Ssam unp_defer++; 60312760Ssam fp->f_flag |= (FMARK|FDEFER); 60412760Ssam } 60512760Ssam 60612760Ssam unp_discard(fp) 60712760Ssam struct file *fp; 60812760Ssam { 60912760Ssam 61012760Ssam fp->f_msgcount--; 61113084Ssam closef(fp); 61212760Ssam } 613