/* IP socket address structure */ structsockaddr_in { uint16_t sin_family; /* Protocol family (always AF_INET) */ uint16_t sin_port; /* Port number in network byte order */ structin_addrsin_addr;/* IP address in network byte order */ unsignedchar sin_zero[8]; /* Pad to sizeof(struct sockaddr) */ };
/* Generic socket address structure (for connect, bind, and accept) */ structsockaddr { uint16_t sa_family; /* Protocol family */ char sa_data[14]; /* Address data */ };
structaddrinfo { int ai_flags; /* Hints argument flags */ int ai_family; /* First arg to socket function */ int ai_socktype; /* Second arg to socket function */ int ai_protocol; /* Third arg to socket function */ char *ai_canonname; /* Canonical hostname */ size_t ai_addrlen; /* Size of ai_addr struct */ structsockaddr *ai_addr;/* Ptr to socket address structure */ structaddrinfo *ai_next;/* Ptr to next item in linked list */ };
/* Get a list of addrinfo records */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 only */ hints.ai_socktype = SOCK_STREAM; /* Connections only */ if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp)) != 0) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc)); exit(1); }
/* Walk the list and display each IP address */ flags = NI_NUMERICHOST; /* Display address string instead of domain name */ for (p = listp; p; p = p->ai_next) { Getnameinfo(p->ai_addr, p->ai_addrlen, buf, MAXLINE, NULL, 0, flags); printf("%s\n", buf); }
intopen_clientfd(char *hostname, char *port){ int clientfd; structaddrinfohints, *listp, *p;
/* Get a list of potential server addresses */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; /* Open a connection */ hints.ai_flags = AI_NUMERICSERV; /* ... using a numeric port arg. */ hints.ai_flags |= AI_ADDRCONFIG; /* Recommended for connections */ Getaddrinfo(hostname, port, &hints, &listp);
/* Walk the list for one that we can successfully connect to */ for (p = listp; p; p = p->ai_next) { /* Create a socket descriptor */ if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; /* Socket failed, try the next */
/* Connect to the server */ if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break; /* Success */ Close(clientfd); /* Connect failed, try another */ }
/* Clean up */ Freeaddrinfo(listp); if (!p) /* All connects failed */ return-1; else/* The last connect succeeded */ return clientfd; }
intopen_listenfd(char *port) { structaddrinfohints, *listp, *p; int listenfd, rc, optval=1;
/* Get a list of potential server addresses */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; /* Accept connections */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */ hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */ if ((rc = getaddrinfo(NULL, port, &hints, &listp)) != 0) { fprintf(stderr, "getaddrinfo failed (port %s): %s\n", port, gai_strerror(rc)); return-2; }
/* Walk the list for one that we can bind to */ for (p = listp; p; p = p->ai_next) { /* Create a socket descriptor */ if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; /* Socket failed, try the next */
/* Eliminates "Address already in use" error from bind */ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt (constvoid *)&optval , sizeof(int));
/* Bind the descriptor to the address */ if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break; /* Success */ if (close(listenfd) < 0) { /* Bind failed, try the next */ fprintf(stderr, "open_listenfd close failed: %s\n", strerror(errno)); return-1; } }
/* Clean up */ freeaddrinfo(listp); if (!p) /* No address worked */ return-1;
/* Make it a listening socket ready to accept connection requests */ if (listen(listenfd, LISTENQ) < 0) { close(listenfd); return-1; } return listenfd; }