problem establishing a TCP socket connection - c

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.

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.)

Invalid argument from sendto in ansi C when trying to implement UDP

I know there are a few similar question on SO, but I feel like everyone has a different issue that is causing this. So I'm posting my particular case.
I'm working on the raspberry pi, using raspbian, a debian derivative. I'm coding in ansi C. This is a server that sends some data to a udp client on another end through port 500.
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
int main()
{
int sockfd;
struct sockaddr_in servaddr,cliaddr;
socklen_t clilen;
char buffer[256];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(500);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
sprintf(buffer,"hi this is a test \n");
if(sendto(sockfd,buffer,sizeof(buffer),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr))==-1)
{ error("fail:")
};
return 0;
}
But this just gives me the error "invalid arguments", I can't figure out what could possibly be wrong. If the type of argument I supply to sendto is incorrect, this would fail on compile. But the type is correct and this compiles, only at runtime does it fail.
You have no initialization for the cliaddr structure. Thus, its contents are random. Your code compiles fine because you have a struct sockaddr_in where it should be but the compiler cannot check if you have properly initialized it.
On the other hand, at runtime when sendto is invoked the glibc or the kernel finds out that that random data in the cliaddr structure doesn't look like a valid address and throws up an invalid argument error.
Solution: initialize the cliaddr variable before using it.
Edit: You also need to properly initialize the socket, the third argument there shouldn't be 0.
Second edit, read me: For resources I recommend the extraordinary guide of Beej. For your exact problem this subchapter can help.

Where is a UNIX socket on the filesystem?

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 :)

authenticate on SSH via BSD socket

I'd like to authenticate on ssh-server via BSD socket. I know how to initiate a connection but don't know how to actually authenticate. Thanks for your time when pointing me to the right direction.
Here is the source code:
//
#include <stdio.h> // printf()
#include <sys/types.h> // socket data types
#include <sys/socket.h> // socket(), connect(), send(), recv()
#include <arpa/inet.h> // sockaddr_in, inet_addr()
#include <stdlib.h> // free()
#include <unistd.h> // close()
int *ssh(char *host, int port, char *user, char *pass);
int main(void)
{
// create socket
int *ssh_socket = ssh("127.0.0.1", 22, "root", "password");
// close and free
close(*ssh_socket);
free(ssh_socket);
return 0;
}
int *ssh(char *host, int port, char *user, char *pass)
{
int *sock = calloc(sizeof(int), 1);
struct sockaddr_in addr = {.sin_family=AF_INET, \
.sin_port=htons(port), \
.sin_addr.s_addr=inet_addr(host)};
*sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // create socket
connect(*sock, (struct sockaddr *)&addr, sizeof(addr)); // init connection
// here is the problem
// how do I authenticate on this socket?
return sock;
}
Use libssh for adding SSH functionality to your program.
SSH is a quite complex protocol with several layers.
Before getting to the user authentication you have to initiate the protocol, check remote host credentials and start an encrypted connection.
And after that, there are several ways to authenticate an user you may want to support (public key, passwd, keyboard-interactive, etc.).
The Wikipedia page for SSH has links to all the related RFCs.
Really, use libssh or libssh2 or the code from OpenSSH!

How to enumerate all IP addresses attached to a machine, in POSIX C?

