[mew-dist 25582] Re: SMTP error handling

KOIE Hidetaka ( 鯉江英隆 ) hide at example.com
2004年 10月 26日 (火) 16:08:44 JST


  Message-Id: <20041026.152637.177324940.kazu at example.com>
  Date:       Tue, 26 Oct 2004 15:26:37 +0900 (JST)
  From:       Kazu Yamamoto (山本和彦) <kazu at example.com>
  Subject:    [mew-dist 25581] Re: SMTP error handling

  | >     selectで待つのはwsetだけでよいとおもいます。
  | 
  | いえ、non-blocking の場合は、rset も必要なんですよ。そういうものらしい
  | です。

FreeBSDのman pageですが
connectのEINPROGRESSの説明をみるとwritingで待てとあります。

  | >     毎回timeoutを設定しなおした方がいいそうです。
  | 
  | そうですか。
  | 
  | >     try回ループするかgettimeofdayで残り時間を算出するかは
  | >     気合い次第です。
  | 
  | 残り時間を算出するというのは、どうやるんですか?
  | 残り時間って分りようがないような。

selectで指定するのがsleepする時間ではなくて
時刻を指定する仕様だったら簡単だったのですが..

  | >     connectが完了したとselectがいったときに
  | >     成功したのか失敗したのかを
  | >     getsockopt(SOL_SOCKET,SO_ERROR)で取得した方がいいとおもいます。
  | >     ありがちなのがECONNREFUSEDです。
  | 
  | ああ、やりますかねぇ。

きっと別のところでエラーが検出されるとおもうので
ここでがんばらなくてもよいという考えもあるとおもいます。

サンプルをつくってみたので参考になれば.

--
鯉江英隆 <hide at example.com>
-------------- next part --------------
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>

main(int ac, char *const *av)
{
    const char *node = av[1];
    const char *port = av[2];
    int err;
    int s;
    struct addrinfo hints;
    struct addrinfo *res0;
    struct addrinfo *res;
    struct timeval now;
    struct timeval deadline;
    socklen_t optlen;

    memset(&hints, 0, sizeof hints);
    hints.ai_socktype = SOCK_STREAM;

    err = getaddrinfo(node, port, &hints, &res0);
    if (err) {
	fprintf(stderr, "caonnot resolv: %s\n", gai_strerror(err));
	exit(1);
    }

    for (res = res0; res; res = res->ai_next) {
	char host[100], serv[100];
	err = getnameinfo(res->ai_addr, res->ai_addrlen,
			host, sizeof host,
			serv, sizeof serv,
			NI_NUMERICHOST|NI_NUMERICSERV);
	if (err) {
	    fprintf(stderr, "getnameinfo: %s\n", gai_strerror(err));
	    exit(1);
	}
	printf("connecting %s %s\n", host, serv);

	s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (s < 0) {
	    perror("socket");
	    exit(1);
	}
	if (fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL, 0)) < 0) {
	    perror("fcntl");
	    exit(1);
	}

	err = connect(s, res->ai_addr, res->ai_addrlen);
	if (err == 0) {
	    printf("connected(1)\n");
	    goto done;
	} else {
	    if (errno == EINPROGRESS)
		break;
	    perror("connect(1)");
	    close(s);
	}
    }
    freeaddrinfo(res0);
    if (res == NULL) {
	fprintf(stderr, "failure\n");
	exit(1);
    }

    gettimeofday(&now, NULL);
    deadline = now;
    deadline.tv_sec += 2;

    for (;;) {
	struct timeval timeout;
	fd_set wfds;

	gettimeofday(&now, NULL);
	timeout.tv_sec  = deadline.tv_sec  - now.tv_sec;
	timeout.tv_usec = deadline.tv_usec - now.tv_usec;
	if (timeout.tv_usec < 0) {
	    timeout.tv_sec--;
	    timeout.tv_usec += 1000000;
	}
	if (timeout.tv_sec < 0) {
	    fprintf(stderr, "timedout\n");
	    exit(1);
	}

	FD_ZERO(&wfds);
	FD_SET(s, &wfds);

	err = select(s+1, NULL, &wfds, NULL, &timeout);
	if (err < 0 && errno != EINTR) {
	    perror("select");
	    exit(1);
	}

	if (FD_ISSET(s, &wfds))
	    break;
    }

    optlen = sizeof err;
    if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) < 0) {
	perror("getsockopt");
	exit(1);
    }
    if (err != 0) {
	errno = err;
	perror("connect:getsockopt");
	exit(1);
    }
    printf("connected(2)\n");
done:
    if (close(s) < 0) {
	perror("close");
    }
    exit(0);
}


Mew-dist メーリングリストの案内