Where is a UNIX socket on the filesystem? - c

I am using Unix domain sockets. Want to know about its location in the system.
If I am creating a socketpair using a system call
socketpair(AF_UNIX,SOCK_STREAM,0,fd) ;
I have read it is unnamed socket (a socket that is not been bound to pathname using bind).
On the other hand, named socket or better a socket bound to file system path name using bind call get stored in some directory we specify.
for example
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};
here sun_path can be /tmp/sock file.
So, similarly , I want to know does unnamed socket have any location in the system or anywhere in the memory or kernel ?
Thanks in advance.

I'm no kernel expert, so take this as an (educated?) guess.
#include <sys/un.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
int main()
{
struct sockaddr_un sun;
socklen_t socklen;
int fd[2];
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd) < 0) {
perror("socketpair");
return 111;
}
socklen = sizeof(sun);
memset(&sun, 0, sizeof sun);
sun.sun_path[0] = '!'; /* replace with any character */
if(getsockname(fd[0], (struct sockaddr *)&sun, &socklen) < 0) {
perror("getsockname");
return 111;
}
printf("sunpath(%s)\n", sun.sun_path);
return 0;
}
This program says the socket doesn't have a corresponding path, so my guess is that a unix socketpair is never associated with a filename -- it only stays alive as a data structure inside the kernel until all references are closed.
A better answer is welcome of course :)

Related

datagram sockets in c. looks like parent process never binds

i have tried to execute the following code of two processes.
the child sends a datagram and the parent is supposed to receive it and print it
. The parent process looks like it does not bind (error: address already in use).
any ideas?
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <stdio.h>
#define N 9
int main(int argc, char *argv[]) {
int pid,s,n,addrlen;
char msg[N];
struct sockaddr_un addr;
addr.sun_family=AF_UNIX;
strcpy(addr.sun_path,"test-socket"); // pathname
addrlen=sizeof(addr.sun_family)+strlen(addr.sun_path);
if (!(pid=fork())) {
printf("child\n");
s=socket(PF_UNIX,SOCK_DGRAM,0);
sleep(3); /* wait for parent to bind */
sendto(s,"hi parent",9,0,(struct sockaddr*)&addr,addrlen);
printf("child sent\n");
close(s);
return(0);
}
printf("father\n");
s=socket(PF_UNIX,SOCK_DGRAM,0);
bind(s,(struct sockaddr *)&addr,addrlen); // error here
n=recvfrom(s,msg,N,0,NULL,NULL);
if(n<=0){printf("error\n");}
msg[n]='\0'; printf("%s\n",msg);
close(s);
unlink("test-socket");
return(0);
}
Why don't you bind before fork? Waiting for a fixed amount of time and then sending data is not a good idea
On my system (Mac OS X Snow Leopard) sockaddr_un looks like this:
struct sockaddr_un {
unsigned char sun_len; /* sockaddr len including null */
sa_family_t sun_family; /* [XSI] AF_UNIX */
char sun_path[104]; /* [XSI] path name (gag) */
};
Assuming yours looks something similar, your calculation of addrlen (sizeof(addr.sun_family)+strlen(addr.sun_path)) is wrong, which will result in calls that use it sendto and bind using a different path than the one you think you are using – it will be truncated.
Your call to bind is probably creating a socket file named something like test-socke (note the missing t at the end). When your program finishes it tries to unlink the non-existing file test-socket. This means that the next time you run the program the file you are trying to bind to (test-socke) already exists, and so bind will fail in the way you are seeing.
To fix this you need to make sure you are using the correct length for addrlen. The simplest and safest way is probably to use sizeof(addr):
addrlen = sizeoff(addr);
You could also use SUN_LEN if it is available, which might save you copying a few bytes if that concerns you:
addrlen = SUN_LEN(&addr);
If you want to calculate the correct length yourself (e.g. SUN_LEN isn’t availble) then try this:
addrlen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path);
(This is adapted from the definition of SUN_LEN on my system.)