Background:
I'm writing a daemon that makes outgoing TCP/IP connections. It will be running on machines with multiple (non-loopback) IP addresses. I'd like the users to be able to specify, in the daemon's config file, which IP address(es) to use for outgoing connections, or * to use all.
The addresses will be used in a rotation, each connection going out from the IP address used least recently. This behavior is important, as is * being a replacement for "all" so daemons running on multiple machines can point to the same config file on a fileshare, and have each use its own set of IP addresses.
Problem:
How do I get a list of all the IP addresses a machine can make outgoing (i.e. to any other computer) connections on? Given a list of all IP addresses, how would I filter out loopback addresses?
I'm in C, and if possible I'd like to use POSIX only, but the daemon will probably only ever run on Linux boxes, so I'd accept a Linux-centric answer.
Each IP address will be available on exactly one (possibly virtual) network device and vice versa, so a way to enumerate network devices and get associated IP addresses would also suffice, though I wouldn't really be happy about it. (Side questions: Is it even possible to associate multiple IP addresses with a single device? How 'bout the same IP under multiple devices? Not important.)
Insufficient Solutions:
gethostname()/gethostbyname() (as this question). Using that method, I only ever get 127.0.0.1 back (or .1.1 in Debian). I suspect this is because the hostname of the machine is in the hosts file, and that's as far as gethostbyname() checks. (I believe that's why in Debian I always get 127.0.1.1: Debian defaults to adding localhost as 127.0.0.1 and the machine's hostname as 127.0.1.1 to the hosts file, right?) I'd like a solution that ignores hosts and gives me everything actually there.
I've had no more luck with getaddrinfo() than gethostname()/gethostbyname(). It seems to be bound by the same problem. I tested this passing the machine's hostname and a NULL service (port) into it; the docs say passing a NULL hostname AND a NULL service is illegal, and this is backed up by testing. Not sure how else to ask it for everything on the machine, but I'm open to suggestions in this vein.
EDIT: this answer shows how to get the IP address from a device name, but doesn't show how to enumerate the device names. Any ideas?
FINAL EDIT: I've accepted caskey's answer to give him the credit for pointing me in the direction of how this needs to be done. I've posted my own answer listing the source code of how exactly to do it in case anyone else needs it.
Here's my proof of concept code using caskey's accepted answer, for posterity's sake:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
static const char * flags(int sd, const char * name)
{
static char buf[1024];
static struct ifreq ifreq;
strcpy(ifreq.ifr_name, name);
int r = ioctl(sd, SIOCGIFFLAGS, (char *)&ifreq);
assert(r == 0);
int l = 0;
#define FLAG(b) if(ifreq.ifr_flags & b) l += snprintf(buf + l, sizeof(buf) - l, #b " ")
FLAG(IFF_UP);
FLAG(IFF_BROADCAST);
FLAG(IFF_DEBUG);
FLAG(IFF_LOOPBACK);
FLAG(IFF_POINTOPOINT);
FLAG(IFF_RUNNING);
FLAG(IFF_NOARP);
FLAG(IFF_PROMISC);
FLAG(IFF_NOTRAILERS);
FLAG(IFF_ALLMULTI);
FLAG(IFF_MASTER);
FLAG(IFF_SLAVE);
FLAG(IFF_MULTICAST);
FLAG(IFF_PORTSEL);
FLAG(IFF_AUTOMEDIA);
FLAG(IFF_DYNAMIC);
#undef FLAG
return buf;
}
int main(void)
{
static struct ifreq ifreqs[32];
struct ifconf ifconf;
memset(&ifconf, 0, sizeof(ifconf));
ifconf.ifc_req = ifreqs;
ifconf.ifc_len = sizeof(ifreqs);
int sd = socket(PF_INET, SOCK_STREAM, 0);
assert(sd >= 0);
int r = ioctl(sd, SIOCGIFCONF, (char *)&ifconf);
assert(r == 0);
for(int i = 0; i < ifconf.ifc_len/sizeof(struct ifreq); ++i)
{
printf("%s: %s\n", ifreqs[i].ifr_name, inet_ntoa(((struct sockaddr_in *)&ifreqs[i].ifr_addr)->sin_addr));
printf(" flags: %s\n", flags(sd, ifreqs[i].ifr_name));
}
close(sd);
return 0;
}
Works like a charm!
This can only be done in an operating system dependent fashion. You could try parsing the output of 'iptables', but the right answer for linux is to use ioctl.
SIOCGIFCONF takes a struct ifconf *. The ifc_buf field points to a
buffer of length ifc_len bytes, into which the kernel writes a list of
type struct ifreq [].
The struct ifreq is documented in linux/if.h:
struct ifreq
{
#define IFHWADDRLEN 6
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
} ifr_ifrn;
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
void * ifru_data;
struct if_settings ifru_settings;
} ifr_ifru;
};
As you can see, it contains the address information you desire.
Some answers to side questions:
Adding multiple IPs to a device can be done with aliasing. Linux creates devices named like eth0:0 when you do this.
ifconfig eth0:0 10.0.0.1
Having the same IP under multiple devices can be done with channel bonding/link aggregation.
You can get the interface info required a couple of ways including calling ioctl() with the SIOCGIFCONF option and looping through the returned structures to get the interface address info.
Given a list of all IP addresses, how would I filter out loopback addresses?
See ifreq struct in caskey's answer. You can determine the loopback (properly) with:
if (ifru_flags & IFF_LOOPBACK)
Constants are in if.h
are you sure you are using gethostname()/gethostbyname() correctly? check out here, the only problem I see with doing this is that it's possible that a domain name has multiple ip addresses mapped to it. If that's the case then there's no way of knowing what the ip address belonging to the local machine is
How do I get a list of all the IP addresses a machine can make outgoing (i.e. to any other computer) connections on? Given a list of all IP addresses, how would I filter out loopback addresses?
Look at the source code of lsof and netstat. You'll see it involves traversing kernel memory structures, not just making system calls.

Resources