man 2 socket ;; the 2 is for system calls; ;; open, close, read, write ;; a 3 would be for library function ;; printf, fgets, fopen Create a socket: socket(AF_INET, SOCK_DGRAM, 0); ^^^^^^^ "internet" : ip addresses, potentially ipv4 addresses ^^^^^^^^^^ datagram -> UDP (messages that fit in a packet) (as opposed to SOCK_STREAM ->TCP, text, ordered bytes, reliable) ^ switches between datagram socket implementations, of which there's only one. Fragmentation ; to be covered a bit more later. Large IP packet, typically larger than 1500 bytes, would be split into fragments to be reassembled at the destination. For long-distance links, we use Path MTU discovery. MTU == Maximum Transmission Unit ; for Ethernet, 1500 bytes. This informs the sender what maximum size packet won't experience fragmentation. Fragmentation does happen; typically for NFS (network file system) traffic. Servers tend to be local because they trust IP addresses, you want to send 4096 bytes at a time. The maximum size of an IP packet is 65,535 bytes. (deduct 20 for the IP header, 8 for the udp header) Jumbo frames (gig ether, -> ~9000 byte MTUs) to be loosely standardized. Small MTU -> multiplexing (other people get a chance) ability to detect bit errors. (2-bit errors, 3-bit errors) Large MTU -> efficiency, perhaps fewer headers wasting bandwidth, fewer times to lookup where a packet goes. Ports 1. Ephemeral - allocated to clients, doesn't matter what they are, allow the kernel to tell which conversation a packet belongs to. 2. Bound - allocated to servers, often well known ( 41710 ), allows clients to contact a specific service. Conversation is identified by the 5-tuple: Source port, Destination port, Source address, Destination IP address, Protocol (TCP or UDP) Implication is that you can send a message to one of our servers (at dest port 41710) from a socket (bound to) a different port. /etc/services lists all the IANA-allocated ports. ssh = 22, http = 80, ntp = 123. assignment: send/broadcast a message, then wait for messages and print them. man 2 bind ;; all the include files you need, are listed here. bind - will give us a port. we can ask for one, or let it come. bind - the addresses and ports are in network byte order. #include struct sockaddr_in { /* internet endpoint address, IP address and port */ sa_family_t sin_family; /* AF_INET ; PF_INET */ in_port_t sin_port; /* ...sin_port = htons(41710); */ struct in_addr sin_addr; /* ...sin_addr.s_addr = "224.0.50.112"; */ /* ...sin_addr.s_addr = inet_addr("224.0.50.112");*/ /* ...sin_addr.s_addr = htonl(0xc000.....);*/ /* ...sin_addr.s_addr = INADDR_ANY; if you were a server */ /* ...sin_addr.s_addr = INADDR_LOCALHOST; */ /* ...sin_addr.s_addr = inet_addr("127.0.0.1"); */ /* ...sin_addr.s_addr = htonl(0x7f000001); */ */ }; ** that was an address, how to fill in the fields setsockopt allow more than one process to bind the same port. --- for most servers, this would be bad. int one = 1; setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); // the ability to attach more than one process (socket) // to the same address and port // on BSD -- there is REUSEPORT option. before the bind. allow us to configure the multicast membership bits. --- subscription to a multicast address. as a sender, you're broadcasting, only interested receivers will pick the packet off the wire. struct ip_mreq mreq; memset(&mreq, 0, sizeof(struct ip_mreq)); ^^^ treated as a character pointer ^^^ set bytes to zero ^^^^ that many bytes. // bzero(&mreq, sizeof(struct ip_mreq)); // another "optional" field might get added mreq.imr_multiaddr.s_addr = inet_addr("224.0.50.111"); // use the right address. mreq.imr_interface.s_addr = htonl(INADDR_ANY); // setsockopt will return -1 on error; 0 on success. if(setsockopt(receiving_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) == -1) { perror("setsockopt!"); fprintf(stderr, "%s: %s\n", "setsockopt!", strerror(errno)); exit(EXIT_FAILURE); } // first parameter is the socket. sendto(sending_socket, buffer_to_send, length_of_buffer, struct sockaddr *destination_adress, socklen_t length_of_dest_address ); struct sockaddr { int family <--- subclass. struct sockaddr_in { // I think this is 12 bytes long int family == AF_INET struct sockaddr_in6 { // I'd bet this is at least 32 bytes long. int family == AF_INET6 HOW to CONSTRUCT a BUFFER struct packet { struct header { // all those fields } hdr; char data[0]; // instead of zero, be 0xffff - 28 - sizeof(header) (or so) char *data; // big mistake. }; char *packet; ((struct header *)packet)->version = 1 [ header ][ data ] in some region of memory you can point to. don't call sizeof(struct packet); the size of the packet is in the length field. * you keep track of it. not the compiler. one call to sendto per packet. (no fragmentation). sizeof(struct packet *) => 4. -- why not to use the pointer scheme. struct packet *the_packet = malloc( 0xffff ); the_packet->data if done the right way == (char *)the_packet + sizeof(header) if done the other (bad; the pointer) way, it'd be zero or some unitialized bytes. struct header *the_header = malloc( 0xffff ); memcpy(the_header + 1, "hello", 5); printf("%p %p\n", the_header, the_header + 1); recvfrom(receiving_socket, buffer, maximum_size_of_buffer, * address, * length); => returns the number of bytes read. address is in/out parameter. in => restrictive, anything but inaddr_any (all zeroes), it will only return a packet from that source. source address to match on. source address is an ip address and UDP port; ip is end-to-end; original source (as IP believes) but most likely, make it all zeroes. out => from which source. for us, we *could* send a unicast response right back. the buffer won't have this information for us. Debugging: printf. inet_ntop I think will convert IP addresses to strings. __FILE__ __LINE__ macros can print where you are. gdb. break at one.c:50 strace - what system calls your code invokes, with what parameters. << anyone can run it. ltrace ... dunno if it's useful here... might not be installed. tcpdump/wireshark - what bytes are in what packets being sent out. << you need to own the machine. man 2 sendto ;; takes the struct sockaddr_in as destination Back to course content, no more programming assignment stuff. ===== Reliability. build a network from cheap components you can get at Fry's. from the overpriced components you can get at ... -- cheap oscillators (telling where a 1 and zero is. -- cheap wires. (original ethernet used catv trunk wire... twisted pair used copper telephone wiring) events outside our control. backhoes dig up wire. "baltimore tunnel fire" -- reasonably large outage on the east coast. reboot routers. power failures laws of physics. noise from external interference, speed of light, attenuation, fading, multipath Phy - encode the bits with enough redundancy that we recover them all. Data Link - retransmissions. if you believe it didn't get received, send again. Transport - retransmissions in TCP use "cumulative acknowledgement" Phy - Problem: put bits on a wire. Subgoal 1: High bandwidth (throughput) (to have short bits) Subgoal 2: Low latency (delay) the first bits should get to other side quickly. NRZ, Baseline Wander, Clock Recovery.