File Coverage

SocketAlarm_util.c
Criterion Covered Total %
statement 55 105 52.3
branch 30 92 32.6
condition n/a
subroutine n/a
pod n/a
total 85 197 43.1


line stmt bran cond sub pod time code
1 1           int snprint_sockaddr(char *buffer, size_t buflen, struct sockaddr *addr) {
2             char tmp[256];
3             int port;
4 1 50         if (addr->sa_family == AF_INET) {
5 1 50         if (!inet_ntop(addr->sa_family, &((struct sockaddr_in*)addr)->sin_addr, tmp, sizeof(tmp)))
6 0           snprintf(tmp, sizeof(tmp), "(invalid?)");
7 1           port= ntohs(((struct sockaddr_in*)addr)->sin_port);
8 1           return snprintf(buffer, buflen, "inet %s:%d", tmp, port);
9             }
10             #ifdef AF_INET6
11 0 0         else if (addr->sa_family == AF_INET6) {
12 0 0         if (!inet_ntop(addr->sa_family, &((struct sockaddr_in6*)addr)->sin6_addr, tmp, sizeof(tmp)))
13 0           snprintf(tmp, sizeof(tmp), "(invalid?)");
14 0           port= ntohs(((struct sockaddr_in6*)addr)->sin6_port);
15 0           return snprintf(buffer, buflen, "inet6 [%s]:%d", tmp, port);
16             }
17             #endif
18             #ifdef AF_UNIX
19 0 0         else if (addr->sa_family == AF_UNIX) {
20 0           return snprintf(buffer, buflen, "unix %s", ((struct sockaddr_un*)addr)->sun_path);
21             }
22             #endif
23 0           return snprintf(buffer, buflen, "(unsupported address family %d)", (int)addr->sa_family);
24             }
25              
26 4           int parse_signal(SV *name_sv) {
27             char *name;
28 4 50         if (looks_like_number(name_sv))
29 4           return SvIV(name_sv);
30 0           name= SvPV_nolen(name_sv);
31 0 0         if (!strcmp(name, "SIGKILL")) return SIGKILL;
32 0 0         if (!strcmp(name, "SIGTERM")) return SIGTERM;
33 0 0         if (!strcmp(name, "SIGUSR1")) return SIGUSR1;
34 0 0         if (!strcmp(name, "SIGUSR2")) return SIGUSR2;
35 0 0         if (!strcmp(name, "SIGALRM")) return SIGALRM;
36 0 0         if (!strcmp(name, "SIGABRT")) return SIGABRT;
37 0 0         if (!strcmp(name, "SIGINT" )) return SIGINT;
38 0 0         if (!strcmp(name, "SIGHUP" )) return SIGHUP;
39 0           croak("Unimplemented signal name %s", name);
40             }
41              
42 49           int fileno_from_sv(SV *sv) {
43             PerlIO *io;
44             GV *gv;
45             SV *rv;
46              
47 49 100         if (!SvOK(sv)) // undef
48 1           return -1;
49              
50 48 100         if (!SvROK(sv)) // scalar, is it only digits?
51 2 50         return looks_like_number(sv)? SvIV(sv) : -1;
52              
53             // is it a globref?
54 46           rv= SvRV(sv);
55 46 50         if (SvTYPE(rv) == SVt_PVGV) {
56 46           io= IoIFP(GvIOp((GV*) rv));
57 46           return PerlIO_fileno(io);
58             }
59            
60 0           return -1;
61             }
62              
63 1           int snprint_fd_table(char *buf, size_t sizeof_buf, int max_fd) {
64             struct stat statbuf;
65             struct sockaddr_storage addr;
66 1           size_t len= 0;
67             int i, j, n_closed;
68              
69 1           len= snprintf(buf, sizeof_buf, "File descriptors {\n");
70 10 100         for (i= 0; i < max_fd; i++) {
71 9           socklen_t addr_len= sizeof(addr);
72 9           char * bufpos= buf + len;
73 9 50         size_t avail= sizeof_buf > len? sizeof_buf - len : 0;
74              
75 9 100         if (fstat(i, &statbuf) < 0) {
76             // Find the next valid fd
77 1016 100         for (j= i+1; j < max_fd; j++)
78 1015 100         if (fstat(j, &statbuf) == 0)
79 2           break;
80 3 100         if (j - i >= 2)
81 2           len += snprintf(bufpos, avail, "%4d-%d: (closed)\n", i, j-1);
82             else
83 1           len += snprintf(bufpos, avail, "%4d: (closed)\n", i);
84 3           i= j;
85             }
86 6 100         else if (!S_ISSOCK(statbuf.st_mode)) {
87             char pathbuf[64];
88             char linkbuf[256];
89             int got;
90 5           snprintf(pathbuf, sizeof(pathbuf), "/proc/%d/fd/%d", getpid(), i);
91 5           pathbuf[sizeof(pathbuf)-1]= '\0';
92 5           got= readlink(pathbuf, linkbuf, sizeof(linkbuf));
93 5 50         if (got > 0 && got < sizeof(linkbuf)) {
    50          
94 5           linkbuf[got]= '\0';
95 5           len += snprintf(bufpos, avail, "%4d: %s\n", i, linkbuf);
96             } else {
97 0           len += snprintf(bufpos, avail, "%4d: (not a socket, no proc/fd?)\n", i);
98             }
99             }
100             else {
101 1 50         if (getsockname(i, (struct sockaddr*) &addr, &addr_len) < 0) {
102 0           len += snprintf(bufpos, avail, "%4d: (getsockname failed)", i);
103             }
104 1 50         else if (addr.ss_family == AF_INET) {
105             char addr_str[INET6_ADDRSTRLEN];
106 1           struct sockaddr_in *sin= (struct sockaddr_in*) &addr;
107 1           inet_ntop(AF_INET, &sin->sin_addr, addr_str, sizeof(addr_str));
108 1           len += snprintf(bufpos, avail, "%4d: inet [%s]:%d", i, addr_str, ntohs(sin->sin_port));
109             }
110 0 0         else if (addr.ss_family == AF_UNIX) {
111 0           struct sockaddr_un *s_un= (struct sockaddr_un*) &addr;
112             char *p;
113             // sanitize socket name, which will be random bytes if anonymous
114 0 0         for (p= s_un->sun_path; *p; p++)
115 0 0         if (*p <= 0x20 || *p >= 0x7F)
    0          
116 0           *p= '?';
117 0           len += snprintf(bufpos, avail, "%4d: unix [%s]", i, s_un->sun_path);
118             }
119             else {
120 0           len += snprintf(bufpos, avail, "%4d: ? socket family %d", i, addr.ss_family);
121             }
122 1           bufpos= buf + len;
123 1 50         avail= sizeof_buf > len? sizeof_buf - len : 0;
124              
125             // Is it connected to anything?
126 1 50         if (getpeername(i, (struct sockaddr*) &addr, &addr_len) == 0) {
127 0 0         if (addr.ss_family == AF_INET) {
128             char addr_str[INET6_ADDRSTRLEN];
129 0           struct sockaddr_in *sin= (struct sockaddr_in*) &addr;
130 0           inet_ntop(AF_INET, &sin->sin_addr, addr_str, sizeof(addr_str));
131 0           len += snprintf(bufpos, avail, " -> [%s]:%d\n", addr_str, ntohs(sin->sin_port));
132             }
133 0 0         else if (addr.ss_family == AF_UNIX) {
134 0           struct sockaddr_un *s_un= (struct sockaddr_un*) &addr;
135             char *p;
136             // sanitize socket name, which will be random bytes if anonymous
137 0 0         for (p= s_un->sun_path; *p; p++)
138 0 0         if (*p <= 0x20 || *p >= 0x7F)
    0          
139 0           *p= '?';
140 0           len += snprintf(bufpos, avail, " -> unix [%s]\n", s_un->sun_path);
141             }
142             else {
143 0           len += snprintf(bufpos, avail, " -> socket family %d\n", addr.ss_family);
144             }
145             }
146             else {
147 1           len++;
148 1 50         if (avail > 0)
149 1           bufpos[0]= '\n';
150             }
151             }
152             }
153             // Did it all fit in the buffer, including NUL terminator?
154 1 50         if (len + 3 <= sizeof_buf) {
155 1           buf[len++]= '}';
156 1           buf[len++]= '\n';
157 1           buf[len ]= '\0';
158             }
159             else { // overwrite last 2 chars to end with newline and NUL
160 0 0         if (sizeof_buf > 1) buf[sizeof_buf-2]= '\n';
161 0 0         if (sizeof_buf > 0) buf[sizeof_buf-1]= '\0';
162 0           len= sizeof_buf-1;
163             }
164 1           return len;
165             }
166              
167             #if 0
168             // neat idea, but no real need for it right now
169             int get_fd_table(AV *out, int max_fd) {
170             struct stat statbuf;
171             size_t len= 0;
172             int i, j, k, n_closed;
173             pid_t pid= 0;
174              
175             for (i= 0; i < max_fd; i++) {
176             if (fstat(i, &statbuf) < 0)
177             continue;
178             else if (!S_ISSOCK(statbuf.st_mode)) {
179             char pathbuf[64];
180             char linkbuf[256];
181             int got;
182             if (!pid) pid= getpid();
183            
184             // Prefer whatever /proc/sel/fd/N says.
185             snprintf(pathbuf, sizeof(pathbuf), "/proc/%d/fd/%d", pid, i);
186             pathbuf[sizeof(pathbuf)-1]= '\0';
187             got= readlink(pathbuf, linkbuf, sizeof(linkbuf));
188             if (got > 0 && got <= sizeof(linkbuf)) {
189             sv= newSVpvn(linkbuf, got);
190             }
191             // for systems without /prod/self/fd, give a simple approximation
192             else if (S_ISREG(statbuf.st_mode)) {
193             sv= newSVpvs("file");
194             } else if (S_ISDIR(statbuf.st_mode)) {
195             sv= newSVpvs("dir");
196             } else if (S_ISCHR(statbuf.st_mode)) {
197             sv= newSVpvs("chardevice");
198             } else if (S_ISBLK(statbuf.st_mode)) {
199             sv= newSVpvs("blockdev");
200             } else if (S_ISFIFO(statbuf.st_mode)) {
201             sv= newSVpvs("pipe");
202             } else {
203             sv= newSVpvs("unknown");
204             }
205             }
206             else {
207             SV *sname= NULL, *pname= NULL;
208             int protocol= -1, family= -1;
209             const char *clname;
210             struct sockaddr_storage addr;
211             socklen_t addr_len= sizeof(addr);
212             if (getsockname(i, (struct sockaddr*) &addr, &addr_len) == 0) {
213             sname= newSVpvn((char*) &addr, addr_len);
214             family= addr.ss_family;
215             }
216              
217             addr_len= sizeof(addr);
218             if (getpeername(i, (struct sockaddr*) &addr, &addr_len) == 0) {
219             pname= newSVpvn((char*) &addr, addr_len);
220             family= addr.ss_family;
221             }
222              
223             if (family == -1) {
224             int len = sizeof(family);
225             if (getsockopt(i, SOL_SOCKET, SO_FAMILY, &family, &len) == -1) {
226             perror("getsockopt SO_FAMILY");
227             family= -1;
228             }
229             }
230              
231             if (protocol == -1) {
232             int len = sizeof(family);
233             if (getsockopt(i, SOL_SOCKET, SO_PROTOCOL, &protocol, &len) == -1) {
234             perror("getsockopt SO_PROTOCOL");
235             protocol= -1;
236             }
237             }
238              
239             if (family == AF_INET) {
240             clname= (protocol == SOCK_STREAM)? "IO::SocketAlarm::FdInfo::TCP"
241             : (protocol == SOCK_DGRAM)? "IO::SocketAlarm::FdInfo::UDP"
242             : "IO::SocketAlarm::FdInfo::INET";
243             }
244             #ifdef AF_INET6
245             else if (family == AF_INET6) {
246             clname= (protocol == SOCK_STREAM)? "IO::SocketAlarm::FdInfo::TCP6"
247             : (protocol == SOCK_DGRAM)? "IO::SocketAlarm::FdInfo::UDP6"
248             : "IO::SocketAlarm::FdInfo::INET6";
249             }
250             #endif
251             #ifdef AF_UNIX
252             else if (family == AF_UNIX) {
253             clname= (protocol == SOCK_STREAM)? "IO::SocketAlarm::FdInfo::UNIX"
254             : (protocol == SOCK_DGRAM)? "IO::SocketAlarm::FdInfo::UNIX_DGRAM"
255             : (protocol == SOCK_SEQPACKET)? "IO::SocketAlarm::FdInfo::UNIX_SEQPACKET"
256             : "IO::SocketAlarm::FdInfo::UNIX";
257             }
258             #endif
259             else clname= "IO::SocketAlarm::FdInfo";
260             }
261             }
262             }
263             #endif
264              
265             // This loads now_ts with the current clock time if it was not already initialized.
266             // Use tv_nsec == -1 as an indicator of being uninitialized.
267 0           bool lazy_build_now_ts(struct timespec *now_ts) {
268 0 0         if (now_ts->tv_nsec == -1) {
269 0 0         if (clock_gettime(CLOCK_MONOTONIC, now_ts) != 0) {
270 0           perror("clock_gettime(CLOCK_MONOTONIC)");
271 0           now_ts->tv_nsec= -1; // ensure remains undefined
272 0           return false; // kind of a serious error... but this runs from the background thread, so can't call 'croak'
273             }
274             }
275 0           return true;
276             }