gethostbyname, connecting to the internet at large? - c

I'm writing a basic proxy server in C for class.
I'm testing with firefox, and I've got the server successfully receiving the browser's requests.
But now I need to send them out to the internet to get the pages the browser wants, and I'm hesitant.
Here is my present code for connecting.
I'm not sure if port 8080 is correct, and I'm not sure what to put for "gethostbyname".
That's the portion I was hoping to get some advice on.
int sock = socket( PF_INET, SOCK_STREAM, 0 );
if ( sock < 0 )
{
perror( "socket() failed" );
return EXIT_FAILURE;
}
struct sockaddr_in server;
struct hostent * hp;
server.sin_family = PF_INET;
hp = gethostbyname( "localhost" );
if ( hp == NULL )
{
perror( "Unknown host" );
return EXIT_FAILURE;
}
bcopy( (char *)hp->h_addr, (char *)&server.sin_addr, hp->h_length );
int port = 8080;
server.sin_port = htons( port );
if ( connect( sock, (struct sockaddr *)&server, sizeof( server ) ) < 0 )
{
perror( "connect() failed" );
return EXIT_FAILURE;
}

That entire gethostbyname, copying around (ha - even with the overly old bcopy)... just use getaddrinfo (extensive error checking left out for brevity):
int ret = getaddrinfo("localhost", "80" /* (or 8080, whichever applies) */, NULL, &res);
if (ret == 0) {
const struct addrinfo *r;
for (r = res; r != NULL || ret != 0; r = r->ai_next)
ret = connect(fd, res->ai_addr, res->ai_addrlen);
}
freeaddrinfo(res);

Related

What IP address should be bound to a server application's socket?

I've just recently started playing around with sockets in C. Today I've been trying to write a server application to run on an old laptop of mine, just to experiment a bit.
I'd like for the server's services to be accessible from remote hosts and I'm confused about which IP address the server's socket should be bound to: is there an IP address that uniquely identifies my machine online or am I missing a step (or possibly many more) here?
struct sockaddr_in serverAddress;
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddress.sin_port = htons(8080);
if(bind(serverSocketDescriptor, (struct sockaddr*) &serverAddress, sizeof(serverAddress)) < 0) {
printf("bind() failed\n");
closesocket(serverSocketDescriptor);
WSACleanup();
return EXIT_FAILURE;
}
You want to bind to INADDR_ANY, which translates to 0.0.0.0.
serverAddress.sin_addr.s_addr = INADDR_ANY;
Binding to this address means the socket is bound to all local addresses, including localhost and any external IPs the host may have.
Suggest reading: server code sequence
// int socket(int domain, int type, int protocol);
sock_t sock = socket(AF_INET, SOCK_STREAM, 0);
if( sock < 0 )
{
perror( "socket failed" );
exit( EXIT_FAILURE );
}
// if wanting to set any socket options (setsockopt())
// this is the place to do so
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr( INADDR_ANY );
server.sin_port = htons(8080);
if( bind( sock, (struct sockaddr*) &server, sizeof(server) ) )
{
perror( "bind() failed" );
close( sock );
exit( EXIT_FAILURE );
}
if( listen(sock, 5) )
{
perror( "listen failed" );
exit( EXIT_FAILURE );
}
struct sockaddr_in client;
size_t len = sizeof( client );
while(1)
{
sock_t clientSock = accept(sock, &client, &len);
if( clientSock < 0 )
{
perror( "accept failed" );
continue;
}
// handle client connection
close( clientSock );
}
close( sock );
Note: for long term consistency, the computer running this code needs to have a 'static' IP address, not a 'dynamic' IP address.

How to set up two UDP sockets in one executable?