Why does bind (socket binding) method generate a file in the current directory?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
int sock;
struct sockaddr sock_name = {AF_UNIX, "Fred"};
socklen_t len=sizeof(struct sockaddr)+5;
if( (sock=socket(AF_UNIX,SOCK_STREAM,0)) ==-1)
{
printf("error creating socket");
return -1;
}
if( bind(sock,&sock_name,len) != 0 )
{
printf("socket bind error");
return -1;
}
close(sock);
return 0;
}
After the first run, this program keeps reporting binding error. I tried to change the name of the sockaddr. It works again. But after changing it back to "Fred" (in this case), the error continues. Is something being stored in memory I didn't clear? Why does this happen and how could I fix it?
I guess I have found the problem. After the first run, I find a file named "Fred" in the current directory. I removed the file and my program worked again. Why does bind method generate a file in the current directory?
When used with Unix domain sockets, bind(2) will create a special file at the specified path. This file identifies the socket in much the same way a host and port identify a TCP or UDP socket. Just like you can't call bind twice to associate two different sockets with a given host and port*, you can't associate more than one Unix socket
But why doesn't the file disappear when you call close(2)? After all, closing a TCP socket makes the host and port it was bound to available for other sockets.**
That's a good question, and the short answer is, it just doesn't.
So it's customary (at least in example code) to call unlink(2) prior to binding. The Unix domain socket section of Beej's IPC guide has a nice example of this.
*With versions of the Linux kernel >= 3.9, this isn't exactly true.
**After TIME_WAIT or immediately if you use the SO_REUSEADDR socket option.
EDIT
You said this is your teacher's code, but I suggest that you replace your printf calls with perror:
if( bind(sock,&sock_name,len) != 0 )
{
perror("socket bind error");
return -1;
}
...which will print out a human-readable representation of the real problem encountered by bind(2):
$ ./your-example-executable
$ ./your-example-executable
socket bind error: Address already in use
Programming doesn't have to be so inscrutable!
When you successfully open a socket, it stays open until it is closed (even if your program terminates).
It appears that the question code is not closing the socket in the event of an (such as the failure of bind()).
Two processes cannot generally open the same socket.
Each time the code is executed, it is a new process, attempting to open the same socket.
The code needs a better scheme to handle errors.
This is how I would do it:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MY_FALSE (0)
#define MY_TRUE (-1)
int main()
{
int rCode=0;
int sock = (-1);
char *socketFile = "Fred");
struct sockaddr sock_name = {AF_UNIX, socketFile};
socklen_t len=sizeof(struct sockaddr)+5;
int bound = MY_FALSE;
if((sock=socket(AF_UNIX,SOCK_STREAM,0)) ==-1)
{
printf("error creating socket");
rCode=(-1);
goto CLEANUP;
}
if( bind(sock,&sock_name,len) != 0 )
{
printf("socket bind error");
rCode=(-1);
goto CLEANUP;
}
bound=MY_TRUE;
This single 'cleanup' area can be used to free allocated memory, close sockets & files, etc.
CLEANUP:
if((-1) != sock)
close(sock);
if(bound)
unlink(socketFile);
return 0;
}

Similar to getifaddrs on old glibc version

There is very useful funcion call getifaddrs which retrieves all machin network addresses. The problem is that I'm using old glibc version which doesn't have this function. Is there any replacement for it? I was looking and found getipnodebyname but it is unuseful when address isn't mapped in /etc/hosts file.
To add to the previous answer, here is an example for the SIOCGIFCONF-approach. You have to do something like this:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int fd;
int get_iface_list(struct ifconf *ifconf)
{
int rval;
if((rval = ioctl(fd, SIOCGIFCONF , (char*) ifconf )) < 0 )
perror("ioctl(SIOGIFCONF)");
return rval;
}
int main()
{
static struct ifreq ifreqs[100];
static struct ifconf ifc;
char *ptr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
return 1;
ifc.ifc_buf = (char*) (ifreqs);
ifc.ifc_len = sizeof(ifreqs);
if(get_iface_list(&ifc) < 0) return -1;
/* Go through the list of interfaces */
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len;)
{
struct ifreq *ifr = (struct ifreq*)ptr;
int len = (sizeof(struct sockaddr) > ifr->ifr_addr.sa_len) ?
sizeof(struct sockaddr) : ifr->ifr_addr.sa_len;
ptr += sizeof(ifr->ifr_name) + len;
/* Do what you need with the ifr-structure.
* ifr->ifr_addr contains either sockaddr_dl,
* sockaddr_in or sockaddr_in6 depending on
* what addresses and L2 protocols the interface
* has associated in it.
*/
}
close(fd);
return 0;
}
There are some gotchas, of course. According to Unix Network Programming chapter 17.6 ioctl(fd, SIOCGIFCONF, array) may not return an error on some platforms if the array pointed in the argument is too small. The data will then be concatenated. Only way to work around this is to call ioctl() in a loop until you get same result length twice while increasing the size of the array. Of course, since this is 2012, I'm not sure how relevant this is anymore.
Size of ifreqs array is purely a guess in this case. Keep in mind though that the array will contain one struct ifreq for every L2 and L3 address associated with a interface. For example, assuming you have also IPv6 addresses, for lo-interface you'd get three entries: ethernet, IPv4 and IPv6. Therefore reserve enough space or apply the kludge.
To get broadcast addresses and other additional information, you will need to additional ioctl() calls in the loop. All possible options depends on what your OS provides, of course.
For more information I'd recommend reading Unix Network Programming by W. Richard Stevens. It is the most comprehesive book about this subject.
The traditional way to do the equivalent was with the SIOCGIFCONF operation to ioctl. Any socket can be used for the operation. It's not as easy as a single function call though.

Raw Sockets on BSD Operating Systems

