getaddrinfo(3)

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

int getaddrinfo(const char *restrict node,
			    const char *restrict service,
			    const struct addrinfo *restrict hints,
			    struct addrinfo **restrict res);

void freeaddrinfo(struct addrinfo *res);

const char *gai_strerror(int errcode);
struct addrinfo {
	int              ai_flags;
	int              ai_family;
	int              ai_socktype;
	int              ai_protocol;
	socklen_t        ai_addrlen;
	struct sockaddr *ai_addr;
	char            *ai_canonname;
	struct addrinfo *ai_next;
};

hostname, host address, service name, port number๋ฅผ ํ•œ๋ฐ๋ชจ์•„ ํ•˜๋‚˜์˜ struct addrinfo ๊ตฌ์กฐ์ฒด์— ๋‹ด์•„์ฃผ๋Š” ์นœ์ ˆํ•œ ํ•จ์ˆ˜์ด๋‹ค. ์ด์ค‘ ํฌ์ธํ„ฐ์ธ ์ด์œ ๋Š” CSAPP Figure 11.15์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค์‹œํ”ผ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ head๋ฅผ ์ด์ค‘ ํฌ์ธํ„ฐ๋กœ ๋งŒ๋“  ๋•๋ถ„์— ํฌ์ธํ„ฐ์˜ ๊ฐ’์„ getaddrinfo๊ฐ€ ์Šค์Šค๋กœ ํ• ๋‹นํ•ด์„œ ๊ทธ ์œ„์น˜๋ฅผ ๋จน์ผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

getaddrinfo๋Š” ํž™ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ์œ„์— ํ• ๋‹น๋ฐ›์€ ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— freeaddrinfo ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ œ๊ฑฐํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Pasted image 20230919190726.png

gpt question: getaddrinfo(NULL, ...) ํ•˜๋Š” ์ด์œ 

Question

๋‹ค์Œ ํ•จ์ˆ˜๋Š” getaddrinfo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ struct addrinfo ๋ฆฌ์ŠคํŠธ๋ฅผ ์–ป์–ด๋‚ด ์ˆœํšŒ๋ฅผ ๋Œ๋ฉด์„œ socket, bind ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด. ์—ฌ๊ธฐ์„œ ๊ถ๊ธˆํ•œ ์ ์€ ์™œ getaddrinfo ์ฒซ๋ฒˆ์งธ ์ธ์ž๋ฅผ NULL๋กœ ์ฃผ๋Š”๊ฑฐ์•ผ? ip์ฃผ์†Œ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ž๋ฆฌ์ธ ๊ฑธ๋กœ ์•„๋Š”๋ฐ NULL์ด ๋“ค์–ด๊ฐ€๋ฉด ๋ฌด์—‡์œผ๋กœ ๋Œ€์ฒด๋˜๋Š”์ง€ ๊ถ๊ธˆํ•ด.

/*  
 * open_listenfd - Open and return a listening socket on port. This
 *     function is reentrant and protocol-independent.
 *
 *     On error, returns: 
 *       -2 for getaddrinfo error
 *       -1 with errno set for other errors.
 */
/* $begin open_listenfd */
int open_listenfd(char *port) 
{
    struct addrinfo hints, *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
                   (const void *)&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;
}

answer

getaddrinfo ํ•จ์ˆ˜์—์„œ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋ฅผ NULL๋กœ ์ „๋‹ฌํ•˜๋Š” ์ด์œ ๋Š” ์„œ๋ฒ„ ์†Œ์ผ“์„ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ์†Œ์ผ“์„ ๋ชจ๋“  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋„คํŠธ์›Œํฌ ์ธํ„ฐํŽ˜์ด์Šค(๋กœ์ปฌ ์ฃผ์†Œ)์— ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

getaddrinfo ํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” ํ˜ธ์ŠคํŠธ ์ด๋ฆ„์ด๋‚˜ IP ์ฃผ์†Œ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด ์ธ์ž์— NULL์„ ์ „๋‹ฌํ•˜๋ฉด, getaddrinfo๋Š” ํ˜„์žฌ ํ˜ธ์ŠคํŠธ(๋กœ์ปฌ ์‹œ์Šคํ…œ)์— ๋Œ€ํ•œ ๋„คํŠธ์›Œํฌ ์ธํ„ฐํŽ˜์ด์Šค ์ฃผ์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์„œ๋ฒ„๊ฐ€ ํ˜„์žฌ ํ˜ธ์ŠคํŠธ์˜ ๋ชจ๋“  ๋„คํŠธ์›Œํฌ ์ธํ„ฐํŽ˜์ด์Šค(์˜ˆ: ๋ชจ๋“  IP ์ฃผ์†Œ)์—์„œ ๋“ค์–ด์˜ค๋Š” ์—ฐ๊ฒฐ์„ ์ˆ˜๋ฝํ•˜๊ณ ์ž ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์„œ๋ฒ„๋Š” ๋ชจ๋“  ๋„คํŠธ์›Œํฌ ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์„ ์ˆ˜์‹ ํ•˜๋ ค๊ณ  ํ•  ๋•Œ NULL์„ ์‚ฌ์šฉํ•˜์—ฌ getaddrinfo๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ getaddrinfo(NULL, port, &hints, &listp)๋Š” ํ˜„์žฌ ํ˜ธ์ŠคํŠธ์˜ ๋ชจ๋“  ๋„คํŠธ์›Œํฌ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ port ๋ฒˆํ˜ธ๋กœ ๋“ค์–ด์˜ค๋Š” ์—ฐ๊ฒฐ์„ ์ˆ˜๋ฝํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์†Œ ์ •๋ณด๋ฅผ ์–ป๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์–ป์€ ์ฃผ์†Œ ์ •๋ณด๋ฅผ ์ด์šฉํ•˜์—ฌ ์„œ๋ฒ„ ์†Œ์ผ“์„ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ์ฃผ์†Œ๋กœ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์„œ๋ฒ„๋Š” ๋ชจ๋“  ๋„คํŠธ์›Œํฌ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๋“ค์–ด์˜ค๋Š” ์—ฐ๊ฒฐ์„ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ •๋ฆฌ