I am new to the topic of network communication, but would like to set up an UDP server client connection, with one participant continuously broadcasting data whether anyone is listening in on it or not and two participants that start receiving and storing these information whenever they are ready to do so (It's fine if they miss what has been sent before that point). The idea is that there is no other communication than one participant sending data (fire and forget) and two participants receiving them, without any form of feedback to the sending part. For now I would like to get it running on my local host, but would like to use it on a network.
I have been looking into a solution for quite some time now and decided to have a client broadcast the file stream continuously on two separate ports so, so that the receiving two servers can bind to a port respectively without blocking each other (If there is a better way, I am open for suggestions).
So far I have been able to set up this kind of communication with one client and one server, following these instructions. However, when I try to set up a second socket in my client executable, I always receive the error message Invalid argument once I reach the sendto() part.
Seeing as I have not been able to find a solution myself, yet I would like to ask for some help.
My code so far consists of the
Client:
/** set up socket_1 properties */
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
/** Read address information of incoming connection */
int status;
struct addrinfo *servinfo;
if ((status = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd;
struct addrinfo *p;
for ( p = servinfo; p != NULL; p = p->ai_next ) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 1: %s.\n", strerror(errno) );
return 2;
}
/** set up socket_2 */
// ( reuse socket_1 hints and change the port number )
/** Read address information of incoming connection */
int status_2;
struct addrinfo *servinfo_2;
if ((status_2 = getaddrinfo(NULL, MYPORT_2, &hints, &servinfo_2)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status_2));
return 1;
}
/** loop through all the results and bind to the first we can */
int sockfd_2;
struct addrinfo *p_2;
for ( p_2 = servinfo_2; p_2 != NULL; p_2 = p_2->ai_next ) {
if ((sockfd_2 = socket(p_2->ai_family, p_2->ai_socktype, p_2->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
// /** Allow the reuse of a socket */
// if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
// printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
// exit(1);
// }
break;
}
if (p_2 == NULL) {
printf("[ERROR]: Failed to bind broadcaster socket 2: %s.\n", strerror(errno) );
return 2;
}
...
some file read/write related stuff
...
while ( /* some condition */ )
{
if ( ( readBytes = pread( fd, buf, BUFFER_SIZE, offset ) ) == -1 ){
printf("[ERROR]: %s.\n", strerror(errno) );
free( buf );
close( fd );
close( sockfd );
exit(1);
}
// the next line is generating the error message
if ( ( numbytes = sendto( sockfd, buf, readBytes, 0, p->ai_addr, p->ai_addrlen ) ) == -1 )
{
perror("sender_1: sendo.\n");
free( buf );
close( fd );
close( sockfd );
exit(1);
}
if ( ( numbytes = sendto( sockfd_2, buf, readBytes, 0, p_2->ai_addr, p_2->ai_addrlen ) ) == -1 )
{
perror("sender_2: sendo.\n");
free( buf );
close( fd );
close( sockfd_2 );
exit(1);
}
}
.
.
.
free( buf );
freeaddrinfo(servinfo);
freeaddrinfo(servinfo_2);
printf( "Broadcasting complete.\n" );
/** Clean what is not necessary anymore */
close( fd );
close( sockfd );
return 0;
}
I tried to add the reuse port and IP functionality to make sure that there is nothing blocking the setup of the new socket, but this did not solve my problem
My server side seems to work fine, but just in case I will post it here, too:
int main(int argc, char **argv)
{
if (argc < 2){
printf("Please provide image Name ID.\n");
exit(1);
}
struct addrinfo hints;
struct addrinfo *servinfo = NULL; // will point to getaddrinfo() results
memset(&hints, 0, sizeof hints); // make sure struct is empty
hints.ai_family = AF_UNSPEC; // don't care if IPv4 or IPv6
hints.ai_socktype = SOCK_DGRAM; // Use UDP protocol
hints.ai_flags = AI_PASSIVE;
int res;
if ((res = getaddrinfo( NULL, argv[1]/* SERVERPORT*/, &hints, &servinfo )) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(res));
return 1;
}
/** Get socket file descriptor */
int sockfd;
struct addrinfo *p = NULL;
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
/** Allow the reuse of an IP */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Allow the reuse of a socket */
if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof(int) ) == -1 ){
printf("[ERROR]: Failed setting reusable socket %s.\n", strerror( errno ) );
exit(1);
}
/** Bind found socket to desired port */
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
printf("[ERROR]: Failed to bind socket to desired port: %s.\n", strerror( errno ) );
continue;
}
break;
}
struct timeval read_timeout;
read_timeout.tv_sec = 30;
read_timeout.tv_usec = 500;
if ( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof read_timeout) < 0 ){
printf( "[ERROR]: %s.\n", strerror(errno) );
}
...
some file read/write stuff
...
while ( ( numbytes = recvfrom(sockfd, buf, BUFFER_SIZE, 0, (struct sockaddr *)&their_addr, &addr_len ) ) != -1)
{
.
.
.
}
printf("Done broadcasting.\n");
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
It would be much appreciated if anybody could provide me some help or point me into the right direction where to look for a solution.
Best regards

How to get client IP by the socket number in C

