[Solution] C errno 115 EINPROGRESS — Operation in Progress Fix

When you call connect() on a non-blocking socket, the connection cannot complete immediately. Instead of blocking, the kernel starts the connection in the background and returns -1 with errno set to EINPROGRESS (110 on Linux). This is not an error — it is the expected behavior for non-blocking I/O. You must use select(), poll(), or epoll() to wait for the socket to become writable, then check the connection result with getsockopt(SO_ERROR).

What You’ll See

// Set socket to non-blocking
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

int result = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
if (result == -1) {
    if (errno == EINPROGRESS) {
        // This is expected — connection is being established
        printf("Connection in progress, errno: %d\n", errno);  // 115
    }
}

Common Mistake

// WRONG — treating EINPROGRESS as a fatal error
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
    perror("connect");  // "Connection in progress"
    close(sockfd);
    return 1;  // exits without ever completing the connection
}

Correct: Non-blocking connect with select()

#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int main(void) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // Set non-blocking
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(80),
    };
    inet_pton(AF_INET, "93.184.216.34", &addr.sin_addr);

    int ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == 0) {
        // Connected immediately (rare, usually on localhost)
    } else if (errno == EINPROGRESS) {
        // Wait for the socket to become writable (connection completed)
        fd_set writefds;
        FD_ZERO(&writefds);
        FD_SET(sockfd, &writefds);

        struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };  // 5-second timeout

        ret = select(sockfd + 1, NULL, &writefds, NULL, &tv);
        if (ret > 0 && FD_ISSET(sockfd, &writefds)) {
            // Check if the connection succeeded or failed
            int error = 0;
            socklen_t len = sizeof(error);
            getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);

            if (error != 0) {
                fprintf(stderr, "Connection failed: %s\n", strerror(error));
                close(sockfd);
                return 1;
            }
            printf("Connected!\n");
        } else {
            fprintf(stderr, "Connection timed out\n");
            close(sockfd);
            return 1;
        }
    } else {
        perror("connect");
        close(sockfd);
        return 1;
    }

    close(sockfd);
    return 0;
}

Correct: Non-blocking connect with poll()

#include <poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int connect_with_poll(const char *ip, int port, int timeout_ms) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
    };
    inet_pton(AF_INET, ip, &addr.sin_addr);

    int ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == 0 || errno == EISCONN) {
        return sockfd;  // already connected
    }

    if (errno != EINPROGRESS) {
        close(sockfd);
        return -1;
    }

    struct pollfd pfd = { .fd = sockfd, .events = POLLOUT };
    ret = poll(&pfd, 1, timeout_ms);

    if (ret > 0 && (pfd.revents & POLLOUT)) {
        int error = 0;
        socklen_t len = sizeof(error);
        getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
        if (error == 0) {
            return sockfd;
        }
    }

    close(sockfd);
    return -1;
}

Correct: Non-blocking connect with epoll (Linux)

#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

int connect_with_epoll(const char *ip, int port, int timeout_ms) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(port),
    };
    inet_pton(AF_INET, ip, &addr.sin_addr);

    int ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == 0 || errno == EISCONN) {
        return sockfd;
    }
    if (errno != EINPROGRESS) {
        close(sockfd);
        return -1;
    }

    int epfd = epoll_create1(0);
    struct epoll_event ev = {
        .events = EPOLLOUT | EPOLLERR | EPOLLHUP,
        .data.fd = sockfd,
    };
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

    struct epoll_event events[1];
    ret = epoll_wait(epfd, events, 1, timeout_ms);

    if (ret > 0) {
        int error = 0;
        socklen_t len = sizeof(error);
        getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
        close(epfd);
        if (error == 0) return sockfd;
    }

    close(epfd);
    close(sockfd);
    return -1;
}

Summary

MethodWhen to Use
select()Portable, works on all Unix systems
poll()Cleaner API than select(), no fd limit
epollHigh-performance Linux-only (thousands of connections)
Check SO_ERRORAlways — after select/poll indicates writability

Comments