ch5

getaddrinfo()

/*
** showip.c -- show IP addresses for a host given on the command line
*/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
	struct addrinfo hints, *res, *p;
	int status;
	char ipstr[INET6_ADDRSTRLEN];

	if (argc != 2) {
	    fprintf(stderr,"usage: showip hostname\n");
	    return 1;
	}

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
	hints.ai_socktype = SOCK_STREAM;

	if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
		return 2;
	}

	printf("IP addresses for %s:\n\n", argv[1]);

	for(p = res;p != NULL; p = p->ai_next) {
		void *addr;
		char *ipver;

		// get the pointer to the address itself,
		// different fields in IPv4 and IPv6:
		if (p->ai_family == AF_INET) { // IPv4
			struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
			addr = &(ipv4->sin_addr);
			ipver = "IPv4";
		} else { // IPv6
			struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
			addr = &(ipv6->sin6_addr);
			ipver = "IPv6";
		}

		// convert the IP to a string and print it:
		inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
		printf("  %s: %s\n", ipver, ipstr);
	}

	freeaddrinfo(res); // free the linked list

	return 0;
}

socket()

int s;
struct addrinfo hints, *res;

// 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.

s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

bind()

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
// sockfd is the socket descriptor returned by socket()
// my_addr is a pointer to a struct sockaddr
1 struct addrinfo hints, *res;
2 int sockfd;
3
4 // first, load up address structs with getaddrinfo(): 5
6 memset(&hints, 0, sizeof hints);
7 hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
8 hints.ai_socktype = SOCK_STREAM;
9 hints.ai_flags = AI_PASSIVE; // fill in my IP for me
10
11 getaddrinfo(NULL, "3490", &hints, &res);
12
13 // make a socket:
14
15 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
16
17 // bind it to the port we passed in to getaddrinfo():
18
19 bind(sockfd, res->ai_addr, res->ai_addrlen);

connect()

#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
// serv_addr is a pointer to a struct sockaddr containing the destination port and IP address.
1 struct addrinfo hints, *res;
2 int sockfd;
3
4 // first, load up address structs with getaddrinfo(): 
5
6 memset(&hints, 0, sizeof hints);
7 hints.ai_family = AF_UNSPEC;
8 hints.ai_socktype = SOCK_STREAM;
9
10 getaddrinfo("www.example.com", "3490", &hints, &res); 11
12 // make a socket:
13
14 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
15
16 // connect!
17
18 connect(sockfd, res->ai_addr, res->ai_addrlen);
19 // return -1 on error.
20 // we don't care about our local port number, only care the remote port, so we didn't call bind().

listen()

int listen(int sockfd, int backlog);
// backlog is the maximum number of connections that can be queued for this socket.
1 getaddrinfo();
2 socket();
3 bind();
4 listen();
5 /* accept() goes here */

accept()

Their connection will be queued up waiting to be accept()ed. You call accept() and you tell it to get the pending connection. It’ll return to you a brand new socket file descriptor to use for this single connection! The original one is still listening for more new connections, and the newly created one is finally ready to send() and recv().

#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
1 #include <string.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <netdb.h>
5
6 #define MYPORT "3490" // the port users will be connecting to
7 #define BACKLOG 10 // how many pending connections queue will hold
8
9 int main(void)
10 {
11 struct sockaddr_storage their_addr;
12 socklen_t addr_size;
13 struct addrinfo hints, *res;
14 int sockfd, new_fd;
15
16 // !! don't forget your error checking for these calls !! 17
18 // first, load up address structs with getaddrinfo():
19
20 memset(&hints, 0, sizeof hints);
21 hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
22 hints.ai_socktype = SOCK_STREAM;
23 hints.ai_flags = AI_PASSIVE; // fill in my IP for me
24
25 getaddrinfo(NULL, MYPORT, &hints, &res);
26
27 // make a socket, bind it, and listen on it: 28
29 sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
30 bind(sockfd, res->ai_addr, res->ai_addrlen);
31 listen(sockfd, BACKLOG);
32
33 // now accept an incoming connection: 34
35 addr_size = sizeof their_addr;
36 new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
37
38 // ready to communicate on socket descriptor new_fd!
39 .
40 .
41 .

send() and recv()

int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, int flags);
// stream sockets use send() and recv() to send and receive data.

sendto() and recvfrom()

Since datagram sockets aren’t connected to a remote host, guess which piece of information we need to give before we send a packet? That’s right! The destination address!

int sendto(int sockfd, const void *buf, int len, int flags, const struct sockaddr *dest_addr, int addrlen);
int recvfrom(int sockfd, void *buf, int len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

close() and shutdown()

int close(int sockfd);
// free socket descriptor sockfd.
int shutdown(int sockfd, int how);
// shutdown() is used to close a socket in a graceful way.
// how is one of the following:
// SHUT_RD   = 0,  // shut down the reading side of the socket
// SHUT_WR   = 1,  // shut down the writing side of the socket
// SHUT_RDWR = 2   // shut down both sides of the socket

getpeername() and gethostname()

#include <sys/types.h>
#include <sys/socket.h>

int getpeername(int sockfd, struct sockaddr *addr, int *addrlen);
// getpeername() returns the address of the remote host to which the socket is connected.
#include <unistd.h>

int gethostname(char *hostname, size_t len);
// gethostname() returns the hostname of the machine.

Last updated