|
|
|
|
 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-02-27 00:58 | 4,731 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - daemonq [ 2005-03-29 15:39 | 602 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-03-29 23:48 | 86 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - beatit [ 2005-03-03 23:27 | 73 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Atu [ 2005-02-28 09:45 | 297 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-02-28 13:33 | 610 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Atu [ 2005-02-28 14:14 | 418 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-02-28 23:02 | 397 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Atu [ 2005-03-02 09:38 | 283 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-03-10 23:42 | 362 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-03-19 23:00 | 369 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - Qiaoxd [ 2005-03-26 22:48 | 82 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - zm1979 [ 2005-03-29 10:17 | 80 byte(s)]
 Re: 为了这个问题都快折腾半个月,郁闷死了!很着急! - xihoujin [ 2005-03-03 17:33 | 130 byte(s)]
|
|
|
|
[Original]
[Print]
[Top]
|
各位老大,怎么没人回答我的问题呀,真的很急,很郁闷。
问题简单的说就是一个网络daemon 程序,通过shell执行一切正常。而通过如下system调用就总是说daemon程序子进程的socketfd 非法, char *cmdline 为daemon程序绝对路径名
int
run_cmd (char *cmdline)
{
int result = SUCCESS, i, max_fd_num;
if (fork () == 0)
{
max_fd_num = getdtablesize ();
for (i = 0; i < max_fd_num; i++)
close (i);
system (cmdline);
exit (0);
}
return result;
}
下面为daemon服务程序中的do_daemon函数
int
do_daemon(int port)
{
struct sockaddr_in sa;
static struct sockaddr_in serv_addr;
int length = sizeof (serv_addr);
int sock, sockl;
pid_t pid;
int boundok = 1;
char reuse = 1;
int devnull;
int cnt;
#ifdef HAVE_SETSID
(void) setsid ();
#endif
if ((pid = fork ()) == -1)
return (-1);
if (pid)
exit (0); /* parent exits */
devnull = open ("/dev/null", O_RDWR, 0);
if (devnull != -1)
{
(void) dup2 (devnull, 0);
(void) dup2 (devnull, 1);
(void) dup2 (devnull, 2);
if (devnull > 2)
(void) close (devnull);
}
sa.sin_family = AF_INET;
bzero ((char *) &sa.sin_addr, sizeof (sa.sin_addr));
sa.sin_port = htons (port);
// to bind proxy with inside interface
if(inside_ip[0])
{
sa.sin_addr.s_addr = inet_addr(inside_ip);
syslog(LOG_INFO,"bind with inside ip : %s:%d",inside_ip,inet_addr(inside_ip));
}
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
syslog (LOG_ERR, "Failed to create socket, %m");
exit (1);
}
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse));
while (bind (sock, (struct sockaddr *) &sa, sizeof (sa)))
{
syslog (LOG_INFO, "Failed to bind port %d, %m,exit!", port);
syslog (LOG_INFO, "Sleeping for 15 seconds");
//test
// exit(0);
sleep(15);
// boundok = 0;
}
#ifndef SOMAXCONN
#define SOMAXCONN 20
#endif
if (listen (sock, SOMAXCONN) < 0)
{
syslog (LOG_ERR, "Failed to listen, %m");
exit (1);
}
#if 0
if (boundok == 0)
{
syslog (LOG_WARNING, "Now ready on port %d", port);
}
#endif
//信号处理
signal (SIGCHLD, xxxx);
while (1)
{
int cstat;
memset (buffer, 0, 1500);
sockl = accept (sock, (struct sockaddr *) 0, (int *) 0);
if (sockl < 0)
{
if (errno == EINTR)
continue;
syslog (LOG_ERR, "Accept failed, %m");
continue;
}
pid = fork ();
if (pid < 0)
{
syslog (LOG_ERR, "Fork failed, %m");
/* 9/8/95 pjc. Make fork failure non-fatal, just throw connection for now */
close (sockl);
continue;
}
if (pid == 0)
break; /* We are the child */
close (sockl);
}
#ifdef HAVE_SETSID
(void) setsid ();
#endif
close (0);
close (1);
close (2);
dup (sockl);
dup (sockl);
dup (sockl);
close (sockl);
close (sock);
}
显然这里把子进程连接套接字重定向到0,可是在子进程调用
getsockname (0, (struct sockaddr *) &serv_addr, &length)时总是报Bad file descriptor.
但是通过shell命令行启动daemon则无问题。
真是急死人了,为这问题都快忙活半个月,郁闷死了
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
如果你能动源码,就自己调试一下
在出错的 getsockname 之前,加一个暂停指令,
如getchar()之类的,或干脆加一个长延时
然后,在暂停的时候到/proc/pid_of_your_procs/fd/目录下,看
是否有0这个文件描述符
然后再进一步调试。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
谢谢,但可能不行。因为自动执行是通过另外一个类似思科ios的shell发出的,该shell没有查看/proc目录的功能,退回到bash才能看到。但也可能在daemon执行时用其它用户登陆到bash就可以看到了。
我有一个想法就是通过bash命令行执行时,没有关闭0、1、2;而通过一楼中run_cmd函数自动执行时,该函数先关闭了所有打开的文件描述符,问题是不是出在这里呢?
另外再提供一个情况就是如果先在bash手动启动该daemon,再进入专用shell再次自动启动同一daemon时,问题虽然没有了,但所有发给console的日志信息全发到client端了,注意子进程的连接套接字为0。
怎么解释这一现象呢,好象发生了关于“0”的混乱。
期盼大家的答复!
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
>但也可能在daemon执行时用其它用户登陆到bash就可以看到了。
这一点你说的对。
确实可能是文件描述符的问题。
我觉得你还是想办法动态调试效果会好一些,
至少比静态分析代码要容易。
这个问题如果可以重现的话,应该很容易解决。
既然你能动它的源码,你就可以在它dup的时候,加一些print指令,
打印出一些必要数据,然后再观察。
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
问题是每次出现,目前我的调试方法也仅限于用syslog函数做日志。
如何实现动态调试,我没用过。是用gdb吗?
我现在特别想知道为什么命令行启动,程序就不出错;而利用run_cmd函数(在一楼)就错;
run_cmd函数看来也没错,因为用它启动其它两个网络服务也一切正常。其它两个daemon的daemon化过程与一楼的do_daemon函数非常类似,只是出问题的daemon 程序添加了父进程和子进程之间的信号灯和共享内存。
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
> 如何实现动态调试,我没用过。是用gdb吗?
在程序运行时,打印或log出你所关心的变量,数据,函数的参数,返回值等;
我觉得你这种情况不需要用gdb.
是否父子进程共享文件描述符和socket过程中出了问题?
多试试吧
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
我也怀疑是父进程和子进程共享的文件描述符及socket出错了,但问题的关键是为什么直接通过命令行执行就没错而用run_cmd调用就出现子进程socket错误呢(注意,命令行执行与run_cmd的区别,前者似乎没有关闭0、1、2,而后者先fork然后在子进程关闭所有文件描述符)。
另外这段do_daemon函数改自fwtk的do_daemon,set_id的调用顺序原来就如此,利用该函数实现的其它程序没有任何问题。
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
关于上述问题的最新进展是,在run_cmd()函数调用该网络daemon后,不再报子进程Bad file descriptor的错误了,而且日志也表明此时子进程连接套接字正常,但是奇怪的是仍然不能正常实现网络代理功能,该在console显示的日志信息却通过上述套接字通过网络传过来(抓包看到的),很是困惑!
再次提醒一下该网络代理daemon通过命令行直接手工启动,则一切正常。恳请得到大家的帮助!
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
把
close (0);
close (1);
close (2);
dup (sockl);
dup (sockl);
dup (sockl);
改成
dup2(sock1,0);
dup2(sock1,1);
dup2(sock1,2);
试试
另外,加点判断,看看下面的open 和dup2有没有成功:
devnull = open ("/dev/null", O_RDWR, 0);
if (devnull != -1)
{
(void) dup2 (devnull, 0);
(void) dup2 (devnull, 1);
(void) dup2 (devnull, 2);
if (devnull > 2)
(void) close (devnull);
}
|
|
|
[Original]
[Print]
[Top]
|
|
|