系统调用 read、write
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
void unix_error(char *message) {
fprintf(stderr, "%s: %s\n", message, strerror(errno));
exit(0);
}
ssize_t Read(int fd, void *buf, size_t count) {
ssize_t read_size;
if ((read_size = read(fd, buf, count)) < 0) {
unix_error("Read error!");
}
return read_size;
}
ssize_t Write(int fd, const void *buf, size_t count) {
ssize_t write_size;
if ((write_size = write(fd, buf, count)) < 0) {
unix_error("Write error!");
}
return write_size;
}
char buf[100];
void test_read() {
int operator = open("./my.txt", O_RDONLY, 0);
int read_size = Read(operator, buf, sizeof(buf));
printf("operator = %d\n", operator);
printf("read_size = %d\n", read_size);
close(operator);
}
void test_write() {
char buf[] = "456789";
int operator = open("./my.txt", O_RDWR, 0);
int write_size = Write(operator, buf, sizeof(buf));
printf("write_size = %d\n", write_size);
int i;
char tmp;
lseek(operator, 0, SEEK_SET);
for (i = 0; i < 8; ++i) {
Read(operator, &tmp, 1);
printf("%d\t", tmp);
}
close(operator);
}
void main(void) {
test_read();
test_write();
}
不带缓冲区的 RIO
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
ssize_t rio_readn(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = read(fd, bufp, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break;
nleft -= nread;
bufp += nread;
}
return (n - nleft);
}
ssize_t rio_writen(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
char buf[100];
void test_read() {
int operator = open("./my.txt", O_RDONLY, 0);
int read_size = rio_readn(operator, buf, sizeof(buf));
printf("operator = %d\n", operator);
printf("read_size = %d\n", read_size);
close(operator);
}
void test_write() {
char buf[] = "32";
int operator = open("./my.txt", O_RDWR, 0);
int write_size = rio_writen(operator, buf, sizeof(buf));
printf("write_size = %d\n", write_size);
int i;
char tmp;
lseek(operator, 0, SEEK_SET);
for (i = 0; i < 8; ++i) {
rio_readn(operator, &tmp, 1);
printf("%d\t", tmp);
}
close(operator);
}
void main(void) {
test_read();
test_write();
}
带缓冲区的读、带缓冲区的文本行读、处理不足值的带缓冲区的读
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#define RIO_BUF_SIZE 8192
typedef struct {
int rio_fd;
int rio_unread_cnt;
char *rio_buf_pointer;
char rio_buf[RIO_BUF_SIZE];
} rio_file_with_buf;
void rio_read_with_buf_init(rio_file_with_buf *p, int fd) {
printf("%d\n", fd);
p->rio_fd = fd;
p->rio_unread_cnt = 0;
p->rio_buf_pointer = p->rio_buf;
}
static ssize_t rio_read(rio_file_with_buf *rp, char *usrbuf, size_t n) {
int this_read_cnt;
while (rp->rio_unread_cnt <= 0) {
rp->rio_unread_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_unread_cnt < 0) {
if (errno != EINTR) {
return -1;
}
} else if (rp->rio_unread_cnt == 0) {
return 0;
} else {
rp->rio_buf_pointer = rp->rio_buf;
}
}
this_read_cnt = rp->rio_unread_cnt < n ? rp->rio_unread_cnt : n;
memcpy(usrbuf, rp->rio_buf_pointer, this_read_cnt);
rp->rio_buf_pointer += this_read_cnt;
rp->rio_unread_cnt -= this_read_cnt;
return this_read_cnt;
}
ssize_t rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0;
else
break;
} else
return -1;
}
*bufp = 0;
return n - 1;
}
ssize_t rio_readnb(rio_file_with_buf *rp, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = rio_read(rp, bufp, nleft)) < 0)
return -1;
else if (nread == 0) {
break;
}
nleft -= nread;
bufp += nread;
}
return (n - nleft);
}
rio_file_with_buf riob;
void test_rio_read() {
ssize_t operator = open("./my.txt", O_RDONLY, 0);
char buf[20];
rio_read_with_buf_init(&riob, operator);
ssize_t read_size = rio_read(&riob, buf, sizeof(buf));
printf("operator = %d\n", operator);
printf("read_size = %d\n", read_size);
close(operator);
}
void test_rio_readlineb() {
ssize_t operator = open("./my.txt", O_RDONLY, 0);
char buf[20];
rio_read_with_buf_init(&riob, operator);
ssize_t read_size = rio_read(&riob, buf, sizeof(buf));
printf("operator = %d\n", operator);
printf("read_size = %d\n", read_size);
close(operator);
}
void test_rio_readnb() {
ssize_t operator = open("./my.txt", O_RDONLY, 0);
char buf[20];
rio_read_with_buf_init(&riob, operator);
ssize_t read_size = rio_read(&riob, buf, sizeof(buf));
printf("operator = %d\n", operator);
printf("read_size = %d\n", read_size);
close(operator);
}
void main(void) {
test_rio_read();
test_rio_readlineb();
test_rio_readnb();
}
getaddrinfo 和 getnameinfo 实现 nslookup
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#define MAXLINESIZE 8192
int main(int argc, char **argv) {
struct addrinfo *p, *listp, hints;
char buf[MAXLINESIZE];
int rc, flags;
if (argc != 2) {
printf("Please, input this style:command-name domain-name!\n");
exit(0);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp))!=0) {
fprintf(stderr, "Error in getaddrinfo:%s\n", gai_strerror(rc));
exit(1);
}
flags = NI_NUMERICHOST;
for (p = listp; p ; p=p->ai_next) {
getnameinfo(p->ai_addr, p->ai_addrlen, buf, MAXLINESIZE, NULL, 0, flags);
printf("%s\n", buf);
}
freeaddrinfo(listp);
exit(0);
}
实现 echo socket
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAXLINESIZE 8192
#define RIO_BUF_SIZE 8192
typedef struct sockaddr SA;
void app_error(char *msg)
{
fprintf(stderr, "%s!\n", msg);
exit(0);
}
typedef struct {
int rio_fd;
int rio_unread_cnt;
char *rio_buf_pointer;
char rio_buf[RIO_BUF_SIZE];
} rio_file_with_buf;
void gai_error(int code, char *msg) {
fprintf(stderr, "%s: %s\n", msg, gai_strerror(code));
exit(0);
}
void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int rc;
if ((rc = getaddrinfo(node, service, hints, res)) != 0) {
gai_error(rc, "Getaddrinfo error: ");
}
}
void unix_error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
void Close(int fd) {
int rc;
if ((rc = close(fd)) < 0)
unix_error("Close error!\n");
}
int open_clientfd(char *hostname, char *port) {
int clientfd;
struct addrinfo hints, *listp, *p;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_ADDRCONFIG;
Getaddrinfo(hostname, port, &hints, &listp);
for (p = listp; p; p = p->ai_next) {
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break;
Close(clientfd);
}
freeaddrinfo(listp);
if (!p) return -1;
return clientfd;
}
void dns_error(char *msg)
{
fprintf(stderr, "%s: DNS error %d!\n", msg, h_errno);
exit(0);
}
int Open_clientfd(char *hostname, char *port) {
int rc;
if ((rc = open_clientfd(hostname, port)) < 0) {
if (rc == -1)
unix_error("Open_clientfd Unix error!\n");
else
dns_error("Open_clientfd DNS error!\n");
}
return rc;
}
int open_listenfd(char *port) {
struct addrinfo hints, *listp, *p;
int listenfd, optval = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_PASSIVE | AI_ADDRCONFIG;
Getaddrinfo(NULL, port, &hints, &listp);
for (p = listp; p; p->ai_next) {
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)continue;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &optval, sizeof(int));
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)break;
Close(listenfd);
}
freeaddrinfo(listp);
if (!p)return -1;
if (listen(listenfd, 1024) < 0) {
Close(listenfd);
return -1;
}
return listenfd;
}
void rio_read_with_buf_init(rio_file_with_buf *p, int fd) {
p->rio_fd = fd;
p->rio_unread_cnt = 0;
p->rio_buf_pointer = p->rio_buf;
}
static ssize_t rio_read(rio_file_with_buf *rp, char *usrbuf, size_t n) {
int this_read_cnt;
while (rp->rio_unread_cnt <= 0) {
rp->rio_unread_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_unread_cnt < 0) {
if (errno != EINTR) {
return -1;
}
} else if (rp->rio_unread_cnt == 0) {
return 0;
} else {
rp->rio_buf_pointer = rp->rio_buf;
}
}
this_read_cnt = rp->rio_unread_cnt < n ? rp->rio_unread_cnt : n;
memcpy(usrbuf, rp->rio_buf_pointer, this_read_cnt);
rp->rio_buf_pointer += this_read_cnt;
rp->rio_unread_cnt -= this_read_cnt;
return this_read_cnt;
}
ssize_t rio_writen(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
ssize_t rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0;
else
break;
} else
return -1;
}
*bufp = 0;
return n - 1;
}
char *Fgets(char *ptr, int n, FILE *stream) {
char *rptr;
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
app_error("Fgets error");
return rptr;
}
void Rio_writen(int fd, void *usrbuf, size_t n) {
if (rio_writen(fd, usrbuf, n) != n)
unix_error("Rio_writen error!\n");
}
void Fputs(const char *ptr, FILE *stream) {
if (fputs(ptr, stream) == EOF)
unix_error("Fputs error!\n");
}
ssize_t Rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
ssize_t rc;
if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0)
unix_error("Rio_readlineb error!\n");
return rc;
}
int Open_listenfd(char *port) {
int rc;
if ((rc = open_listenfd(port)) < 0)
unix_error("Open_listenfd error!\n");
return rc;
}
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags) {
int rc;
if ((rc = getnameinfo(sa, salen, host, hostlen, serv,
servlen, flags)) != 0)
gai_error(rc, "Getnameinfo error: ");
}
void echo(int connfd) {
size_t n;
char buf[MAXLINESIZE];
rio_file_with_buf rio;
rio_read_with_buf_init(&rio, connfd);
while ((n = Rio_readlineb(&rio, buf, MAXLINESIZE)) != 0) {
printf("Received %d bytes\n", (int) n);
Rio_writen(connfd, buf, n);
}
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
int rc;
if ((rc = accept(s, addr, addrlen)) < 0)
unix_error("Accept error!\n");
return rc;
}
int main(int argc, char **argv) {
int listenfd, connfd;
socklen_t clientlen;
struct sockaddr_storage clientaddr;
char client_hostname[MAXLINESIZE], client_port[MAXLINESIZE];
if (argc != 2) {
printf("Please input the command like this: <command-name> <port>");
exit(0);
}
listenfd = Open_listenfd(argv[1]);
while (1) {
clientlen = sizeof(struct sockaddr_storage);
connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen);
Getnameinfo((SA *) &clientaddr, clientlen, client_hostname, MAXLINESIZE, client_port, MAXLINESIZE, 0);
printf("Connect to (%s, %s)\n", client_hostname, client_port);
echo(connfd);
Close(connfd);
}
}
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAXLINESIZE 8192
#define RIO_BUF_SIZE 8192
void app_error(char *msg)
{
fprintf(stderr, "%s!\n", msg);
exit(0);
}
typedef struct {
int rio_fd;
int rio_unread_cnt;
char *rio_buf_pointer;
char rio_buf[RIO_BUF_SIZE];
} rio_file_with_buf;
void gai_error(int code, char *msg) {
fprintf(stderr, "%s: %s\n", msg, gai_strerror(code));
exit(0);
}
void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int rc;
if ((rc = getaddrinfo(node, service, hints, res)) != 0) {
gai_error(rc, "Getaddrinfo error!\n");
}
}
void unix_error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
void Close(int fd) {
int rc;
if ((rc = close(fd)) < 0)
unix_error("Close error!\n");
}
int open_clientfd(char *hostname, char *port) {
int clientfd;
struct addrinfo hints, *listp, *p;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_ADDRCONFIG;
Getaddrinfo(hostname, port, &hints, &listp);
for (p = listp; p; p = p->ai_next) {
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break;
Close(clientfd);
}
freeaddrinfo(listp);
if (!p) return -1;
return clientfd;
}
void dns_error(char *msg)
{
fprintf(stderr, "%s: DNS error %d!\n", msg, h_errno);
exit(0);
}
int Open_clientfd(char *hostname, char* port) {
int rc;
if ((rc = open_clientfd(hostname, port)) < 0) {
if (rc == -1)
unix_error("Open_clientfd Unix error!\n");
else
dns_error("Open_clientfd DNS error!\n");
}
return rc;
}
int open_listenfd(char *port) {
struct addrinfo hints, *listp, *p;
int listenfd, optval = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_PASSIVE | AI_ADDRCONFIG;
Getaddrinfo(NULL, port, &hints, &listp);
for (p = listp; p; p->ai_next) {
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)continue;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &optval, sizeof(int));
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)break;
Close(listenfd);
}
freeaddrinfo(listp);
if (!p)return -1;
if (listen(listenfd, 1024) < 0) {
Close(listenfd);
return -1;
}
return listenfd;
}
void rio_read_with_buf_init(rio_file_with_buf *p, int fd) {
printf("%d\n", fd);
p->rio_fd = fd;
p->rio_unread_cnt = 0;
p->rio_buf_pointer = p->rio_buf;
}
static ssize_t rio_read(rio_file_with_buf *rp, char *usrbuf, size_t n) {
int this_read_cnt;
while (rp->rio_unread_cnt <= 0) {
rp->rio_unread_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_unread_cnt < 0) {
if (errno != EINTR) {
return -1;
}
} else if (rp->rio_unread_cnt == 0) {
return 0;
} else {
rp->rio_buf_pointer = rp->rio_buf;
}
}
this_read_cnt = rp->rio_unread_cnt < n ? rp->rio_unread_cnt : n;
memcpy(usrbuf, rp->rio_buf_pointer, this_read_cnt);
rp->rio_buf_pointer += this_read_cnt;
rp->rio_unread_cnt -= this_read_cnt;
return this_read_cnt;
}
ssize_t rio_writen(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
ssize_t rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0;
else
break;
} else
return -1;
}
*bufp = 0;
return n - 1;
}
char *Fgets(char *ptr, int n, FILE *stream) {
char *rptr;
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
app_error("Fgets error");
return rptr;
}
void Rio_writen(int fd, void *usrbuf, size_t n) {
if (rio_writen(fd, usrbuf, n) != n)
unix_error("Rio_writen error!\n");
}
void Fputs(const char *ptr, FILE *stream) {
if (fputs(ptr, stream) == EOF)
unix_error("Fputs error!\n");
}
ssize_t Rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
ssize_t rc;
if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0)
unix_error("Rio_readlineb error!\n");
return rc;
}
int main(int argc, char **argv) {
int clientfd;
char *host, *port, buf[MAXLINESIZE];
rio_file_with_buf rio;
if (argc != 3) {
printf("Please input the command like this: <command-name> <host> <port>");
exit(0);
}
host = argv[1];
port = argv[2];
clientfd = Open_clientfd(host, port);
rio_read_with_buf_init(&rio, clientfd);
while (Fgets(buf, MAXLINESIZE, stdin) != NULL) {
Rio_writen(clientfd, buf, strlen(buf));
Rio_readlineb(&rio, buf, MAXLINESIZE);
Fputs(buf, stdout);
}
Close(clientfd);
exit(0);
}
Tiny Web Server
#include <stdio.h>
#define __USE_GNU
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAXLINESIZE 8192
#define RIO_BUF_SIZE 8192
extern char **environ;
typedef struct sockaddr SA;
void app_error(char *msg)
{
fprintf(stderr, "%s!\n", msg);
exit(0);
}
typedef struct {
int rio_fd;
int rio_unread_cnt;
char *rio_buf_pointer;
char rio_buf[RIO_BUF_SIZE];
} rio_file_with_buf;
void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int rc;
if ((rc = getaddrinfo(node, service, hints, res)) != 0) {
printf("Getaddrinfo error: ");
}
}
void unix_error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
void Close(int fd) {
int rc;
if ((rc = close(fd)) < 0)
unix_error("Close error!\n");
}
int open_clientfd(char *hostname, char *port) {
int clientfd;
struct addrinfo hints, *listp, *p;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_ADDRCONFIG;
Getaddrinfo(hostname, port, &hints, &listp);
for (p = listp; p; p = p->ai_next) {
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break;
Close(clientfd);
}
freeaddrinfo(listp);
if (!p) return -1;
return clientfd;
}
void dns_error(char *msg)
{
fprintf(stderr, "%s: DNS error %d!\n", msg, h_errno);
exit(0);
}
int Open_clientfd(char *hostname, char *port) {
int rc;
if ((rc = open_clientfd(hostname, port)) < 0) {
if (rc == -1)
unix_error("Open_clientfd Unix error!\n");
else
dns_error("Open_clientfd DNS error!\n");
}
return rc;
}
int open_listenfd(char *port) {
struct addrinfo hints, *listp, *p;
int listenfd, optval = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_PASSIVE | AI_ADDRCONFIG;
Getaddrinfo(NULL, port, &hints, &listp);
for (p = listp; p; p->ai_next) {
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)continue;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &optval, sizeof(int));
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)break;
Close(listenfd);
}
freeaddrinfo(listp);
if (!p)return -1;
if (listen(listenfd, 1024) < 0) {
Close(listenfd);
return -1;
}
return listenfd;
}
void rio_read_with_buf_init(rio_file_with_buf *p, int fd) {
p->rio_fd = fd;
p->rio_unread_cnt = 0;
p->rio_buf_pointer = p->rio_buf;
}
static ssize_t rio_read(rio_file_with_buf *rp, char *usrbuf, size_t n) {
int this_read_cnt;
while (rp->rio_unread_cnt <= 0) {
rp->rio_unread_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_unread_cnt < 0) {
if (errno != EINTR) {
return -1;
}
} else if (rp->rio_unread_cnt == 0) {
return 0;
} else {
rp->rio_buf_pointer = rp->rio_buf;
}
}
this_read_cnt = rp->rio_unread_cnt < n ? rp->rio_unread_cnt : n;
memcpy(usrbuf, rp->rio_buf_pointer, this_read_cnt);
rp->rio_buf_pointer += this_read_cnt;
rp->rio_unread_cnt -= this_read_cnt;
return this_read_cnt;
}
ssize_t rio_writen(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
ssize_t rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0;
else
break;
} else
return -1;
}
*bufp = 0;
return n - 1;
}
char *Fgets(char *ptr, int n, FILE *stream) {
char *rptr;
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
app_error("Fgets error");
return rptr;
}
void Rio_writen(int fd, void *usrbuf, size_t n) {
if (rio_writen(fd, usrbuf, n) != n)
unix_error("Rio_writen error!\n");
}
void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) {
char buf[MAXLINESIZE], body[MAXLINESIZE];
sprintf(body, "<html><title>Tiny Error</title>");
sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);
sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
sprintf(body, "%s<hr><em>The Tiny Web server</em>\r\n", body);
sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg);
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-type: text/html\r\n");
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-length: %d\r\n\r\n", (int) strlen(body));
Rio_writen(fd, buf, strlen(buf));
Rio_writen(fd, body, strlen(body));
}
void Fputs(const char *ptr, FILE *stream) {
if (fputs(ptr, stream) == EOF)
unix_error("Fputs error!\n");
}
ssize_t Rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
ssize_t rc;
if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0)
unix_error("Rio_readlineb error!\n");
return rc;
}
int Open_listenfd(char *port) {
int rc;
if ((rc = open_listenfd(port)) < 0)
unix_error("Open_listenfd error!\n");
return rc;
}
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags) {
int rc;
if ((rc = getnameinfo(sa, salen, host, hostlen, serv,
servlen, flags)) != 0)
printf("Getnameinfo error: ");
}
void echo(int connfd) {
size_t n;
char buf[MAXLINESIZE];
rio_file_with_buf rio;
rio_read_with_buf_init(&rio, connfd);
while ((n = Rio_readlineb(&rio, buf, MAXLINESIZE)) != 0) {
printf("Received %d bytes\n", (int) n);
Rio_writen(connfd, buf, n);
}
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
int rc;
if ((rc = accept(s, addr, addrlen)) < 0)
unix_error("Accept error!\n");
return rc;
}
void read_requesthdrs(rio_file_with_buf *rp) {
char buf[MAXLINESIZE];
Rio_readlineb(rp, buf, MAXLINESIZE);
while (strcmp(buf, "\r\n")) {
Rio_readlineb(rp, buf, MAXLINESIZE);
printf("%s", buf);
}
return;
}
void Execve(const char *filename, char *const argv[], char *const envp[]) {
if (execve(filename, argv, envp) < 0)
unix_error("Execve error");
}
pid_t Wait(int *status) {
pid_t pid;
if ((pid = wait(status)) < 0)
unix_error("Wait error");
return pid;
}
int Dup2(int fd1, int fd2) {
int rc;
if ((rc = dup2(fd1, fd2)) < 0)
unix_error("Dup2 error");
return rc;
}
void serve_dynamic(int fd, char *filename, char *cgiargs) {
char buf[MAXLINESIZE], *emptylist[] = {NULL};
sprintf(buf, "HTTP/1.0 200 OK\r\n");
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Server: Tiny Web Server.\r\n");
Rio_writen(fd, buf, strlen(buf));
if (Fork() == 0) {
setenv("QUERY_STRING", cgiargs, 1);
Dup2(fd, STDOUT_FILENO);
Execve(filename, emptylist, environ);
}
Wait(NULL);
}
int parse_uri(char *uri, char *filename, char *cgiargs) {
char *ptr;
if (!strstr(uri, "cgi-bin")) {
strcpy(cgiargs, "");
strcpy(filename, ".");
strcat(filename, uri);
if (uri[strlen(uri) - 1] == '/') {
strcat(filename, "home.html");
}
return 1;
}
ptr = index(uri, '?');
if (ptr) {
strcpy(cgiargs, ptr + 1);
*ptr = '\0';
} else {
strcpy(cgiargs, "");
}
strcpy(filename, ".");
strcat(filename, uri);
return 0;
}
pid_t Fork(void) {
pid_t pid;
if ((pid = fork()) < 0)
unix_error("Fork error");
return pid;
}
void get_filetype(char *filename, char *filetype) {
if (strstr(filename, ".html"))
strcpy(filetype, "text/html");
else if (strstr(filename, ".gif"))
strcpy(filetype, "image/gif");
else if (strstr(filename, ".png"))
strcpy(filetype, "text/png");
else if (strstr(filename, ".jpg"))
strcpy(filetype, "text/jpeg");
else
strcpy(filetype, "text/plain");
}
int Open(const char *pathname, int flags, mode_t mode) {
int rc;
if ((rc = open(pathname, flags, mode)) < 0)
unix_error("Open error");
return rc;
}
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) {
void *ptr;
if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1))
unix_error("mmap error");
return (ptr);
}
void Munmap(void *start, size_t length) {
if (munmap(start, length) < 0)
unix_error("munmap error");
}
void serve_static(int fd, char *filename, int filesize) {
int srcfd;
char *srcp, filetype[MAXLINESIZE], buf[RIO_BUF_SIZE];
get_filetype(filename, filetype);
sprintf(buf, "HTTP/1.0 200 OK\r\n");
sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
sprintf(buf, "%sConnection: close\r\n", buf);
sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
Rio_writen(fd, buf, strlen(buf));
printf("Response headers:\n");
printf("%s", buf);
srcfd = Open(filename, O_RDONLY, 0);
srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
Close(srcfd);
Rio_writen(fd, srcp, filesize);
Munmap(srcp, filesize);
}
void doit(int fd) {
int is_static;
struct stat sbuf;
char buf[MAXLINESIZE], method[MAXLINESIZE], uri[MAXLINESIZE], version[MAXLINESIZE];
char filename[MAXLINESIZE], cgiargs[MAXLINESIZE];
rio_file_with_buf rio;
rio_read_with_buf_init(&rio, fd);
Rio_readlineb(&rio, buf, MAXLINESIZE);
printf("Request headers:\n");
printf("%s", buf);
sscanf(buf, "%s %s %s", method, uri, version);
if (strcasecmp(method, "GET")) {
clienterror(fd, method, "501", "Not implemented!", "Tiny does not implement this.");
return;
}
read_requesthdrs(&rio);
is_static = parse_uri(uri, filename, cgiargs);
if (stat(filename, &sbuf) < 0) {
clienterror(fd, filename, "404", "Not found!", "Tiny could not find this file.");
return;
}
if (is_static) {
if (!S_ISREG(sbuf.st_mode) || !(S_IRUSR & sbuf.st_mode)) {
clienterror(fd, filename, "403", "Forbidden!", "Tiny could not read this file.");
return;
}
serve_static(fd, filename, sbuf.st_size);
} else {
if (!S_ISREG(sbuf.st_mode) || !(S_IXUSR & sbuf.st_mode)) {
clienterror(fd, filename, "403", "Forbidden!", "Tiny could not read this file.");
return;
}
serve_dynamic(fd, filename, cgiargs);
}
}
int main(int argc, char **argv) {
int listenfd, connfd;
char hostname[MAXLINESIZE], port[MAXLINESIZE];
socklen_t clientlen;
struct sockaddr_storage clientaddr;
if (argc != 2) {
printf("Please input the command like this: <command-name> <port>");
exit(0);
}
listenfd = Open_listenfd(argv[1]);
while (1) {
clientlen = sizeof(clientaddr);
connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen);
Getnameinfo((SA *) &clientaddr, clientlen, hostname, MAXLINESIZE, port, MAXLINESIZE, 0);
printf("Connect from (%s, %s)\n", hostname, port);
doit(connfd);
Close(connfd);
}
}
adder
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAXLINESIZE 8192
#define RIO_BUF_SIZE 8192
typedef struct sockaddr SA;
void app_error(char *msg)
{
fprintf(stderr, "%s!\n", msg);
exit(0);
}
typedef struct {
int rio_fd;
int rio_unread_cnt;
char *rio_buf_pointer;
char rio_buf[RIO_BUF_SIZE];
} rio_file_with_buf;
void gai_error(int code, char *msg) {
fprintf(stderr, "%s: %s\n", msg, gai_strerror(code));
exit(0);
}
void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
int rc;
if ((rc = getaddrinfo(node, service, hints, res)) != 0) {
gai_error(rc, "Getaddrinfo error: ");
}
}
void unix_error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(0);
}
void Close(int fd) {
int rc;
if ((rc = close(fd)) < 0)
unix_error("Close error!\n");
}
int open_clientfd(char *hostname, char *port) {
int clientfd;
struct addrinfo hints, *listp, *p;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_ADDRCONFIG;
Getaddrinfo(hostname, port, &hints, &listp);
for (p = listp; p; p = p->ai_next) {
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break;
Close(clientfd);
}
freeaddrinfo(listp);
if (!p) return -1;
return clientfd;
}
void dns_error(char *msg)
{
fprintf(stderr, "%s: DNS error %d!\n", msg, h_errno);
exit(0);
}
int Open_clientfd(char *hostname, char *port) {
int rc;
if ((rc = open_clientfd(hostname, port)) < 0) {
if (rc == -1)
unix_error("Open_clientfd Unix error!\n");
else
dns_error("Open_clientfd DNS error!\n");
}
return rc;
}
int open_listenfd(char *port) {
struct addrinfo hints, *listp, *p;
int listenfd, optval = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_PASSIVE | AI_ADDRCONFIG;
Getaddrinfo(NULL, port, &hints, &listp);
for (p = listp; p; p->ai_next) {
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)continue;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &optval, sizeof(int));
if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)break;
Close(listenfd);
}
freeaddrinfo(listp);
if (!p)return -1;
if (listen(listenfd, 1024) < 0) {
Close(listenfd);
return -1;
}
return listenfd;
}
void rio_read_with_buf_init(rio_file_with_buf *p, int fd) {
p->rio_fd = fd;
p->rio_unread_cnt = 0;
p->rio_buf_pointer = p->rio_buf;
}
static ssize_t rio_read(rio_file_with_buf *rp, char *usrbuf, size_t n) {
int this_read_cnt;
while (rp->rio_unread_cnt <= 0) {
rp->rio_unread_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf));
if (rp->rio_unread_cnt < 0) {
if (errno != EINTR) {
return -1;
}
} else if (rp->rio_unread_cnt == 0) {
return 0;
} else {
rp->rio_buf_pointer = rp->rio_buf;
}
}
this_read_cnt = rp->rio_unread_cnt < n ? rp->rio_unread_cnt : n;
memcpy(usrbuf, rp->rio_buf_pointer, this_read_cnt);
rp->rio_buf_pointer += this_read_cnt;
rp->rio_unread_cnt -= this_read_cnt;
return this_read_cnt;
}
ssize_t rio_writen(int fd, void *usrbuf, size_t n) {
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
ssize_t rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
int n, rc;
char c, *bufp = usrbuf;
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n') {
n++;
break;
}
} else if (rc == 0) {
if (n == 1)
return 0;
else
break;
} else
return -1;
}
*bufp = 0;
return n - 1;
}
char *Fgets(char *ptr, int n, FILE *stream) {
char *rptr;
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
app_error("Fgets error");
return rptr;
}
void Rio_writen(int fd, void *usrbuf, size_t n) {
if (rio_writen(fd, usrbuf, n) != n)
unix_error("Rio_writen error!\n");
}
void Fputs(const char *ptr, FILE *stream) {
if (fputs(ptr, stream) == EOF)
unix_error("Fputs error!\n");
}
ssize_t Rio_readlineb(rio_file_with_buf *rp, void *usrbuf, size_t maxlen) {
ssize_t rc;
if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0)
unix_error("Rio_readlineb error!\n");
return rc;
}
int Open_listenfd(char *port) {
int rc;
if ((rc = open_listenfd(port)) < 0)
unix_error("Open_listenfd error!\n");
return rc;
}
void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host,
size_t hostlen, char *serv, size_t servlen, int flags) {
int rc;
if ((rc = getnameinfo(sa, salen, host, hostlen, serv,
servlen, flags)) != 0)
gai_error(rc, "Getnameinfo error: ");
}
void echo(int connfd) {
size_t n;
char buf[MAXLINESIZE];
rio_file_with_buf rio;
rio_read_with_buf_init(&rio, connfd);
while ((n = Rio_readlineb(&rio, buf, MAXLINESIZE)) != 0) {
printf("Received %d bytes\n", (int) n);
Rio_writen(connfd, buf, n);
}
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
int rc;
if ((rc = accept(s, addr, addrlen)) < 0)
unix_error("Accept error!\n");
return rc;
}
int main(void) {
char *buf, *p;
char arg1[MAXLINESIZE], arg2[MAXLINESIZE], content[MAXLINESIZE];
int n1 = 0, n2 = 0;
if ((buf=getenv("QUERY_STRING"))!=NULL){
p = strchr(buf, '&');
*p = '\0';
strcpy(arg1, buf);
strcpy(arg2, p + 1);
n1 = atoi(arg1);
n2 = atoi(arg2);
}
sprintf(content, "QUERY_STRING=%s", buf);
sprintf(content, "%sThe answer is: %d + %d = %d\r\n", content, n1, n2, n1+n2);
printf("Connection: close\r\n");
printf("Content-length: %d\r\n", (int)strlen(content));
printf("Content-type: text/html\r\n\r\n");
printf("%s", content);
fflush(stdout);
exit(0);
}