I've declared a struct sockaddr_in server in my main function.
I pass it into this function to return a socket file descriptor
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
int sockfd, len;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd < 0){
perror("Failed to open socket: ");
exit(-1);
}
len = sizeof(server);
bzero(server, len);
server->sin_family= AF_INET;
inet_pton(AF_INET, ip_addr, &server->sin_addr);
server->sin_port= htons(port);
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){
perror("Bind failed: ");
exit(-1);
}
return sockfd;
}
The struct is passed into the function using this call
sockfd = openSocket(vector->ip_addr, vector->port, &server);
However I get the following error.
Bind failed: : Address family not supported by protocol family
len = sizeof(server);
This determines the size of the pointer. You want the size of the structure it points to, so this should be:
len = sizeof(*server);
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
[...]
if((bind(sockfd, (struct sockaddr*)&server, len)) < 0){
server is already declared as a pointer, so I think the & operator
isn't needed in the bind() call.
int openSocket(char* ip_addr, int port, struct sockaddr_in* server){
This is interesting - you use sockaddr_in which has the following properties you need to set:
sun_family -- This must equal AF_INET.
sin_addr -- This is another structure with an unsigned long named s_addr which you'll probably want to set to INADDR_ANY +.
sin_port -- This requires a server port which needs converting with htons(). (Make sure this port is not in use ++! My go-to port is 3333 for testing...)
It seems you're using inet_pton() but I'm not sure it has the same affect for setting sin_port. Other that it looks fine.
The other area is there might be an issue is this line:
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
The 0 on the end specifies [1]:
"Specifying a protocol of 0 causes socket() to use an unspecified default protocol appropriate for the requested socket type."
I could imagine a possibility where the unspecified default is either not correct for your Operating System or that there is no default. I would try SOCK_STREAM to test whether this works.
+ NOTE: This would technically need htonl() but my understanding an this does nothing for this particular case.
++ NOTE: If you are writing client and server applications remember to be careful about which owns the port.
[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/socket.html
Related
I expect the following code* to fail since the server address hasn't been set with a valid value (verified in debugger - the whole struct is indeed initialized to 0, making address family AF_UNSPEC).
* incomplete illustrative snippet
static struct sockaddr_in g_server_addr;
int main(void)
{
int hdl;
hdl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == hdl)
{
printf("Client Socket creation failed.");
return -1;
}
if(-1 == connect(hdl, (struct sockaddr *) &g_server_addr, sizeof(g_server_addr)))
{
printf("Connect() on socket failed.");
return -1;
}
return 0;
}
I need connect() to fail when called with incorrect input.
(This code is being tested on an Ubuntu machine.)
From the connect manpage:
Connectionless sockets may dissolve the association by connecting to an address with the sa_family member of sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2).
The manpage is a bit outdated, it will work on any socket, which can be disconnected at all, as for example TCP sockets.
In practice, there is no error when trying to dissolve the association on a stream socket, which is not yet connected. This is, why you don't get an error.
If you need to get an error, initialize the address family with an invalid family:
static struct sockaddr_in g_server_addr = { -1 };
This will yield the error -1 EAFNOSUPPORT (Address family not supported by protocol)
See also net/ipv4/af_inet.c of a recent linux kernel:
int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags) {
...
if (uaddr->sa_family == AF_UNSPEC) {
err = sk->sk_prot->disconnect(sk, flags);
sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED;
goto out;
}
...
out:
return err;
I'm trying to write server application. I want to get client's ip. My problem is with inet_ntop function. I can't get it working properly. Here is my usage :
void client_loop(uint16_t port) {
int cfd;
int socket = bind_socket(port, INADDR_ANY);
char ip[INET_ADDRSTRLEN];
struct sockaddr client_addr;
struct sockaddr_in *addr_in;
socklen_t cli_len;
while (work) {
if ((cfd = TEMP_FAILURE_RETRY(accept(socket, &client_addr, &cli_len))) < 0) {
if (EAGAIN == errno || EWOULDBLOCK == errno)
continue;
ERR("accept");
}
addr_in=(struct sockaddr_in *)&client_addr;
inet_ntop(AF_INET, &(addr_in->sin_addr),ip, sizeof(ip));
printf("INET_NTOP: %s\n",ip);
}
}
First usage of inet_ntop always returns 0.0.0.0 Then it works properly. When im moving inet_ntop to outside function it works properly only for connections from localhost. Thanks.
EDIT:
Fixed. The problem was that cli_len wasn't initialized so accept wasn't filling client_addr.
With this line its working like a boss:
socklen_t cli_len=sizeof(struct sockaddr);
i couldn't find the issue, but i see that you have given cli_len as argument, but you have to use sizeof(ip) in place of the 4 th argument (cli_len) of inet_ntop. and also please check for the cli_len also before calling inet_ntop
I am tying to connect to a bit torrent tracker, http://tracker.thepiratebay.org. The gethostbyname() keeps returning null, how should I fix this? Also do you see anything else wrong with this code?
int sock;
struct sockaddr_in servAddr;
int portNum = 80;
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
printf("fail create socket");
return 0;
}
char *path = "http://tracker.thepiratebay.org/";
struct hostent *hp = gethostbyname(path);
if(hp==NULL){
printf("null");
else{
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
memcpy( (char *) &servAddr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length );
servAddr.sin_port = htons(portNum);
}
//send request to tracker server
if (send(sock, requestToSend, strlen(requestToSend), 0) != strlen(requestToSend)){
printf("fail send");
return 0;
}
The problem here is that http://tracker.thepiratebay.org/ is a URL, but gethostbyname() expects just the host name. The host name is tracker.thepiratebay.org.
It would make it much easier if you just use libcurl, which will handle all of that HTTP stuff for you. It is extremely common to use libcurl in applications that connect to HTTP servers; it is an excellent library. It's certainly easier than socket programming.
Use getaddrinfo()
The modern alternative to gethostbyname() is getaddrinfo(). It's not that gethostbyname() doesn't do what you want, rather, getaddrinfo() is simply better in every conceivable way.
struct addrinfo hint, *ap;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
int r = getaddrinfo("tracker.thepiratebay.org", "http", &hint, &ap);
This will not only get you the address for the host you want, but it will also fill in the port number. You can use "http" as the port, or you can use "80" for the port, they are the same thing (as long as /etc/services has the right entry).
Other problems
This line is wrong.
memcpy( (char *) &servAddr.sin_addr.s_addr, (char *) hp->h_addr, hp->h_length );
You don't know that gethostbyname() returned an IPv4 address, and it is foolish to try and copy it into a struct sockaddr_in. If gethostbyname() returned an IPv6 address, you have just smashed your stack and your program will crash -- or worse, it might not crash.
Either check that it returns an IPv4 address, or simply copy hp->h_addr into a generic struct sockaddr that was returned from malloc(hp->h_length). This is a bit ugly but it's the way it goes.
Finally, it is wrong to cast the arguments to memcpy(). It's not an error, but it's wrong. Don't do it, it can cause otherwise legitimate compiler errors to be suppressed, e.g., if you accidentally cast an int to char *.
I am an experienced Linux socket programmer and am writing a server application which has many outgoing interfaces. Now server socket binds to a random source port in the start of the process along with INADDR_ANY.
Later at some point when submitting response to a specific node, i need to assign a fixed source ip address. The standard way to do this is calling bind. However, bind is called once for the port number, successive calls fail with invalid argument error.
Creating a new socket is not really a good choice since i will have to be doing this very often upon responding to some clients.
I have also explored SO and a lot of socket options such as IP_FREEBIND, but it doesn't quite suite my scenario.
Perhaps using IP_PKT_INFO and setting source address might work unless it suffers the same problem i.e. not allowing a socket once bound to INADDRANY to rebind to a fixed source ip latter.
Is there a way to unbind an existing socket or an alternate way to setting source ip address in outgoing packet?
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(1500);
addr.sin_addr.s_addr = INADDR_ANY;
// first bind succeeds
if ( (status = bind(sock, (struct sockaddr *) &addr, sizeof(addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying address\n");
// second bind fails
if((status = bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr))) < 0)
printf("re bind error with ip %s\n", strerror(errno));
Any ideas in this regard will be highly appreciated. I have gone through considerable material on sockets, SO etc. but no success yet.
I finally found the solution myself so accepting my own answer (shameless but correct plugin), supplemented with code sample.
I originally wanted to rewrite source address of an outgoing packet without creating the socket again where the socket was already bound. Calling bind multiple times fail for this case, and (in my particular situation), i was not able to just have separate sockets for each source ip and use it.
I found some references in IP_PACKET_INFO but it was a pain to get it to work correctly. Following reference was helpful.
Setting source of udp socket
Sample Code
Here is a trivial application which creates a udp socket, binds it to a local port, then before sending a particular message, it appends the outgoing source ip address. Keeping in mind that in my case, i created a sudo interface and assigned it another ip. The send call will fail if this is not the case.
int status=-1;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
int opt = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in bind_addr;
memset(&bind_addr, 0, sizeof(struct sockaddr_in));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(44000); // locally bound port
if((status = bind(sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
// currently using addr as destination
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(80); // destination port
if (inet_aton("74.125.236.35", &(addr.sin_addr)) == 0)
printf("Failed copying remote address\n");
else
printf("Success copying remote address\n");
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying src address\n");
else
printf("Success copying src address\n");
char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];
char msg[10] = "hello";
int len = strlen(msg);
struct msghdr mh;
memset(&mh, 0, sizeof(mh));
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
struct iovec iov[1];
iov[0].iov_base = msg;
iov[0].iov_len = len;
mh.msg_name = &addr; // destination address of packet
mh.msg_namelen = sizeof(addr);
mh.msg_control = cmbuf;
mh.msg_controllen = sizeof(cmbuf);
mh.msg_flags = 0;
mh.msg_iov = iov;
mh.msg_iovlen = 1;
// after initializing msghdr & control data to
// CMSG_SPACE(sizeof(struct in_pktinfo))
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg);
//src_interface_index 0 allows choosing interface of the source ip specified
pktinfo->ipi_ifindex = 0;
pktinfo->ipi_spec_dst = src_addr.sin_addr;
int rc = sendmsg(sock, &mh, 0);
printf("Result %d\n", rc);
The key statement is
pktinfo->ipi_spec_dst = src_addr.sin_addr;
where we are specifying the source ip address to be used. The rest of things like cmsg struct etc. are merely used in order to be able to write ipoktinfo struct ourselves
There is no way to unbind and rebind an existing socket.
Why don't you create a socket for each interface instead? Since the UDP/IP protocol is connectionless, you can choose the source IP address by choosing which socket you use to send the reply with; there is no need to use the same socket the incoming datagram was received on.
The downsides are that you can no longer bind to the wildcard address, and you must use select(), poll(), multiple threads, or some other mechanism to receive datagrams from multiple sources concurrently. You'll also need some logic to efficiently pick the socket based on the client IP address.
In most cases, I suspect that adding a few route entries to route each remote IP address to the desired host IP address, and using a separate socket for each host IP address and port combination, solves the issues perfectly -- and using the very efficient kernel functionality to do so. While the behaviour may be an application requirement, I suspect it is better solved using the network interface configuration instead. Unfortunately, often the requirements are written by semi-functional idiots better suited for manual labor, and your hands are tied.. if so, I commiserate.
If you have a test network with workstations having multiple physical network interfaces, I can provide a simple example C99 test program you can use to verify the design works.
Suppose the listening socket passed to accept has non-default options set on it with setsockopt. Are these options (some or all of them?) inherited by the resulting file descriptors for accepted connections?
Several of the socket options are handled at lower levels of the system. While most of the socket options could be set using the setsockopt. Reference:man setsockopt And since you are mentioning only POSIX on any Linux, in general, as your scope. The accept() (Reference: man accept) does have a certain amount of discretion on what socket options should be inherited and what options to reject from the listening fd.
accept() does not modify the original socket passed to it as argument. The new socket returned by accept() does not inherit file status flags such as O_NONBLOCK,O_ASYNC from the listening socket.
So, instead of relying on the inheritance or non-inheritance of the listening socket properties(which is bound to vary across implementations and licenses), the accepted socket should be explicitly set with the desired socket options.(Best practice)
man pages and the implementation codes in your machine would be the most relevant specification for the accept() behavior.There's no common or standard specification existing across multiple variants of Linux.
No, they're not necessarily inherited. Try this sample, which sets the receive buffer size (SO_RCVBUF) on the initial socket to a non-default value and then compares the result with the inherited socket. Run this code, which listens on TCP port 12345, and then connect to it from any other program.
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
void die(const char *f)
{
printf("%s: %s\n", f, strerror(errno));
exit(1);
}
int main(void)
{
int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
die("socket");
int rcvbuf;
socklen_t optlen = sizeof(rcvbuf);
if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (1)");
printf("initial rcvbuf: %d\n", rcvbuf);
rcvbuf *= 2;
if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
die("setsockopt");
printf("set rcvbuf to %d\n", rcvbuf);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = INADDR_ANY;
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
die("bind");
if(listen(s, 10) < 0)
die("listen");
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int s2 = accept(s, (struct sockaddr *)&client_addr, &addr_len);
if(s2 < 0)
die("accept");
printf("accepted connection\n");
optlen = sizeof(rcvbuf);
if(getsockopt(s2, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (2)");
printf("new rcvbuf: %d\n", rcvbuf);
return 0;
}
Result on a machine running Linux 3.0.0-21-generic:
initial rcvbuf: 87380
set rcvbuf to 174760
accepted connection
new rcvbuf: 262142
Socket options is the place where things go that don't fit elsewhere. So, it's expected for different socket options to have different inheriting behaviour. Whether to inherit or not a socket option is decided on a case by case basis.
The answer is No for POSIX conforming implementations, as I read it.
From the POSIX-2017 spec for accept():
The accept() function shall extract the first connection on the queue of pending connections, create a new socket with the same socket type protocol and address family as the specified socket, and allocate a new file descriptor for that socket.
Note it is explicitly a "new socket", not a "full or partial copy of the socket being unqueued", so should have no options different from the default for that socket type and address family. While the copy behavior may be desirable, this is left as an extension interface a platform may have. I haven't seen that any platform does implement one, however, so it could be added to the standard. It is therefore on the application to use getsockopt()/setsockopt() to copy any attributes, that differ from the defaults, from the queue socket to the returned socket, not the responsibility of the interface, before any use of that socket to send or receive data.