home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3
/
hamradioversion3.0examsandprograms1992.iso
/
misc
/
9q920411
/
sockuser.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-03-10
|
12KB
|
547 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;
int newline,len;
if((up = itop(s)) == NULLUSOCK){
errno = EBADF;
return -1;
}
if(c == '\n' && (up->flag & SOCK_ASCII)){
newline = 1;
len = strlen(up->eol);
} else {
newline = 0;
len = 1;
}
/* Make sure there's room in the current buffer, if any */
if((bp = up->obuf) != NULLBUF){
if((bp->cnt >= bp->size - len) && usflush(s) == -1)
return EOF;
}
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;
}
}
/* Note: the buffer must be larger than the end-of-line sequence! */
bp = up->obuf;
cp = &bp->data[bp->cnt];
if(newline){
/* Translate into appropriate end-of-line sequence */
strncpy(cp,up->eol,len);
} else {
*cp = c;
}
bp->cnt += len;
/* Flush if necessary */
if(c == up->flush && up->flush != -1 && 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;
int16 flushpt;
int ascii;
if((up = itop(s)) == NULLUSOCK){
errno = EBADF;
return EOF;
}
ascii = up->flag & SOCK_ASCII;
if(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);
}
/* Note: the buffer must be larger than the end-of-line sequence! */
bp = up->obuf;
wp = &bp->data[bp->cnt];
if(ascii && (cp = strchr(buf,'\n')) != NULLCHAR){
/* Copy up to, but not including, newline */
clen = cp - buf;
} else {
/* Copy whole thing */
clen = len;
}
/* ...but no more than the room available */
clen = min(clen,bp->size - bp->cnt);
if(clen != 0){
memcpy(wp,buf,clen);
wp += clen;
bp->cnt += clen;
buf += clen;
len -= clen;
}
/* Set flush threshold to allow for eol, if enabled */
if(ascii)
flushpt = bp->size - eol_len;
else
flushpt = bp->size;
if(ascii && *buf == '\n' && bp->cnt < flushpt){
/* Add 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 >= flushpt){
/* Buffer full, flush and get another */
if(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;
}