home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
misc
/
tcpipsrc
/
sockuser.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-26
|
11KB
|
533 lines
/* Higher level user subroutines built on top of the socket primitives
* Copyright 1991 Phil Karn, KA9Q
*/
#include "global.h"
#ifdef ANSIPROTO
#include <stdarg.h>
#endif
#include "mbuf.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "session.h"
#include "nr4.h"
/* Higher-level receive routine, intended for connection-oriented sockets.
* Can be used with datagram sockets, although the sender id is lost.
*/
int
recv(s,buf,len,flags)
int s; /* Socket index */
char *buf; /* User buffer */
int len; /* Max length to receive */
int flags; /* Unused; will eventually select oob data, etc */
{
struct mbuf *bp;
int cnt;
if(len == 0)
return 0; /* Otherwise would be interp as "all" */
cnt = recv_mbuf(s,&bp,flags,NULLCHAR,(int *)NULL);
if(cnt > 0){
cnt = min(cnt,len);
pullup(&bp,buf,(int16)cnt);
free_p(bp);
}
return cnt;
}
/* Higher level receive routine, intended for datagram sockets. Can also
* be used for connection-oriented sockets, although from and fromlen are
* ignored.
*/
int
recvfrom(s,buf,len,flags,from,fromlen)
int s; /* Socket index */
char *buf; /* User buffer */
int len; /* Maximum length */
int flags; /* Unused; will eventually select oob data, etc */
char *from; /* Source address, only for datagrams */
int *fromlen; /* Length of source address */
{
struct mbuf *bp;
register int cnt;
cnt = recv_mbuf(s,&bp,flags,from,fromlen);
if(cnt > 0){
cnt = min(cnt,len);
pullup(&bp,buf,(int16)cnt);
free_p(bp);
}
return cnt;
}
/* High level send routine */
int
send(s,buf,len,flags)
int s; /* Socket index */
char *buf; /* User buffer */
int len; /* Length of buffer */
int flags; /* Unused; will eventually select oob data, etc */
{
register struct mbuf *bp;
char sock[MAXSOCKSIZE];
int i = MAXSOCKSIZE;
if(getpeername(s,sock,&i) == -1)
return -1;
bp = qdata(buf,(int16)len);
return send_mbuf(s,bp,flags,sock,i);
}
/* High level send routine, intended for datagram sockets. Can be used on
* connection-oriented sockets, but "to" and "tolen" are ignored.
*/
int
sendto(s,buf,len,flags,to,tolen)
int s; /* Socket index */
char *buf; /* User buffer */
int len; /* Length of buffer */
int flags; /* Unused; will eventually select oob data, etc */
char *to; /* Destination, only for datagrams */
int tolen; /* Length of destination */
{
register struct mbuf *bp;
bp = qdata(buf,(int16)len);
return send_mbuf(s,bp,flags,to,tolen);
}
/* Receive a newline-terminated line from a socket, returning # chars read.
* The end-of-line sequence is recognized and translated into a single '\n'.
*/
int
recvline(s,buf,len)
int s; /* Socket index */
char *buf; /* User buffer */
unsigned len; /* Length of buffer */
{
int c;
int cnt = 0;
while(len-- > 1){
if((c = recvchar(s)) == EOF){
cnt = -1;
break;
}
if(buf != NULLCHAR)
*buf++ = c;
cnt++;
if(uchar(c) == '\n')
break;
}
if(buf != NULLCHAR)
*buf = '\0';
return cnt;
}
#if defined(ANSIPROTO)
/* Do printf on a user socket */
int
usprintf(int s,char *fmt,...)
{
va_list args;
int len;
va_start(args,fmt);
len = usvprintf(s,fmt,args);
va_end(args);
return len;
}
/* Printf on standard output socket */
int
tprintf(char *fmt,...)
{
va_list args;
int len;
va_start(args,fmt);
len = usvprintf(Curproc->output,fmt,args);
va_end(args);
return len;
}
/* The guts of printf, uses variable arg version of sprintf */
int
usvprintf(int s,char *fmt, va_list args)
{
int len,withargs;
char *buf;
if(strchr(fmt,'%') == NULLCHAR){
/* Common case optimization: no args, so we don't
* need vsprintf()
*/
withargs = 0;
buf = fmt;
len = strlen(fmt);
} else {
/* Use a default value that is hopefully longer than the
* biggest output string we'll ever print (!)
*/
withargs = 1;
buf = mallocw(SOBUF);
vsprintf(buf,fmt,args);
len = strlen(buf);
}
if(usputs(s,buf) == EOF)
len = -1;
if(withargs)
free(buf);
return len;
}
#else
/*VARARGS*/
/* Printf to standard output socket */
int
tprintf(fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
char *fmt; /* Message format */
int arg1,arg2,arg3; /* Arguments */
int arg4,arg5,arg6;
int arg7,arg8,arg9;
int arg10,arg11,arg12;
{
return usprintf(Curproc->output,fmt,arg1,arg2,arg3,arg4,arg5,arg6
arg7,arg8,arg9,arg10,arg11,arg12);
}
/* Printf to socket. Doesn't use ANSI vsprintf */
int
usprintf(s,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
int s; /* Socket index */
char *fmt; /* Message format */
int arg1,arg2,arg3; /* Arguments */
int arg4,arg5,arg6;
int arg7,arg8,arg9;
int arg10,arg11,arg12;
{
int len,withargs;
char *buf;
if(strchr(fmt,'%') == NULLCHAR){
/* No args, so we don't need vsprintf() */
withargs = 0;
buf = fmt;
len = strlen(fmt);
} else {
/* Use a default value that is hopefully longer than the
* biggest output string we'll ever print (!)
*/
withargs = 1;
buf = mallocw(SOBUF);
sprintf(buf,fmt,arg1,arg2,arg3,arg4,arg5,arg6,arg7
arg8,arg9,arg10,arg11,arg12);
len = strlen(buf);
}
if(usputs(s,buf) == EOF)
len = -1;
if(withargs)
free(buf);
return len;
}
#endif
/* Buffered putchar to a socket */
int
usputc(s,c)
int s;
char c;
{
struct usock *up;
register struct mbuf *bp;
char *cp;
if((up = itop(s)) == NULLUSOCK){
errno = EBADF;
return -1;
}
if(up->obuf == NULLBUF){
/* Allocate a buffer of appropriate size */
switch(up->type){
case TYPE_NETROML4:
up->obuf = ambufw(NR4MAXINFO);
break;
default:
up->obuf = ambufw(BUFSIZ);
break;
}
}
bp = up->obuf;
if(c == '\n' && (up->flag & SOCK_ASCII)){
/* Translate into appropriate end-of-line sequence */
for(cp = up->eol;*cp != '\0';cp++)
bp->data[bp->cnt++] = *cp;
} else {
bp->data[bp->cnt++] = c;
}
/* Always leave enough room for an eol sequence in the next call */
if((c == up->flush && up->flush != -1) || bp->cnt >= bp->size-2)
if(usflush(s) == -1)
return -1;
return (int)uchar(c);
}
/* Put a character to standard output socket */
int
tputc(c)
char c;
{
return usputc(Curproc->output,c);
}
#ifndef oldusputs
/* Buffered puts to a socket */
int
usputs(s,buf)
int s;
char *buf;
{
register struct usock *up;
register struct mbuf *bp;
char *cp,*wp;
int16 len,clen;
int doflush;
int eol_len;
int newline;
if((up = itop(s)) == NULLUSOCK){
errno = EBADF;
return EOF;
}
if(up->flag & SOCK_ASCII)
eol_len = strlen(up->eol);
doflush = (up->flush != -1) && (strchr(buf,up->flush) != NULLCHAR);
len = strlen(buf);
while(len != 0){
if(up->obuf == NULLBUF){
/* Allocate a buffer of appropriate size */
switch(up->type){
case TYPE_NETROML4:
clen = NR4MAXINFO;
break;
default:
clen = BUFSIZ;
break;
}
up->obuf = ambufw(clen);
}
bp = up->obuf;
wp = &bp->data[bp->cnt];
if((up->flag && SOCK_ASCII)
&& (cp = strchr(buf,'\n')) != NULLCHAR){
newline = 1;
/* Ensure space for the eol sequence */
if(bp->cnt + eol_len >= bp->size){
/* Not enough room; flush and
* go back for another buffer
*/
if(usflush(s) == -1)
return EOF;
continue;
}
/* Copy only up to newline, allowing space for eol */
clen = cp - buf;
clen = min(clen,bp->size - bp->cnt - eol_len);
} else {
newline = 0;
clen = min(len,bp->size - bp->cnt);
}
/* Copy as much data as possible to mbuf */
if(clen != 0){
memcpy(wp,buf,clen);
wp += clen;
bp->cnt += clen;
buf += clen;
len -= clen;
}
if(newline){
/* Translate into appropriate end-of-line sequence */
strncpy(wp,up->eol,eol_len);
wp += eol_len;
bp->cnt += eol_len;
buf++; /* Skip newline in buffer */
len--;
}
if((bp->cnt >= bp->size) && usflush(s) == -1)
return EOF;
}
if(doflush && usflush(s) == -1)
return EOF;
return 0;
}
#else
int
usputs(s,x)
int s;
register char *x;
{
while(*x != '\0')
if(usputc(s,*x++) == EOF)
return EOF;
return 0;
}
#endif
/* Put a string to standard output socket */
int
tputs(s)
char *s;
{
return usputs(Curproc->output,s);
}
/* Read a raw character from a socket with stream buffering. */
int
rrecvchar(s)
int s; /* Socket index */
{
register struct usock *up;
if((up = itop(s)) == NULLUSOCK){
return EOF;
}
/* Replenish if necessary */
if(up->ibuf == NULLBUF && recv_mbuf(s,&up->ibuf,0,NULLCHAR,0) <= 0)
return EOF;
return PULLCHAR(&up->ibuf); /* Returns -1 if eof */
}
/* This function recognizes the end-of-line sequence for the stream
* and translates it into a single '\n'.
*/
int
recvchar(s)
int s; /* Socket index */
{
int c;
register struct usock *up;
if((up = itop(s)) == NULLUSOCK)
return EOF;
c = rrecvchar(s);
if(c != up->eol[0] || !(up->flag & SOCK_ASCII))
return c;
/* This is the first char of a eol sequence. If the eol sequence is
* more than one char long, eat the next character in the input stream.
*/
if(up->eol[1] != '\0'){
(void)rrecvchar(s);
}
return '\n';
}
/* Flush output on a socket stream */
int
usflush(s)
int s;
{
register struct usock *up;
struct mbuf *bp;
if((up = itop(s)) == NULLUSOCK)
return -1;
if(up->obuf != NULLBUF){
bp = up->obuf;
up->obuf = NULLBUF;
return send_mbuf(s,bp,0,NULLCHAR,0);
}
return 0;
}
/* Flush output socket */
void
tflush()
{
usflush(Current->output);
}
/* Print prompt and read one character */
int
keywait(prompt,flush)
char *prompt; /* Optional prompt */
int flush; /* Flush queued input? */
{
int c;
int i;
if(flush && socklen(Curproc->input,1) != 0)
recv_mbuf(Curproc->input,NULLBUFP,0,NULLCHAR,0); /* flush */
if(prompt == NULLCHAR)
prompt = "Hit enter to continue";
tprintf(prompt);
tflush();
c = recvchar(Curproc->input);
/* Get rid of the prompt */
for(i=strlen(prompt);i != 0;i--)
tputc('\b');
for(i=strlen(prompt);i != 0;i--)
tputc(' ');
for(i=strlen(prompt);i != 0;i--)
tputc('\b');
tflush();
return (int)c;
}
/* Set the end-of-line sequence on a socket */
int
seteol(s,seq)
int s;
char *seq;
{
register struct usock *up;
if((up = itop(s)) == NULLUSOCK)
return -1;
if(seq != NULLCHAR)
strncpy(up->eol,seq,sizeof(up->eol));
else
*up->eol = '\0';
return 0;
}
/* Enable/disable eol translation, return previous state */
int
sockmode(s,mode)
int s,mode;
{
struct usock *up;
int prev;
if((up = itop(s)) == NULLUSOCK)
return -1;
usflush(s);
prev = up->flag;
switch(mode){
case SOCK_BINARY:
case SOCK_ASCII:
up->flag = mode;
break;
default:
break;
}
return prev;
}
/* Specify the character to trigger automatic output buffer
* flushing, or -1 to disable it. Return the previous setting.
*/
int
setflush(s,c)
int s;
int c;
{
register struct usock *up;
int old;
if((up = itop(s)) == NULLUSOCK)
return -1;
old = up->flush;
up->flush = c;
return old;
}