VNode to Socket

I'm trying to list all open sockets and their PIDs on Solaris 10 in C++.

In Solaris 11, they made this really simple by adding the PID to the mib structs (example, tcpConnCreationProcess in inet/mib2.h). This functionality isn't in Solaris 10, and can be seen in the new netstat source code.

In Solaris 10, I'm trying to use the KVM interface to get this information. Now I have the exact opposite problem where I can get the PIDs and fds without a problem, but getting the actual socket seems to be difficult.

According to some reading, the vnode struct contains the socket object (sonode?).

Is there an easy way to go from where I am to getting the socket information?

//http://www.solarisinternals.com/si/sample/solaris_internals_ch14_file_system_framework.pdf
//http://www.solarisinternals.com/si/reading/vnode.pdf
//http://www.brendangregg.com/DTrace/socketsnoop.d

//compile with:
//	g++ testing.cpp -lkvm -lelf -lnsl -lsocket -m64

#define	_KMEMUSER 1

#include <kvm.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/segments.h>
#include <sys/strsubr.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/vnode.h>

#include <iostream>
#include <stdexcept>

template<typename T> T kernel_get(kvm_t* kd,const T* kernel_pointer)
{
	T temp;

	if(kvm_read(kd,(uintptr_t)kernel_pointer,&temp,sizeof(T))==-1)
		throw std::runtime_error("Error reading from kernel memory.");

	return temp;
}

int main()
{
	char err[4096];
	kvm_t* kd=kvm_open(NULL,NULL,NULL,O_RDONLY,err);

	if(kd==NULL)
	{
		std::cout<<"Could not open kernel virtual memory."<<std::endl;
		return 1;
	}

	while(true)
	{
		proc_t* proc=kvm_nextproc(kd);

		if(proc==NULL)
			break;

		pid_t pid=kernel_get(kd,proc->p_pidp).pid_id;

		user_t* user=&proc->p_user;
		size_t num_entries=user->u_finfo.fi_nfiles;
		size_t socket_count=0;

		for(size_t ii=0;ii<num_entries;++ii)
		{
			uf_entry_t entry=kernel_get(kd,user->u_finfo.fi_list+ii);

			if(entry.uf_file!=NULL)
			{
				file_t file=kernel_get(kd,entry.uf_file);
				vnode_t vnode=kernel_get(kd,file.f_vnode);

				if(vnode.v_type==VSOCK)
				{
					++socket_count;
					//vnode.v_stream? vnode.v_vfsp? vnode.v_data?
				}
			}
		}

		if(socket_count>0)
			std::cout<<pid<<"\t"<<socket_count<<std::endl;
	}

	kvm_close(kd);

	return 0;
}

Use procfs. If you go into for example, /proc/self/path, all of the open descriptors and "file names" for the process are there. Rich Teer's 'Solaris System Programming' has procfs examples. This is what the pfiles command uses.

the download for the example code in the book: Rich Teer's Home Page
and some other code as well.