I know I should have started this earlier than version 3.0. I'm working on a time machine right now to help rectify the situation.
Release | Description of changes |
3.0.8, 2009-02-16 | getpeername() man page example [book v3.0.7 pp. 95-96]: replaced
"&" with real ampersands (C doesn't like &—who
knew) in call to getpeername(). Added address-of operators (&)
before the "s->sin_addr" and "s->sin6_addr" parameters to both
calls to inet_ntop(). Thanks to Rafael for reporting these.
getpeername(s, (struct sockaddr*) |
3.0.9, 2009-02-18 | getpeername() man page example again (I know!) [book v3.0.7 p. 96]:
replaced AF_INET with AF_INET6 where appropriate. How many bugs can I
have in 10 lines of code? I wrote a short program that counted exactly
how many bugs I had, and it was this: -37! Thanks again to Rafael who
won't let me off the hook until I get it right. :)
} else { // AF_INET6 [... snip ...] inet_ntop( |
3.0.10, 2009-02-23 | bind() man page example [book v3.0.7 p. 81]: need an address-of on
myaddr. (Thanks to Venkat for the report!)
bind(s, (struct sockaddr*)myaddr, sizeof myaddr); bind(s, (struct sockaddr*)&myaddr, sizeof myaddr);I also changed and added some comments in the same example [book v3.0.7 pp. 80-81]. The "proper" way doesn't demonstrate error checking, so it's not very proper. // |
3.0.11, 2009-02-24 | Section 5.2 socket() syscall example [book v3.0.7 p. 25]: forgot to
declare the type of hints. Also added a clarifying comment about the
proper use of the getaddrinfo() results linked list. (This bug caught by
Kaio—thanks, as always!)
struct addrinfo *res; struct addrinfo hints, *res;and // do the lookup // [pretend we already filled out the "hints" struct] getaddrinfo("www.example.com", "http", &hints, &res); // [again, you should do error-checking on getaddrinfo(), and walk // the "res" linked list looking for valid entries instead of just // assuming the first one is good (like many of these examples do.) // See the section on client/server for real examples.] |
3.0.12, 2009-02-24 | And the hits just keep coming today! These are from Mick—a
couple of typos.
Section 3.1, "IP Addresses, versions 4 and 6" [book v3.0.7 p. 9]: and was common written in "dots and numbers" form and was commonly written in "dots and numbers" formAnd, same section [book v3.0.7 p. 10]: That we need not just twice as many address, not a billion times as many That we need not just twice as many addresses, not a billion times as many |
3.0.13, 2009-03-23 | A big batch today from Rainer Kupke: "&" removals and a
quick note about using errno in multithreaded environments.
couple of typos. Hopefully this is all the stupid & errors caused
by my lame indiscriminate use of CDATA in my source XML...
Section 9.2, "bind()" [book v3.0.7 p. 81]: bind(s, (struct sockaddr*)myaddr, sizeof myaddr); bind(s, (struct sockaddr*)&myaddr, sizeof myaddr);or bind(s, (struct sockaddr*)&Section 9.18, "recv(), recvfrom()" [book v3.0.7 p. 116]: byte_count = recvfrom(sockfd, buf, sizeof buf, 0, &Section 9.19, "select()" [book v3.0.7 p. 118], lots of them bundled here... Gah, sorry! FD_ZERO(&Section 9.21, "send(), sendto()" [book v3.0.7 p. 122]: send(stream_socket, &Section 5.2, "socket()—Get the file descriptor!" [book v3.0.7 p 25]: The global variable errno is set to the error's value (see theSection 9.10, "errno" [book v3.0.7 p 97], add the following paragraph to the end of the description: One thing to note, for you multithreading enthusiasts, is that on most systems errno is defined in a threadsafe manner. (That is, it's not actually a global variable, but it behaves just like a global variable would in a single-threaded environment.) |
3.0.14, 2009-09-08 | A few changes, one substantial:
Section 6.3, "Datagram Sockets" [book v3.0.7 p 41]: type change in listener.c line 38:
Section 6.3, "select(): Synchronous I/O Multiplexing" [book v3.0.7 p XX]: added text: This being said, in modern times Section 7.4, "Serialization—How to Pack Data" [book v3.0.7 pp. 55-57]: addition and changes to ieee754.c: #include <inttypes.h>
long double unpack754( printf("float encoded: 0x%08 printf("double encoded: 0x%016 Section 7.4, "Serialization—How to Pack Data" [book v3.0.7 pp. 58-62]: multitude of changes, too many to list, to pack2.c to get it to function properly on 32-bit and 64-bit machines. It now relies on C99 features, but it was the cleanest way to get it portable. Modern gcc should have no trouble. (Thanks to Bruce L. for the catch and testing.) Section 7.4, "Serialization—How to Pack Data" [book v3.0.7 pp. XX-XX]: text added: [THE END] (Before I begin this section in earnest, I should tell you that there are libraries out there for doing this, and rolling your own and remaining portable and error-free is quite a challenge. So hunt around and do your homework before deciding to implement this stuff yourself. I include the information here for those curious about how things like this work.) Actually all the methods, above, have their drawbacks and advantages, Section 7.4, "Serialization—How to Pack Data" [book v3.0.7 pp. XX-XX]: text added: But if you want your source code to be portable, that's an assumption you can't necessarily make. (On the other hand, if you want things to be fast, you should optimize this out on platforms that don't need to do it! That's what htons() and its ilk do.) |
3.0.15, 2012-07-03 | In the man page section for bind():
inet_pton(AF_INET, "63.161.169.137", &myaddr.sin_addr.s_addr); inet_pton(AF_INET, "63.161.169.137", &(myaddr.sin_addr) In Section 5.1, "getaddrinfo()—Prepare to launch!", the following was added to showip.c: #include <netinet/in.h> |
3.0.16, 2015-08-11 | In Section 6.1, A Simple Stream Server, the error output for
bind() should happen before the close() call:
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { perror("server: bind"); close(sockfd); continue; } Also modify child reaper signal handler to not obliterate errno: void sigchld_handler(int s) { // waitpid() might overwrite errno, so we save and restore it: int saved_errno = errno; while(waitpid(-1, NULL, WNOHANG) > 0); errno = saved_errno; } In Section 5.1, "getaddrinfo()—Prepare to launch!", the following was added to showip.c: #include <netinet/in.h> In the setsockopt/getsockopt man page, the incorrect instructions about optval were corrected: The final parameter, optlen, should be set to the length of optval, probably sizeof(int), but varies depending on the option. Note that in the case of getsockopt(), this is a pointer to a socklen_t, and it specifies the maximum size object that will be stored in optval (to prevent buffer overflows). And getsockopt() will modify the value of optlen to reflect the number of bytes actually set. In server.c, move the freeaddrinfo() call to before the error checking: freeaddrinfo(servinfo); // all done with this structure if (p == NULL) { fprintf(stderr, "server: failed to bind\n"); return 2; } In Section 6.1, remove the "\n", since the code doesn't actually send that. All this server does is send the string "Hello, world!" out over a stream connection. All you need to do to test this server is run it in one window, and telnet to it from another with: In 9.24 "struct sockaddr and pals", added missing # to include: #include <netinet/in.h> In 3.1.1 Subnets, do proper math on 224: And now for more outdated information! Ready? In the Ancient Times, there were "classes" of subnets, where the first one, two, or three bytes of the address was the network part. If you were lucky enough to have one byte for the network and three for the host, you could have 24 bits-worth of hosts on your network (16 million or so). That was a "Class A" network. On the opposite end was a "Class C", with three bytes of network, and one byte of host (256 hosts, minus a couple that were reserved.) In 10.2 Web References, update BSD Sockets: A Quick and Dirty Primer URL to: http://www.cis.temple.edu/~giorgio/old/cis307s96/readings/docs/sockets.html In 7.1 Blocking: If you try to read from a non-blocking socket and there's no data there, it's not allowed to block—it will return -1 and errno will be set to EAGAIN or EWOULDBLOCK. (Wait—it can return EAGAIN or EWOULDBLOCK? Which do you check for? The specification doesn't actually specify which your system will return, so for portability, check them both.) In 3.4.1 Private (Or Disconnected) Networks, remove bad apostrophe: But if I ask my local computer what its IP address is, it says 10.0.0.5. In 9.19 select(), fix variable name in recv() call: if (FD_ISSET(s2, &readfds)) { recv(s2, buf2, sizeof buf2, 0); } In 6.3 Datagram Sockets, fix error message in talker.c: fprintf(stderr, "talker: failed to create socket\n"); In 3.4 IP Addresses, Part Deux, fix sample code IP address to match documentation IP address: inet_pton(AF_INET, "10.12.110.57", &(sa.sin_addr)); // IPv4 In 3.3 structs, added missing word: (Also, all the code written before struct addrinfo was invented we packed all this stuff by hand, so you'll see a lot of IPv4 code out in the wild that does exactly that. You know, in old versions of this guide and so on.) In 5.2 socket(), fix article: Now, get some milk and cookies, because it's times for a story. Once upon a time, a long time ago, it was thought that maybe an address family In 9.5 getaddrinfo(), fix typo: This is really where you get to define what the getaddrinfo() function is going to do. In 9.14 inet_ntop(), fix the same typo: These functions don't do DNS lookups—you'll need getaddrinfo() for that. In 9.24 struct sockaddr and pals, fix the same typo again: Often you'll use getaddrinfo() to fill these structures out, and then will read them when you have to. In 7.4 Serialization, fix signed char unpacking in unpack() See, I told you not to roll your own!! :-) case 'c': // 8-bit c = va_arg(ap, signed char*); if (*buf <= 0x7f) { *c = *buf;} // re-sign else { *c = -1 - (unsigned char)(0xffu - *buf); } buf++; break; |
3.0.17, 2015-09-23 | In 9.7 gethostbyname(), fixed typo: Returns a pointer to a resultant struct hostent on success, or NULL on error. |
3.0.18, 2016-01-05 | In 9.5. getaddrinfo(), freeaddrinfo(), gai_strerror(); also in client.c: reversed close() and perror() calls so the perror would refer to the right syscall. perror("connect"); close(sockfd); |
3.0.19, 2016-02-08 | In 7.2. select()--Asynchronous I/O Multiplexing, added this paragraph to the end: Quick note to all you Linux fans out there: sometimes, in rare circumstances, Linux's select() can return “ready-to-read” and then not actually be ready to read! This means it will block on the read() after the select() says it won't! Why you little—! Anyway, the workaround solution is to set the O_NONBLOCK flag on the receiving socket so it errors with EWOULDBLOCK (which you can just safely ignore if it occurs). See the fcntl() reference page for more info on setting a socket to non-blocking. In 9.19. select(), added this paragraph to the end: Note for Linux users: Linux's select() can return “ready-to-read” and then not actually be ready to read, thus causing the subsequent read() call to block. You can work around this bug by setting O_NONBLOCK flag on the receiving socket so it errors with EWOULDBLOCK , then ignoring this error if it occurs. See the fcntl() reference page for more info on setting a socket to non-blocking. |
3.0.20, 2016-03-11 | In 9.17. poll(), added the fd field so that it works at all: ufds[1].fd = s2; |
3.0.21, 2016-06-08 | In 5.3, fixed example to be resistant to Solaris: if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) |