/*------------------------------------------------------------------------ * rstrunc - handle a truncate request *------------------------------------------------------------------------ */ void rstrunc ( struct rf_msg_treq *reqptr, /* ptr to read request */ struct rf_msg_tres *resptr /* ptr to read response */ ) { int fd; /* file descriptor */ /* DEBUG */ printf("DEBUG: reached rstrunc\n"); /* if file is open, close it */ if (findex >= 0) { close(fptr->desc); fptr->desc = -1; } fd = open(reqptr->rf_name, O_TRUNC); if (fd < 0) { snderr( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_tres) ); } else { close(fd); } /* Return OK status */ sndok ( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_tres) ); return; }
/*------------------------------------------------------------------------ * rsdelete - handle a delete request *------------------------------------------------------------------------ */ void rsdelete ( struct rf_msg_dreq *reqptr, /* ptr to read request */ struct rf_msg_dres *resptr /* ptr to read response */ ) { int retval; /* return value */ /*DEBUG*/ printf("DEBUG: reached rsdelete\n"); /* if file is open, close it */ if (findex >= 0) { close(fptr->desc); fptr->desc = -1; } retval = unlink(reqptr->rf_name); if (retval < 0) { snderr( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_dres) ); return; } /* Return OK status */ sndok ( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_sres) ); return; }
/*------------------------------------------------------------------------ * rsstat - handle a stat request *------------------------------------------------------------------------ */ void rsstat ( struct rf_msg_sreq *reqptr, /* ptr to read request */ struct rf_msg_sres *resptr /* ptr to read response */ ) { struct stat stbuf; /* buffer for file status */ int sreturn; /* stat return value */ sreturn = stat(reqptr->rf_name, &stbuf); if (sreturn < 0) { /* file does not exist */ resptr->rf_size = 0; snderr( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_sres) ); return; } /* Place the file size in the response message */ resptr->rf_size = htonl(stbuf.st_size); /* Copy the header and send the response */ sndok ( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_sres) ); return; }
/*------------------------------------------------------------------------ * rsread - handle a read request *------------------------------------------------------------------------ */ void rsread ( struct rf_msg_rreq *reqptr, /* ptr to read request */ struct rf_msg_rres *resptr /* ptr to read response */ ) { int fd; /* file descriptor */ int i, j; /* general loop indexes */ struct stat buf; /* buffer for file status */ int retval; /* function return value */ char *to, *from; /* used during copy */ int nbytes; /* num. of bytes read from file */ retval = stat(reqptr->rf_name, &buf); if(retval >= 0) { if(buf.st_mode & S_IFDIR) { rsdirread(reqptr, resptr); return; } } /* if file is not open, try to open it */ if (findex < 0) { if ( (fd = rsofile(reqptr->rf_name,O_RDWR)) < 0 ) { resptr->rf_pos = reqptr->rf_pos; resptr->rf_len = 0; /* set length to zero */ snderr( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_rreq) ); return; } for (i=0; i<MAXFILES; i++) { /* If entry is free, stop searching */ if (ofiles[i].desc < 0) { break; } } if (i >= MAXFILES) { /* table is full */ i = fnext; /* choose entry to close */ close(ofiles[fnext].desc); /* move to next slot for the future , wrap */ /* around the table, if necessary */ fnext++; if (fnext >= MAXFILES) { fnext = 0; } } ofiles[i].desc = fd; from = reqptr->rf_name; to =ofiles[i].name; /* copy name to open file table */ while ( (*to++ = *from++) ) { ; } } else { fd = fptr->desc; } /* stat file to get its current size */ retval = fstat(fd, &buf); /* if requested offset is beyond EOF, return error */ if ( (retval<0) || (ntohl(reqptr->rf_pos) > buf.st_size) ) { resptr->rf_pos = reqptr->rf_pos; resptr->rf_len = 0; /* set length to zero */ snderr( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_rreq) ); return; } /* seek to specified offset and read data */ lseek(fd, ntohl(reqptr->rf_pos), SEEK_SET); memset(resptr->rf_data, NULLCH, RF_DATALEN); nbytes = read(fd, resptr->rf_data, ntohl(reqptr->rf_len)); if (nbytes < 0) { resptr->rf_pos = reqptr->rf_pos; resptr->rf_len = 0; /* set length to zero */ snderr( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_rreq) ); return; } /* set bytes read */ resptr->rf_pos = reqptr->rf_pos; resptr->rf_len = htonl(nbytes); sndok( (struct rf_msg_hdr *)reqptr, (struct rf_msg_hdr *)resptr, sizeof(struct rf_msg_rres) ); return; }
int sosend(struct socket *so, struct mbuf *nam, /* sockaddr, if UDP socket, NULL if TCP */ char *data, /* data to send */ int *data_length, /* IN/OUT length of (remaining) data */ int flags) { struct mbuf *head = (struct mbuf *)NULL; struct mbuf *m; int space; int resid; int len; int error = 0; int dontroute; int first = 1; resid = *data_length; /* * In theory resid should be unsigned. * However, space must be signed, as it might be less than 0 * if we over-committed, and we must use a signed comparison * of space and resid. On the other hand, a negative resid * causes us to loop sending 0-length segments to the protocol. */ if (resid < 0) return (EINVAL); INET_TRACE (INETM_IO, ("INET:sosend: so %lx resid %d sb_hiwat %d so_state %x\n", so, resid, so->so_snd.sb_hiwat, so->so_state)); if (sosendallatonce(so) && (resid > (int)so->so_snd.sb_hiwat)) return (EMSGSIZE); dontroute = (flags & MSG_DONTROUTE) && ((so->so_options & SO_DONTROUTE) == 0) && (so->so_proto->pr_flags & PR_ATOMIC); #define snderr(errno) { error = errno; goto release; } restart: sblock(&so->so_snd); do { if (so->so_error) { error = so->so_error; so->so_error = 0; /* ??? */ goto release; } if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); if ((so->so_state & SS_ISCONNECTED) == 0) { if (so->so_proto->pr_flags & PR_CONNREQUIRED) snderr(ENOTCONN); if (nam == 0) snderr(EDESTADDRREQ); } if (flags & MSG_OOB) space = 1024; else { space = (int)sbspace(&so->so_snd); if ((sosendallatonce(so) && (space < resid)) || ((resid >= CLBYTES) && (space < CLBYTES) && (so->so_snd.sb_cc >= CLBYTES) && ((so->so_state & SS_NBIO) == 0) && ((flags & MSG_DONTWAIT) == 0))) { if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { if (first) error = EWOULDBLOCK; goto release; } sbunlock(&so->so_snd); sbwait(&so->so_snd); goto restart; } } if ( space <= 0 ) { /* no space in socket send buffer - see if we can wait */ if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { if (first) /* report first error */ error = EWOULDBLOCK; goto release; } /* If blocking socket, let someone else run */ sbunlock(&so->so_snd); sbwait(&so->so_snd); goto restart; } while (space > 0) { len = resid; if ( so->so_type == SOCK_STREAM ) { m = m_getwithdata(MT_TXDATA, len); if (!m) snderr(ENOBUFS); MEMCPY(m->m_data, data, len); so->so_snd.sb_flags |= SB_MBCOMP; /* allow compression */ } else { m = m_get (M_WAIT, MT_TXDATA); m->m_data = data; } INET_TRACE (INETM_IO, ("sosend:got %d bytes so %lx mlen %d, off %d mtod %x\n", len, so, m->m_len, m->m_off, mtod (m, caddr_t))); *data_length -= len; resid -= len; data += len; m->m_len = len; if (head == (struct mbuf *)NULL) head = m; if (error) goto release; if (*data_length <= 0) break; } if (dontroute) so->so_options |= SO_DONTROUTE; so->so_req = (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND; error = (*so->so_proto->pr_usrreq)(so, head, nam); if (dontroute) so->so_options &= ~SO_DONTROUTE; head = (struct mbuf *)NULL; first = 0; } while ((resid != 0) && (error == 0)); release: sbunlock(&so->so_snd); if (head) m_freem(head); return error; }
/* * Slightly changed version of sosend() */ static int kttcp_sosend(struct socket *so, unsigned long long slen, unsigned long long *done, struct lwp *l, int flags) { struct mbuf **mp, *m, *top; long space, len, mlen; int error, dontroute, atomic; long long resid; atomic = sosendallatonce(so); resid = slen; top = NULL; /* * In theory resid should be unsigned. * However, space must be signed, as it might be less than 0 * if we over-committed, and we must use a signed comparison * of space and resid. On the other hand, a negative resid * causes us to loop sending 0-length segments to the protocol. */ if (resid < 0) { error = EINVAL; goto out; } dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && (so->so_proto->pr_flags & PR_ATOMIC); l->l_ru.ru_msgsnd++; #define snderr(errno) { error = errno; goto release; } solock(so); restart: if ((error = sblock(&so->so_snd, SBLOCKWAIT(flags))) != 0) goto out; do { if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); if (so->so_error) { error = so->so_error; so->so_error = 0; goto release; } if ((so->so_state & SS_ISCONNECTED) == 0) { if (so->so_proto->pr_flags & PR_CONNREQUIRED) { snderr(ENOTCONN); } else { snderr(EDESTADDRREQ); } } space = sbspace(&so->so_snd); if (flags & MSG_OOB) space += 1024; if ((atomic && resid > so->so_snd.sb_hiwat)) snderr(EMSGSIZE); if (space < resid && (atomic || space < so->so_snd.sb_lowat)) { if (so->so_state & SS_NBIO) snderr(EWOULDBLOCK); SBLASTRECORDCHK(&so->so_rcv, "kttcp_soreceive sbwait 1"); SBLASTMBUFCHK(&so->so_rcv, "kttcp_soreceive sbwait 1"); sbunlock(&so->so_snd); error = sbwait(&so->so_snd); if (error) goto out; goto restart; } mp = ⊤ do { sounlock(so); do { if (top == 0) { m = m_gethdr(M_WAIT, MT_DATA); mlen = MHLEN; m->m_pkthdr.len = 0; m->m_pkthdr.rcvif = NULL; } else { m = m_get(M_WAIT, MT_DATA); mlen = MLEN; } if (resid >= MINCLSIZE && space >= MCLBYTES) { m_clget(m, M_WAIT); if ((m->m_flags & M_EXT) == 0) goto nopages; mlen = MCLBYTES; #ifdef MAPPED_MBUFS len = lmin(MCLBYTES, resid); #else if (atomic && top == 0) { len = lmin(MCLBYTES - max_hdr, resid); m->m_data += max_hdr; } else len = lmin(MCLBYTES, resid); #endif space -= len; } else { nopages: len = lmin(lmin(mlen, resid), space); space -= len; /* * For datagram protocols, leave room * for protocol headers in first mbuf. */ if (atomic && top == 0 && len < mlen) MH_ALIGN(m, len); } resid -= len; m->m_len = len; *mp = m; top->m_pkthdr.len += len; if (error) goto release; mp = &m->m_next; if (resid <= 0) { if (flags & MSG_EOR) top->m_flags |= M_EOR; break; } } while (space > 0 && atomic); solock(so); if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); if (dontroute) so->so_options |= SO_DONTROUTE; if (resid > 0) so->so_state |= SS_MORETOCOME; if (flags & MSG_OOB) error = (*so->so_proto->pr_usrreqs->pr_sendoob)(so, top, NULL); else error = (*so->so_proto->pr_usrreqs->pr_send)(so, top, NULL, NULL, l); if (dontroute) so->so_options &= ~SO_DONTROUTE; if (resid > 0) so->so_state &= ~SS_MORETOCOME; top = 0; mp = ⊤ if (error) goto release; } while (resid && space > 0); } while (resid); release: sbunlock(&so->so_snd); out: sounlock(so); if (top) m_freem(top); *done = slen - resid; #if 0 printf("sosend: error %d slen %llu resid %lld\n", error, slen, resid); #endif return (error); }