c - in_addr_t variable as paramether of connect - c

I have a variable of in_addr_t type and I would like to use connect() with the given ip. I'm therefore needing a (struct sockaddr *) variable as parameter for the connect(). How to insert use the in_addr_t variable instead?
in_addr_t var; // Given variable, not actually declared here ofc
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in *srvraddr = malloc(sizeof(struct sockaddr_in));
memset((void *) srvraddr, 0, sizeof(struct sockaddr_in));
srvraddr->sin_family = AF_INET;
srvraddr->sin_port = htons(PORT_A); // Big - little endian arch compatibility
srvraddr->sin_addr.s_addr = var; // Somehow assign var here? <<<<<
connect(sockfd, (struct sockaddr *) srvraddr, sizeof(struct sockaddr_in));
Whatever I try to do connect always returns me -1.
Using perror I get the following error: Connection refused.

How to insert use the in_addr_t variable instead?
You cannot use an in_addr_t with connect() instead of a struct sockaddr_in. connect() accepts varying address structure types, but not arbitrary ones. The correct structure type for an IPv4 address is the struct sockaddr_in that you're already using. You need to store an appropriate representation of the remote host address into that.
Evidently, you already have an in_addr_t that you assert represents the remote address, but are uncertain how to use it:
in_addr_t var; // Given variable, not actually declared here ofc
[...]
srvraddr->sin_addr.s_addr = var; // Somehow assign var here? <<<<<
What you present is already exactly what POSIX expects you to do, however. POSIX requires that the sin_addr member of a struct sockaddr_in be a structure having at minimum a s_addr member of type in_addr_t. Supposing that the in_addr_t you have is in fact a correct representation of the machine address to which you want to connect, assigning that value to sin_addr.s_addr of your address structure is just right. In principle, there could be more members of that struct, but in practice, implementations that want to be interoperable will not require you to set any other members. Most don't have other members at all.
Do note, however, that just because connect() receives the address structure via a pointer does not mean you need to use dynamic allocation. It would be a bit more idiomatic to do this:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in srvraddr = { 0 };
srvraddr.sin_family = AF_INET;
srvraddr.sin_port = htons(PORT_A);
srvraddr.sin_addr.s_addr = var;
connect(sockfd, (struct sockaddr *) &srvraddr, sizeof(srvraddr));
Among other things, that saves you having to free the memory afterward.
Whatever I try to do connect always returns me -1. Using perror I get the following error: Connection refused.
As far as I can see, the code you've presented is fine. You may want to check how you are obtaining the in_addr_t value in the first place, and to verify the port number you are using. On the other hand, do not overlook the possibility that the problem is at the remote host: perhaps the port you are trying to connect to is just not open (to you).

This is my way of using connect() to get a connection to "example.com" on port 80:
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
int main(void)
{
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
fprintf(stderr, "socket");
return 0;
}
char domain[] = "example.com";
struct hostent *he;
he = gethostbyname (domain);
if (!he)
{
switch (h_errno)
{
case HOST_NOT_FOUND:
fputs ("The host was not found.\n", stderr);
break;
case NO_ADDRESS:
fputs ("The name is valid but it has no address.\n", stderr);
break;
case NO_RECOVERY:
fputs ("A non-recoverable name server error occurred.\n", stderr);
break;
case TRY_AGAIN:
fputs ("The name server is temporarily unavailable.", stderr);
break;
}
return 1;
}
if (he->h_length < 4)
return 1;
struct sockaddr_in srvraddr;
srvraddr.sin_len = sizeof(srvraddr);
srvraddr.sin_family = AF_INET;
srvraddr.sin_port = htons(80);
srvraddr.sin_addr = * (struct in_addr *) he->h_addr_list[0];
if (connect(sockfd, (struct sockaddr*)&srvraddr, srvraddr.sin_len) == -1) {
fprintf(stderr,"connect() failed\n");
return 1;
}
// Use conection here...
close(sockfd);
return 0;
}

Related

custom tcp over udp socket bind

