archie/prospero/lib/pfs/socket.c
2024-05-27 16:13:40 +02:00

224 lines
5.8 KiB
C

/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-license.h>.
*/
/* These routines are pulled from lib/psrv/gopher_gw/goph_gw_dsdb.c
and user/vcache/gopherget.c since they are common to both*/
#include <usc-license.h>
#include <netdb.h> /* Must be before pmachine.h */
#include <pfs.h>
#include <pmachine.h>
#include <errno.h>
#include <perrno.h>
#include <posix_signal.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pfs_threads.h>
#include <sockettime.h>
#ifdef TIMEOUT_APPROACH
EXTERN_TYPEP_DEF(jmp_buf, Jmpenv);
#define Jmpenv p_th_arJmpenv[p__th_self_num()]
static void
reprimeAlarm(int oldalarm, SIGNAL_RET_TYPE(*oldintr)())
{
if (signal(SIGALRM, oldintr) == SIG_ERR)
perror("signal died:"), exit(-1);
alarm(oldalarm);
}
/* These are probably not used, can remove if usefull for threading */
EXTERN_INT_DEF(syscall_oldalarmtime); /* Save old alarm time */
#define syscall_oldalarmtime p_th_arsyscall_oldalarmtime[p__th_self_num()]
/* SIGNAL_RET_TYPE (*syscall_oldintr)();*/ /* Old signal */
EXTERN_TYPEP_DEF(void *,syscall_oldintr); /* Old signal */
#define syscall_oldintr p_th_arsyscall_oldintr[p__th_self_num()]
static SIGNAL_RET_TYPE
alarmJmp(int sig)
{
reprimeAlarm(syscall_oldalarmtime,syscall_oldintr);
longjmp(Jmpenv,1);
}
#endif /*TIMEOUT_APPROACH*/
#ifdef SELECT_APPROACH
int
wait_till_stream_readable(FILE *str, int timeout)
{
if (str->_cnt > 0) return 1;
return (wait_till_readable(fileno(str),timeout));
}
#endif /*SELECT_APPROACH*/
/* This is adapted from interruptable_connect in gopher */
int
quick_connect(int s, struct sockaddr *name, int namelen, int timeout)
{
int retval;
#ifdef TIMEOUT_APPROACH
syscall_oldalarmtime = alarm(timeout);
if ((syscall_oldintr = signal(SIGALRM, alarmJmp)) == SIG_ERR)
perror("signal died:\n"), exit(-1);
if (setjmp(Jmpenv)) {
/* Note alarmJmp will reprime alarm*/
errno = ETIMEDOUT;
return(-1);
}
#endif
while ( (((retval = connect(s, name, namelen)) == -1)
&& (errno == EINTR)));
#ifdef TIMEOUT_APPROACH
reprimeAlarm(syscall_oldalarmtime,syscall_oldintr);
#endif
return retval;
}
int
quick_read(int fd, char *nptr, int nbytes, int timeout)
{
int retval;
#ifdef TIMEOUT_APPROACH
syscall_oldalarmtime = alarm(timeout);
if ((syscall_oldintr = signal(SIGALRM, alarmJmp)) == SIG_ERR)
perror("signal died:\n"), exit(-1);
if (setjmp(Jmpenv)) {
/* Note alarmJmp will reprime alarm*/
errno = ETIMEDOUT;
return(-1);
}
#endif /*TIMEOUT_APPROACH*/
#ifdef SELECT_APPROACH
switch (wait_till_readable(fd,timeout)) {
case -1: p_err_string = qsprintf_stcopyr(p_err_string,
"INTERNAL: read select failed: %s", unixerrstr());
return NULL;
case 0: p_err_string = qsprintf_stcopyr(p_err_string,
"Waited more than %d secs for response", timeout);
return NULL;
}
/* Default is going to be 1 - which is success */
#endif /*SELECT_APPROACH*/
retval = read(fd, nptr, nbytes); /* socket or -1 */
#ifdef TIMEOUT_APPROACH
reprimeAlarm(syscall_oldalarmtime,syscall_oldintr);
#endif
return retval;
}
char *
quick_fgets(char *s, int n, FILE *stream, int timeout)
/* Do a fgets, with opportunity for timeout handling, depending on system
same return code as fgets, but can return NULL (and not set error)
in some circumstances */
{
char *retval;
#ifdef TIMEOUT_APPROACH
syscall_oldalarmtime = alarm(timeout);
if ((syscall_oldintr = signal(SIGALRM, alarmJmp)) == SIG_ERR)
perror("signal died:\n"), exit(-1);
if (setjmp(Jmpenv)) {
/* Note alarmJmp will reprime alarm*/
errno = ETIMEDOUT;
return(NULL);
}
#endif
#ifdef SELECT_APPROACH
switch (wait_till_stream_readable(stream,timeout)) {
case -1: p_err_string = qsprintf_stcopyr(p_err_string,
"INTERNAL: read select failed: %s", unixerrstr());
return NULL;
case 0: p_err_string = qsprintf_stcopyr(p_err_string,
"waited more than %d secs for a response", timeout);
errno = ETIMEDOUT;
return NULL;
}
/* Default is going to be 1 - which is success */
#endif /*SELECT_APPROACH*/
retval = fgets(s, n, stream);
#ifdef SELECT_APPROACH
/* fgets can retunr an incomplete line, since it is non-blocking */
if (retval) {
int buflen = strlen(s);
if ((s[buflen -1 ] != '\n') && (n-1 > buflen)) {
retval = quick_fgets(s+buflen, n-buflen, stream, timeout);
}
}
#endif /*SELECT_APPROACH*/
#ifdef TIMEOUT_APPROACH
reprimeAlarm(syscall_oldalarmtime,syscall_oldintr);
#endif
return retval;
}
#if 0
int
quick_fgetc(FILE *stream, int timeout)
{
int retval;
#ifdef TIMEOUT_APPROACH
syscall_oldalarmtime = alarm(timeout);
if ((syscall_oldintr = signal(SIGALRM, alarmJmp)) == SIG_ERR)
perror("signal died:\n"), exit(-1);
if (setjmp(Jmpenv)) {
/* Note alarmJmp will reprime alarm*/
errno = ETIMEDOUT;
return(EOF);
}
#endif
#ifdef SELECT_APPROACH
switch (wait_till_stream_readable(stream,timeout)) {
case -1: p_err_string = qsprintf_stcopyr(p_err_string,
"INTERNAL: quick_fgetc: select failed: %s", unixerrstr());
return EOF;
case 0: p_err_string = qsprintf_stcopyr(p_err_string,
"waited more than %d secs for a response", timeout);
errno = ETIMEDOUT;
return EOF;
}
/* Default is going to be 1 - which is success */
#endif /*SELECT_APPROACH*/
retval = getc(stream);
#ifdef TIMEOUT_APPROACH
reprimeAlarm(syscall_oldalarmtime,syscall_oldintr);
#endif
return retval;
}
#endif
int quick_fgetc (FILE *stream, int timeout)
{
char c[2];
char *retval;
if (!(retval = quick_fgets(c, 2, stream, timeout))) {
/* errno set in quick_fgets */
return EOF;
}
return c[0];
}