diff options
Diffstat (limited to 'hw4/l4basic/l4posix.c')
-rw-r--r-- | hw4/l4basic/l4posix.c | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/hw4/l4basic/l4posix.c b/hw4/l4basic/l4posix.c new file mode 100644 index 0000000..82b42a0 --- /dev/null +++ b/hw4/l4basic/l4posix.c @@ -0,0 +1,333 @@ +#include "memwrap.h" +/* This file is modified by autogen.sh */ +/* vim: set sw=4 ts=4 sts=4 et: */ +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE 700 +#include "l4posix.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +char* lbs_posix_strcat (const char* str, ...) { + va_list ap; + char* strp; + char* strnow; + char* newstr; + int len = strlen (str); + + va_start (ap, str); + while ((strp = va_arg (ap, char*)) != NULL) { + len += strlen (strp); + } + va_end (ap); + + newstr = xmalloc (len + 1); + + va_start (ap, str); + strnow = stpcpy (newstr, str); + while ((strp = va_arg (ap, char*)) != NULL) { + strnow = stpcpy (strnow, strp); + } + newstr[len] = '\0'; + va_end (ap); + + return newstr; +} + +int lbs_posix_add_fd (int fd, int fdflags) { + int orgfd = fcntl (fd, F_GETFD); + if (orgfd < 0) { + return -1; + } + return fcntl (fd, F_SETFD, orgfd | fdflags); +} + +int lbs_posix_del_fd (int fd, int fdflags) { + int orgfd = fcntl (fd, F_GETFD); + if (orgfd < 0) { + return -1; + } + return fcntl (fd, F_SETFD, orgfd & ~(fdflags)); +} + +int lbs_posix_add_fl (int fd, int flflags) { + int orgfl = fcntl (fd, F_GETFL); + if (orgfl < 0) { + return -1; + } + return fcntl (fd, F_SETFL, orgfl | flflags); +} + +int lbs_posix_del_fl (int fd, int flflags) { + int orgfl = fcntl (fd, F_GETFL); + if (orgfl < 0) { + return -1; + } + return fcntl (fd, F_SETFL, orgfl & ~(flflags)); +} + +char* lbs_posix_readlink (const char* filename) { + struct stat st; + if (lstat (filename, &st) < 0) { + return NULL; + } + size_t bufsize = st.st_size ? st.st_size : 8192; + char* buf = xmalloc (bufsize + 1); + if (buf == NULL) { + return NULL; + } + ssize_t written = readlink (filename, buf, bufsize); + if (written < 0) { + free (buf); + return NULL; + } + buf[written] = '\0'; + return buf; +} + +char* lbs_posix_getcwd (void) { + char *cwd, *result; + size_t size = pathconf (".", _PC_PATH_MAX); + + size = size > 0 ? size : 256; + size = size > 8192 ? 8192 : size; + cwd = xmalloc (sizeof (char) * size); + + while ((result = getcwd (cwd, size)) == NULL && errno == ERANGE) { + size *= 2; + cwd = xrealloc (cwd, size); + } + + return cwd; +} + +size_t lbs_posix_write_all (int fd, const char* str, size_t size) { + ssize_t wtn = 0; + if (size <= 0) { + size = strlen (str); + } + size_t rem = size; + while (rem > 0) { + wtn = write (fd, str, rem); + if (wtn < 0) { + if (errno != EINTR && errno != EAGAIN) { + break; + } + continue; + } + str += wtn; + rem -= wtn; + } + + rem = rem > 0 ? rem : 0; + return size - rem; +} + +void lbs_posix_buffer_init (LbsPosixBuffer* buf) { + buf->buf_start = 0; + buf->buf_len = 0; + buf->buf_line = NULL; + buf->buf_line_len = 0; + buf->buf_error = false; + buf->buf_eof = false; +} + +void lbs_posix_buffer_clear (LbsPosixBuffer* buf, bool initial) { + buf->buf_start = 0; + buf->buf_len = 0; + + if (!initial) { + free (buf->buf_line); + } + buf->buf_line = NULL; + buf->buf_line_len = 0; + buf->buf_error = false; + buf->buf_eof = false; +} + +char* lbs_posix_buffer_getline (int fd, LbsPosixBuffer* buf, int delim) { + if (buf->buf_error || buf->buf_eof) { + return NULL; + } + + if (buf->buf_len == 0) { + int rval = read (fd, buf->buf, LBS_POSIX_BUFFER_SIZE); + if (rval < 0) { + if (errno != EAGAIN && errno != EINTR) { + buf->buf_error = true; + } + return NULL; + } + if (rval == 0) { + buf->buf_eof = true; + return NULL; + } + buf->buf_start = 0; + buf->buf_len = rval; + } + + int i; + for (i = 0; i < buf->buf_len; i++) { + if (buf->buf[buf->buf_start + i] == delim) { + break; + } + } + + int buf_line_start = buf->buf_line_len; + buf->buf_line_len += i; + buf->buf_line = xrealloc (buf->buf_line, buf->buf_line_len + 1); + memcpy (buf->buf_line + buf_line_start, buf->buf + buf->buf_start, i); + buf->buf_line[buf->buf_line_len] = '\0'; + + /* remove CR if delim is LF and delim is found */ + if (i < buf->buf_len && delim == '\n' && buf->buf_line_len - 1 >= 0 && + buf->buf_line[buf->buf_line_len - 1] == '\r') { + buf->buf_line[buf->buf_line_len - 1] = '\0'; + buf->buf_line_len--; + } + + int buf_len_saved = buf->buf_len; + buf->buf_start += i + 1; + buf->buf_len -= i + 1; + if (buf->buf_len <= 0) { + buf->buf_start = 0; + buf->buf_len = 0; + } + + if (i < buf_len_saved) { + /* delim is found */ + char* newstr = buf->buf_line; + buf->buf_line = NULL; + buf->buf_line_len = 0; + memmove (buf->buf, buf->buf + buf->buf_start, buf->buf_len); + buf->buf_start = 0; + return newstr; + } + + return NULL; +} + +#define SOCKADDR(x) ((struct sockaddr*)(x)) +#define SOCKADDR_UN(x) ((struct sockaddr_un*)(x)) +#define SOCKADDR_IN(x) ((struct sockaddr_in*)(x)) +#define SOCKADDR_IN6(x) ((struct sockaddr_in6*)(x)) + +static char* lbs_posix_socket_name ( + int sockfd, int (*getter) (int, struct sockaddr*, socklen_t*)) { + + struct sockaddr_storage sock; + socklen_t socklen = sizeof (sock); + + memset (&sock, 0, socklen); + if ((*getter)(sockfd, SOCKADDR (&sock), &socklen) < 0) { + return xstrdup ("invalid socket"); + } + + int domain = sock.ss_family; + if (domain == AF_UNIX) { + return xstrdup ("local process"); + } + + socklen_t ipstrlen; + void* ipnet; + char* ipstr; + if (domain == AF_INET) { + ipstrlen = INET_ADDRSTRLEN; + ipnet = &(SOCKADDR_IN (&sock)->sin_addr); + } else { + ipstrlen = INET6_ADDRSTRLEN; + ipnet = &(SOCKADDR_IN6 (&sock)->sin6_addr); + } + + ipstr = xmalloc (ipstrlen); + if (inet_ntop (domain, ipnet, ipstr, ipstrlen) == NULL) { + free (ipstr); + return xstrdup ("unknown address"); + } + + return ipstr; +} + +char* lbs_posix_socket_sockname (int sockfd) { + return lbs_posix_socket_name (sockfd, getsockname); +} + +char* lbs_posix_socket_peername (int sockfd) { + return lbs_posix_socket_name (sockfd, getpeername); +} + +void lbs_posix_exchange_data (int fd[2], LbsPosixProgress prog_cb) { + int nfds, active; + fd_set rset, wset; + fd_set rres, wres; + LbsPosixBuffer buf[2]; + + FD_ZERO (&rset); + FD_SET (fd[0], &rset); + FD_SET (fd[1], &rset); + FD_ZERO (&wset); + + active = 2; + nfds = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1; + lbs_posix_buffer_clear (&buf[0], true); + lbs_posix_buffer_clear (&buf[1], true); + + while (active && (*prog_cb) (fd, buf)) { + rres = rset; + wres = wset; + if (select (nfds, &rres, &wres, NULL, NULL) >= 0) { + for (int i = 0; i < 2; i++) { + if (buf[i].buf_len) { + /* read buffer full */ + if (FD_ISSET (fd[!i], &wres)) { + int wb = write (fd[!i], + buf[i].buf + buf[i].buf_start, buf[i].buf_len); + if (wb > 0) { + buf[i].buf_start += wb; + buf[i].buf_len -= wb; + if (!buf[i].buf_len) { + FD_CLR (fd[!i], &wset); + FD_SET (fd[i], &rset); + } + } else { + if (wb < 0 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else { + FD_CLR (fd[!i], &wset); + active = 0; + } + } + } + } else { + /* read buffer empty */ + if (FD_ISSET (fd[i], &rres)) { + int rb = read (fd[i], buf[i].buf, LBS_POSIX_BUFFER_SIZE); + if (rb > 0) { + buf[i].buf_start = 0; + buf[i].buf_len = rb; + FD_CLR (fd[i], &rset); + FD_SET (fd[!i], &wset); + } else { + if (rb < 0 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else{ + FD_CLR (fd[i], &rset); + active = 0; + } + } + } + } + } + } + } +} |