add listen-timeout to function as an accept timeout
[socat/sam.git] / fdname.c
blobbc1510329fa13d289e199a827e64a5d43cad77ec
1 /* source: fdname.c */
2 /* Copyright Gerhard Rieger 2003-2008 */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* the subroutine sockname prints the basic info about the address of a socket
6 NOTE: it works on UNIX (kernel) file descriptors, not on libc files! */
8 #include "config.h"
9 #include "xioconfig.h" /* what features are enabled */
11 #include "sysincludes.h"
13 #include "mytypes.h"
14 #include "compat.h"
15 #include "error.h"
16 #include "sycls.h"
17 #include "sysutils.h"
19 #include "filan.h"
22 struct sockopt {
23 int so;
24 char *name;
28 int statname(const char *file, int fd, int filetype, FILE *outfile);
29 int cdevname(int fd, FILE *outfile);
30 int sockname(int fd, FILE *outfile);
31 int unixame(int fd, FILE *outfile);
32 int tcpname(int fd, FILE *outfile);
35 int fdname(const char *file, int fd, FILE *outfile, const char *numform) {
36 struct stat buf = {0};
37 int filetype;
38 Debug1("checking file descriptor %u", fd);
39 if (fd >= 0) {
40 if (Fstat(fd, &buf) < 0) {
41 if (errno == EBADF) {
42 Debug2("fstat(%d): %s", fd, strerror(errno));
43 return -1;
44 } else {
45 Error2("fstat(%d): %s", fd, strerror(errno));
48 filetype = (buf.st_mode&S_IFMT)>>12;
49 if (numform != NULL) {
50 fprintf(outfile, numform, fd);
52 return statname(file, fd, filetype, outfile);
53 } else {
54 if (Stat(file, &buf) < 0) {
55 Error2("stat(\"%s\"): %s", file, strerror(errno));
57 filetype = (buf.st_mode&S_IFMT)>>12;
58 return statname(file, -1, filetype, outfile);
62 #if HAVE_PROC_DIR_FD
63 static int procgetfdname(int fd, char *filepath, size_t pathsize) {
64 static pid_t pid = -1;
65 char procpath[PATH_MAX];
66 int len;
68 /* even if configure has shown that we have /proc, we must check if it
69 exists at runtime, because we might be in a chroot environment */
70 #if HAVE_STAT64
72 struct stat64 buf;
73 if (Stat64("/proc", &buf) < 0) {
74 return -1;
76 if (!S_ISDIR(buf.st_mode)) {
77 return -1;
80 #else /* !HAVE_STAT64 */
82 struct stat buf;
83 if (Stat("/proc", &buf) < 0) {
84 return -1;
86 if (!S_ISDIR(buf.st_mode)) {
87 return -1;
90 #endif /* !HAVE_STAT64 */
92 if (pid < 0) pid = Getpid();
93 snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/fd/%d", pid, fd);
94 if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) {
95 Error4("readlink(\"%s\", %p, "F_Zu"): %s",
96 procpath, filepath, pathsize, strerror(errno));
97 return -1;
99 filepath[len] = '\0';
100 return 0;
102 #endif /* HAVE_PROC_DIR_FD */
104 int statname(const char *file, int fd, int filetype, FILE *outfile) {
105 char filepath[PATH_MAX];
106 int result;
108 filepath[0] = '\0';
109 #if HAVE_PROC_DIR_FD
110 if (fd >= 0) {
111 procgetfdname(fd, filepath, sizeof(filepath));
112 if (filepath[0] == '/') {
113 file = filepath;
116 #endif /* HAVE_PROC_DIR_FD */
117 /* now see for type specific infos */
118 switch (filetype) {
119 case (S_IFIFO>>12): /* 1, FIFO */
120 fputs("pipe", outfile);
121 if (file) fprintf(outfile, " %s", file);
122 break;
123 case (S_IFCHR>>12): /* 2, character device */
124 if (cdevname(fd, outfile) == 0) {
125 if (file) fprintf(outfile, " %s", file);
127 break;
128 case (S_IFDIR>>12): /* 4, directory */
129 fputs("dir", outfile);
130 if (file) fprintf(outfile, " %s", file);
131 break;
132 case (S_IFBLK>>12): /* 6, block device */
133 fputs("blkdev", outfile);
134 if (file) fprintf(outfile, " %s", file);
135 break;
136 case (S_IFREG>>12): /* 8, regular file */
137 fputs("file", outfile);
138 if (file) fprintf(outfile, " %s", file);
139 break;
140 case (S_IFLNK>>12): /* 10, symbolic link */
141 fputs("link", outfile);
142 if (file) fprintf(outfile, " %s", file);
143 break;
144 case (S_IFSOCK>>12): /* 12, socket */
145 #if _WITH_SOCKET
146 if (fd >= 0) {
147 result = sockname(fd, outfile);
148 } else if (file) {
149 fprintf(outfile, "socket %s", file);
150 } else {
151 fputs("socket", outfile);
153 #else
154 Error("SOCKET support not compiled in");
155 return -1;
156 #endif /* !_WITH_SOCKET */
157 break;
159 /* ioctl() */
160 fputc('\n', outfile);
162 return 0;
166 /* character device analysis */
167 /* return -1 on error, 0 if no name was found, or 1 if it printed ttyname */
168 int cdevname(int fd, FILE *outfile) {
169 int ret;
171 if ((ret = Isatty(fd)) < 0) {
172 Error2("isatty(%d): %s", fd, strerror(errno));
173 return -1;
175 if (ret > 0) {
176 char *name;
178 fputs("tty", outfile);
179 if ((name = Ttyname(fd)) != NULL) {
180 fputc(' ', outfile);
181 fputs(name, outfile);
182 return 1;
184 } else {
185 fputs("chrdev", outfile);
187 return 0;
191 #if _WITH_SOCKET
192 int sockname(int fd, FILE *outfile) {
193 #define FDNAME_OPTLEN 256
194 #define FDNAME_NAMELEN 256
195 socklen_t optlen;
196 int opttype;
197 #ifdef SO_ACCEPTCONN
198 int optacceptconn;
199 #endif
200 int result /*0, i*/;
201 char namebuff[FDNAME_NAMELEN];
202 char peerbuff[FDNAME_NAMELEN];
203 /* in Linux these optcodes are 'enum', but on AIX they are bits! */
204 union sockaddr_union sockname, peername; /* the longest I know of */
205 socklen_t namelen;
206 #if 0 && defined(SIOCGIFNAME)
207 /*Linux struct ifreq ifc = {{{ 0 }}};*/
208 struct ifreq ifc = {{ 0 }};
209 #endif
211 optlen = FDNAME_OPTLEN;
213 Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen);
214 #ifdef SO_ACCEPTCONN
215 Getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &optacceptconn, &optlen);
216 #endif
218 namelen = sizeof(sockname);
219 result = Getsockname(fd, &sockname.soa, &namelen);
220 if (result < 0) {
221 Error2("getsockname(%d): %s", fd, strerror(errno));
222 return -1;
225 namelen = sizeof(peername);
226 result = Getpeername(fd, (struct sockaddr *)&peername, &namelen);
227 if (result < 0) {
228 Error2("getpeername(%d): %s", fd, strerror(errno));
231 switch (sockname.soa.sa_family) {
232 #if WITH_UNIX
233 case AF_UNIX:
234 fprintf(outfile, "unix%s%s %s",
235 opttype==SOCK_DGRAM?"datagram":"",
236 #ifdef SO_ACCEPTCONN
237 optacceptconn?"(listening)":
238 #endif
240 sockaddr_unix_info(&sockname.un, namelen,
241 namebuff, sizeof(namebuff)));
242 break;
243 #endif
244 #if WITH_IP4
245 case AF_INET:
246 switch (opttype) {
247 #if WITH_TCP
248 case SOCK_STREAM:
249 fprintf(outfile, "tcp%s %s %s",
250 #ifdef SO_ACCEPTCONN
251 optacceptconn?"(listening)":
252 #endif
254 sockaddr_inet4_info(&sockname.ip4,
255 namebuff, sizeof(namebuff)),
256 sockaddr_inet4_info(&peername.ip4,
257 peerbuff, sizeof(peerbuff)));
258 break;
259 #endif
260 #if WITH_UDP
261 case SOCK_DGRAM:
262 fprintf(outfile, "udp%s %s %s",
263 #ifdef SO_ACCEPTCONN
264 optacceptconn?"(listening)":
265 #endif
267 sockaddr_inet4_info(&sockname.ip4,
268 namebuff, sizeof(namebuff)),
269 sockaddr_inet4_info(&peername.ip4,
270 peerbuff, sizeof(peerbuff)));
271 break;
272 #endif
273 default:
274 fprintf(outfile, "ip %s",
275 sockaddr_inet4_info(&sockname.ip4,
276 namebuff, sizeof(namebuff)));
277 break;
279 break;
280 #endif /* WITH_IP4 */
282 #if WITH_IP6
283 case AF_INET6:
284 switch (opttype) {
285 #if WITH_TCP
286 case SOCK_STREAM:
287 fprintf(outfile, "tcp6%s %s %s",
288 #ifdef SO_ACCEPTCONN
289 optacceptconn?"(listening)":
290 #endif
292 sockaddr_inet6_info(&sockname.ip6,
293 namebuff, sizeof(namebuff)),
294 sockaddr_inet6_info(&peername.ip6,
295 peerbuff, sizeof(peerbuff)));
296 break;
297 #endif
298 #if WITH_UDP
299 case SOCK_DGRAM:
300 fprintf(outfile, "udp6%s %s %s",
301 #ifdef SO_ACCEPTCONN
302 optacceptconn?"(listening)":
303 #endif
305 sockaddr_inet6_info(&sockname.ip6,
306 namebuff, sizeof(namebuff)),
307 sockaddr_inet6_info(&peername.ip6,
308 peerbuff, sizeof(peerbuff)));
309 break;
310 #endif
311 default:
312 fprintf(outfile, "ip6 %s",
313 sockaddr_inet6_info(&sockname.ip6,
314 namebuff, sizeof(namebuff)));
315 break;
317 #endif /* WITH_IP6 */
318 default:
319 fputs("socket", outfile);
322 return result;
323 #undef FDNAME_OPTLEN
324 #undef FDNAME_NAMELEN
326 #endif /* _WITH_SOCKET */