1 /* uipc_socket2.c 4.2 81/11/16 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/proc.h" 8 #include "../h/file.h" 9 #include "../h/inode.h" 10 #include "../h/buf.h" 11 #include "../h/mbuf.h" 12 #include "../h/protocol.h" 13 #include "../h/protosw.h" 14 #include "../h/socket.h" 15 #include "../h/socketvar.h" 16 #include "../h/inaddr.h" 17 #include "../net/inet.h" 18 #include "../net/inet_systm.h" 19 20 /* 21 * Primitive routines for operating on sockets and socket buffers 22 */ 23 24 /* 25 * Procedures to manipulate state flags of socket 26 * and do appropriate wakeups. 27 */ 28 soisconnecting(so) 29 struct socket *so; 30 { 31 32 so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); 33 so->so_state |= SS_ISCONNECTING; 34 wakeup((caddr_t)&so->so_timeo); 35 } 36 37 soisconnected(so) 38 struct socket *so; 39 { 40 41 so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); 42 so->so_state |= SS_ISCONNECTED; 43 wakeup((caddr_t)&so->so_timeo); 44 } 45 46 soisdisconnecting(so) 47 struct socket *so; 48 { 49 50 so->so_state &= ~(SS_ISCONNECTED|SS_ISCONNECTING); 51 so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); 52 wakeup((caddr_t)&so->so_timeo); 53 } 54 55 soisdisconnected(so) 56 struct socket *so; 57 { 58 59 so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); 60 so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE); 61 wakeup((caddr_t)&so->so_timeo); 62 sowwakeup(so); 63 sorwakeup(so); 64 } 65 66 socantsendmore(so) 67 struct socket *so; 68 { 69 70 so->so_state |= SS_CANTSENDMORE; 71 sowwakeup(so); 72 } 73 74 socantrcvmore(so) 75 struct socket *so; 76 { 77 78 so->so_state |= SS_CANTRCVMORE; 79 sorwakeup(so); 80 } 81 82 /* 83 * Select a socket. 84 */ 85 soselect(so, flag) 86 register struct socket *so; 87 int flag; 88 { 89 90 if (flag & FREAD) { 91 if (soreadable(so)) 92 return (1); 93 sbselqueue(&so->so_rcv); 94 } 95 if (flag & FWRITE) { 96 if (sowriteable(so)) 97 return (1); 98 sbselqueue(&so->so_snd); 99 } 100 return (0); 101 } 102 103 /* 104 * Queue a process for a select on a socket buffer. 105 */ 106 sbselqueue(sb) 107 struct sockbuf *sb; 108 { 109 register struct proc *p; 110 111 if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)&selwait) 112 sb->sb_flags |= SB_COLL; 113 else 114 sb->sb_sel = u.u_procp; 115 } 116 117 /* 118 * Wait for data to arrive at/drain from a socket buffer. 119 */ 120 sbwait(sb) 121 struct sockbuf *sb; 122 { 123 124 sb->sb_flags |= SB_WAIT; 125 sleep((caddr_t)&sb->sb_cc, PZERO+1); 126 } 127 128 /* 129 * Wakeup processes waiting on a socket buffer. 130 */ 131 sbwakeup(sb) 132 struct sockbuf *sb; 133 { 134 135 if (sb->sb_sel) { 136 selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL); 137 sb->sb_sel = 0; 138 sb->sb_flags &= ~SB_COLL; 139 } 140 if (sb->sb_flags & SB_WAIT) { 141 sb->sb_flags &= ~SB_WAIT; 142 wakeup((caddr_t)sb->sb_cc); 143 } 144 } 145 146 /* 147 * Allot mbufs to a sockbuf. 148 */ 149 sbreserve(sb, cc) 150 struct sockbuf *sb; 151 { 152 153 if (m_reserve(cc) == 0) 154 return (0); 155 sb->sb_cc = cc; 156 sb->sb_mbcnt = (cc*2)/MSIZE; 157 return (1); 158 } 159 160 /* 161 * Free mbufs held by a socket, and reserved mbuf space. 162 */ 163 sbrelease(sb) 164 struct sockbuf *sb; 165 { 166 167 sbflush(sb); 168 m_release(sb->sb_cc); 169 sb->sb_cc = sb->sb_mbcnt = 0; 170 } 171 172 /* 173 * Routines to add (at the end) and remove (from the beginning) 174 * data from a mbuf queue. 175 */ 176 177 /* 178 * Append mbuf queue m to sockbuf sb. 179 */ 180 sbappend(sb, m) 181 register struct mbuf *m; 182 register struct sockbuf *sb; 183 { 184 register struct mbuf **np, *n; 185 186 np = &sb->sb_mb; 187 while ((n = *np) && n->m_next) 188 np = &n->m_next; 189 while (m) { 190 if (n && n->m_off <= MMAXOFF && m->m_off <= MMAXOFF && 191 (int)n->m_act == 0 && (int)m->m_act == 0 && 192 (n->m_off + n->m_len + m->m_off) <= MMAXOFF) { 193 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), 194 (unsigned)m->m_len); 195 n->m_len += m->m_len; 196 sb->sb_cc += m->m_len; 197 m = m_free(m); 198 continue; 199 } 200 sballoc(sb, m); 201 *np = m; 202 n = m; 203 np = &n->m_next; 204 m = m->m_next; 205 } 206 } 207 208 /* 209 * Free all mbufs on a sockbuf mbuf chain. 210 * Check that resource allocations return to 0. 211 */ 212 sbflush(sb) 213 struct sockbuf *sb; 214 { 215 216 if (sb->sb_flags & SB_LOCK) 217 panic("sbflush"); 218 sbdrop(sb, sb->sb_cc); 219 if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb) 220 panic("sbflush 2"); 221 } 222 223 /* 224 * Drop data from (the front of) a sockbuf chain. 225 */ 226 sbdrop(sb, len) 227 register struct sockbuf *sb; 228 register int len; 229 { 230 register struct mbuf *m = sb->sb_mb, *mn; 231 232 while (len > 0) { 233 if (m == 0) 234 panic("sbdrop"); 235 if (m->m_len <= len) { 236 len -= m->m_len; 237 sbfree(sb, m); 238 MFREE(m, mn); 239 m = mn; 240 } else { 241 m->m_len -= len; 242 m->m_off += len; 243 sb->sb_cc -= len; 244 break; 245 } 246 } 247 sb->sb_mb = m; 248 } 249 250 struct mbuf * 251 sbcopy(sb, off, len) 252 struct sockbuf *sb; 253 int off; 254 register int len; 255 { 256 register struct mbuf *m, *n, **np; 257 struct mbuf *top, *p; 258 COUNT(SB_COPY); 259 260 if (len == 0) 261 return (0); 262 if (off < 0 || len < 0) 263 panic("sb_copy"); 264 m = sb->sb_mb; 265 while (off > 0) { 266 if (m == 0) 267 panic("sb_copy"); 268 if (off < m->m_len) 269 break; 270 off -= m->m_len; 271 m = m->m_next; 272 } 273 np = ⊤ 274 top = 0; 275 while (len > 0) { 276 MGET(n, 1); 277 *np = n; 278 if (n == 0) 279 goto nospace; 280 if (m == 0) 281 panic("sb_copy"); 282 n->m_len = MIN(len, m->m_len - off); 283 if (m->m_off > MMAXOFF) { 284 p = mtod(m, struct mbuf *); 285 n->m_off = ((int)p - (int)n) + off; 286 mprefcnt[mtopf(p)]++; 287 } else { 288 n->m_off = MMINOFF; 289 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 290 (unsigned)n->m_len); 291 } 292 len -= n->m_len; 293 off = 0; 294 m = m->m_next; 295 np = &n->m_next; 296 } 297 return (top); 298 nospace: 299 printf("snd_copy: no space\n"); 300 m_freem(top); 301 return (0); 302 } 303