I am trying to make basic reliable connection over udp. I have defined the custom bind function which takes same kind of arguments as TCP bind but in my function during passing parameters I got the error message as below:
bind() failed: Address family not supported by protocol
I have defined the r_bind function in one file and is accessed from next file. The function is as below:
int r_bind(int sockfd, struct sockaddr *addr,socklen_t addrlen){
return bind(sockfd, (struct sockaddr*) &addr, addrlen);
}
typedef struct brp_socket{
int sockfd;
struct sockaddr_in brp_serveraddr;
struct sockaddr_in brp_useraddr;
}brp_socket;
I have made call from user1.c file. The socket was created successfully but during binding I got the error. I have made the following function call.
brp_socket socket_list[BRP_MAX_SOCKET];
int socket_index = 0;
int servSock; // Socket descriptor for server
servSock = r_socket(AF_INET, SOCK_BRP, 0)
socket_list[socket_index].sockfd = servSock;
memset(&socket_list[socket_index].brp_serveraddr, 0, sizeof(socket_list[socket_index].brp_serveraddr)); // Zero out structure
socket_list[socket_index].brp_serveraddr.sin_family = AF_INET; // IPv4 address family
socket_list[socket_index].brp_serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface
socket_list[socket_index].brp_serveraddr.sin_port = htons(servPort); // Local port
if (r_bind(socket_list[socket_index].sockfd, (struct sockaddr*)&(socket_list[socket_index].brp_serveraddr), sizeof(socket_list[socket_index].brp_serveraddr)) < 0)
#define SOCK_BRP 1
int r_socket(int domain, int type, int protocol){
if(type == 1)
{
return socket(domain,SOCK_DGRAM,protocol);
}
}
Here BRP_SOCK is custom made protocol type.
Can anyone suggest me where I made the mistake?

Setup IP Address info from unsigned int in C

I got in my code a problem about sending something.
I got for example 2 Server.
This is Server 1:
unsigned int ip = 19216821;
unsigned int port = 4000;
char str[0];
sprintf(str, "%d", ip);
if ((dest_he=gethostbyname(str)) == NULL) { // get the host info
herror("gethostbyname");
exit(1);
}
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr = *((struct in_addr *)dest_he->h_addr);
memset(dest_addr.sin_zero, '\0', sizeof dest_addr.sin_zero);
then i want to send my buffer to dest_addr
if(sendto(sockfd, &buffer, sizeof(buffer),0, (struct sockaddr *)&dest_addr ,sizeof(struct sockaddr_storage)) == -1){
printf("error sending data\n");
return -1;
}
but I still get sendto(..) == -1.
My other Server is still waiting for an answer.
Server 2:
if(recvfrom(sockfd, &buffer, sizeof(buffer),0, (struct sockaddr *)&rand_addr ,&addr_size) == -1){
printf("error receiving data");
return -1;
}
I think my problem is that i setup the dest_addr wrong or?
First of all, your title doesn't really match your description. Nevertheless I'll make my best to answer your question.
Basically, you're not using correctly the function gethostbyname. As the name says it gets the host by its name not address. Hence, a correct usage would be:
struct hostent *host = gethostbyname("localhost");
To copy the result to your struct you can use:
memcpy(&dest_addr.sin_addr, host->h_addr_list[0], host->h_length);
On the other hand, if you want to send a message to a known IP-Address you can use:
char *ip = "127.0.0.1"
inet_aton(ip , &dest_addr.sin_addr)
Other than that everything looks fine. There are plenty of examples online on how to use TCP, UDP or even RAW sockets. I hope this was the answer you were expecting.

Creating a client in C: does not connect to the server

