1 /*
2  * Copyright (c) 2004-2009 Hyperic, Inc.
3  * Copyright (c) 2009 SpringSource, Inc.
4  * Copyright (c) 2009-2010 VMware, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "sigar.h"
20 #include "sigar_private.h"
21 #include "sigar_util.h"
22 #include "sigar_os.h"
23 
24 #include <net/if.h>
25 #include <sys/dk.h>
26 #ifndef __ia64__
27 #include <sys/lwp.h>
28 #endif
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <errno.h>
32 
33 #ifdef _PSTAT64
34 typedef int64_t pstat_int_t;
35 #else
36 typedef int32_t pstat_int_t;
37 #endif
38 
sigar_os_open(sigar_t **sigar)39 int sigar_os_open(sigar_t **sigar)
40 {
41     *sigar = malloc(sizeof(**sigar));
42 
43     /* does not change while system is running */
44     pstat_getstatic(&(*sigar)->pstatic,
45                     sizeof((*sigar)->pstatic),
46                     1, 0);
47 
48     (*sigar)->ticks = sysconf(_SC_CLK_TCK);
49 
50     (*sigar)->last_pid = -1;
51 
52     (*sigar)->pinfo = NULL;
53 
54     (*sigar)->mib = -1;
55 
56     return SIGAR_OK;
57 
58 }
59 
sigar_os_close(sigar_t *sigar)60 int sigar_os_close(sigar_t *sigar)
61 {
62     if (sigar->pinfo) {
63         free(sigar->pinfo);
64     }
65     if (sigar->mib >= 0) {
66         close_mib(sigar->mib);
67     }
68     free(sigar);
69     return SIGAR_OK;
70 }
71 
sigar_os_error_string(sigar_t *sigar, int err)72 char *sigar_os_error_string(sigar_t *sigar, int err)
73 {
74     return NULL;
75 }
76 
sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)77 int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
78 {
79     struct pst_dynamic stats;
80     struct pst_vminfo vminfo;
81     sigar_uint64_t pagesize = sigar->pstatic.page_size;
82     sigar_uint64_t kern;
83 
84     mem->total = sigar->pstatic.physical_memory * pagesize;
85 
86     pstat_getdynamic(&stats, sizeof(stats), 1, 0);
87 
88     mem->free = stats.psd_free * pagesize;
89     mem->used = mem->total - mem->free;
90 
91     pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0);
92 
93     /* "kernel dynamic memory" */
94     kern = vminfo.psv_kern_dynmem * pagesize;
95     mem->actual_free = mem->free + kern;
96     mem->actual_used = mem->used - kern;
97 
98     sigar_mem_calc_ram(sigar, mem);
99 
100     return SIGAR_OK;
101 }
102 
sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)103 int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
104 {
105     struct pst_swapinfo swapinfo;
106     struct pst_vminfo vminfo;
107     int i=0;
108 
109     swap->total = swap->free = 0;
110 
111     while (pstat_getswap(&swapinfo, sizeof(swapinfo), 1, i++) > 0) {
112         swapinfo.pss_nfpgs *= 4;  /* nfpgs is in 512 byte blocks */
113 
114         if (swapinfo.pss_nblksenabled == 0) {
115             swapinfo.pss_nblksenabled = swapinfo.pss_nfpgs;
116         }
117 
118         swap->total += swapinfo.pss_nblksenabled;
119         swap->free  += swapinfo.pss_nfpgs;
120     }
121 
122     swap->used = swap->total - swap->free;
123 
124     pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0);
125 
126     swap->page_in = vminfo.psv_spgin;
127     swap->page_out = vminfo.psv_spgout;
128 
129     swap->allocstall = -1;
130     swap->allocstall_dma = -1;
131     swap->allocstall_dma32 = -1;
132     swap->allocstall_normal = -1;
133     swap->allocstall_movable = -1;
134 
135     return SIGAR_OK;
136 }
137 
get_cpu_metrics(sigar_t *sigar, sigar_cpu_t *cpu, pstat_int_t *cpu_time)138 static void get_cpu_metrics(sigar_t *sigar,
139                             sigar_cpu_t *cpu,
140                             pstat_int_t *cpu_time)
141 {
142     cpu->user = SIGAR_TICK2MSEC(cpu_time[CP_USER]);
143 
144     cpu->sys  = SIGAR_TICK2MSEC(cpu_time[CP_SYS] +
145                                 cpu_time[CP_SSYS]);
146 
147     cpu->nice = SIGAR_TICK2MSEC(cpu_time[CP_NICE]);
148 
149     cpu->idle = SIGAR_TICK2MSEC(cpu_time[CP_IDLE]);
150 
151     cpu->wait = SIGAR_TICK2MSEC(cpu_time[CP_SWAIT] +
152                                 cpu_time[CP_BLOCK]);
153 
154     cpu->irq = SIGAR_TICK2MSEC(cpu_time[CP_INTR]);
155     cpu->soft_irq = 0; /*N/A*/
156     cpu->stolen = 0; /*N/A*/
157 
158     cpu->total =
159         cpu->user + cpu->sys + cpu->nice + cpu->idle + cpu->wait + cpu->irq;
160 }
161 
sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)162 int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
163 {
164     struct pst_dynamic stats;
165 
166     pstat_getdynamic(&stats, sizeof(stats), 1, 0);
167     sigar->ncpu = stats.psd_proc_cnt;
168 
169     get_cpu_metrics(sigar, cpu, stats.psd_cpu_time);
170 
171     return SIGAR_OK;
172 }
173 
174 #define PROC_ELTS 16
175 
sigar_os_proc_list_get(sigar_t *sigar, sigar_proc_list_t *proclist)176 int sigar_os_proc_list_get(sigar_t *sigar,
177                            sigar_proc_list_t *proclist)
178 {
179     int num, idx=0;
180     struct pst_status proctab[PROC_ELTS];
181 
182     while ((num = pstat_getproc(proctab, sizeof(proctab[0]),
183                                 PROC_ELTS, idx)) > 0)
184     {
185         int i;
186 
187         for (i=0; i<num; i++) {
188             SIGAR_PROC_LIST_GROW(proclist);
189             proclist->data[proclist->number++] =
190                 proctab[i].pst_pid;
191         }
192 
193         idx = proctab[num-1].pst_idx + 1;
194     }
195 
196     if (proclist->number == 0) {
197         return errno;
198     }
199 
200     return SIGAR_OK;
201 }
202 
sigar_pstat_getproc(sigar_t *sigar, sigar_pid_t pid)203 static int sigar_pstat_getproc(sigar_t *sigar, sigar_pid_t pid)
204 {
205     int status, num;
206     time_t timenow = time(NULL);
207 
208     if (sigar->pinfo == NULL) {
209         sigar->pinfo = malloc(sizeof(*sigar->pinfo));
210     }
211 
212     if (sigar->last_pid == pid) {
213         if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) {
214             return SIGAR_OK;
215         }
216     }
217 
218     sigar->last_pid = pid;
219     sigar->last_getprocs = timenow;
220 
221     if (pstat_getproc(sigar->pinfo,
222                       sizeof(*sigar->pinfo),
223                       0, pid) == -1)
224     {
225         return errno;
226     }
227 
228     return SIGAR_OK;
229 }
230 
sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_mem_t *procmem)231 int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
232                        sigar_proc_mem_t *procmem)
233 {
234     int pagesize = sigar->pstatic.page_size;
235     int status = sigar_pstat_getproc(sigar, pid);
236     struct pst_status *pinfo = sigar->pinfo;
237 
238     if (status != SIGAR_OK) {
239         return status;
240     }
241 
242     procmem->size =
243         pinfo->pst_vtsize + /* text */
244         pinfo->pst_vdsize + /* data */
245         pinfo->pst_vssize + /* stack */
246         pinfo->pst_vshmsize + /* shared memory */
247         pinfo->pst_vmmsize + /* mem-mapped files */
248         pinfo->pst_vusize + /* U-Area & K-Stack */
249         pinfo->pst_viosize; /* I/O dev mapping */
250 
251     procmem->size *= pagesize;
252 
253     procmem->resident = pinfo->pst_rssize * pagesize;
254 
255     procmem->share = pinfo->pst_vshmsize * pagesize;
256 
257     procmem->minor_faults = pinfo->pst_minorfaults;
258     procmem->major_faults = pinfo->pst_majorfaults;
259     procmem->page_faults =
260         procmem->minor_faults +
261         procmem->major_faults;
262 
263     return SIGAR_OK;
264 }
265 
sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *proctime)266 int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
267                         sigar_proc_time_t *proctime)
268 {
269     int status = sigar_pstat_getproc(sigar, pid);
270     struct pst_status *pinfo = sigar->pinfo;
271 
272     if (status != SIGAR_OK) {
273         return status;
274     }
275 
276     proctime->start_time = pinfo->pst_start;
277     proctime->start_time *= SIGAR_MSEC;
278     proctime->user = pinfo->pst_utime * SIGAR_MSEC;
279     proctime->sys  = pinfo->pst_stime * SIGAR_MSEC;
280     proctime->total = proctime->user + proctime->sys;
281 
282     return SIGAR_OK;
283 }
284 
sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, sigar_proc_state_t *procstate)285 int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
286                          sigar_proc_state_t *procstate)
287 {
288     int status = sigar_pstat_getproc(sigar, pid);
289     struct pst_status *pinfo = sigar->pinfo;
290 
291     if (status != SIGAR_OK) {
292         return status;
293     }
294 
295 
296     SIGAR_SSTRCPY(procstate->name, pinfo->pst_ucomm);
297     procstate->ppid = pinfo->pst_ppid;
298     procstate->tty  = makedev(pinfo->pst_term.psd_major,
299                               pinfo->pst_term.psd_minor);
300     procstate->priority = pinfo->pst_pri;
301     procstate->nice     = pinfo->pst_nice;
302     procstate->threads  = pinfo->pst_nlwps;
303     procstate->processor = pinfo->pst_procnum;
304 
305     /* cast to prevent compiler warning: */
306     /* Case label too big for the type of the switch expression */
307     switch ((int32_t)pinfo->pst_stat) {
308       case PS_SLEEP:
309         procstate->state = 'S';
310         break;
311       case PS_RUN:
312         procstate->state = 'R';
313         break;
314       case PS_STOP:
315         procstate->state = 'T';
316         break;
317       case PS_ZOMBIE:
318         procstate->state = 'Z';
319         break;
320       case PS_IDLE:
321         procstate->state = 'D';
322         break;
323     }
324 
325     return SIGAR_OK;
326 }
327 
328 
329 #define TIME_NSEC(t) \
330     (SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec)
331 
332 #include <mntent.h>
333 
sigar_os_fs_type_get(sigar_file_system_t *fsp)334 int sigar_os_fs_type_get(sigar_file_system_t *fsp)
335 {
336     char *type = fsp->sys_type_name;
337 
338     switch (*type) {
339       case 'h':
340         if (strEQ(type, "hfs")) {
341             fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
342         }
343         break;
344       case 'c':
345         if (strEQ(type, "cdfs")) {
346             fsp->type = SIGAR_FSTYPE_CDROM;
347         }
348         break;
349     }
350 
351     return fsp->type;
352 }
353 
sigar_file_system_list_get(sigar_t *sigar, sigar_file_system_list_t *fslist)354 int sigar_file_system_list_get(sigar_t *sigar,
355                                sigar_file_system_list_t *fslist)
356 {
357     struct mntent *ent;
358 
359     FILE *fp;
360     sigar_file_system_t *fsp;
361 
362     if (!(fp = setmntent(MNT_MNTTAB, "r"))) {
363         return errno;
364     }
365 
366     sigar_file_system_list_create(fslist);
367 
368     while ((ent = getmntent(fp))) {
369         if ((*(ent->mnt_type) == 's') &&
370             strEQ(ent->mnt_type, "swap"))
371         {
372             /*
373              * in this case, devname == "...", for
374              * which statfs chokes on.  so skip it.
375              * also notice hpux df command has no swap info.
376              */
377             continue;
378         }
379 
380         SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
381 
382         fsp = &fslist->data[fslist->number++];
383 
384         SIGAR_SSTRCPY(fsp->dir_name, ent->mnt_dir);
385         SIGAR_SSTRCPY(fsp->dev_name, ent->mnt_fsname);
386         SIGAR_SSTRCPY(fsp->sys_type_name, ent->mnt_type);
387         SIGAR_SSTRCPY(fsp->options, ent->mnt_opts);
388         sigar_fs_type_init(fsp);
389     }
390 
391     endmntent(fp);
392 
393     return SIGAR_OK;
394 }
395 
create_fsdev_cache(sigar_t *sigar)396 static int create_fsdev_cache(sigar_t *sigar)
397 {
398     sigar_file_system_list_t fslist;
399     int i;
400     int status =
401         sigar_file_system_list_get(sigar, &fslist);
402 
403     if (status != SIGAR_OK) {
404         return status;
405     }
406 
407     sigar->fsdev = sigar_cache_new(15);
408 
409     for (i=0; i<fslist.number; i++) {
410         sigar_file_system_t *fsp = &fslist.data[i];
411 
412         if (fsp->type == SIGAR_FSTYPE_LOCAL_DISK) {
413             sigar_cache_entry_t *ent;
414             struct stat sb;
415 
416             if (stat(fsp->dir_name, &sb) < 0) {
417                 continue;
418             }
419 
420             ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb));
421             ent->value = strdup(fsp->dev_name);
422         }
423     }
424 
425     return SIGAR_OK;
426 }
427 
sigar_get_mib_info(sigar_t *sigar, struct nmparms *parms)428 static int sigar_get_mib_info(sigar_t *sigar,
429                               struct nmparms *parms)
430 {
431     if (sigar->mib < 0) {
432         if ((sigar->mib = open_mib("/dev/ip", O_RDONLY, 0, 0)) < 0) {
433             return errno;
434         }
435     }
436     return get_mib_info(sigar->mib, parms);
437 }
438 
439 /* wrapper around get_physical_stat() */
sigar_get_physical_stat(sigar_t *sigar, int *count)440 static int sigar_get_physical_stat(sigar_t *sigar, int *count)
441 {
442     int status;
443     unsigned int len;
444     struct nmparms parms;
445 
446     len = sizeof(*count);
447     parms.objid = ID_ifNumber;
448     parms.buffer = count;
449     parms.len = &len;
450 
451     if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
452         return status;
453     }
454 
455     len = sizeof(nmapi_phystat) * *count;
456 
457     if (sigar->ifconf_len < len) {
458         sigar->ifconf_buf = realloc(sigar->ifconf_buf, len);
459         sigar->ifconf_len = len;
460     }
461 
462     if (get_physical_stat(sigar->ifconf_buf, &len) < 0) {
463         return errno;
464     }
465     else {
466         return SIGAR_OK;
467     }
468 }
469 
470 #define SIGAR_IF_NAMESIZE 16
471 /* hpux if_indextoname() does not work as advertised in 11.11 */
sigar_if_indextoname(sigar_t *sigar, char *name, int index)472 static int sigar_if_indextoname(sigar_t *sigar,
473                                 char *name,
474                                 int index)
475 {
476     int i, status, count;
477     nmapi_phystat *stat;
478 
479     if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) {
480         return status;
481     }
482 
483     for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf;
484          i<count;
485          i++, stat++)
486     {
487         if (stat->if_entry.ifIndex == index) {
488             strncpy(name, stat->nm_device, SIGAR_IF_NAMESIZE);
489             return SIGAR_OK;
490         }
491     }
492 
493     return ENXIO;
494 }
495 
get_mib_ifstat(sigar_t *sigar, const char *name, mib_ifEntry *mib)496 static int get_mib_ifstat(sigar_t *sigar,
497                           const char *name,
498                           mib_ifEntry *mib)
499 {
500     int i, status, count;
501     nmapi_phystat *stat;
502 
503     if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) {
504         return status;
505     }
506 
507     for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf;
508          i<count;
509          i++, stat++)
510     {
511         if (strEQ(stat->nm_device, name)) {
512             memcpy(mib, &stat->if_entry, sizeof(*mib));
513             return SIGAR_OK;
514         }
515     }
516 
517     return ENXIO;
518 }
519 
520 
sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig)521 int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name,
522                                         sigar_net_interface_config_t *ifconfig)
523 {
524     int sock;
525     struct if_laddrreq iflr;
526 
527     if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
528         return errno;
529     }
530 
531     SIGAR_SSTRCPY(iflr.iflr_name, name);
532 
533     if (ioctl(sock, SIOCGLIFADDR, &iflr) == 0) {
534         struct in6_addr *addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr);
535 
536         sigar_net_address6_set(ifconfig->address6, addr);
537         sigar_net_interface_scope6_set(ifconfig, addr);
538 
539         if (ioctl(sock, SIOCGLIFNETMASK, &iflr) == 0) {
540             addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr);
541             ifconfig->prefix6_length = 10; /*XXX*/
542         }
543     }
544 
545     close(sock);
546     return SIGAR_OK;
547 }
548 
net_conn_get_udp_listen(sigar_net_connection_walker_t *walker)549 static int net_conn_get_udp_listen(sigar_net_connection_walker_t *walker)
550 {
551     sigar_t *sigar = walker->sigar;
552     int flags = walker->flags;
553     int status, count, i;
554     unsigned int len;
555     mib_udpLsnEnt *entries;
556     struct nmparms parms;
557 
558     len = sizeof(count);
559     parms.objid = ID_udpLsnNumEnt;
560     parms.buffer = &count;
561     parms.len = &len;
562 
563     if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
564         return status;
565     }
566 
567     if (count <= 0) {
568         return ENOENT;
569     }
570 
571     len =  count * sizeof(*entries);
572     entries = malloc(len);
573     parms.objid = ID_udpLsnTable;
574     parms.buffer = entries;
575     parms.len = &len;
576 
577     if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
578         free(entries);
579         return status;
580     }
581 
582     for (i=0; i<count; i++) {
583         sigar_net_connection_t conn;
584         mib_udpLsnEnt *entry = &entries[i];
585 
586         SIGAR_ZERO(&conn);
587 
588         conn.type = SIGAR_NETCONN_UDP;
589 
590         conn.local_port  = (unsigned short)entry->LocalPort;
591         conn.remote_port = 0;
592 
593         sigar_net_address_set(conn.local_address,
594                               entry->LocalAddress);
595 
596         sigar_net_address_set(conn.remote_address, 0);
597 
598         conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
599 
600         if (walker->add_connection(walker, &conn) != SIGAR_OK) {
601             break;
602         }
603     }
604 
605     free(entries);
606     return SIGAR_OK;
607 }
608 
net_conn_get_udp(sigar_net_connection_walker_t *walker)609 static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
610 {
611     int status = SIGAR_OK;
612 
613     if (walker->flags & SIGAR_NETCONN_SERVER) {
614         status = net_conn_get_udp_listen(walker);
615     }
616 
617     return status;
618 }
619 
620 #define IS_TCP_SERVER(state, flags) \
621     ((flags & SIGAR_NETCONN_SERVER) && (state == TCLISTEN))
622 
623 #define IS_TCP_CLIENT(state, flags) \
624     ((flags & SIGAR_NETCONN_CLIENT) && (state != TCLISTEN))
625 
net_conn_get_tcp(sigar_net_connection_walker_t *walker)626 static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
627 {
628     sigar_t *sigar = walker->sigar;
629     int flags = walker->flags;
630     int status, count, i;
631     unsigned int len;
632     mib_tcpConnEnt *entries;
633     struct nmparms parms;
634 
635     len = sizeof(count);
636     parms.objid = ID_tcpConnNumEnt;
637     parms.buffer = &count;
638     parms.len = &len;
639 
640     if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
641         return status;
642     }
643 
644     if (count <= 0) {
645         return ENOENT;
646     }
647 
648     len =  count * sizeof(*entries);
649     entries = malloc(len);
650     parms.objid = ID_tcpConnTable;
651     parms.buffer = entries;
652     parms.len = &len;
653 
654     if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) {
655         free(entries);
656         return status;
657     }
658 
659     for (i=0; i<count; i++) {
660         sigar_net_connection_t conn;
661         mib_tcpConnEnt *entry = &entries[i];
662         int state = entry->State;
663 
664         if (!(IS_TCP_SERVER(state, flags) ||
665               IS_TCP_CLIENT(state, flags)))
666         {
667             continue;
668         }
669 
670         SIGAR_ZERO(&conn);
671 
672         switch (state) {
673           case TCCLOSED:
674             conn.state = SIGAR_TCP_CLOSE;
675             break;
676           case TCLISTEN:
677             conn.state = SIGAR_TCP_LISTEN;
678             break;
679           case TCSYNSENT:
680             conn.state = SIGAR_TCP_SYN_SENT;
681             break;
682           case TCSYNRECEIVE:
683             conn.state = SIGAR_TCP_SYN_RECV;
684             break;
685           case TCESTABLISED:
686             conn.state = SIGAR_TCP_ESTABLISHED;
687             break;
688           case TCFINWAIT1:
689             conn.state = SIGAR_TCP_FIN_WAIT1;
690             break;
691           case TCFINWAIT2:
692             conn.state = SIGAR_TCP_FIN_WAIT2;
693             break;
694           case TCCLOSEWAIT:
695             conn.state = SIGAR_TCP_CLOSE_WAIT;
696             break;
697           case TCCLOSING:
698             conn.state = SIGAR_TCP_CLOSING;
699             break;
700           case TCLASTACK:
701             conn.state = SIGAR_TCP_LAST_ACK;
702             break;
703           case TCTIMEWAIT:
704             conn.state = SIGAR_TCP_TIME_WAIT;
705             break;
706           case TCDELETETCB:
707           default:
708             conn.state = SIGAR_TCP_UNKNOWN;
709             break;
710         }
711 
712         conn.local_port  = (unsigned short)entry->LocalPort;
713         conn.remote_port = (unsigned short)entry->RemPort;
714         conn.type = SIGAR_NETCONN_TCP;
715 
716         sigar_net_address_set(conn.local_address, entry->LocalAddress);
717         sigar_net_address_set(conn.remote_address, entry->RemAddress);
718 
719         conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
720 
721         if (walker->add_connection(walker, &conn) != SIGAR_OK) {
722             break;
723         }
724     }
725 
726     free(entries);
727 
728     return SIGAR_OK;
729 }
730 
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)731 int sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
732 {
733     int status;
734 
735     if (walker->flags & SIGAR_NETCONN_TCP) {
736         status = net_conn_get_tcp(walker);
737 
738         if (status != SIGAR_OK) {
739             return status;
740         }
741     }
742 
743     if (walker->flags & SIGAR_NETCONN_UDP) {
744         status = net_conn_get_udp(walker);
745 
746         if (status != SIGAR_OK) {
747             return status;
748         }
749     }
750 
751     return SIGAR_OK;
752 }
753 
754 #define tcpsoff(x) sigar_offsetof(sigar_tcp_t, x)
755 
756 static struct {
757     unsigned int id;
758     size_t offset;
759 } tcps_lu[] = {
760 #if 0
761     { ID_tcpRtoAlgorithm, tcpsoff(xxx) },
762     { ID_tcpRtoMin, tcpsoff(xxx) },
763     { ID_tcpRtoMax, tcpsoff(xxx) },
764     { ID_tcpMaxConn, tcpsoff(max_conn) },
765 #endif
766     { ID_tcpActiveOpens, tcpsoff(active_opens) },
767     { ID_tcpPassiveOpens, tcpsoff(passive_opens) },
768     { ID_tcpAttemptFails, tcpsoff(attempt_fails) },
769     { ID_tcpEstabResets, tcpsoff(estab_resets) },
770     { ID_tcpCurrEstab, tcpsoff(curr_estab) },
771     { ID_tcpInSegs, tcpsoff(in_segs) },
772     { ID_tcpOutSegs, tcpsoff(out_segs) },
773     { ID_tcpRetransSegs, tcpsoff(retrans_segs) },
774     { ID_tcpInErrs, tcpsoff(in_errs) },
775     { ID_tcpOutRsts, tcpsoff(out_rsts) }
776 };
777