I'm writing a simple client-server code in C.
i was asked for the server to print the IP address of the client that connected to it.
However, i can't seem to find a way to know the client's IP address from the server console.
Is there a way to do that?
// Initialize Winsock.
if ( StartupRes != NO_ERROR )
{
printf( "error %ld at WSAStartup( ), ending program.\n", WSAGetLastError() );
// Tell the user that we could not find a usable WinSock DLL.
return;
}
/* The WinSock DLL is acceptable. Proceed. */
// Create a socket.
MainSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( MainSocket == INVALID_SOCKET )
{
printf( "Error at socket( ): %ld\n", WSAGetLastError( ) );
return;
}
// Create a sockaddr_in object and set its values.
// Declare variables
Address = inet_addr(CHANNEL_IP);
if ( Address == INADDR_NONE )
{
printf("The string \"%s\" cannot be converted into an ip address. ending program.\n",
CHANNEL_IP);
return;
}
service.sin_family = AF_INET;
service.sin_addr.s_addr = Address;
service.sin_port = htons(clientinfo->senderPort);
//Bind the socket
bindRes = bind( MainSocket, ( SOCKADDR* ) &service, sizeof( service ) );
if ( bindRes == SOCKET_ERROR )
{
printf( "Channel-bind( ) failed with error %ld. Ending program\n", WSAGetLastError( ) );
return;
}
// Listen on the Socket.
ListenRes = listen( MainSocket, SOMAXCONN );
if ( ListenRes == SOCKET_ERROR )
{
printf( "Failed listening on socket, error %ld.\n", WSAGetLastError() );
return;
}
printf("Channel waiting for sender to connect...\n");
//Accepting connection
SenderSocket = accept( MainSocket, NULL, NULL );
if ( SenderSocket == INVALID_SOCKET ){
printf( "Accepting connection with client failed, error %ld\n", WSAGetLastError() ) ;
return;}
else
printf( "Sender Connected.\n" );
You need to pass in non-null values for the second and third parameters to accept:
struct sockaddr_in client_addr;
socklen_t slen = sizeof(client_addr);
SenderSocket = accept( MainSocket, (struct sockaddr *)&client_addr, &slen );
You can then get the client's IP and port from client_addr.

How to get the name of the client when receiving an HTTP request?