int createclientsock(char * hostname, int port){
struct hostent * hp;
printf("Attempting to create client socket!\n");
memset(&client_addr,'0',sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(port); /* holds the remote port */
/* If internet "a.d.c.d" address is specified, use inet_addr()
* to convert it into real address. If host name is specified,
* use gethostbyname() to resolve its address */
client_addr.sin_addr.s_addr = inet_addr(hostname); /* If "a.b.c.d" addr */
if (client_addr.sin_addr.s_addr == -1) {
hp = gethostbyname(hostname);
/* Call method to create server socketyname(hostname);*/
/*printf("host name: %s",hp);*/
if (hp == NULL) {
printf("ERROR: Host name %s not found\n", hostname);
exit(1);
}
}
/* Create an Address Family (AF) stream socket, implying the use of tcp as the underlying protocol */
client_fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Client_fd: %d\n",client_fd);/*ANDY: it gets to here without printing errors, the client_fd = 3 ...im not sure what that means*/
/* use the sockaddr_in struct in the to variable to connect */
if (connect(client_fd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) {
printf("ERROR: could not connect!\n");
exit(1);
}
return client_fd;
}
It gets to the connect part and takes a long time before finally printing the error statement "ERROR: could not connect!\n"
Not sure if this is your actual problem but the line:
memset(&client_addr,'0',sizeof(client_addr));
is probably not what you want. It's fills the structure with the character '0' rather than zero bytes. It would be better written as:
memset(&client_addr,'\0',sizeof(client_addr));
In addition, if you use a DNS name rather than an IP address, you never load it into the client_addr structure. You get back the hostent pointer but you should then use the h_addr_list field in that structure to populate client_addr.sin_addr.s_addr.

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

How to get peer address from OpenSSL BIO object

I'm programming TLS server using OpenSSL 1.0.0 library, as such I'm using BIO* objects, not SSL* objects (I'm using IBM documentation: part 1, part 2 and part 3).
To get a socket to remote client I run following code:
BIO *new_client;
while(1)
{
if (BIO_do_accept(socket) <= 0)
{ handle error }
new_client = BIO_pop(socket);
BIO_do_handshake(new_client);
// fire a thread and do rest of communication
}
This works without problem, I can send data to client, client can respond. If I don't provide my custom CA cert file to client, client refuses connection because failure of verification of certificate, etc. In short, everything looks perfectly well.
Problem is, I can't get peer host address.
I can't find any OpenSSL specific API to do that. Then I tried to get the file descriptor of the socket and invoke getpeername() using following code:
// get peer address
int sock_fd;
if (BIO_get_fd(socket, &sock_fd) == -1)
{
fprintf(stderr, "Uninitialized socket passed to worker");
goto listen_cleanup;
}
printf("socket fd: %i\n", sock_fd);
struct sockaddr addr;
socklen_t addr_len;
// make enough space for ipv6 address and few extra chars
ctx->hostname = malloc(sizeof(char) * 80);
if (!ctx->hostname)
{
fprintf(stderr, "Out of memory\n");
goto internal_error;
}
// ignore failures, as any problem will be caught in TLS handshake
getpeername(sock_fd, &addr, &addr_len);
if (addr.sa_family == AF_INET)
inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr,
ctx->hostname, 40);
else if (addr.sa_family == AF_INET6)
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
ctx->hostname, 40);
else
{
fprintf(stderr, "Unknown socket type passed to worker(): %i\n",
addr.sa_family);
goto internal_error;
}
but both before and after BIO_do_handshake(), it fails while checking sa_family, I get Unknown socket type passed to worker(): 50576.
How to get peer address while using OpenSSL BIO objects that wrap TLS?
The prototype is:
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
The addrlen argument is actually an in/out argument, and this is where you problem is. You need to intialize it to the size in bytes of the sockaddr argument, i.e.
addr_len = sizeof(addr); // this is what's missing
getpeername(sock_fd, &addr, &addr_len);
The getpeername function then stores in addr_len the number of bytes it wants to write into addr.
In your defense the documentation can be unclear on this point. When I do a google search for getpeername the top entry is this one. In my opinion it fails to adequately explain the address_len argument. The next entry, however, makes it all clear.
Although the top answer addresses the issue of initializing addrlen, your code will not work for IPv6 as there is not enough room being provided to getpeername for a sockaddr_in6. Running this code:
#include <stdio.h>
#include <netinet/in.h>
int main( int argc, char *argv[] ) {
printf("sizeof( struct sockaddr ) = %d\n", sizeof( struct sockaddr ));
printf("sizeof( struct sockaddr_in ) = %d\n", sizeof( struct sockaddr_in));
printf("sizeof( struct sockaddr_in6 ) = %d\n", sizeof( struct sockaddr_in6));
}
results in:
sizeof( struct sockaddr ) = 16
sizeof( struct sockaddr_in ) = 16
sizeof( struct sockaddr_in6 ) = 28
IMHO the best way to call the network functions in a protocol agnostic way is to use a union:
union address {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
};
and then invoke getpeername by:
union address peer;
socklen_t addrlen = sizeof( peer );
getpeername( sock_fd, &peer.addr, &addrlen );
Rounding out the code you've used addr.sa_family as the family selector which is great, but simplifying the use of inet_ntop:
if (peer.addr.sa_family == AF_INET)
inet_ntop(AF_INET, peer.addr4.sin_addr, ctx->hostname, 80 );
else if (peer.addr.sa_family == AF_INET6)
inet_ntop(AF_INET6, peer.addr6.sin6_addr, ctx->hostname, 80 );
else
....

Resources