/* * ***************************************************************************** * file name : network_util.c * author : Hung Q. Ngo (hungngo@cse.buffalo.edu) * description : implementations of basic networking functions * modified from Stevens' code * ***************************************************************************** */ #include "generic.h" #include "network_util.h" #include "error_handlers.h" /* * ---------------------------------------------------------------------------- * readn: * read 'n' bytes or upto EOF from descriptor 'fd' into 'vptr' * returns number of bytes read or -1 on error * ---------------------------------------------------------------------------- */ ssize_t readn(int fd, void* vptr, size_t n) { size_t nleft; ssize_t nread; char* ptr; ptr = vptr; nleft = n; while (nleft > 0) { /* keep reading upto n bytes */ if ( (nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) { /* got interrupted by a signal ? */ nread = 0; /* and call read() again */ } else { return(-1); } } else if (nread == 0) { break; /* EOF */ } nleft -= nread; ptr += nread; } return(n - nleft); /* return >= 0 */ } /* * ---------------------------------------------------------------------------- * writen: * write 'n' bytes from 'vptr' to descriptor 'fd' * returns number of bytes written or -1 on error * ---------------------------------------------------------------------------- */ ssize_t writen(int fd, const void* vptr, size_t n) { size_t nleft; ssize_t nwritten; const char* ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (errno == EINTR) { /* interrupted by a signal ? */ nwritten = 0; /* and call write() again */ } else { return(-1); } } nleft -= nwritten; ptr += nwritten; } return(n); } /* * ---------------------------------------------------------------------------- * my_read: * internal function, reads upto MAXLINE characters at a time, and then * return them one at a time. * this is much more efficient than 'read'ing one byte at a time, but the * price is that it's not "reentrant" or "thread-safe", due to the use * of static variables * ---------------------------------------------------------------------------- */ static ssize_t my_read(int fd, char* ptr) { static int read_count = 0; static char* read_ptr; static char read_buf[MAXLINE]; int got_signal; got_signal = 0; if (read_count <= 0) { again: if ( (read_count = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) { goto again; /* bad programming practice ? may be not */ } else { return(-1); } } else if (read_count == 0) { return(0); } read_ptr = read_buf; } read_count--; *ptr = *read_ptr++; return(1); } /* * ---------------------------------------------------------------------------- * readline: * read upto '\n' or maxlen bytes from 'fd' into 'vptr' * returns number of bytes read or -1 on error * ---------------------------------------------------------------------------- */ ssize_t readline(int fd, void *vptr, size_t maxlen) { int n, rc; char c, *ptr; ptr = vptr; for (n = 1; n < maxlen; n++) { if ( (rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '\n') { break; /* newline is stored, like fgets() */ } } else if (rc == 0) { if (n == 1) { return(0); /* EOF, no data read */ } else { break; /* EOF, some data was read */ } } else { return(-1); /* error, errno set by read() */ } } *ptr = 0; /* null terminate like fgets() */ return(n); } /* * ---------------------------------------------------------------------------- * simpler_sigaction: * appropriately calls POSIX's sigaction, except for SIGALARM, we try to * restart any interrupted system calls after any other signals * 'signo' is the signal number * 'func' is the signal handler * SIG_ERR is returned if the call to sigaction fails * ---------------------------------------------------------------------------- */ Sigfunc* simpler_sigaction(int signo, Sigfunc *func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x : only in the case of SIGALARM * we do not want to restart the sys. call */ #endif } else { #ifdef SA_RESTART act.sa_flags |= SA_RESTART; /* SVR4, 44BSD : restart interrupted system * calls */ #endif } if (sigaction(signo, &act, &oact) < 0) { return(SIG_ERR); } return(oact.sa_handler); } /* * ---------------------------------------------------------------------------- * sig_child_handler: * we do not want zombies, so try to wait for all children to finish whenever * a SIGCHLD is received * ---------------------------------------------------------------------------- */ void sig_child_handler(int signo) { pid_t pid; int stat; while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { note("Child process %d terminated\n", pid); } }