fix to way send looks at space: sleep when none!
[unix-history] / usr / src / sys / kern / uipc_socket.c
... / ...
CommitLineData
1/* uipc_socket.c 4.12 81/11/22 */
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/protosw.h"
13#include "../h/socket.h"
14#include "../h/socketvar.h"
15#include "../h/stat.h"
16#include "../net/inet.h"
17#include "../net/inet_systm.h"
18
19/*
20 * Socket support routines.
21 *
22 * DEAL WITH INTERRUPT NOTIFICATION.
23 */
24
25/*
26 * Create a socket.
27 */
28socreate(aso, type, asp, asa, options)
29 struct socket **aso;
30 int type;
31 struct sockproto *asp;
32 struct sockaddr *asa;
33 int options;
34{
35 register struct protosw *prp;
36 register struct socket *so;
37 struct mbuf *m;
38 int pf, proto, error;
39COUNT(SOCREATE);
40
41 /*
42 * Use process standard protocol/protocol family if none
43 * specified by address argument.
44 */
45 if (asp == 0) {
46 pf = PF_INET; /* should be u.u_protof */
47 proto = 0;
48 } else {
49 pf = asp->sp_family;
50 proto = asp->sp_protocol;
51 }
52
53 /*
54 * If protocol specified, look for it, otherwise
55 * for a protocol of the correct type in the right family.
56 */
57 if (proto)
58 prp = pffindproto(pf, proto);
59 else
60 prp = pffindtype(pf, type);
61 if (prp == 0)
62 return (EPROTONOSUPPORT);
63
64 /*
65 * Get a socket structure.
66 */
67 m = m_getclr(M_WAIT);
68 if (m == 0)
69 return (ENOBUFS);
70 so = mtod(m, struct socket *);
71 so->so_options = options;
72
73 /*
74 * Attach protocol to socket, initializing
75 * and reserving resources.
76 */
77 so->so_proto = prp;
78 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
79 if (error) {
80 (void) m_free(dtom(so));
81 return (error);
82 }
83 *aso = so;
84 return (0);
85}
86
87sofree(so)
88 struct socket *so;
89{
90
91COUNT(SOFREE);
92 if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
93 return;
94 sbrelease(&so->so_snd);
95 sbrelease(&so->so_rcv);
96 (void) m_free(dtom(so));
97}
98
99/*
100 * Close a socket on last file table reference removal.
101 * Initiate disconnect if connected.
102 * Free socket when disconnect complete.
103 */
104soclose(so)
105 register struct socket *so;
106{
107 int s = splnet(); /* conservative */
108
109COUNT(SOCLOSE);
110 if (so->so_pcb == 0)
111 goto discard;
112 if (so->so_state & SS_ISCONNECTED) {
113 if ((so->so_state & SS_ISDISCONNECTING) == 0) {
114 u.u_error = sodisconnect(so, (struct sockaddr *)0);
115 if (u.u_error) {
116 splx(s);
117 return;
118 }
119 }
120 if ((so->so_state & SS_ISDISCONNECTING) &&
121 (so->so_options & SO_NBIO)) {
122 u.u_error = EINPROGRESS;
123 splx(s);
124 return;
125 }
126 while (so->so_state & SS_ISCONNECTED)
127 sleep((caddr_t)&so->so_timeo, PZERO+1);
128 }
129 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
130discard:
131 so->so_state |= SS_USERGONE;
132 sofree(so);
133 splx(s);
134}
135
136sosplice(pso, so)
137 struct socket *pso, *so;
138{
139
140COUNT(SOSPLICE);
141 if (pso->so_proto->pr_family != PF_LOCAL) {
142 struct socket *tso;
143 tso = pso; pso = so; so = tso;
144 }
145 if (pso->so_proto->pr_family != PF_LOCAL)
146 return (EOPNOTSUPP);
147 /* check types and buffer space */
148 /* merge buffers */
149 return (0);
150}
151
152/*ARGSUSED*/
153sostat(so, sb)
154 struct socket *so;
155 struct stat *sb;
156{
157
158COUNT(SOSTAT);
159 return (EOPNOTSUPP);
160}
161
162/*
163 * Accept connection on a socket.
164 */
165soaccept(so, asa)
166 struct socket *so;
167 struct sockaddr *asa;
168{
169 int s = splnet();
170 int error;
171
172COUNT(SOACCEPT);
173 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
174 error = EISCONN;
175 goto bad;
176 }
177 if ((so->so_options & SO_ACCEPTCONN) == 0) {
178 error = EINVAL; /* XXX */
179 goto bad;
180 }
181 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
182bad:
183 splx(s);
184 return (error);
185}
186
187/*
188 * Connect socket to a specified address.
189 * If already connected or connecting, then avoid
190 * the protocol entry, to keep its job simpler.
191 */
192soconnect(so, asa)
193 struct socket *so;
194 struct sockaddr *asa;
195{
196 int s = splnet();
197 int error;
198
199COUNT(SOCONNECT);
200 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
201 error = EISCONN;
202 goto bad;
203 }
204 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
205bad:
206 splx(s);
207 return (error);
208}
209
210/*
211 * Disconnect from a socket.
212 * Address parameter is from system call for later multicast
213 * protocols. Check to make sure that connected and no disconnect
214 * in progress (for protocol's sake), and then invoke protocol.
215 */
216sodisconnect(so, asa)
217 struct socket *so;
218 struct sockaddr *asa;
219{
220 int s = splnet();
221 int error;
222
223COUNT(SODISCONNECT);
224 if ((so->so_state & SS_ISCONNECTED) == 0) {
225 error = ENOTCONN;
226 goto bad;
227 }
228 if (so->so_state & SS_ISDISCONNECTING) {
229 error = EALREADY;
230 goto bad;
231 }
232 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
233bad:
234 splx(s);
235 return (error);
236}
237
238/*
239 * Send on a socket.
240 * If send must go all at once and message is larger than
241 * send buffering, then hard error.
242 * Lock against other senders.
243 * If must go all at once and not enough room now, then
244 * inform user that this would block and do nothing.
245 */
246sosend(so, asa)
247 register struct socket *so;
248 struct sockaddr *asa;
249{
250 struct mbuf *top = 0;
251 register struct mbuf *m, **mp = ⊤
252 register u_int len;
253 int error = 0, space, s;
254
255COUNT(SOSEND);
256 if (so->so_state & SS_CANTSENDMORE)
257 return (EPIPE);
258 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
259 return (EMSGSIZE);
260 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
261 return (EWOULDBLOCK);
262 sblock(&so->so_snd);
263#define snderr(errno) { error = errno; splx(s); goto release; }
264
265 s = splnet();
266again:
267 if ((so->so_state & SS_ISCONNECTED) == 0) {
268 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
269 snderr(ENOTCONN);
270 if (asa == 0)
271 snderr(EDESTADDRREQ);
272 }
273 if (so->so_error)
274 snderr(so->so_error);
275 if (top) {
276 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
277 if (error) {
278 splx(s);
279 goto release;
280 }
281 top = 0;
282 mp = ⊤
283 }
284 if (u.u_count == 0) {
285 splx(s);
286 goto release;
287 }
288 space = sbspace(&so->so_snd);
289 if (space == 0 || sosendallatonce(so) && space < u.u_count) {
290 if (so->so_options & SO_NBIO)
291 snderr(EWOULDBLOCK);
292 sbunlock(&so->so_snd);
293 sbwait(&so->so_snd);
294 splx(s);
295 goto again;
296 }
297 splx(s);
298 while (u.u_count && space > 0) {
299 MGET(m, 1);
300 if (m == NULL) {
301 error = ENOBUFS;
302 m_freem(top);
303 goto release;
304 }
305 if (u.u_count >= PGSIZE && space >= NMBPG) {
306 register struct mbuf *p;
307 MPGET(p, 1);
308 if (p == 0)
309 goto nopages;
310 m->m_off = (int)p - (int)m;
311 len = PGSIZE;
312 } else {
313nopages:
314 m->m_off = MMINOFF;
315 len = MIN(MLEN, u.u_count);
316 }
317 iomove(mtod(m, caddr_t), len, B_WRITE);
318 m->m_len = len;
319 *mp = m;
320 mp = &m->m_next;
321 space = sbspace(&so->so_snd);
322 }
323 s = splnet();
324 goto again;
325
326release:
327 sbunlock(&so->so_snd);
328 return (error);
329}
330
331soreceive(so, asa)
332 register struct socket *so;
333 struct sockaddr *asa;
334{
335 register struct mbuf *m, *n;
336 u_int len;
337 int eor, s, error = 0;
338
339COUNT(SORECEIVE);
340restart:
341 sblock(&so->so_rcv);
342 s = splnet();
343
344#define rcverr(errno) { error = errno; splx(s); goto release; }
345 if (so->so_rcv.sb_cc == 0) {
346 if (so->so_state & SS_CANTRCVMORE) {
347 splx(s);
348 goto release;
349 }
350 if ((so->so_state & SS_ISCONNECTED) == 0 &&
351 (so->so_proto->pr_flags & PR_CONNREQUIRED))
352 rcverr(ENOTCONN);
353 if (so->so_options & SO_NBIO)
354 rcverr (EWOULDBLOCK);
355 sbunlock(&so->so_rcv);
356 sbwait(&so->so_rcv);
357 splx(s);
358 goto restart;
359 }
360 m = so->so_rcv.sb_mb;
361 if (m == 0)
362 panic("receive");
363 if ((so->so_proto->pr_flags & PR_ADDR)) {
364 if (asa) {
365 so->so_rcv.sb_cc -= m->m_len;
366 len = MIN(m->m_len, sizeof (struct sockaddr));
367 bcopy(mtod(m, caddr_t), (caddr_t)asa, len);
368 } else
369 bzero((caddr_t)asa, sizeof (*asa));
370 m = m_free(m);
371 if (m == 0)
372 panic("receive 2");
373 so->so_rcv.sb_mb = m;
374 }
375 eor = 0;
376 do {
377 len = MIN(m->m_len, u.u_count);
378 if (len == m->m_len) {
379 eor = (int)m->m_act;
380 sbfree(&so->so_rcv, m);
381 }
382 splx(s);
383 iomove(mtod(m, caddr_t), len, B_READ);
384 s = splnet();
385 if (len == m->m_len) {
386 MFREE(m, n);
387 so->so_rcv.sb_mb = n;
388 } else {
389 m->m_off += len;
390 m->m_len -= len;
391 so->so_rcv.sb_cc -= len;
392 }
393 } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
394 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
395 do {
396 if (m == 0)
397 panic("receive 3");
398 sbfree(&so->so_rcv, m);
399 eor = (int)m->m_act;
400 so->so_rcv.sb_mb = m->m_next;
401 MFREE(m, n);
402 m = n;
403 } while (eor == 0);
404 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
405 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
406release:
407 sbunlock(&so->so_rcv);
408 splx(s);
409 return (error);
410}
411
412/*ARGSUSED*/
413soioctl(so, cmd, cmdp)
414 register struct socket *so;
415 int cmd;
416 register caddr_t cmdp;
417{
418
419COUNT(SOIOCTL);
420 switch (cmdp) {
421
422 }
423 switch (so->so_type) {
424
425 case SOCK_STREAM:
426 break;
427
428 case SOCK_DGRAM:
429 break;
430
431 case SOCK_RDM:
432 break;
433
434 case SOCK_RAW:
435 break;
436
437 }
438}