** begin lecture 2 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. ** begin lecture 3 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. ** begin lecture 4 if you're sending "hello" [ header, with all integer fields in network byte order ] [ hello ] not [ lleh\0\0\0o ] only things to convert are the 32-bit integers, and 16-bit integers. htonl htons small trick when calculating the checksum. (but not for this one!) Weird issues: ** some csic machines act lame. ** "nauseated" does not seem to be among them. <- login there. ** send me mail with which ones work and don't. ** if you can explain it correctly.... I will be impressed. CLASSROOM ETHERNET -- we will eventually talk about how to share it. -- for now, use it as an motivating example for why we care about clock recovery. -- clock recovery: have to find the middle of the 1 or the zero and be able to tell when there are several consecutive 1's or 0's. (stadium concert video example) Encoding schemes: -- NRZ encoding : non-return to zero direct: 1 is high, 0 is low. RS-232 -12v => 1, +12v => 0 (pretty resilient) internal PC bus (but architects get to cheat, they have a clock) downside: no help for the clock. clock recovery: repeated 1's or repeated zeroes could get lost. baseline wander: spends too long at some level, average tracks up (or down) into the noise. what we need: transitions. 0's and 1's in equal parts, and frequently changing. (transitions help with both problems (clock recovery and baseline wander)) -- NRZI to encode a 1: change (from low to high or high to low) to encode a 0: no change 11111111111 (original signal) HLHLHLHLHLH (H = high, L is low) solves half the problem (consecutive 1's) doesn't solve the other half (consecutive 0's) -- Manchester Encoding to encode a 1: ( high/low ) to encode a 0: ( low/high ) 1 1 1 1 1 1 1 1 1 1 1 (original signal) HLHLHLHLHLHLHLHLHLHLHL 1 0 1 0 1 0 1 0 1 0 1 (original signal) HLLHHLLHHLLHHLLHHLLHHL Good: each bit gets a transition. Bad: send at half the rate. (many transitions encode nothing) this is in all ethernet before 100 Mbit. -- 4B/5B 4-bit sequence in your message, turn it into 5 bits on the wire. Have a table. This table will ensure that there are never more than three consecutive zeroes. 16 possible 4-bit sequences. 32 possible 5-bit sequences. not gonna use 00000 not gonna use 00001 not gonna use 00010 not gonna use 00011 gonna use 10001 (maybe... not in the list) not gonna use 11000 not gonna use 01000 could totally use 11111 could totally use 11001 catch is you put two of them together. all valid codewords start with at most one zero, and end with at most two. (verified!) rule eliminates less than 16. rest can be used for framing / control there is a table in the book, you could double check my rule generated by no notes. -- 4B/5B + NRZI recall 4B/5B: Have a table. This table will ensure that there are never more than three consecutive zeroes. recall NRZI: solves half the problem (consecutive 1's) 0100 1000 0110 1001 (original signal 0x4869) 01010 10010 01110 10011 (to 4b/5b) spaces not transmitted 01100 11100 01011 00010 (add nrzi) scheme in fast (100mbit) ethernet. wikipedia pages are fairly good... (it's not important to me that you could match the encoding scheme to the ieee standard.) -- scrambling SONET (optical, serious metropolitan or long-distance networks) 0100100001101001 (your bits) 0110010111010010 (*random* signal everyone has agreed on) 0010110110111011 (xor, and pray) advantage: no extra bits. disadvantage: could be unlucky. (ideally, you would not get unlucky more than once) devices that implement this are expensive. squeeze out as much performance as possible. might mean that you don't need as many transitions most of the time? not fighting three consecutive bits, maybe fighting 20 consecutive bits. based on not assuming random data. * if you believed all traffic to be encrypted, you wouldn't need scrambling. * that doesn't happen. FRAMING - mark the beginning and the end of a string of bits (frame) Options: (i) 4b/5b codewords (symbol outside the vocabulary) (ii) sentinel (like double-quote in programming language) (iii) fixed-size frames (using timing) 4b/5b scheme: 10001 (valid codeword, not in the table) stick that at the beginning and end of a frame. HDLC as used in some PPP. append 01111110 I believe there is both a bitwise version (counting 6 1's after a zero) and a byte-wise version (seeking 0x7e as a frame delimiter) For HDLC, just like a \" in a string, you have to escape: adding an extra zero after five 1's (regardless of whether a zero or 1 follows the five 1's.) [ check with the text ] If the end-of-frame marker is in the message, the sender will add that zero to make sure that it's not in the message. The receiver will remove the zero. What if we want to send 011111[0]0 somewhere deep within the frame (so it would have frame markers)? Still have to stuff! [011111]{0}[00] where [original] {stuffed bit} Just like in the quoted string... you have to be able to recognize the escape (as in "c:\\" where you want the escape character) Means you have some probability of lengthening the frame. (not free) (iii) fixed size frames not all that interesting. ATM cell is 48 bytes long (plus 5 of header). if everything is of this fixed size, don't need to waste any bytes delimiting the beginning and end of a frame. may be some periodic clock-synchronizing signal. ERROR DETECTION. Version 1: Parity Bit count the 1's, if odd, parity bit is 1, if even, 0. add the 1's. chance of detecting a single bit error? 100% (the error might be in the parity bit too) chance of detecting a two-bit error? 0%. if you have only 8 bits to send (a character over a serial connection) Version 2: Checksum. instead of adding the 1's, add the 16-bit words.o "internet checksum" is the ones complement of the sum of the 16-bit words. if you store the checksum as the negative sum of 16-bit words... to check, just *add* the 16-bit words and hope you get 0. an aside about handling the carry when adding 16-bit words for a checksum. 0xffff 0x0002 ------ 0x0003 nevermind that. I will bring in some code. chance of detecting a single bit error? 100% (the error might be in the parity bit too) chance of detecting a two-bit error? depends on which two bits. I'd guess it's still 80%-like... considered to be rather weak. (relatively few bytes to protect, have another scheme at your disposal.) ** lecture 5 CRC;