chenyinuo
chenyinuo

Reputation: 99

ERROR opening socket: Success

#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.

Upvotes: 1

Views: 1881

Answers (3)

Nominal Animal
Nominal Animal

Reputation: 39396

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.

Upvotes: 2

Penguin Brian
Penguin Brian

Reputation: 2141

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

Upvotes: 3

DYZ
DYZ

Reputation: 57085

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.

Upvotes: 1

Related Questions