I'm writing a basic proxy server in C.
I want to identify the server/machine I am receiving the request from, by name or IP.
How does one do this? I'm not sure where to get the information from.
Here's my connection code:
unsigned short port = atoi(argv[1]); /* port number to listen on */
struct sockaddr_in server;
server.sin_family = PF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( port );
/* host-to-network-short() convert to big endian */
int len = sizeof( server );
if ( bind( sock, (struct sockaddr *)&server, len ) < 0 )
{
perror( "bind() failed" );
return EXIT_FAILURE;
}
/* activate the socket as a listener */
listen( sock, 5 ); /* 5 is number of backlogged waiting client requests */
//printf( "Listener socket created and bound to port %d on fd %d\n", port, sock );
struct sockaddr_in client;
while ( 1 )
{
// printf( "Blocked on accept()\n" );
unsigned int fromlen;
int newsock = accept( sock, (struct sockaddr *)&client, &fromlen );
/* accept() blocks */
//printf( "Accepted client connection\n" );
char buffer[5000];
int n = read( newsock, buffer, 4999 );
if ( n < 1 )
{
perror("Read() failed.\n");
}
else
{
buffer[n] = '\0';
//printf( "Rcvd message from client: \n\n----\n\n%s\n\n----\n\n", buffer );
}
Here is how you retrieve IP & hostname:
struct sockaddr_in client;
[...]
int newsock = accept( sock, (struct sockaddr *)&client, &fromlen );
printf("Client accepted: %s \n", inet_ntoa(client.sin_addr));
// And the host name
struct hostent *hostName;
struct in_addr ipv4addr;
inet_pton(AF_INET, inet_ntoa(client.sin_addr), &ipv4addr);
hostName = gethostbyaddr(&ipv4addr, sizeof ipv4addr, AF_INET);
printf("Host name: %s\n", hostName->h_name);

Error "No such device" in call setsockopt when joining multicast group

I have a code in which send multicast datagrams.
A critical piece of code:
uint32_t port;
int sockfd, err_ip;
const uint32_t sizebuff = 65535 - (20 + 8);
unsigned char *buff = (unsigned char *) malloc(sizebuff);
struct sockaddr_in servaddr, cliaddr;
struct in_addr serv_in_addr;
struct ip_mreq req;
port = str2uint16(cmdsrv->ipport);
bzero(buff, (size_t)sizebuff);
bzero(&servaddr, sizeof(servaddr));
bzero(&serv_in_addr, sizeof(serv_in_addr));
err_ip = inet_aton(cmdsrv->ipaddr, &serv_in_addr);
if(( err_ip != 0 ) && ( port != 0 )) {
servaddr.sin_family = AF_INET;
servaddr.sin_addr = serv_in_addr;
servaddr.sin_port = htons(port);
memcpy(&req.imr_multiaddr,&serv_in_addr,sizeof(req.imr_multiaddr));
req.imr_interface.s_addr = INADDR_ANY;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if( sockfd == -1 ) {
int outerror = errno;
char *retstr = "Couldn't open socket\n";
pthread_exit(retstr);
}
else {
struct in_addr ifaddr;
ifaddr.s_addr = INADDR_ANY;
int optres3 =
setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
sizeof( ifaddr ));
if( optres3 == -1 ) {
int perrno = errno;
char *retstr = "Can't set IP_MULTICAST_IF for socket\n";
printf( "Error setsockopt: ERRNO = %s\n", strerror( perrno ));
printf( "%s",retstr );
pthread_exit(retstr);
}
unsigned char ttl = 32;
int optres2 =
setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
sizeof( ttl ));
if( optres2 == -1 ) {
int perrno = errno;
char *retstr = "Can't set IP_MULTICAST_TTL for socket\n";
printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
printf("%s",retstr);
pthread_exit(retstr);
}
int optres =
setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
sizeof( req ));
if( optres == -1 ) {
int perrno = errno;
char *retstr = "Can't join to multicast-group\n";
printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
printf("%s",retstr);
pthread_exit(retstr);
}
// Bind port with socket
uint16_t cliport;
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = INADDR_ANY;
if( strcmp( cmdsrv->ipport, "16011" ) == 0 ) {
cliport = str2uint16("16003");
cliaddr.sin_port = htons(cliport);
}
else if( strcmp( cmdsrv->ipport, "16012" ) == 0 ) {
cliport = str2uint16("16004");
cliaddr.sin_port = htons(cliport);
}
else {
printf("Device hasn't such port");
pthread_exit(NULL);
}
int bindres =
bind( sockfd, (struct sockaddr*)&cliaddr, sizeof( cliaddr ));
if( bindres == -1 ) {
int perrno = errno;
perror("Error in bind\n");
}
// ADD 1 BYTE
data rawdata;
rawdata.desc = 23;
printf( "SIZEOF = %d\n", sizeof( *( cmdsrv->cmd )));
memcpy( &rawdata.cmd, cmdsrv->cmd, sizeof( *( cmdsrv->cmd )));
printf( "RAWDATA: desc = %d, cmd = %d\n", rawdata.desc, rawdata.cmd );
int outerror = 0;
printf( "Send command to IP:\n addr = %s, port = %d\n",
inet_ntoa( servaddr.sin_addr ), ntohs( servaddr.sin_port ));
int size = sendto( sockfd, &rawdata, sizeof( rawdata ), 0,
(struct sockaddr*)&servaddr, sizeof( servaddr ));
if( size == -1 ) {
perror("Can't send command to socket");
}
...
Sometimes program executes successfully (at this moment I have IP - 192.168.80.122). I can capture my multicast datagram by wireshark. That's all OK.
But if I change my IP to 192.168.1.2, I get error when is called
int optres =
setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
sizeof( req ));
And I can't even capture my multicast packet. Nothing is sent.
Where's bug?
If it works for one IP but not for another, maybe this can help.
What does "IP_ADD_MEMBERSHIP: No such device" mean?
It means that the tool is trying to use multicast but the network interface doesn't support it There are two likely causes:
Your machine doesn't have multicast support enabled. For example, on Linux and FreeBSD it is possible to compile a kernel which doesn't support multicast.
You don't have a route for multicast traffic. Some systems don't add this by default, and you need to run. route add -net 224.0.0.0 netmask 224.0.0.0 eth0 (or similar). If you wish to use RAT in unicast mode only, it is possible to add the multicast route on the loopback interface.
IP_ADD_MEMBERSHIP and bind() are only required for receiving multicast, use IP_MULTICAST_IF instead for effectively a "send-only membership" of a multicast group.
IP_MULTICAST_IF sets the kernel to send multicast packets for a given group on a given interface, it is effectively "send-only" as you will not be able to receive traffic on that group after setting. This varies by platform: Posix platforms generally function this way as an optimisation, whilst Win32 will perform software level routing to propagate locally generated packets.
You might not use the interface address as INADDR_ANY.
req.imr_interface.s_addr = INADDR_ANY;
check where the loopback is running using ifconfig.
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
You need to use interface address as inet addr i.e. 127.0.0.1
Check your loopback interface address and use that address only.

Resources