diff options
author | Sanjit Bhat <[email protected]> | 2023-10-26 06:44:48 -0400 |
---|---|---|
committer | Sanjit Bhat <[email protected]> | 2023-10-26 06:44:48 -0400 |
commit | cfae93475dfb4cb5cfe264f4c029136e1447c262 (patch) | |
tree | 699903e093e3a23caf7ce3899e7c80e48511f900 /user | |
parent | 1ed40716eb54e371df9d1814b9129666b3fe4f09 (diff) | |
download | xv6-labs-cfae93475dfb4cb5cfe264f4c029136e1447c262.tar.gz xv6-labs-cfae93475dfb4cb5cfe264f4c029136e1447c262.tar.bz2 xv6-labs-cfae93475dfb4cb5cfe264f4c029136e1447c262.zip |
net add missing files
Diffstat (limited to 'user')
-rw-r--r-- | user/nettests.c | 297 | ||||
-rw-r--r-- | user/pingpong.c | 52 |
2 files changed, 349 insertions, 0 deletions
diff --git a/user/nettests.c b/user/nettests.c new file mode 100644 index 0000000..2f7d6cd --- /dev/null +++ b/user/nettests.c @@ -0,0 +1,297 @@ +#include "kernel/types.h" +#include "kernel/net.h" +#include "kernel/stat.h" +#include "user/user.h" + +// +// send a UDP packet to the localhost (outside of qemu), +// and receive a response. +// +static void +ping(uint16 sport, uint16 dport, int attempts) +{ + int fd; + char *obuf = "a message from xv6!"; + uint32 dst; + + // 10.0.2.2, which qemu remaps to the external host, + // i.e. the machine you're running qemu on. + dst = (10 << 24) | (0 << 16) | (2 << 8) | (2 << 0); + + // you can send a UDP packet to any Internet address + // by using a different dst. + + if((fd = connect(dst, sport, dport)) < 0){ + fprintf(2, "ping: connect() failed\n"); + exit(1); + } + + for(int i = 0; i < attempts; i++) { + if(write(fd, obuf, strlen(obuf)) < 0){ + fprintf(2, "ping: send() failed\n"); + exit(1); + } + } + + char ibuf[128]; + int cc = read(fd, ibuf, sizeof(ibuf)-1); + if(cc < 0){ + fprintf(2, "ping: recv() failed\n"); + exit(1); + } + + close(fd); + ibuf[cc] = '\0'; + if(strcmp(ibuf, "this is the host!") != 0){ + fprintf(2, "ping didn't receive correct payload\n"); + exit(1); + } +} + +// Encode a DNS name +static void +encode_qname(char *qn, char *host) +{ + char *l = host; + + for(char *c = host; c < host+strlen(host)+1; c++) { + if(*c == '.') { + *qn++ = (char) (c-l); + for(char *d = l; d < c; d++) { + *qn++ = *d; + } + l = c+1; // skip . + } + } + *qn = '\0'; +} + +// Decode a DNS name +static void +decode_qname(char *qn, int max) +{ + char *qnMax = qn + max; + while(1){ + if(qn >= qnMax){ + printf("invalid DNS reply\n"); + exit(1); + } + int l = *qn; + if(l == 0) + break; + for(int i = 0; i < l; i++) { + *qn = *(qn+1); + qn++; + } + *qn++ = '.'; + } +} + +// Make a DNS request +static int +dns_req(uint8 *obuf) +{ + int len = 0; + + struct dns *hdr = (struct dns *) obuf; + hdr->id = htons(6828); + hdr->rd = 1; + hdr->qdcount = htons(1); + + len += sizeof(struct dns); + + // qname part of question + char *qname = (char *) (obuf + sizeof(struct dns)); + char *s = "pdos.csail.mit.edu."; + encode_qname(qname, s); + len += strlen(qname) + 1; + + // constants part of question + struct dns_question *h = (struct dns_question *) (qname+strlen(qname)+1); + h->qtype = htons(0x1); + h->qclass = htons(0x1); + + len += sizeof(struct dns_question); + return len; +} + +// Process DNS response +static void +dns_rep(uint8 *ibuf, int cc) +{ + struct dns *hdr = (struct dns *) ibuf; + int len; + char *qname = 0; + int record = 0; + + if(cc < sizeof(struct dns)){ + printf("DNS reply too short\n"); + exit(1); + } + + if(!hdr->qr) { + printf("Not a DNS reply for %d\n", ntohs(hdr->id)); + exit(1); + } + + if(hdr->id != htons(6828)){ + printf("DNS wrong id: %d\n", ntohs(hdr->id)); + exit(1); + } + + if(hdr->rcode != 0) { + printf("DNS rcode error: %x\n", hdr->rcode); + exit(1); + } + + //printf("qdcount: %x\n", ntohs(hdr->qdcount)); + //printf("ancount: %x\n", ntohs(hdr->ancount)); + //printf("nscount: %x\n", ntohs(hdr->nscount)); + //printf("arcount: %x\n", ntohs(hdr->arcount)); + + len = sizeof(struct dns); + + for(int i =0; i < ntohs(hdr->qdcount); i++) { + char *qn = (char *) (ibuf+len); + qname = qn; + decode_qname(qn, cc - len); + len += strlen(qn)+1; + len += sizeof(struct dns_question); + } + + for(int i = 0; i < ntohs(hdr->ancount); i++) { + if(len >= cc){ + printf("invalid DNS reply\n"); + exit(1); + } + + char *qn = (char *) (ibuf+len); + + if((int) qn[0] > 63) { // compression? + qn = (char *)(ibuf+qn[1]); + len += 2; + } else { + decode_qname(qn, cc - len); + len += strlen(qn)+1; + } + + struct dns_data *d = (struct dns_data *) (ibuf+len); + len += sizeof(struct dns_data); + //printf("type %d ttl %d len %d\n", ntohs(d->type), ntohl(d->ttl), ntohs(d->len)); + if(ntohs(d->type) == ARECORD && ntohs(d->len) == 4) { + record = 1; + printf("DNS arecord for %s is ", qname ? qname : "" ); + uint8 *ip = (ibuf+len); + printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + if(ip[0] != 128 || ip[1] != 52 || ip[2] != 129 || ip[3] != 126) { + printf("wrong ip address"); + exit(1); + } + len += 4; + } + } + + // needed for DNS servers with EDNS support + for(int i = 0; i < ntohs(hdr->arcount); i++) { + char *qn = (char *) (ibuf+len); + if(*qn != 0) { + printf("invalid name for EDNS\n"); + exit(1); + } + len += 1; + + struct dns_data *d = (struct dns_data *) (ibuf+len); + len += sizeof(struct dns_data); + if(ntohs(d->type) != 41) { + printf("invalid type for EDNS\n"); + exit(1); + } + len += ntohs(d->len); + } + + if(len != cc) { + printf("Processed %d data bytes but received %d\n", len, cc); + exit(1); + } + if(!record) { + printf("Didn't receive an arecord\n"); + exit(1); + } +} + +static void +dns() +{ + #define N 1000 + uint8 obuf[N]; + uint8 ibuf[N]; + uint32 dst; + int fd; + int len; + + memset(obuf, 0, N); + memset(ibuf, 0, N); + + // 8.8.8.8: google's name server + dst = (8 << 24) | (8 << 16) | (8 << 8) | (8 << 0); + + if((fd = connect(dst, 10000, 53)) < 0){ + fprintf(2, "ping: connect() failed\n"); + exit(1); + } + + len = dns_req(obuf); + + if(write(fd, obuf, len) < 0){ + fprintf(2, "dns: send() failed\n"); + exit(1); + } + int cc = read(fd, ibuf, sizeof(ibuf)); + if(cc < 0){ + fprintf(2, "dns: recv() failed\n"); + exit(1); + } + dns_rep(ibuf, cc); + + close(fd); +} + +int +main(int argc, char *argv[]) +{ + int i, ret; + uint16 dport = NET_TESTS_PORT; + + printf("nettests running on port %d\n", dport); + + printf("testing ping: "); + ping(2000, dport, 1); + printf("OK\n"); + + printf("testing single-process pings: "); + for (i = 0; i < 100; i++) + ping(2000, dport, 1); + printf("OK\n"); + + printf("testing multi-process pings: "); + for (i = 0; i < 10; i++){ + int pid = fork(); + if (pid == 0){ + ping(2000 + i + 1, dport, 1); + exit(0); + } + } + for (i = 0; i < 10; i++){ + wait(&ret); + if (ret != 0) + exit(1); + } + printf("OK\n"); + + printf("testing DNS\n"); + dns(); + printf("DNS OK\n"); + + printf("all tests passed.\n"); + exit(0); +} diff --git a/user/pingpong.c b/user/pingpong.c new file mode 100644 index 0000000..6ed12e7 --- /dev/null +++ b/user/pingpong.c @@ -0,0 +1,52 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +#define N 5 +char buf[N]; + +void +pong(int *parent_to_child, int *child_to_parent) { + if (read(parent_to_child[0], buf, N) < 0) { + printf("read failed\n"); + } + printf("%d: received %s\n", getpid(), buf); + if (write(child_to_parent[1], "pong", 4) != 4) { + printf("write failed\n"); + } +} + +void +ping(int *parent_to_child, int *child_to_parent) { + + if (write(parent_to_child[1], "ping", 4) != 4) { + printf("write failed\n"); + } + if (read(child_to_parent[0], buf, N) < 0) { + printf("read failed\n"); + } + printf("%d: received %s\n", getpid(), buf); +} + +int +main(int argc, char *argv[]) +{ + int parent_to_child[2]; + int child_to_parent[2]; + + int pid; + + if (pipe(parent_to_child) < 0 || pipe(child_to_parent) < 0) { + printf("pipe failed\n"); + } + if ((pid = fork()) < 0) { + printf("fork failed\n"); + } + if (pid == 0) { + pong(parent_to_child, child_to_parent); + } else { + ping(parent_to_child, child_to_parent); + } + + exit(0); +} |