Unix系统编程:获取网络标识符传递给getaddrinfo
Unix system programming: get a network identifier to be passed to getaddrinfo
我正在阅读一本书中使用系统调用构建服务器的 C 代码。
main
函数如下:
int main(int argc, char* argv[])
{
printf("entered main\n");
struct addrinfo *ailist, *aip, hint;
int sockfd, err, n;
char *host;
if (argc != 1)
{
printf("usage: ruptimed\n");
exit(1);
}
if ((n=sysconf(_SC_HOST_NAME_MAX))<0)
{
n = HOST_NAME_MAX;
}
if((host = malloc(n)) == NULL)
{
printf("malloc error\n");
exit(1);
}
if (gethostname(host, n)<0)
{
printf("gethostname error\n");
exit(1);
}
printf("host: %s\n", host);
printf("Daemonizing\n");
int res = daemonize("ruptimed");
printf("%d\n", res);
printf("Daemonized\n");
memset(&hint, 0, sizeof(hint)); //set to 0 all bytes
printf("hint initialized\n");
hint.ai_flags = AI_CANONNAME;
hint.ai_socktype = SOCK_STREAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
printf("getting addresses\n");
if((err = getaddrinfo(host, "ruptime", &hint, &ailist))!=0)
{
printf("error %s\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
printf("Got addresses\n");
for (aip = ailist; aip!=NULL; aip = aip->ai_next)
{
if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN))>=0)
{
printf("starting to serve\n");
serve(sockfd);
exit(0);
}
}
exit(1);
}
我的问题是使用 gethostname
获取主机名,然后将其用于 getaddrinfo
。
运行 OSX 上的代码 我在 host
字符指针变量中得到了一个名称,例如 pippo's-MacBook-pro.local
。将其传递给 getaddrinfo
会导致错误:nodename nor servname provided, or not known
.
我期待 gethostname
到 return 本地 IP 或本地网络标识符(即使是 localhost 也适合学习)。我怀疑如果没有在机器上进行适当的设置,这样的名称是否可以用于识别(本地)服务器(另外我不记得这本书中有任何关于设置主机名的内容)。
如何获取要传递给 getaddrinfo
的网络标识符(例如本地 IP)?
如果我想使用 gethostname
应该进行哪些更改或设置?
代码
server.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h> //_SC_HOST_NAME_MAX
#include<string.h>
#include<netdb.h> //Here are defined AF_INET and the others of the family
#include<syslog.h> //LOG_ERR
#include<errno.h> //errno
#include <sys/types.h>
#include"utilities.h"
#include "error.h"
#define BUFLEN 128
#define QLEN 10
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 156
#endif
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen);
void serve(int sockfd);
int main(int argc, char* argv[])
{
printf("entered main\n");
struct addrinfo *ailist, *aip, hint;
int sockfd, err, n;
char *host;
if (argc != 1)
{
printf("usage: ruptimed\n");
exit(1);
}
if ((n=sysconf(_SC_HOST_NAME_MAX))<0)
{
n = HOST_NAME_MAX;
}
if((host = malloc(n)) == NULL)
{
printf("malloc error\n");
exit(1);
}
if (gethostname(host, n)<0)
{
printf("gethostname error\n");
exit(1);
}
printf("host: %s\n", host);
printf("Daemonizing\n");
int res = daemonize("ruptimed");
printf("%d\n", res);
printf("Daemonized\n");
memset(&hint, 0, sizeof(hint)); //set to 0 all bytes
printf("hint initialized\n");
hint.ai_flags = AI_CANONNAME;
hint.ai_socktype = SOCK_STREAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
printf("getting addresses\n");
if((err = getaddrinfo(host, "ruptime", &hint, &ailist))!=0)
{
printf("error %s\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
printf("Got addresses\n");
for (aip = ailist; aip!=NULL; aip = aip->ai_next)
{
if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN))>=0)
{
printf("starting to serve\n");
serve(sockfd);
exit(0);
}
}
exit(1);
}
void serve(int sockfd)
{
int clfd;
FILE *fp;
char buf[BUFLEN];
set_cloexec(sockfd);
for(;;)
{
/*After listen, the socket can receive connect requests. accept
retrieves a connect request and converts it into a connection.
The file returned by accept is a socket descriptor connected to the client that
called connect, haing the same coket type and family type. The original
soket remains available to receive otherconneion requests. If we don't care
about client's identity we can set the second (struct sockaddr *addr)
and third parameter (socklen_t *len) to NULL*/
if((clfd = accept(sockfd, NULL, NULL))<0)
{
/*This generates a log mesage.
syslog(int priority, const char *fformat,...)
priority is a combination of facility and level. Levels are ordered from highest to lowest:
LOG_EMERG: emergency system unusable
LOG_ALERT: condiotin that must be fied immediately
LOG_CRIT: critical condition
LOG_ERR: error condition
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
format and other arguments are passed to vsprintf function forf formatting.*/
syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
exit(1);
}
/* set the FD_CLOEXEC file descriptor flag */
/*it causes the file descriptor to be automatically and atomically closed
when any of the exec family function is called*/
set_cloexec(clfd);
/**pg. 542 Since a common operation is to create a pipe to another process
to either read its output or write its input Stdio has provided popen and
pclose: popen creates pipe, close the unused ends of the pipe,
forks a child and call exec to execute cmdstr and
returns a file pointer (connected to std output if "r", to stdin if "w").
pclose closes the stream, waits for the command to terminate*/
if ((fp = popen("/usr/bin/uptime", "r")) == NULL)
{
/*sprintf copy the string passed as second parameter inside buf*/
sprintf(buf, "error: %s\n", strerror(errno));
/*pag 610. send is similar to write. send(int sockfd, const void *buf, size_t nbytes, it flags)*/
send(clfd, buf, strlen(buf),0);
}
else
{
/*get data from the pipe that reads created to exec /usr/bin/uptime */
while(fgets(buf, BUFLEN, fp)!=NULL)
{
/* clfd is returned by accept and it is a socket descriptor
connected to the client that called connect*/
send(clfd, buf, strlen(buf), 0);
}
/*see popen pag. 542*/
pclose(fp);
}
close(clfd);
}
}
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
int fd, err;
int reuse = 1;
if ((fd = socket(addr->sa_family, type, 0))<0)
{
return (-1);
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int))<0)
{
goto errout;
}
if(bind(fd, addr, alen)<0)
{
goto errout;
}
if (type == SOCK_STREAM || type == SOCK_SEQPACKET)
{
if(listen(fd, qlen)<0)
{
goto errout;
}
}
return fd;
errout:
err = errno;
close (fd);
errno = err;
return(-1);
}
utilities.c
:包含demonize
和setcloexec
函数。在 daemonize
函数中,我没有关闭文件描述符进行调试。
#include "utilities.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/time.h>//getrlimit
#include <sys/resource.h>//getrlimit
#include <signal.h> //sigempyset , asigcation (umask?)
#include <sys/resource.h>
#include <fcntl.h> //O_RDWR
#include <stdarg.h>
#include "error.h"
int daemonize(const char *cmd)
{
int fd0, fd1, fd2;
unsigned int i;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/* *Clear file creation mask.*/
umask(0);
/* *Get maximum number of file descriptors. */
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
{
err_quit("%s: can’t get file limit", cmd);
}
/* *Become a session leader to lose controlling TTY. */
if ((pid = fork()) < 0)
{
err_quit("%s: can’t fork", cmd);
}
else if (pid != 0) /* parent */
{
exit(0); //the parent will exit
}
setsid();
/* *Ensure future opens won’t allocate controlling TTYs. */
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
{
err_quit("%s: can’t ignore SIGHUP", cmd);
}
if ((pid = fork()) < 0)
{
err_quit("%s: can’t fork", cmd);
}
else if (pid != 0) /* parent */
{
exit(0);
}
/*
*Change the current working directory to the root so
* we won’t prevent file systems from being unmounted.
*/
if (chdir("/") < 0)
{
err_quit("%s: can’t change directory to /", cmd);
}
/* Close all open file descriptors. */
if (rl.rlim_max == RLIM_INFINITY)
{
rl.rlim_max = 1024;
}
printf("closing file descriptors\n");
/*for (i = 0; i < rl.rlim_max; i++)
{
close(i);
}*/
/* *Attach file descriptors 0, 1, and 2 to /dev/null.*/
//printf not working
/*printf("closed all file descriptors for daemonizing\n");*/
/*fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);*/
/* *Initialize the log file. Daemons do not have a controlling terminal so
they can't write to stderror. We don't want them to write to the console device
because on many workstations the control device runs a windowing system. They can't
write on separate files either. A central daemon error-logging facility is required.
This is the BSD. 3 ways to generate log messages:
1) kernel routines call the log function. These messages can be read from /dev/klog
2) Most user processes (daemons) call syslog to generate log messages. This causes
messages to be sent to the UNIX domain datagram socket /dev/log
3) A user process on this host or on other host connected to this with TCP/ID
can send log messages to UDP port 514. Explicit network programmin is required
(it is not managed by syslog.
The syslogd daemon reads al three of log messages.
openlog is optional since if not called, syslog calls it. Also closelog is optional
openlog(const char *ident, int option, int facility)
It lets us specify ident that is added to each logmessage. option is a bitmask:
LOG_CONS tells that if the log message can't be sent to syslogd via UNIX
domain datagram, the message is written to the console instead.
facility lets the configuration file specify that messages from different
facilities are to be handled differently. It can be specified also in the 'priority'
argument of syslog. LOG_DAEMON is for system deamons
*/
/*
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != 0 || fd1 != 1 || fd2 != 2)
{*/
/*This generates a log mesage.
syslog(int priority, const char *fformat,...)
priority is a combination of facility and level. Levels are ordered from highest to lowest:
LOG_EMERG: emergency system unusable
LOG_ALERT: condiotin that must be fied immediately
LOG_CRIT: critical condition
LOG_ERR: error condition
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
format and other arguments are passed to vsprintf function forf formatting.*/
/*syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2);
exit(1);
}*/
return 0;
}
/*The function set the FD_CLOEXEC flag of the file descriptor already open that
is passed to as parameter. FD_CLOEXEC causes the file descriptor to be
automatically and atomically closed when any of the exec family function is
called*/
int set_cloexec(int fd)
{
int val;
/* retrieve the flags of the file descriptor */
if((val = fcntl(fd, F_GETFD, 0))<0)
{
return -1;
}
/* set the FD_CLOEXEC file descriptor flag */
/*it causes the file descriptor to be automatically and atomically closed
when any of the exec family function is called*/
val |= FD_CLOEXEC;
return (fcntl(fd, F_SETFD, val));
}
错误函数我用了
/* Fatal error unrelated to a system call.
* Print a message and terminate*/
void err_quit (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
err_doit (0, 0, fmt, ap);
va_end (ap);
exit(1);
}
/*Print a message and return to caller.
*Caller specifies "errnoflag"*/
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
char buf [MAXLINE];
vsnprintf (buf, MAXLINE-1, fmt, ap);
if (errnoflag)
{
snprintf (buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s",
strerror (error));
}
strcat(buf, "\n");
fflush(stdout); /*in case stdout and stderr are the same*/
fputs (buf, stderr);
fflush(NULL); /* flushes all stdio output streams*/
}
getaddrinfo
调用中有一个相对简单的错字
if((err = getaddrinfo("host", "ruptime", &hint, &ailist))!=0)
/* ^^^^^^ */
/* Should be the variable host */
{
printf("error %s\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
代码正在查找 "host"
的地址。我还将 "ruptime"
替换为 NULL
,因为 ruptime 不是 /etc/services 中的条目。有关详细信息,请参阅 getaddrinfo(3)。
我正在阅读一本书中使用系统调用构建服务器的 C 代码。
main
函数如下:
int main(int argc, char* argv[])
{
printf("entered main\n");
struct addrinfo *ailist, *aip, hint;
int sockfd, err, n;
char *host;
if (argc != 1)
{
printf("usage: ruptimed\n");
exit(1);
}
if ((n=sysconf(_SC_HOST_NAME_MAX))<0)
{
n = HOST_NAME_MAX;
}
if((host = malloc(n)) == NULL)
{
printf("malloc error\n");
exit(1);
}
if (gethostname(host, n)<0)
{
printf("gethostname error\n");
exit(1);
}
printf("host: %s\n", host);
printf("Daemonizing\n");
int res = daemonize("ruptimed");
printf("%d\n", res);
printf("Daemonized\n");
memset(&hint, 0, sizeof(hint)); //set to 0 all bytes
printf("hint initialized\n");
hint.ai_flags = AI_CANONNAME;
hint.ai_socktype = SOCK_STREAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
printf("getting addresses\n");
if((err = getaddrinfo(host, "ruptime", &hint, &ailist))!=0)
{
printf("error %s\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
printf("Got addresses\n");
for (aip = ailist; aip!=NULL; aip = aip->ai_next)
{
if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN))>=0)
{
printf("starting to serve\n");
serve(sockfd);
exit(0);
}
}
exit(1);
}
我的问题是使用 gethostname
获取主机名,然后将其用于 getaddrinfo
。
运行 OSX 上的代码 我在 host
字符指针变量中得到了一个名称,例如 pippo's-MacBook-pro.local
。将其传递给 getaddrinfo
会导致错误:nodename nor servname provided, or not known
.
我期待 gethostname
到 return 本地 IP 或本地网络标识符(即使是 localhost 也适合学习)。我怀疑如果没有在机器上进行适当的设置,这样的名称是否可以用于识别(本地)服务器(另外我不记得这本书中有任何关于设置主机名的内容)。
如何获取要传递给 getaddrinfo
的网络标识符(例如本地 IP)?
如果我想使用 gethostname
应该进行哪些更改或设置?
代码
server.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h> //_SC_HOST_NAME_MAX
#include<string.h>
#include<netdb.h> //Here are defined AF_INET and the others of the family
#include<syslog.h> //LOG_ERR
#include<errno.h> //errno
#include <sys/types.h>
#include"utilities.h"
#include "error.h"
#define BUFLEN 128
#define QLEN 10
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 156
#endif
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen);
void serve(int sockfd);
int main(int argc, char* argv[])
{
printf("entered main\n");
struct addrinfo *ailist, *aip, hint;
int sockfd, err, n;
char *host;
if (argc != 1)
{
printf("usage: ruptimed\n");
exit(1);
}
if ((n=sysconf(_SC_HOST_NAME_MAX))<0)
{
n = HOST_NAME_MAX;
}
if((host = malloc(n)) == NULL)
{
printf("malloc error\n");
exit(1);
}
if (gethostname(host, n)<0)
{
printf("gethostname error\n");
exit(1);
}
printf("host: %s\n", host);
printf("Daemonizing\n");
int res = daemonize("ruptimed");
printf("%d\n", res);
printf("Daemonized\n");
memset(&hint, 0, sizeof(hint)); //set to 0 all bytes
printf("hint initialized\n");
hint.ai_flags = AI_CANONNAME;
hint.ai_socktype = SOCK_STREAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
printf("getting addresses\n");
if((err = getaddrinfo(host, "ruptime", &hint, &ailist))!=0)
{
printf("error %s\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
printf("Got addresses\n");
for (aip = ailist; aip!=NULL; aip = aip->ai_next)
{
if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN))>=0)
{
printf("starting to serve\n");
serve(sockfd);
exit(0);
}
}
exit(1);
}
void serve(int sockfd)
{
int clfd;
FILE *fp;
char buf[BUFLEN];
set_cloexec(sockfd);
for(;;)
{
/*After listen, the socket can receive connect requests. accept
retrieves a connect request and converts it into a connection.
The file returned by accept is a socket descriptor connected to the client that
called connect, haing the same coket type and family type. The original
soket remains available to receive otherconneion requests. If we don't care
about client's identity we can set the second (struct sockaddr *addr)
and third parameter (socklen_t *len) to NULL*/
if((clfd = accept(sockfd, NULL, NULL))<0)
{
/*This generates a log mesage.
syslog(int priority, const char *fformat,...)
priority is a combination of facility and level. Levels are ordered from highest to lowest:
LOG_EMERG: emergency system unusable
LOG_ALERT: condiotin that must be fied immediately
LOG_CRIT: critical condition
LOG_ERR: error condition
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
format and other arguments are passed to vsprintf function forf formatting.*/
syslog(LOG_ERR, "ruptimed: accept error: %s", strerror(errno));
exit(1);
}
/* set the FD_CLOEXEC file descriptor flag */
/*it causes the file descriptor to be automatically and atomically closed
when any of the exec family function is called*/
set_cloexec(clfd);
/**pg. 542 Since a common operation is to create a pipe to another process
to either read its output or write its input Stdio has provided popen and
pclose: popen creates pipe, close the unused ends of the pipe,
forks a child and call exec to execute cmdstr and
returns a file pointer (connected to std output if "r", to stdin if "w").
pclose closes the stream, waits for the command to terminate*/
if ((fp = popen("/usr/bin/uptime", "r")) == NULL)
{
/*sprintf copy the string passed as second parameter inside buf*/
sprintf(buf, "error: %s\n", strerror(errno));
/*pag 610. send is similar to write. send(int sockfd, const void *buf, size_t nbytes, it flags)*/
send(clfd, buf, strlen(buf),0);
}
else
{
/*get data from the pipe that reads created to exec /usr/bin/uptime */
while(fgets(buf, BUFLEN, fp)!=NULL)
{
/* clfd is returned by accept and it is a socket descriptor
connected to the client that called connect*/
send(clfd, buf, strlen(buf), 0);
}
/*see popen pag. 542*/
pclose(fp);
}
close(clfd);
}
}
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
int fd, err;
int reuse = 1;
if ((fd = socket(addr->sa_family, type, 0))<0)
{
return (-1);
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int))<0)
{
goto errout;
}
if(bind(fd, addr, alen)<0)
{
goto errout;
}
if (type == SOCK_STREAM || type == SOCK_SEQPACKET)
{
if(listen(fd, qlen)<0)
{
goto errout;
}
}
return fd;
errout:
err = errno;
close (fd);
errno = err;
return(-1);
}
utilities.c
:包含demonize
和setcloexec
函数。在 daemonize
函数中,我没有关闭文件描述符进行调试。
#include "utilities.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/time.h>//getrlimit
#include <sys/resource.h>//getrlimit
#include <signal.h> //sigempyset , asigcation (umask?)
#include <sys/resource.h>
#include <fcntl.h> //O_RDWR
#include <stdarg.h>
#include "error.h"
int daemonize(const char *cmd)
{
int fd0, fd1, fd2;
unsigned int i;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/* *Clear file creation mask.*/
umask(0);
/* *Get maximum number of file descriptors. */
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
{
err_quit("%s: can’t get file limit", cmd);
}
/* *Become a session leader to lose controlling TTY. */
if ((pid = fork()) < 0)
{
err_quit("%s: can’t fork", cmd);
}
else if (pid != 0) /* parent */
{
exit(0); //the parent will exit
}
setsid();
/* *Ensure future opens won’t allocate controlling TTYs. */
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
{
err_quit("%s: can’t ignore SIGHUP", cmd);
}
if ((pid = fork()) < 0)
{
err_quit("%s: can’t fork", cmd);
}
else if (pid != 0) /* parent */
{
exit(0);
}
/*
*Change the current working directory to the root so
* we won’t prevent file systems from being unmounted.
*/
if (chdir("/") < 0)
{
err_quit("%s: can’t change directory to /", cmd);
}
/* Close all open file descriptors. */
if (rl.rlim_max == RLIM_INFINITY)
{
rl.rlim_max = 1024;
}
printf("closing file descriptors\n");
/*for (i = 0; i < rl.rlim_max; i++)
{
close(i);
}*/
/* *Attach file descriptors 0, 1, and 2 to /dev/null.*/
//printf not working
/*printf("closed all file descriptors for daemonizing\n");*/
/*fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);*/
/* *Initialize the log file. Daemons do not have a controlling terminal so
they can't write to stderror. We don't want them to write to the console device
because on many workstations the control device runs a windowing system. They can't
write on separate files either. A central daemon error-logging facility is required.
This is the BSD. 3 ways to generate log messages:
1) kernel routines call the log function. These messages can be read from /dev/klog
2) Most user processes (daemons) call syslog to generate log messages. This causes
messages to be sent to the UNIX domain datagram socket /dev/log
3) A user process on this host or on other host connected to this with TCP/ID
can send log messages to UDP port 514. Explicit network programmin is required
(it is not managed by syslog.
The syslogd daemon reads al three of log messages.
openlog is optional since if not called, syslog calls it. Also closelog is optional
openlog(const char *ident, int option, int facility)
It lets us specify ident that is added to each logmessage. option is a bitmask:
LOG_CONS tells that if the log message can't be sent to syslogd via UNIX
domain datagram, the message is written to the console instead.
facility lets the configuration file specify that messages from different
facilities are to be handled differently. It can be specified also in the 'priority'
argument of syslog. LOG_DAEMON is for system deamons
*/
/*
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != 0 || fd1 != 1 || fd2 != 2)
{*/
/*This generates a log mesage.
syslog(int priority, const char *fformat,...)
priority is a combination of facility and level. Levels are ordered from highest to lowest:
LOG_EMERG: emergency system unusable
LOG_ALERT: condiotin that must be fied immediately
LOG_CRIT: critical condition
LOG_ERR: error condition
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
format and other arguments are passed to vsprintf function forf formatting.*/
/*syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2);
exit(1);
}*/
return 0;
}
/*The function set the FD_CLOEXEC flag of the file descriptor already open that
is passed to as parameter. FD_CLOEXEC causes the file descriptor to be
automatically and atomically closed when any of the exec family function is
called*/
int set_cloexec(int fd)
{
int val;
/* retrieve the flags of the file descriptor */
if((val = fcntl(fd, F_GETFD, 0))<0)
{
return -1;
}
/* set the FD_CLOEXEC file descriptor flag */
/*it causes the file descriptor to be automatically and atomically closed
when any of the exec family function is called*/
val |= FD_CLOEXEC;
return (fcntl(fd, F_SETFD, val));
}
错误函数我用了
/* Fatal error unrelated to a system call.
* Print a message and terminate*/
void err_quit (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
err_doit (0, 0, fmt, ap);
va_end (ap);
exit(1);
}
/*Print a message and return to caller.
*Caller specifies "errnoflag"*/
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
char buf [MAXLINE];
vsnprintf (buf, MAXLINE-1, fmt, ap);
if (errnoflag)
{
snprintf (buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s",
strerror (error));
}
strcat(buf, "\n");
fflush(stdout); /*in case stdout and stderr are the same*/
fputs (buf, stderr);
fflush(NULL); /* flushes all stdio output streams*/
}
getaddrinfo
调用中有一个相对简单的错字
if((err = getaddrinfo("host", "ruptime", &hint, &ailist))!=0)
/* ^^^^^^ */
/* Should be the variable host */
{
printf("error %s\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
代码正在查找 "host"
的地址。我还将 "ruptime"
替换为 NULL
,因为 ruptime 不是 /etc/services 中的条目。有关详细信息,请参阅 getaddrinfo(3)。