#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3)
{
fprintf(stderr, "usage %s hostname port\n", argv[0]);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0);
{
error("ERROR opening socket");
}
server = gethostbyname(argv[1]);
if (server == NULL)
{
fprintf(stderr, "ERROR, no such host\n");
exit(0);
}
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
serv_addr.sin_port = htons(portno);
if(connect(sockfd, &serv_addr, sizeof(serv_addr)) < 0)
{
error("ERROR connecting");
}
printf("Please enter the message:");
bzero(buffer, 256);
fgets(buffer, 255, stdin);
n = write(sockfd, buffer, strlen(buffer));
if (n <0)
{
error("ERROR reading from socket");
}
printf("%s\n", buffer);
return 0;
}
When I run this program, I got the error
ERROR opening socket: Success
then the program does nothing. Also, I got the warning that
warning: passing argument 2 of ‘connect’ from incompatible pointer type [enabled by default]
if(connect(sockfd,&serv_addr, sizeof(serv_addr)) < 0)
^
In file included from Clientown.c:3:0:
/usr/include/sys/socket.h:138:12: note: expected ‘const struct sockaddr *’ but argument is of type ‘struct sockaddr_in *’
extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
How is this happening? I am new to c and I really stuck with this code. Is there something wrong with the connect? Does the warning matter? Can someone help to me fix it? Thanks.
You have a semicolon where there should not be a semicolon:
if (sockfd < 0);
{
error("ERROR opening socket");
}
As a result, the error() function will always be called, even if the if condition fails. You want:
if (sockfd < 0)
{
error("ERROR opening socket");
}
Penguin Brian already answered the stated question, but I'd like to point out that since the asker is using POSIX/BSD sockets, they should also use the proper interfaces, namely getaddrinfo(). It handles both name and port/service translation, and supports IPv4 and IPv6 (allowing the caller to restrict to either one if desired, of course).
The man 3 getaddrinfo man page does include two example programs (client and server type), but here's mine, for illustration, with sufficient error checking:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
struct addrinfo hints, *list, *curr;
const char *host, *port;
int sockfd, result;
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("\n");
printf("Usage: %s [ -h | --help ]\n", argv[0]);
printf(" %s host port\n", argv[0]);
printf("\n");
return EXIT_FAILURE;
}
host = argv[1];
port = argv[2];
/* "" or "-" host refers to loopback. */
if (!host[0] || (host[0] == '-' && !host[1]))
host = NULL;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* TCP */
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
list = NULL;
result = getaddrinfo(host, port, &hints, &list);
if (result) {
fprintf(stderr, "%s.\n", gai_strerror(result));
return EXIT_FAILURE;
}
for (curr = list; curr; curr = curr->ai_next) {
sockfd = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
if (sockfd == -1)
continue;
if (connect(sockfd, curr->ai_addr, curr->ai_addrlen) != -1)
break;
close(sockfd);
sockfd = -1;
}
if (sockfd == -1) {
freeaddrinfo(list);
fprintf(stderr, "Cannot connect.\n");
return EXIT_FAILURE;
}
printf("Descriptor %d is now connected. Disconnecting.\n", sockfd);
fflush(stdout);
if (close(sockfd)) {
fprintf(stderr, "Error closing socket: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("Done.\n");
return EXIT_SUCCESS;
}
Note that the above code does not record or report the error messages from the connect() call, because the getaddrinfo() interface provides multiple alternatives, and I'm not sure which of the errors produced in a typical case is the proper one to report. (Remember that even in a successful connection case, one or more of the connect() calls in the loop may have failed, without any actual "error" having occurred.) The getaddrinfo() call itself will fail if the host (node) or port (service) part is invalid.
In my own applications, I tend to use an error cookie -- one bit per error -- to record all the errors from the connect() calls for one result list from a getaddrinfo() call. The errors I test for are EADDRINUSE (local port already in use), ECONNREFUSED (connection refused), ENETUNREACH (network unreachable), EACCES (permission denied), EADDRNOTAVAIL (all ephemeral ports already in use), EAFNOSUPPORT (address family (IPv4/IPv6) not supported), and a catch-all for all other errors.
If none of the connect() calls succeed, I check the cookie for errors that did occur -- as an unordered set; i.e., ignoring the order in which they occurred --, and report the first match to the above list. It's not foolproof by any measure, more like trying-to-be-helpful heuristic, and I suspect that a generic error message ("Cannot connect" or similar -- this is what browsers do, after all) is generally just as useful to most users.
On the second question: You pass a pointer to a specific Internet socket address structure, but connect expects a generic socket address structure, so simply cast one type of pointer to the other:
connect(sockfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)
This warning is actually almost irrelevant, since all pointer types on modern architectures have the same size.
Related
Spending way too much time trying to figure out why inet_ntop is always returning the same IP address of 2.0.19.86 inside of my barebones C UDP socket program.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "4950" // the port users will be connecting to
int main(int argc, char *argv[])
{
int sock;
struct addrinfo addr_type, *server_info, *p;
int err;
int numbytes;
if (argc != 3) {
fprintf(stderr,"usage: talker hostname message\n");
exit(1);
}
//Specify type of response we want to git
memset(&addr_type, 0, sizeof addr_type);
addr_type.ai_family = AF_INET; // set to AF_INET to use IPv4
addr_type.ai_socktype = SOCK_DGRAM;
//Get the address info (like IP address) and store in server_info struct
if ((err = getaddrinfo(argv[1], SERVERPORT, &addr_type, &server_info)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return 1;
}
// There might be multiple IP addresses...loop through and use the first one that works
for(p = server_info; p != NULL; p = p->ai_next) {
if ((sock = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("Error when creating socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Client failed to create socket\n");
return 2;
}
char s[INET_ADDRSTRLEN];
inet_ntop(AF_INET,(struct sockaddr_in *)p->ai_addr,s, sizeof s);
printf("sending to %s....\n",s);
if ((numbytes = sendto(sock, argv[2], strlen(argv[2]), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("Error sending message");
exit(1);
}
printf("client sent %d bytes to %s\n", numbytes, argv[1]);
freeaddrinfo(server_info);
close(sock);
return 0;
}
The lines I am particularly stuck on is:
char s[INET_ADDRSTRLEN];
inet_ntop(AF_INET,(struct sockaddr_in *)p->ai_addr,s, sizeof s);
printf("sending to %s....\n",s);
For example I run the program with ./client www.google.com hello and get the following:
sending to 2.0.19.86....
client sent 5 bytes to www.google.com
I run the program again with ./client localhost hello and inet_ntop still returns the same IP.
sending to 2.0.19.86....
client sent 5 bytes to localhost
No errors are being thrown when I am creating the socket, and the message sends successfully when I send it to the receiving program over localhost, why is inet_ntop still outputting this weird address?
In your call to inet_ntop:
inet_ntop(AF_INET,(struct sockaddr_in *)p->ai_addr,s, sizeof s);
You're not passing in the correct structure. When AF_INET is passed as the first argument, the second argument should have type struct in_addr *, not struct sockaddr_in *.
You need to call out the sin_addr member which is of this type.
inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, s, sizeof s);
I'm trying to implement communication by UDP protocol, and I'm getting an error: "Error sending: Address family not supported by protocol". I've checked in Google for this problem but couldn't managed to find answer.
Please be patient, I'm only starting my adventure with coding in C.
Here is a C code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define BUFLEN 512
// define function that deals with errors
void error(const char *msg)
{
perror(msg); // print error msg
exit(1); // exit the main() function
}
int main(int argc, char *argv[])
{
struct sockaddr_in serv1_addr, serv2_addr, cli1_addr, cli2_addr; //definicja struktur adresów servera i clienta
struct hostent *server; //defines host addres struct
int cl1_sockfd, se1_sockfd, se2_sockfd, i, c1len = sizeof(cli1_addr), c2len = sizeof(cli2_addr), recv_len, portno1,portno2; // creates inits
int cli1_len = sizeof(cli1_addr);
int cli2_len = sizeof(cli2_addr);
char buf[BUFLEN];
if (argc < 4) {
fprintf(stderr,"ERROR, no port provided\n"); // deal with wrong port
exit(1);
}
//tworzenie soceketu servera
if ((se1_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
error("socket1"); //if socket() return -1 -- error
}
if ((se2_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1){
error("socket2"); //if socket() return -1 -- error
}
//zero out the structure
memset( &serv1_addr, 0, sizeof(serv1_addr)); //put zero into structure
memset( &serv2_addr, 0, sizeof(serv2_addr)); //put zero into structure
portno1 = atoi(argv[2]); // get port number
portno2 = atoi(argv[3]);
serv1_addr.sin_family = AF_INET; // specify address family (IPv4)
serv1_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv1_addr.sin_port = htons(portno1); // set port number
serv2_addr.sin_family = AF_INET; // specify address family (IPv4)
serv2_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv2_addr.sin_port = htons(portno2); // set port number
if(connect(se1_sockfd,(struct sockaddr *) &serv1_addr, sizeof(serv1_addr)) < 0)
error ("ERROR connecting1"); //if connection failed
if(connect(se2_sockfd,(struct sockaddr *) &serv2_addr, sizeof(serv2_addr)) < 0)
error ("ERROR connecting2"); //if connection failed
while(1) //inf loop
{
printf("Please enter the message: "); //write the msg to socket
bzero(buf, 512); //fill buffer with zeros
fgets(buf, 512, stdin); //read into buffer
if( sendto( se1_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli1_addr, cli1_len) < 0)
error ("Error sending1");
if( sendto( se2_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli2_addr, cli2_len) < 0)
error ("Error sending2");
if (recvfrom(se1_sockfd, buf, BUFLEN, 0, (struct sockaddr *) &cli1_addr, &cli1_len) == -1){
error("recivfrom()1"); //if reciving failed -- error
}
printf("Data: %s\n", buf);
if (recvfrom(se2_sockfd, buf, BUFLEN, 0, (struct sockaddr *) &cli2_addr, &cli2_len) == -1){
error("recivfrom()2"); //if reciving failed -- error
}
printf("Data: %s\n", buf);
}
close(se1_sockfd);
close(se2_sockfd);
return 0;
}
Thanks for your help. ;)
Your issue is likely because of uninitialized destination address. sendto() takes destination address as the one before the last argument. But you are trying to provide not-initialized address (like for recvfrom())
if( sendto( se1_sockfd, buf, BUFLEN, 0, (struct sockaddr*) &cli1_addr, cli1_len) < 0)
error ("Error sending1");
^^^
Try serv1_addr instead ?
Also need to provide appropriate size.
One more thing. As long as you use sendto() - no need to perform connect(). UDP is connectionless and connect() only establishes default destination address for those who is going to use send() on such socket. But this is not your case because you provide destination address each time you call sendto(). Even more - you may use different addresses each time.
P.S. Reference: sendto()
I am building a multiclient UDP server in c,but when i tried to connect to my server from a system, i get this error ERROR on gethostbyaddr: Success
Please find the below server code.I have tried the solutions from similar questions(gethostbyaddr() returns NULL but errno result in SUCCESS) but i couldn't get it working.Any help will be greatly appreciated
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv) {
int sockfd; /* socket */
int portno; /* port to listen on */
int clientlen; /* byte size of client's address */
struct sockaddr_in serveraddr; /* server's addr */
struct sockaddr_in clientaddr; /* client addr */
struct hostent *hostp; /* client host info */
char buf[BUFSIZE]; /* message buf */
char *hostaddrp; /* dotted decimal host addr string */
int optval; /* flag value for setsockopt */
int n; /* message byte size */
FILE *fp; /* file variable */
char str[10];
int i = 0;
char userlist[10];
int array_size;
char line[256];
int cred,flag;
/*
* check command line arguments
*/
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]);
exit(1);
}
portno = atoi(argv[1]);
/*
* socket: create the parent socket
*/
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* setsockopt: Handy debugging trick that lets
* us rerun the server immediately after we kill it;
* otherwise we have to wait about 20 secs.
* Eliminates "ERROR on binding: Address already in use" error.
*/
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
/*
* build the server's Internet address
*/
bzero((char *) &serveraddr, sizeof(serveraddr));
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)portno);
/*
* bind: associate the parent socket with a port
*/
if (bind(sockfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error("ERROR on binding");
/*
* main loop: wait for a datagram, then echo it
*/
clientlen = sizeof(clientaddr);
while (1) {
/*
* recvfrom: receive a UDP datagram from a client
*/
bzero(buf, BUFSIZE);
n = recvfrom(sockfd, buf, BUFSIZE, 0,
(struct sockaddr *) &clientaddr, &clientlen);
if (n < 0)
error("ERROR in recvfrom");
/*
* gethostbyaddr: determine who sent the datagram
*/
hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
sizeof(clientaddr.sin_addr.s_addr), AF_INET);
if (hostp == NULL)
error("ERROR on gethostbyaddr");
hostaddrp = inet_ntoa(clientaddr.sin_addr);
if (hostaddrp == NULL)
error("ERROR on inet_ntoa\n");
printf("server received datagram from %s (%s)\n",
hostp->h_name, hostaddrp);
printf("server received %d/%d bytes: %s\n", strlen(buf), n, buf);
fp = fopen("users.txt", "r");
while (fgets(line, sizeof(line), fp)) {
//printf("%s\n",line);
cred = strncmp(buf,line,strlen(line)-1);
//printf("%d",strlen(line)-1);
if(cred == 0){
printf("Authenticated....");
flag = 1;
break;
}
else{
printf("Invalid username/password");
}
}
fclose(fp);
gethostbyaddr() expects a pointer to a struct in_addr as 1st parameter, which would be &clientaddr.sin_addr for the code you show.
Form the relevant (Linux) documentation (man gethostbyaddr):
[...] The host address argument is a pointer to a struct of a type depending on the address type, for example a struct in_addr * (probably obtained via a call to inet_addr(3)) for address type AF_INET.
gethostbyaddr() sets the error code in h_errno not in errno.
Form the relevant (Linux) documentation (man gethostbyaddr):
RETURN VALUE
[...[ The gethostbyname() and gethostbyaddr() functions return the hostent structure or a null pointer if an error occurs. On error, the h_errno variable holds an error number.
The possible error code are given by the man-page as well:
ERRORS
The variable h_errno can have the following values:
HOST_NOT_FOUND
The specified host is unknown.
NO_ADDRESS or NO_DATA
The requested name is valid but does not have an IP address.
NO_RECOVERY
A nonrecoverable name server error occurred.
TRY_AGAIN
A temporary error occurred on an authoritative name server. Try again later.
I coded this little server and it doesn't work. The message directly at the beginning isn't printed out as well and I don't know how to analyse the problem by using gdb. Could you help me? Is there any library missing or whats wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 7890
int main(void) {
printf("HelloWorld");
int sockfd, sock_client;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
printf("Could no open socket\n");
}
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == -1) {
printf("Coud not reuse\n");
}
printf("socket was created");
struct sockaddr_in sockaddr_host, sockaddr_client;
sockaddr_host.sin_family = AF_INET;
sockaddr_host.sin_port = htons(PORT);
sockaddr_host.sin_addr.s_addr = 0;
memset(&(sockaddr_host.sin_zero), '\0', 8);
if (bind(sockfd, (struct sockaddr *) &sockaddr_host, sizeof (sockaddr_host)) == -1) {
printf("Could not bind socket");
}
if (listen(sockfd, 1) == -1) {
printf("Could not start listening");
} else {
printf("Server is listening on %s: %d", inet_ntoa(sockaddr_host.sin_addr), ntohs(sockaddr_host.sin_port));
}
while (1) {
socklen_t client_length = sizeof (sockaddr_client);
if ((sock_client = accept(sockfd, (struct sockaddr *) &sockaddr_client, &client_length)) == -1) {
printf("Could not accept connection");
}
printf("sever: got connection from %s on port %d", inet_ntoa(sockaddr_client.sin_addr), ntohs(sockaddr_client.sin_port));
char message[] = "Hello\n";
if (send(sockfd, message, sizeof (message), 0) == -1) {
printf("Could not send message");
}
close(sock_client);
close(sockfd);
}
return 0;
}
If you were missing a library, the linker would already complain.
Standard output is usually line buffered. Add a newline after HelloWorld and you will see at least the first output.
printf("HelloWorld\n");
Same with the other printf.
After adding \n to each printf, you will see
HelloWorld
socket was created
Server is listening on 0.0.0.0: 7890
When you now connect to your server, e.g. with netcat
nc localhost 7890
your server will output
sever: got connection from 127.0.0.1 on port 36496
Some errors remain though.
if(send(sockfd, message, sizeof(message), 0) == -1) {
should be rather
if(send(sock_client, message, sizeof(message) - 1, 0) == -1) {
Otherwise the server sends the message to itself. Also sizeof(message) includes the final \0.
Finally, you shouldn't close(sockfd);, if you want to continue receiving further connection requests beyond the first one.
As you said
The message directly at the beginning isn't printed out as well
After the printf add fflush as
printf("HelloWorld");
fflush(stdout);
Is there any library missing
I don't thinks so any library is missing because you have successfully compiled the program and created the executable.
I am new to socket programming.I looked at a program in the Tutorialspoint.I made a little changes to the program but while compiling I am encountering errors.I am attaching an image telling about the errors..
In addition, I don't understand what is sin_family and sin_port.Shall I replace them with serv_addr_family and serv_addr_port respectively?
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <netdb.h>
#define portno 5432
int main(int argc, char *argv[])
{
int sockfd,n;
const struct sockaddr_in serv_addr;
const struct hostent *server;
char buffer[256];
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
return;
}
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
return;
}
/* Create a socket point */
bzero((char *)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy(*server->h_addr,
(char *)&serv_addr.sin_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("ERROR opening socket");
return;
}
/* Now connect to the server */
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
{
perror("ERROR connecting");
return;
}
/* Now ask for a message from the user, this message
* will be read by server
*/
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
/* Send message to the server */
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
{
perror("ERROR writing to socket");
return;
}
/* Now read server response */
bzero(buffer,256);
n = read(sockfd,buffer,255);
if (n < 0)
{
perror("ERROR reading from socket");
return;
}
printf("%s\n",buffer);
return 0;
}
you have to remove const before the stuct.
it's used to configure your socket.(port, ip, ...)
int sockfd,n;
const struct sockaddr_in serv_addr;
const struct hostent *server;
to
int sockfd,n;
struct sockaddr_in serv_addr;
struct hostent *server;
There are a few things to correct here:
Firstly,
const struct sockaddr_in serv_addr;
You won't be able to modify serv_addr as it is read-only.
So you may need to remove the const keyword.
On rectifying the above step. You will still run into undefined-behavior in the following statement.
bcopy(*server->h_addr, (char *)&serv_addr.sin_addr, server->h_length);
Change to to below:
bcopy(server->h_addr, (char *)&serv_addr.sin_addr, server->h_length);
Notice the removal of * in the first argument.
The deference is incorrect.
As per comments, I too recommend usage of memcpy like functions.
As a part of good coding practice. Always return with the proper return-type.
Leads to -Wreturn-type as your main expects an int returned .
Example Change:
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
return;
}
to return -1 maybe.