I am exploring network programming in C.The code is supposed to connect to a server on port 80 send an http request and from the response print on what server is the web page running on, but it runs into Invalid Argument error. The error occurs with error message "[ERR] connecting to target server: Invalid argument" so the error should be somewhere in the connect() function.
rec = connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr) == -1);
if(rec == -1)
fail("[ERR] connecting to target server");
Although I have seen a lot of similar issues, none of the fixes neither worked or applied to this case, strangely this code works as a standalone program when parsing argc[1] instead of char *name, regardless of what the exact string literal is(ip or hostname, experimented with multiple for both). The only difference between the two being that the entire web server function is written in main and passed command-line arguments(working example) while here it is written as a standalone function and called in main where it was tested on a few web page names and IP addresses.
Any help would be appreciated as I feel this might be some simple mistake I overlooked or something I don't understand well enough. Thanks!
int web_server(char *name){
int sockfd, rec;
struct hostent *host_info;
//struct in_addr *address;
struct sockaddr_in target_addr;
unsigned char buffer[4096];
if(is_ip(name)){
target_addr.sin_addr.s_addr = inet_addr(name);
} else if(host_info = gethostbyname(name)){
if(host_info == NULL){
fail("[ERR] looking up hostname!");
}else{
target_addr.sin_addr = *((struct in_addr *) host_info -> h_addr);
}
} else{
fail("[ERR] getting address");
}
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(80);
memset(&(target_addr.sin_zero), 0, 8);
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if(sockfd == -1){
fail("[ERR] in socket");
}
rec = connect(sockfd, (struct sockaddr *)&target_addr, sizeof(struct sockaddr) == -1);
if(rec == -1)
fail("[ERR] connecting to target server");
send_string(sockfd, "HEAD / HTTP/1.0\r\n\r\n");
while(recv_line(sockfd, buffer)){
if(strncasecmp(buffer, "Server: ", 7) == 0){
printf("The web server for %s is %s\n", name, buffer+8);
}
}
close(sockfd);
printf("Server line not found\n");
exit(1);
}
int main(){
web_server("127.0.0.1");//doesn't work with hostnames either
}
Related
There are some other questions related to this, but they are not solving my problem. So I am asking so that some other possible solution can be seen.
I am implementing the socket programming. Socket is being successfully created, and it connects successfully to localhost. But when I choose some remote server, then it gives the error 10061 and sometimes 10060. I tried many remote servers(for example: google.com and my company hostname also).
I checked the firewall it is OFF. my code is given below:
/*
Socket Programming on Windows Machine
Author : Raza Javed
Date : 11-10-2022
*/
#include<stdio.h>
#include<winsock2.h>
#include<string.h>
int main(int argc, char *argv[])
{
// Winsock Initialization
WSADATA wsa; // WSADATA is the structure that holds the information about Winsock library
SOCKET s;
struct sockaddr_in server;
struct in_addr **addr_list;
struct hostent *he;
char *hostname = "localhost";
char ip[100];
printf("Initializing Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa)!=0)
{
printf("Failed. Error Code : %d", WSAGetLastError()); //WSAGetLastError is used to get more information about what error occured.
return 1;
}
printf("Initialized.\n");
// Socket Creation
if((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
printf("Could not create the socket: %d", WSAGetLastError());
}
printf("Socket Created.\n");
// Getting IP using "gethostbyname"
if ((he = gethostbyname(hostname)) == NULL)
{
printf("gethostbyname failed : %d", WSAGetLastError());
return 1;
}
addr_list = (struct in_addr **)he -> h_addr_list; // Casting h_addr_list to in_addr
for(int i = 0; addr_list[i] != NULL; i++)
{
strcpy(ip, inet_ntoa(*addr_list[i]));
}
printf("%s resolved to %s\n", hostname, ip);
// Connecting to server
//memset(&server, "\0", sizeof(server));
server.sin_addr.s_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(49835);
if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0)
{
printf("connect error : %d", WSAGetLastError());
getchar();
return 1;
}
puts("connected");
getchar(); // To hold the terminal screen
return 0;
}
Listening port can be seen here:
TCP 127.0.0.1:49835 0.0.0.0:0 LISTENING
In case of localhost, I get the following output:
Initializing Winsock...Initialized.
Socket Created.
localhost resolved to 127.0.0.1
connected
But when I change it to some remote server for example google like below:
char *hostname = "www.google.com";
Then the output is:
Initializing Winsock...Initialized.
Socket Created.
www.google.com resolved to 142.251.209.132
connect error : 10060
Can someone please help in this. I am completely not getting it.
I found the solution myself. maybe it would be helpful for someone else.
The mistake I was doing is that I have been always using the 'wrong port' to connect. To connect to remote server for example www.google.com, the port number will be 80, so the line of the code above will be:
server.sin_port = htons(80);
because it is for HTTP connection.
just by changing the line like above. It is connected now. Results below:
Initializing Winsock...Initialized.
Socket Created.
www.google.com resolved to 142.250.186.100
connected
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.
I have a very simple socket client program that I want to use to ping my mail server (as an example) to make sure it's alive and responding. I am using the following code to connect:
portno=25;
sockfd=socket(AF_INET,SOCK_STREAM,0);
if (sockfd<0) error("Cannot open socket");
server=gethostbyname(argv[2]);
if (server==NULL) {
printf("Error: No such host exists\n");
exit(3);
}
bzero((char*)&srvr,sizeof(srvr));
srvr.sin_family=AF_INET;
bcopy((char*)&server->h_addr,(char*)&srvr.sin_addr.s_addr,server->h_length);
srvr.sin_port=htons(portno);
if (connect(sockfd,(struct sockaddr*)&srvr,sizeof(srvr)) <0) error("Error connecting");
I pass the server name (as localhost) on the command line as the second parameter. It always hangs in the connect call. I have tried to also connect to one of google's mail servers with the same result.
I am able to telnet into port 25 on both my local server and the google server and issue the HELO command and get a response. I am running the program as root.
I am unsure how to proceed further in order to determine the problem. Any help would be appreciated.
The code is apparently not complete. You might want to make a couple of debug messaging including a check for the correct input to gethostbyname().
You should normally use IPPROTO_TCP as protocol, instead of 0.
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
You might want to use a tool like strace to see more details about how the system calls went on.
It's usually better to use getaddrinfo().
const char *node = "www.fedoraproject.org";
const char *service = "http";
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP,
.ai_flags = AI_ADDRCONFIG,
.ai_canonname = NULL,
.ai_addr = NULL,
.ai_next = NULL
};
struct addrinfo *result;
int error;
error = getaddrinfo(node, service, &hints, &result);
struct addrinfo *item;
int sock;
for (item = result; item; item = item->ai_next) {
sock = socket(item->ai_family, item->ai_socktype, item->ai_protocol);
if (sock == -1)
continue;
if (connect(sock, item->ai_addr, item->ai_addrlen) != -1) {
fprintf(stderr, "Connected successfully.");
break;
}
close(sock);
}
freeaddrinfo(result);
See: https://fedoraproject.org/wiki/Networking/NameResolution#Connecting_to_services_using_getaddrinfo.28.29
Basically my server/client socket functions work perfectly fine using the loopback address, or even my eth0 address on my laptop. Howver, once I move my code into the test environment it will be used in, I get connection time outs, or connection refused depending on the changes I have tried to make.
As of now the code I am about to post results in a Connection time out.
CLIENT
void buildConnection(int* txmt_sock, Connection conn_info)
{
struct sockaddr_in servinfo; /* server address */
servinfo.sin_family = AF_INET;
servinfo.sin_addr.s_addr = INADDR_ANY;
servinfo.sin_port = htons(conn_info.port);
if(inet_aton(conn_info.ip, &servinfo.sin_addr) < 1)
{
fprintf(stderr, "Read error: %s\n", strerror(errno));
abort();
}
/*int socket(int domain, int type, int protocol)*/
if ((*txmt_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("client: socket");
abort();
}
/*int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);*/
if (connect(*txmt_sock,(struct sockaddr *)&servinfo,(socklen_t)sizeof(servinfo)) == -1)
{
close(*txmt_sock);
perror("client: connect");
abort();
}
printf("Successfully connected on port %s:%d\n", conn_info.ip, conn_info.port);
}
SERVER
void returnConnection(Connection* conn_info)
{
int status, ext_conn, yes = 1;
char portStr[5];
struct addrinfo hints, *servinfo;
struct sockaddr_storage ext_addr;
socklen_t addr_size;
struct sockaddr *restrict;
/* Formats PORT for use with getaddrinfo(), can't cast #define*/
snprintf(portStr, 6, "%d", conn_info->port);
memset(&hints, 0, sizeof(hints)); /*make sure the struct is empty*/
hints.ai_family = AF_UNSPEC; /*don't care IPv4 or IPv6*/
hints.ai_socktype = SOCK_STREAM; /*TCP stream sockets*/
hints.ai_flags = AI_PASSIVE; /*fill in my IP for me*/
if ((status = getaddrinfo(NULL, portStr, &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
if((conn_info->listen_sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
{
fprintf(stderr, "Socket error: %s\n", strerror(errno));
exit(1);
}
if(setsockopt(conn_info->listen_sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
if(bind(conn_info->listen_sock, servinfo->ai_addr, servinfo->ai_addrlen) == -1)
{
fprintf(stderr, "Bind error: %s\n", strerror(errno));
exit(1);
}
freeaddrinfo(servinfo);
if(listen(conn_info->listen_sock, 1) == 1)
{
fprintf(stderr, "Listening error: %s\n", strerror(errno));
exit(1);
}
addr_size = sizeof(ext_conn);
if((ext_conn = accept(conn_info->listen_sock, (struct sockaddr *)&ext_addr, &addr_size)) == -1)
{
fprintf(stderr, "Accept error: %s\n", strerror(errno));
exit(1);
};
conn_info->receiving_sock = ext_conn;
}
This is a multi-threaded program that collects image data from 8 different ports/threads. I use my Connection struct to store all the pertinent data for each thread. Each thread has it's own Connection.
typedef struct connection{
char* file;
int port;
char* ip;
pthread_t *thread;
}Connection;
Connection->ip is not used in the server side, but is uses on the Client side. The server side of the code resides on a multi-cpu, multi-nic IBM server. I am not certain if I need to manually assign the IP or not because of that. I am assuming the OS and network cards manage on their own using the incoming PORT numbers from the clients, and the individual PORT numbers that my Server threads listen on. But all I know is that it works on my laptop to itself.
It's a completely new vanilla install on this machine with openSuse, so I don't think any of the ports I am using, 5050-5053 and 5055-5058, are turned off or anything like that.
In C, I am trying to connect to a server using the following function:
int clientConnect() {
//1. Set up connection address and port
char *ipAddress = SMSA_DEFAULT_IP;
int port = SMSA_DEFAULT_PORT;
//1a. Set up a sockaddr_in struct as described in lecture
struct sockaddr_in caddr;
caddr.sin_family = AF_INET;
caddr.sin_addr.s_addr = htonl(SMSA_DEFAULT_IP);
caddr.sin_port = htons( port );
//2. Create a socket
server_socket = socket(PF_INET, SOCK_STREAM, 0);
if(server_socket == -1)
{
logMessage(1, "There was an error creating a socket in clientConnect()");
return -1;
}
//3. Connect
if( connect(server_socket, (const struct sockaddr *)&caddr, sizeof(struct sockaddr) ) == -1)
{
logMessage(1, "There was an error connecting in clientConnect()");\
return -1;
}
logMessage(2, "The connection was made!");
return 0;}
When this function is called, I get a message in my log There was an error connecting in clientConnect(). This is my first time doing network programming with C so I suspect I am missing something.
The last argument to connect should be sizeof caddr:
connect(server_socket, (const struct sockaddr *)&caddr, sizeof caddr);