I've been writing some sockets code in C. I need modify packet headers and control how they're sent out, so I took the raw sockets approach. However, the code I wrote will not compile on BSD systems (Mac OS X/Darwin, FreeBSD, etc.)
I've done a bunch of research on this and have found that BSD systems can't handle raw sockets the way Linux (or even Windows) does. From what I've read, it seems I need to use bpf (berkley packet filter), but I can't figure out how bpf works or how I would go about using it with raw sockets.
If someone could shed some light on this one, I'd be very excited :D
P.S. I'll even be happy with some source code showing how raw sockets are handled in a BSD environment. It doesn't have to be a guide or explanation. I just want to see how it works.
Using raw sockets isn't hard but it's not entirely portable. For instance, both in BSD and in Linux you can send whatever you want, but in BSD you can't receive anything that has a handler (like TCP and UDP).
Here is an example program that sends a SYN.
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
int
main(int argc, char *argv[])
{
int s, rc;
struct protoent *p;
struct sockaddr_in sin;
struct tcphdr tcp;
if (argc != 2)
errx(EX_USAGE, "%s addr", argv[0]);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = 0;
/* Parse command line address. */
if (inet_pton(AF_INET, argv[1], &sin.sin_addr) <= 0)
err(EX_USAGE, "Parse address");
/* Look up tcp although it's 6. */
p = getprotobyname("tcp");
if (p == NULL)
err(EX_UNAVAILABLE, "getprotobyname");
/* Make a new shiny (Firefly) socket. */
s = socket(AF_INET, SOCK_RAW, p->p_proto);
if (s < 0)
err(EX_OSERR, "socket");
memset(&tcp, 0, sizeof(tcp));
/* Fill in some random stuff. */
tcp.th_sport = htons(4567);
tcp.th_dport = htons(80);
tcp.th_seq = 4; /* Chosen by fair dice roll. */
tcp.th_ack = 0;
tcp.th_off = 5;
tcp.th_flags = TH_SYN;
tcp.th_win = htonl(65535);
rc = sendto(s, &tcp, sizeof(tcp), 0, (struct sockaddr *)&sin,
sizeof(sin));
printf("Wrote %d bytes\n", rc);
return 0;
}
Of course, more BSD-specific solutions are available. For instance you could use divert(4) to intercept packets as they traverse your system and alter them.

problem establishing a TCP socket connection

I'm not a software person, but I could really use some advice.
I'm writing a C program (cut/paste below) to establish a TCP socket connection from my Mac Pro to a Windows XP-based test-instrument sitting next to it over LAN (Ethernet). The program compiles without any warnings or errors. But executing the code using GNU Debugger, I can see it exits at 'exit(2)' which is the "if(connect(MySocket" line. There's no timeout, it just exits immediately.
I compile using:
gcc -g -Wall talk2me.c -o talk2me
but I don't get any hints in the output nor when debugging at to what might be the issue.
I'm sure the 10.0.1.100 and port 5025 are correct (using Matlab code I can communicate fine using these parameters). Any idea where else I could look to debug?
Outside of the code itself, are there any other requirements (perhaps system-level) that need to be satisfied (like running the code from a certain directory, or setting a parameter in unix to allow connections, etc.)? It may be something obvious that I'm missing because I'm a hardware guy, so feel free to assume I'm doing something stupid. I can run a 'hello world' program fine, it that helps. Thanks in advance, ggk
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h> //for inet_addr
#include <unistd.h> // for function 'close'
int main(void)
{
int MySocket;
if((MySocket=socket(PF_INET,SOCK_STREAM,0))==-1) exit(1);
struct in_addr {
unsigned long s_addr;
};
struct sockaddr_in {
short int sin_family; // Address family
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Padding
};
struct sockaddr_in MyAddress;
// Initialize the whole structure to zero
memset(&MyAddress,0,sizeof(struct sockaddr_in));
// Then set the individual fields
MyAddress.sin_family=PF_INET; // IPv4
MyAddress.sin_port=htons(5025); // Port number used by instrument
MyAddress.sin_addr.s_addr=inet_addr("10.0.1.100"); // IP Address
if(connect(MySocket,(struct sockaddr *) &MyAddress,
sizeof(struct sockaddr_in))==-1) exit(2);
// Send SCPI command
if(send(MySocket,"*IDN?\n",6,0)==-1) exit(3);
// Read response
char buffer[200];
int actual;
if((actual=recv(MySocket,&buffer[0],200,0))==-1) exit(4);
buffer[actual]=0; // Add zero character (C string)
printf("Instrument ID: %s\n",buffer);
// Close socket
if(close(MySocket)==-1) exit(99);
return 0;
}
You have defined struct in_addr and struct sockaddr_in yourself at the top of main. Do not do that, these are types found in header files(netinet/in.h), you have to use those, not your own versions.
Try connection with telnet from your mac box to 10.0.1.100 port 5025 , does that work ?
replace that exit(2); with {perror("connect"); exit(2); } to get a description of what is wrong.

Resources