gethostbyname() alternatives in c - c

I am currently doing a project on networking game where I need to design a game where maximum of 3 clients can connect to the server and the game is played between all the clients and server. I am using the "sockaddr_in" structure at both the server and client side.
In my game, anyone can become the server and the clients should give the correct IP address and port number to be able to connect to the server. When I hard code the values of the IP address of server and port number in "server_address.sin_addr.s_addr" and "server_address.sin_port" respectively the game works fine. But hard coded will not solve my problem of anyone being a server and asking the clients to enter the server's address and port number. So, I used "gethostbyname()" function call on the client's side. But it did not solve my problem. (may the reason is that behaviour of gethostbyname() when passed a numeric string is unspecified. (Source : link) .
Below is the code used by me at server side :
struct sockaddr_in serv_addr, client_addr;
/* open a socket */
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
err_ret = errno;
return err_ret;
}
/* set initial values */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = inet_addr(IP);
memset(&(serv_addr.sin_zero), 0, 8);
/* bind address with socket */
if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
err_ret = errno;
return err_ret;
}
and at client side
struct sockaddr_in serv_addr;
struct hostent *to;
/* generate address */
if((to = gethostbyname(IP))==NULL)
{
err_ret = h_errno;
fprintf(stderr, "gethostbyname() error...\n");
return err_ret;
}
/* open a socket */
if((newfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
err_ret = errno;
fprintf(stderr, "socket() error...\n");
return err_ret;
}
/* set initial values */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
memcpy(&serv_addr.sin_addr, to->h_addr_list[0], to->h_length);
memset(&(serv_addr.sin_zero), 0, 8);
Can anyone here tell an efficient way to carry out the above process?
Any help would be appreciated.

getaddrinfo has superseded gethostbyname. That should make it easier to create sockaddr_in structs from IP address strings.
Sample code to convert either a string in numeric form or as a hostname to a sockaddr_in.
struct addrinfo hints = {};
addrinfo* pResultList = NULL;
struct sockaddr_in addr = {};
char* hostname = "1.2.3.4";
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// hints.ai_flags = AI_NUMERICHOST; // if you know hostname is a numeric stirng, you can skip the DNS lookup by setting this flag
result = getaddrinfo(hostname , NULL, &hints, &pResultList);
if (result)
memcpy(&addr, pResultList->ai_addr, sizeof(addr));
if (pResultList != NULL)
{
::freeaddrinfo(pResultList);
}

Related

Invalid argument to connect()

I'm trying to write code to setup a client socket that can send/receive messages from a server. Here's what I have:
// Create the socket
int s = socket(AF_INET, SOCK_STREAM, 0); // TODO: error checking
// Setup the client and server addresses
struct sockaddr_in cli_addr;
memset(&cli_addr, 0, sizeof(cli_addr));
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(7654);
cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(11111);
serv_addr.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");
// Bind the socket to the client address (so we can receive messsages)
if (bind(s, (struct sockaddr*)&cli_addr, sizeof(cli_addr)) == -1) {
perror("bind failed");
exit(errno);
}
// Connect the socket to the server address (so we can send messages)
if (connect(s, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
perror("connect failed");
exit(errno);
}
When I run this, I'm getting the error connect failed: Invalid argument. I don't see what I'm doing incorrectly here, though.
cli_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
...
serv_addr.sin_addr.s_addr = inet_addr("XXX.XXX.XXX.XXX");
You'll bind the socket to localhost (127.0.0.1) but then you connect to an address which likely is not localhost. There is no way such a TCP with a fully internal IP address (i.e. not accessible from outside the machine) to an IP address of a different system can be created, hence "Invalid argument".
It is unclear what you are trying to achieve with the bind in the first place so it might be the best to just remove it. In this case it will automatically pick a local IP and port which can be used in a connection to the given destination IP.

Getting an address IP and using a socket to connect to it

I'm writing an HTTP client using UNIX sockets (as part of a homework assignment). I currently have this working code to connect to a given IP Address:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
char *server_address = "127.0.0.1";
struct sockaddr_in address;
if (sockfd < 0) {
printf("Unable to open socket\n");
exit(1);
}
// Try to connect to server_address on port PORT
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(server_address);
address.sin_port = htons(PORT);
if (connect(sockfd, (struct sockaddr*) &address, sizeof(address)) < 0) {
printf("Unable to connect to host\n");
exit(1);
}
However, I now want to modify it so that server_address could also be something that is not an IP, such as "google.com". I've been trying to figure out how to do this using gethostbyname, but I am having trouble.
Will gethostbyname accept both an IP Address OR an address like "google.com" and have it work correctly? (or should I try and run a regex on the address first and do something else if it is an IP Address)?
I have tried the following code to try to get it working with something like "google.com", but I am getting a warning warning: assignment makes integer from pointer without a cast
struct hostent *host_entity = gethostbyname(server_address);
address.sin_addr.s_addr = host_entity->h_addr_list[0];
I know I am doing-it-wrong, but the gethostbyname documentation is atrocious.
What you want is maybe getaddrinfo(3):
#include <sys/socket.h>
#include <netdb.h>
static int
resolve(const char *host, const char *port)
{
struct addrinfo *aires;
struct addrinfo hints = {0};
int s = -1;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
#if defined AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif /* AI_ADDRCONFIG */
#if defined AI_V4MAPPED
hints.ai_flags |= AI_V4MAPPED;
#endif /* AI_V4MAPPED */
hints.ai_protocol = 0;
if (getaddrinfo(host, port, &hints, &aires) < 0) {
goto out;
}
/* now try them all */
for (const struct addrinfo *ai = aires;
ai != NULL &&
((s = socket(ai->ai_family, ai->ai_socktype, 0)) < 0 ||
connect(s, ai->ai_addr, ai->ai_addrlen) < 0);
close(s), s = -1, ai = ai->ai_next);
out:
freeaddrinfo(aires);
return s;
}
This version gets you a socket from a host/port pair. It also takes IP addresses for host and service strings for port. It will, however, connect to the host in question already.

bind() fails with windows socket error 10049

I try to make a client/server program in C with IPv6 and UDP. When the program binds the socket it return the WSAError 10049. I know that this is a problem with the adress name but don't see whats the problem. I hope someone can help.
struct sockaddr_in6 server, client;
SOCKET sock;
char buffer[BUFFERSIZE];
LPTSTR recvBuff[1024];
DWORD recvBuffLen = 1024UL;
int len = sizeof(client);
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0)
error("Fehler beim Anlegen des Sockets");
server.sin6_family = AF_INET6;
server.sin6_port = htons(6000);
server.sin6_addr = in6addr_any;
if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1)
error("Fehler beim binden des Sockets");
This normally results from an attempt to bind to an address that is not valid for the local computer..
You should use PF_INET here instead of AF_INET. They have the same value, but you're not specifying an address family AF here, you're specifying a protocol family PF. This is just a style recommendation.
I would suggest to memset zero the below arrays,structures:
struct sockaddr_in6 server, client;
SOCKET sock;
char buffer[BUFFERSIZE];
LPTSTR recvBuff[1024];
Before you can use the sockaddr_in6 struct, you will have to memset it to zero:
memset(server, 0, sizeof(struct sockaddr_in6));
The reason is that the struct sockaddr_in6 structure contains other fields which you are not initializing (such as sin6_scope_id) and which might contain garbage.
I have faced the same error.
#askMish 's answer is quite right.I didn't understand it at the first place,however I find it out eventually.
This normally results from an attempt to bind to an address that is not valid for the local computer..
Normally we have our computer under some gateway.
If we run ipconfig we will find the IP address is 192.168.something.
So that's the IP we could use to bind in code.
While other should connect with the public IP(if you can surf Internet you have one for sure.) like 47.93.something if they are in the same LAN with you.
You need to find that IP at your gateway(possibly your family's route).
I had that same error code when calling bind() under windows.
The reason in my case was not the same as in the initial poster's code, but i guess other will have made the very same mistake as me:
I generated the local address on which i want the server to be bound locally using the inet_addr()-function.
I assigned this result to the local address structure struct sockaddr_in localaddr this way:
localaddr.sin_addr.s_addr = htonl(inaddr);
But inet_addr() already returns the address in byte-network-order, so the call htonl(inaddr) was wrong in my code and caused error 10049:
SOCKET tcpsock_bindlisten(unsigned short port, const char* bindaddr)
{
SOCKET srvsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
unsigned long inaddr = bindaddr ? inet_addr(bindaddr) : INADDR_ANY;
struct sockaddr_in localaddr;
memset(&localaddr, 0, sizeof(struct sockaddr_in));
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(port);
// ERROR HERE! address returned from inet_addr is already in network-byte-order!
localaddr.sin_addr.s_addr = htonl(inaddr);
// CORRECT THIS WAY:
localaddr.sin_addr.s_addr = inaddr;
if (bind(srvsock, (struct sockaddr *) &localaddr, sizeof(localaddr)) != 0)
{
print_socketerror("tcpsock bind()");
return INVALID_SOCKET;
}
if (listen(srvsock, SVRSOCK_BACKLOG) != 0)
{
print_socketerror("tcpsock listen()");
return INVALID_SOCKET;
}
return srvsock;
}
When calling bind() using "all local interfaces" (INADDR_ANY) it worked, because of this coincidence INADDR_ANY == htonl(INADDR_ANY):
int main()
{
...
// this works for this special case:
SOCKET svrsock1 = tcpsock_bindlisten(4444, NULL);
// did not work!
SOCKET svrsock2 = tcpsock_bindlisten(5555, "192.168.0.123");
}

UDP Socket in C - Setting it up wrong?

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

C open socket on a specific IP

My website can be accessed using any of 2 different static IPs (IPv4).
Is it possible to open a TCP connection to another server, specifying which of the 2 IPs to use as a return address ?
x.x.x.x (my server) => z.z.z.z (destination server)
y.y.y.y (my server) => z.z.z.z (destination server)
Error-checking, etc. in this example has been omitted for simplicity sakes :
struct addrinfo hints, *result;
hints.ai_flags = 0;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_addrlen = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
getaddrinfo(domain, "80", &hints, &result);
socket(result->ai_family, result->ai_socktype, result->ai_protocol);
Like #hochl says, you use the bind system call:
struct sockaddr_in sin = { 0 };
int sock;
/* Create a socket address, with a specific port and (local) ipnumber */
sin.sin_family = AF_INET;
sin.sin_port = htons(80);
inet_aton("1.2.3.4", &sin.sin_addr);
/* Create socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
/* Bind socket to the local address */
bind(sock, (struct sockaddr *) &sin, sizeof(sin));
/* Now connect to remote server... */
/* connect(...) */
It should be noted that use of inet_aton is normally discouraged, in favor of inet_pton.
Not sure, but can't you bind your socket to one of your local addresses before you connect? In this case you may choose which of your IPs is used for the connection.

Resources