/* * dsock.c - SCO OpenServer socket processing functions for lsof */ /* * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #ifndef lint static char copyright[] = "@(#) Copyright 1995 Purdue Research Foundation.\nAll rights reserved.\n"; static char *rcsid = "$Id: dsock.c,v 1.15 2004/03/10 23:52:12 abe Exp $"; #endif #include "lsof.h" /* * process_socket() - process socket */ void process_socket(i) struct inode *i; /* inode pointer */ { char *cp; struct domain d; unsigned char *fa = (unsigned char *)NULL; int fam, j, k; int fp, lp; unsigned char *la = (unsigned char *)NULL; int p; struct inpcb pcb; short pcbs = 0; short udpsf, udpsl; struct socket s; KA_T sa, spa; struct stdata sd; struct queue sh; short shs = 0; struct tcpcb t; short ts = 0; struct udpdev udp; short udptm = 0; #if OSRV<500 struct sockaddr_in *si; #else /* OSRV>=500 */ struct sockaddr_in si; struct un_dev ud; #endif /* OSRV<500 */ (void) snpf(Lf->type, sizeof(Lf->type), "sock"); /* * Read socket. */ if (!Socktab) { (void) enter_nm("No kernel socket table"); return; } spa = Socktab + (GET_MIN_DEV(i->i_rdev) * sizeof(struct socket *)); if (kread(spa, (char *)&sa, sizeof(sa))) { (void) snpf(Namech, Namechl, "can't read socket pointer at %s", print_kptr(spa, (char *)NULL, 0)); enter_nm(Namech); } if (kread(sa, (char *)&s, sizeof(s))) { (void) snpf(Namech, Namechl, "can't read socket structure at %s", print_kptr(sa, (char *)NULL, 0)); enter_nm(Namech); return; } /* * Read domain structure. */ if (!s.so_proto.pr_domain || kread((KA_T)s.so_proto.pr_domain, (char *)&d, sizeof(d))) { (void) snpf(Namech, Namechl, "can't read protocol domain from %s", print_kptr((KA_T)s.so_proto.pr_domain, (char *)NULL, 0)); enter_nm(Namech); return; } /* * Process by protocol domain. */ switch ((fam = d.dom_family)) { case AF_INET: if (Fnet) Lf->sf |= SELNET; (void) snpf(Lf->type, sizeof(Lf->type), "inet"); printiproto((int)s.so_proto.pr_protocol); Lf->inp_ty = 2; /* * Get protocol control block address from stream head queue structure. */ if (s.so_stp && !readstdata((KA_T)s.so_stp, &sd) && !readsthead((KA_T)sd.sd_wrq, &sh)) shs = 1; if (shs && sh.q_ptr) { enter_dev_ch(print_kptr((KA_T)sh.q_ptr, (char *)NULL, 0)); if (kread((KA_T)sh.q_ptr, (char *)&pcb, sizeof(pcb)) == 0) pcbs = 1; } /* * Print local and remote addresses. */ if (pcbs) { if (pcb.inp_ppcb && strcasecmp(Lf->iproto, "udp") == 0) { /* * If this is a UDP socket file, get the udpdev structure * at the PCB's per-protocol control block address. It * may contain a foreign address. */ if (!kread((KA_T)pcb.inp_ppcb, (char *)&udp, sizeof(udp))) { #if OSRV>=500 if (udp.ud_lsin.sin_addr.s_addr != INADDR_ANY || udp.ud_lsin.sin_port != 0) udpsl = 1; else udpsl = 0; #endif /* OSRV>=500 */ if (udp.ud_fsin.sin_addr.s_addr != INADDR_ANY || udp.ud_fsin.sin_port != 0) udpsf = 1; else udpsf = 0; } } else udpsf = udpsl = 0; /* * Print the local address from the PCB. If there is none, and if * this is a 5.0.0 or greater UDP stream, and if it has a local * address set, use it. */ la = (unsigned char *)&pcb.inp_laddr; lp = (int)ntohs(pcb.inp_lport); #if OSRV>=500 if (((struct in_addr *)la)->s_addr == INADDR_ANY && lp == 0 && udpsl) { la = (unsigned char *)&udp.ud_lsin.sin_addr; lp = (int)ntohs(udp.ud_lsin.sin_port); } #endif /* OSRV>=500 */ /* * Use the PCB's foreign address if it is set. If not, and if this * is a UDP socket file, use the udpdev structure's foreign address * if it's set. */ if (pcb.inp_faddr.s_addr != INADDR_ANY || pcb.inp_fport != 0) { fa = (unsigned char *)&pcb.inp_faddr; fp = (int)ntohs(pcb.inp_fport); } else if (udpsf) { fa = (unsigned char *)&udp.ud_fsin.sin_addr; fp = (int)ntohs(udp.ud_fsin.sin_port); udptm = 1; } if (la || fa) { (void) ent_inaddr(la, lp, fa, fp, AF_INET); if (udptm && !Lf->nma) (void)udp_tm(udp.ud_ftime); } if (pcb.inp_ppcb && strcasecmp(Lf->iproto, "tcp") == 0 && kread((KA_T)pcb.inp_ppcb, (char *)&t, sizeof(t)) == 0) { ts = 1; /* * Save the TCP state from its control block. */ Lf->lts.type = 0; Lf->lts.state.i = (int)t.t_state; } } else { #if OSRV<500 if ((si = (struct sockaddr_in *)&s.so_name)) { la = (unsigned char *)&si->sin_addr; lp = (int)ntohs(si->sin_port); } if ((si = (struct sockaddr_in *)&s.so_peer)) { if (si->sin_addr.s_addr != INADDR_ANY || si->sin_port != 0) { fa = (unsigned char *)&si->sin_addr; fp = (int)ntohs(si->sin_port); } } #else /* OSRV>=500 */ if (s.so_name && !kread((KA_T)s.so_name, (char *)&si, sizeof(si))) { la = (unsigned char *)&si.sin_addr; lp = (int)ntohs(si.sin_port); } if (s.so_peer && !kread((KA_T)s.so_peer, (char *)&si, sizeof(si))) { if (si.sin_addr.s_addr != INADDR_ANY || si.sin_port != 0) { fa = (unsigned char *)&si.sin_addr; fp = (int)ntohs(si.sin_port); } } #endif /* OSRV<500 */ if (la || fa) (void) ent_inaddr(la, lp, fa, fp, AF_INET); } /* * Save options, sizes, states and values. */ #if defined(HASSOOPT) Lf->lts.ltm = (unsigned int)s.so_linger; Lf->lts.opt = (unsigned int)s.so_options; Lf->lts.qlen = (unsigned int)s.so_qlen; Lf->lts.qlim = (unsigned int)s.so_qlimit; Lf->lts.qlens = Lf->lts.qlims = (unsigned char)1; if (ts && t.t_timer[TCPT_KEEP]) { Lf->lts.opt |= SO_KEEPALIVE; Lf->lts.kai = (unsigned long)t.t_timer[TCPT_KEEP]; } #endif /* defined(HASSOOPT) */ #if defined(HASSOSTATE) Lf->lts.ss = s.so_state; #endif /* defined(HASSOSTATE) */ if (ts) { #if defined(HASTCPOPT) Lf->lts.topt = (unsigned int)t.t_flags; Lf->lts.mss = (unsigned long)t.t_maxseg; Lf->lts.msss = (unsigned char)1; #endif /* defined(HASTCPOPT) */ #if defined(HASTCPTPIQ) Lf->lts.rq = (unsigned long)t.t_iqsize; Lf->lts.sq = (unsigned long)t.t_qsize; Lf->lts.rqs = Lf->lts.sqs = 1; #endif /* defined(HASTCPTPIQ) */ if (Fsize) { if (Lf->access == 'r') Lf->sz = (SZOFFTYPE)t.t_iqsize; else if (Lf->access == 'w') Lf->sz = (SZOFFTYPE)t.t_qsize; else Lf->sz = (SZOFFTYPE)(t.t_iqsize + t.t_qsize); Lf->sz_def = 1; } else Lf->off_def = 1; } else if (shs) { if (Fsize) { Lf->sz = (SZOFFTYPE)sh.q_count; Lf->sz_def = 1; } else Lf->off_def = 1; } else Lf->off_def = 1; break; #if OSRV>=500 case AF_UNIX: if (Funix) Lf->sf |= SELUNX; (void) snpf(Lf->type, sizeof(Lf->type), "unix"); /* * Read Unix protocol control block and the Unix address structure. */ enter_dev_ch(print_kptr(sa, (char *)NULL, 0)); Lf->off_def = 1; if (s.so_stp && !readstdata((KA_T)s.so_stp, &sd) && !readsthead((KA_T)sd.sd_wrq, &sh)) { if (!sh.q_ptr || kread((KA_T)sh.q_ptr, (char *)&ud, sizeof(ud))) { (void) snpf(Namech, Namechl, "can't read un_dev from %s", print_kptr((KA_T)sh.q_ptr, (char *)NULL, 0)); break; } if (ud.so_rq) enter_dev_ch(print_kptr((KA_T)ud.so_rq, (char *)NULL, 0)); if (ud.local_addr.sun_family == AF_UNIX) { Lf->inode = (unsigned long)ud.bnd_param.user_addr.inode_no; Lf->inp_ty = 1; ud.local_addr.sun_path[sizeof(ud.local_addr.sun_path) - 1] = '\0'; if (Sfile && is_file_named(ud.local_addr.sun_path, 0)) Lf->sf |= SELNM; if (!Namech[0]) (void) snpf(Namech,Namechl,"%s",ud.local_addr.sun_path); } else if (ud.for_addr.sun_family == AF_UNIX) { Lf->inode = (unsigned long)ud.bnd_param.user_addr.inode_no; Lf->inp_ty = 1; ud.for_addr.sun_path[sizeof(ud.for_addr.sun_path) - 1] = '\0'; if (Sfile && is_file_named(ud.for_addr.sun_path, 0)) Lf->sf |= SELNM; else (void) snpf(Namech,Namechl,"%s",ud.for_addr.sun_path); } else if (ud.other_q) (void) snpf(Namech, Namechl, "->%s", print_kptr((KA_T)ud.other_q, (char *)NULL, 0)); } else (void) snpf(Namech, Namechl, "can't get un_dev"); break; #endif /* OSRV>=500 */ default: printunkaf(fam, 1); } enter_nm(Namech); } /* * udp_tm() - compute time since UDP packet was last sent */ void udp_tm(tm) time_t tm; /* time when packet was sent */ { static char buf[32], *cp; time_t et, lbolt; MALLOC_S len; short hr, min, sec; /* * Read the lightning bolt timer and compute the elapsed time. * No elapsed time is returned if: * the global clock frequency variable, Hz, is negative; * the lightning bolt timer is unavailable; * the lightning bolt time is less than the UDP send time; * the elapsed time is zero. */ if (!Lbolt) return; if (Hz < 0 || kread((KA_T)Lbolt, (char *)&lbolt, sizeof(lbolt)) || tm >= lbolt || (et = (time_t)((lbolt - tm) / Hz)) == 0) return; /* * If the time is 100 hours or greater, return the elapsed time as seconds. */ if (et >= (100 * 60 * 60)) { (void) snpf(buf, sizeof(buf), "%lds", et); cp = &buf[strlen(buf)]; } else { /* * Convert seconds to hours, minutes and seconds. */ hr = (short)(et / (60 * 60)); et %= (60 * 60); min = (short)(et / 60); sec = (short)(et % 60); cp = buf; /* * Format the elapsed time and attach single character suffixes to * represent the units: * * `h' = hours * `m' = minutes * `s' = seconds */ if (hr) { (void) snpf(cp, sizeof(buf) - (cp - buf), "%dh", hr); cp += 2 + ((hr > 9) ? 1 : 0); } if (min) { (void) snpf(cp, sizeof(buf) - (cp - buf), "%dm", min); cp += 2 + ((min > 9) ? 1 : 0); } if (sec) { (void) snpf(cp, sizeof(buf) - (cp - buf), "%ds", sec); cp += 2 + ((sec > 9) ? 1 : 0); } } /* * Add the `` ago'' trailer. Return the string's address and length. */ (void) snpf(cp, sizeof(buf) - (cp - buf), " ago"); len = (MALLOC_S)(strlen(buf) + 1); if (len < 2) return; if (!(cp = (char *)malloc(len))) { (void) fprintf(stderr, "%s: no space for %d character UDP time\n", Pn, len); Exit(1); } (void) snpf(cp, len, "%s", buf); Lf->nma = cp; }