bind๋ฅผ ํ•  ๋•Œ ๋„ฃ๋Š” struct addrinfo ๊ตฌ์กฐ์ฒด ์•ˆ์— ๋“ค์–ด๊ฐ€๋Š” ์ฃผ์†Œ์™€ ํฌํŠธ์— ๋Œ€ํ•˜์—ฌ ์ฃผ์†Œ๋ฅผ NULL๋กœ ์ฃผ๋ฉด ์•Œ์•„์„œ "ํ•ด๋‹น ํฌํŠธ๋กœ ๋“ค์–ด์˜ค๋Š” ๋ชจ๋“  ํ˜ธ์ŠคํŠธ๋กœ๋ถ€ํ„ฐ์˜ ์ ‘์†์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค"๋ผ๊ณ  ๋œปํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

gpt question getaddrinfo hint ๋„ฃ๋Š”๋ฒ•

question

์„œ๋ฒ„์—๊ฒŒ HTTP GET ์š”์ฒญ์„ ์ „์†กํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ getaddrinfo ํ•จ์ˆ˜ ์ธ์ž๋ฅผ ์–ด๋–ป๊ฒŒ ๋„ฃ์–ด์•ผ ์˜ฌ๋ฐ”๋ฅธ struct addrinfo ๋ฆฌ์ŠคํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์„๊นŒ?

answer

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>

int main() {
    struct addrinfo hints, *res;
    int status;

    // ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ ๋˜๋Š” IP ์ฃผ์†Œ, ํฌํŠธ ๋ฒˆํ˜ธ, ํžŒํŠธ ์ดˆ๊ธฐํ™”
    const char *hostname = "www.example.com"; // ๋Œ€์ƒ ์„œ๋ฒ„ ์ฃผ์†Œ
    const char *port = "80"; // HTTP ํฌํŠธ ๋ฒˆํ˜ธ
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // IPv4 ๋˜๋Š” IPv6
    hints.ai_socktype = SOCK_STREAM; // TCP ์†Œ์ผ“

    // getaddrinfo ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ์ฃผ์†Œ ์ •๋ณด ์–ป๊ธฐ
    if ((status = getaddrinfo(hostname, port, &hints, &res)) != 0) {
        fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
        return 1;
    }

    // addrinfo ๋ฆฌ์ŠคํŠธ(res)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— HTTP GET ์š”์ฒญ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์Œ

    // addrinfo ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ํ›„ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
    freeaddrinfo(res);

    return 0;
}

์œ„ ์˜ˆ์ œ์—์„œ ์ฃผ์š”ํ•œ ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. getaddrinfo ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ hostname ๋ณ€์ˆ˜์— ๋Œ€์ƒ ์„œ๋ฒ„์˜ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ ๋˜๋Š” IP ์ฃผ์†Œ๋ฅผ ์ง€์ •ํ•˜๊ณ , port ๋ณ€์ˆ˜์—๋Š” HTTP ํฌํŠธ ๋ฒˆํ˜ธ(์ผ๋ฐ˜์ ์œผ๋กœ 80)๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. hints ๊ตฌ์กฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , ํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์†์„ฑ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์ œ์—์„œ๋Š” IPv4 ๋˜๋Š” IPv6 ์ฃผ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , TCP ์†Œ์ผ“์„ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
  3. getaddrinfo ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ res ํฌ์ธํ„ฐ๋ฅผ ํ†ตํ•ด ์ฃผ์†Œ ์ •๋ณด๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์–ป์€ struct addrinfo ๋ฆฌ์ŠคํŠธ(res)์—๋Š” ์„œ๋ฒ„์˜ ์ฃผ์†Œ ์ •๋ณด๊ฐ€ ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  4. addrinfo ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTTP GET ์š”์ฒญ์„ ์„œ๋ฒ„์— ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ HTTP ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ์†Œ์ผ“ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  5. ์ž‘์—…์ด ๋๋‚œ ํ›„, ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด freeaddrinfo ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ res์— ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์„ค์ •๋œ getaddrinfo ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•ด ์˜ฌ๋ฐ”๋ฅธ ์„œ๋ฒ„ ์ฃผ์†Œ ์ •๋ณด๋ฅผ ์–ป๊ณ , ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTTP GET ์š”์ฒญ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.