I'm writing a simple UDP client and an error returned as "invalid argument", but I don't know what's wrong. It is compiled on linux. My code is as below.
int udp_fd = -1;
struct sockaddr_in addr;
int port = 1701;
udp_fd = socket(AF_PPPOX, SOCK_DGRAM, 0);
if (udp_fd < 0) {
printf("fail to get UDP socket\n");
return 0;
}
memset((char *) &addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("31.25.210.118");
addr.sin_port = htons(port);
if(connect(udp_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 ) {
printf("UDP connect failed, errno = %s\n", strerror(errno));
return 0;
}
You are using an AF_INET address with an AF_PPPoX socket. This is mixing apples and parakeets.
PPP stands for "point-to-point", there is no such thing as IP address in this domain. Pick your game. You either connect over the Internet, and use socket(AF_INET, ..., or connect over PPP and use one of the PPP protocols like PX_PROTO_OLAC or PX_PROTO_OPNS, and a corresponding socket address type (sockaddr_pppolac or sockaddr_pppopns) instead of sockaddr_in.
Related
I am trying to listen to multicast on all interfaces in system, but responds only on this on which I've received multicast packet.
What I've did is to create a socket for each of the interfaces and here the problems starts.
When I bind interface to INADDR_ANY it will receive packets for all interfaces and send on default one. If I bind port to specific interface it will not receive multicast packet (but it will be able to send it on correct interface).
I've tried setting options like IP_ADD_MEMBERSHIP or IP_MULTICAST_IF but without success.
I think the other options whould be to create one socket to receive on all ifs and senders sockets for all interfaces, but on this approach I have no idea on which ifs packet entered...
Code samples (simplified, without error handling and stuff):
Creating socket:
//here i am looping over all interfaces from getifaddrs
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
sockets[i] = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
setsockopt(sockets[i], SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
mreq.imr_multiaddr.s_addr=inet_addr(MDNS_ADDRESS);
mreq.imr_interface.s_addr=pAddr->sin_addr.s_addr;
setsockopt(sockets[i], IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
setsockopt(sockets[i], IPPROTO_IP, IP_MULTICAST_IF, &pAddr, sizeof(struct in_addr));
memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY; //or pAddr->sin_addr.s_addr;
my_addr.sin_port = htons(port);
bind(sockets[i], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1);
Receiving and sending:
recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len);
//do some magic and response (response should be a multicast too)
destination.sin_addr.s_addr = inet_addr(MULTICAST_ADDRESS);
destination.sin_family = AF_INET;
destination.sin_port = htons( port );
sendto(sockfd, buffer, len, 0, (struct sockaddr *)&destination, sizeof destination);
I would like to create something similar in work to mDNS so when packet entered on specific interface program should answer on the same if with some data about this if. It should not send this on other ifs as it may not be relevant for them, but it should send it as multicast so any other host in same network will receive the respond.
You should only need one socket for this.
First bind to INADDR_ANY and your port of choice. Then call setsockopt with IP_ADD_MEMBERSHIP on each interface you want to receive multicast on. Finally, call setsockopt with IP_MULTICAST_IF on the interface you want to send multicast on. Make sure to check for errors on each call.
int socket s;
struct sockaddr_in sin;
struct ip_mreq mreq;
struct in_addr out_addr;
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr=htonl(INADDR_ANY);
sin.sin_port = htons(1044); // or whatever port you listen on
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket failed");
exit(1);
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin))==-1) {
perror("bind failed");
exit(1);
}
// Do this in a loop for each interface
mreq.imr_multiaddr = inet_addr("230.4.4.1"); // your multicast address
mreq.imr_interface = inet_addr("192.168.1.1"); // your incoming interface IP
if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == -1) {
perror("Error joining multicast group");
exit(1);
}
out_addr.s_addr = inet_addr("192.168.1.1"); // your outgoing interface IP
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&out_addr,sizeof(out_addr))== -1) {
perror("Error setting outgoing interface");
exit(1);
}
When using multicast, you should always bind to the INADDR_ANY address. Failure to do so breaks multicast on Linux systems.
Initially, I accepted #dbush answer as it allowed me to get on right track. For sake of completeness I post more detailed answer and as suggested by him I accepted my own answer.
Some of the code was found here: Setting the source IP for a UDP socket
I was able to do all of this with single socket and setting IP_PKTINFO.
Code samples (simplified, without error handling and stuff):
Creating socket:
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1) {
perror("socket");
exit(1);
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0) {
perror("setsockopt");
exit(1);
}
optval2 = 1;
if(setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &optval2, sizeof(optval2)) < 0) {
perror("setsockopt");
exit(1);
}
memset(&my_addr, 0, sizeof(struct sockaddr_in));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(5353);
if (bind(sockfd, (struct sockaddr *)&my_addr,
sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
Receiving and responding:
char buf[MAXBUFLEN];
char cmsgbuf[MAXBUFLEN];
struct iovec iov[1];
iov[0].iov_base=buf;
iov[0].iov_len=sizeof(buf);
struct cmsghdr *cmsg;
struct msghdr message;
message.msg_name=&their_addr;
message.msg_namelen=sizeof(their_addr);
message.msg_iov=iov;
message.msg_iovlen=1;
message.msg_control=cmsgbuf;
message.msg_controllen=MAXBUFLEN;
if ((numbytes = recvmsg(sockfd, &message, 0)) == -1) {
perror("recvfrom");
exit(1);
}
for (cmsg = CMSG_FIRSTHDR(&message); cmsg != NULL; cmsg = CMSG_NXTHDR(&message, cmsg)) {
// ignore the control headers that don't match what we want
if (cmsg->cmsg_level != IPPROTO_IP ||
cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
struct in_pktinfo *pi = CMSG_DATA(cmsg);
addr = pi->ipi_spec_dst.s_addr;
}
//DO SOME MAGIC
//HERE WE ARE SETTING ADDR - INTERFACE WITH THIS ADDR WILL SEND MULTICAST
sock_opt_addr.s_addr = addr;
setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &sock_opt_addr, sizeof(sock_opt_addr));
sendto(sockfd, buffer, len, 0, (struct sockaddr *)&destination, sizeof destination);
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
I'm working on a project that involves sending various requests to a server through UDP. However, I seem to be setting up the socket entirely wrong, as the server does not respond to any of my requests. We were provided with a server binary to test against, and the code below ellicits no response. Am I setting up the UDP socket correctly? If so, am I somehow using sendto wrong? I have confirmed that I am sending the correct number of bits.
The input for the program is: ./client [URL] [port] [username], and I always test with ./client localhost 8080 user. Here is the struct I am sending and the code.
struct request_login {
int req_type; /* = REQ_LOGIN */
char req_username[32];
} packed;
Code:
struct sockaddr_in sa;
int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd == -1){
printf("Could not create socket.");
exit(EXIT_FAILURE);
}
// Prepare the socket address
memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(argv[1]);
// Convert to network order
sa.sin_port = htonl(atoi(argv[2]));
// Assemble and send login request
struct request_login * reqlogin = (struct request_login *) malloc(sizeof(struct request_login));
reqlogin->req_type = REQ_LOGIN;
strcpy(reqlogin->req_username, argv[3]);
int res = sendto(sockfd, reqlogin, sizeof (struct request_login), 0, (struct sockaddr*)&sa, sizeof sa);
free(reqlogin)
Huh?
This:
sa.sin_addr.s_addr = inet_addr(argv[1]);
certainly won't do the right thing if, as you say, argv[1] is typically "localhost". You need to look up the host name, so that you get an IP address. You can only use inet_addr() if the input is a dotted IP address, not a host name.
Look at getaddrinfo().
After re-reading your code a couple of times, I think I know what one cause of the error may be:
sa.sin_port = htonl(atoi(argv[2]));
The port number is a short so you should use htons instead. It's very small and easy to miss.
try this instead:
struct addrinfo hint;
memset(&chk,0,sizeof(chk));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = IPPROTO_UDP;
struct addrinfo* servAddr = NULL;
int ret = getaddrinfo(argv[1],atoi(argv[2]),&hint,&servAddr);
if (-1 == ret)
{
perror("getaddrinfo failed");
exit(EXIT_FAILURE);
}
int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd == -1){
printf("Could not create socket.");
exit(EXIT_FAILURE);
}
// Assemble and send login request
struct request_login reqlogin;
reqlogin.req_type = REQ_LOGIN;
strcpy(reqlogin.req_username, argv[3]);
int res = sendto(sockfd, &reqlogin, sizeof (struct request_login), 0, servAddr->ai_addr, servAddr->ai_addrlen);
My application is running on CentOS 5.5.
I'm using raw socket to send data:
sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sd < 0) {
// Error
}
const int opt_on = 1;
rc = setsockopt(m_SocketDescriptor, IPPROTO_IP, IP_HDRINCL, &opt_on, sizeof(opt_on));
if (rc < 0) {
close(sd);
// Error
}
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = my_ip_address;
if (sendto(m_SocketDescriptor, DataBuffer, (size_t)TotalSize, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) {
close(sd);
// Error
}
How can I bind this socket to specific network interface (say eth1)?
const char *opt;
opt = "eth0";
const len = strnlen(opt, IFNAMSIZ);
if (len == IFNAMSIZ) {
fprintf(stderr, "Too long iface name");
return 1;
}
setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, len);
First line: set up your variable
Second line: tell the program which interface to bind to
Lines 3-5: get length of interface name and check if it's size not too big.
Six line: set the socket options for socket sd, binding to the device opt.
setsockopt prototype:
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
Also, make sure you include the if.h, socket.h and string.h header files
As mentioned earlier, the correct thing to do is use the struct ifreq to specify the interface name. Here is my code sample.
#define SERVERPORT 5555
...
struct ifreq ifr;
/* Create the socket */
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
{
printf("Error in socket() creation - %s", strerror(errno));
}
/* Bind to eth1 interface only - this is a private VLAN */
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth1");
if ((rc = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0)
{
perror("Server-setsockopt() error for SO_BINDTODEVICE");
printf("%s\n", strerror(errno));
close(sd);
exit(-1);
}
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVERPORT);
serveraddr.sin_addr.s_addr = inet_addr("9.1.2.3");
int rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
I would also like to add that from a security perspective, while it is good to bind the socket to an interface, it does not make sense to use INADDR_ANY as the listening IP address. Doing so would make the port appear open in netstat on all network interfaces.
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver
Instead, I specified an IP address specific to the interface being used (a private VLAN). This fixed the netstat output too:
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 9.1.2.3:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver
Bind socket to specific interface IP address
int bind_using_iface_ip(int fd, char *ipaddr, uint16_t port)
{
struct sockaddr_in localaddr = {0};
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(port);
localaddr.sin_addr.s_addr = inet_addr(ipaddr);
return bind(fd, (struct sockaddr*) &localaddr, sizeof(struct sockaddr_in));
}
Bind socket to specific interface name
int bind_using_iface_name(int fd, char *iface_name)
{
return setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface_name, strlen(iface_name))
}
In bind_using_iface_ip, to bind to any port 0 should be passed. And also if the fd is raw socket then need to pass port as 0. This bind mechanism is common for all kind of sockets like raw, dgram and stream.
Based from the answers I got from this thread, I've created this:
//Server
sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/
timeout = 50000;
serv_sock_input[0] = TCP(1234);
serv_sock_input[1] = UDP(9876);
input_protocols[0] = "tcp";
input_protocols[1] = "udp";
while (1)
{
FD_ZERO(&sock_set);
for (x = 0; x<number_of_inputs; x++)
{
FD_SET(serv_sock_input[x], &sock_set);
}
select_timeout.tv_sec = timeout;
select_timeout.tv_usec = 0;
if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
printf("No requests");
else
{
for (x = 0; x<number_of_inputs; x++)
{
if (FD_ISSET(serv_sock_input[x],&sock_set))
{
printf("\nRequest on port %d: \n", x);
if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE
{
accept_socket(serv_sock_input[x]);
printf("Input TCP Port %d\n",x);
close_socket(serv_sock_input[x]);
}
else
{
printf("Input UDP Port %d\n",x);
}
}
}
}
}
sock_term();
}
int TCP (unsigned short port)
{
int sock;
struct sockaddr_in servAddr;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
exit(1);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
exit(1);
if (listen(sock, 5) < 0)
exit(1);
return sock;
}
int UDP (unsigned short port)
{
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for sending/receiving datagrams */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
exit(1);
/* Construct local address structure */
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family */
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
exit(1);
return sock;
}
//Client
sock_init();
if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
exit(1);
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
client_addr.sin_port = htons(1234);
if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0)
exit(1);
closesocket(client_sock_output);
sock_term();
When the server starts, the server gets blocked at the if(select(...)) statement.
So when I run the Server, and then the client, the client connects to the server (sometimes it takes a couple times to run the client before they connect). Then the if(select...)) statement is no longer true and it proceeds to the else.
After that, the client closes the connection, and the program. However, and this is where my problem happens, the if(select(...)) statement is always false. I get this output:
Request on port 0:
Input TCP Port 0
Request on port 1:
Input UDP Port 1
This output repeats forever. How come it doesn't get stuck at the if(select(...))?
You have two problems: you don't understand how accept() works in TCP, and you need to read the incoming data in UDP.
select() tells you that a listening socket has connection to accept, or reading socket has data to read.
For select to stop telling you this, you need to actually read the data or accept the connection.
In your UDP branch, you need to call receiv to actually get the data. If you don't, select will keep telling you that you have data.
In your TCP branch, you call accept_socket. I don't know what is your implementation of it, but it's most probably wrong to close the socket you just called accept() on. accept() returns a new socket for you - the one you should be using for IO. If anything needs to be closed, it's that new socket.
Please check why you have this in server.
if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
replace it with
if (select(maxDescPlus1, &sock_set, NULL, NULL, &select_timeout) == 0)
where maxDescPlus1 --> is number of descriptors to select plus 1 value.