Thomas
Thomas

Reputation: 1706

Get access to the file descriptor of a socket

This is part of a .c file that in included into a tcp server-client message service that has one client per thread; I want to use select inside the server thread to handle new incoming connections or data being written in a buffer but the problem I have is that I need the socket file descriptor to do that of the clients and of the server.

In this part of the code the socket descriptor of the server is inside s->sd but I can seem to access it outside this function because it returns (socket).

What can I do? (large parts of code are omitted to make it readable)

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

typedef struct {
  int sd; //id of the socket??
  char *ip_addr;
  int port;   
  } MySocket;   

Socket tcp_passive_open(int port) 
{                                                                                      
  MySocket *s = (MySocket *)malloc( sizeof(MySocket) );
  struct sockaddr_in addr;
  s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);

  memset(&addr, 0, sizeof(struct sockaddr_in));
  addr.sin_family = PROTOCOLFAMILY;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(port);

  if ( bind(s->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0 ) {
    die("tcp_open_server failed(): bind() failed"); 
  }

  s->port = port;
  s->ip_addr = NULL;  //INADDR_ANY ...  
  return (Socket)s;  
}

main:

Socket server = tcp_passive_open( PORT );
FD_SET(SOCKETDESCRIPTOR_SERVER??,&master_socketDescriptors);

Upvotes: 1

Views: 15440

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597971

MySocket::sd is the descriptor you need to use with select(). Both socket() and accept() return socket descriptors that can be used with select(). Change tcp_passive_open() to return a MySocket* instead of a Socket, then your main server thread will have access to the server's socket descriptor to pass to select() for detecting incoming connections, eg:

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

typedef struct {
    int sd;
    char *ip_addr;
    int port;
} MySocket;

MySocket* tcp_passive_open(int port) {
    MySocket *s = (MySocket *)malloc( sizeof(MySocket) );
    if ( s == NULL ) {
        die("tcp_open_server failed(): malloc() failed");
    }

    s->sd = socket(PROTOCOLFAMILY, TYPE, PROTOCOL);
    if ( s->sd == -1 ) {
        die("tcp_open_server failed(): socket() failed");
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = PROTOCOLFAMILY;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);

    if ( bind(s->sd, (struct sockaddr *)&addr, sizeof(addr)) != 0 ) {
        die("tcp_open_server failed(): bind() failed");
    }

    s->port = port;
    s->ip_addr = NULL;  //INADDR_ANY ...
    return s;
}

.

MySocket* server = tcp_passive_open( PORT );
FD_SET(server->sd, &master_socketDescriptors); 

Afterwards, when select() reports a pending inbound connection connection on the server socket, call accept() to accept the connection and obtain its socket descriptor, then you can allocate a separate MySocket for it:

int sd = accept(server->sd, ...);
if ( sd != -1 ) {
    MySocket *client = (MySocket*) malloc(sizeof(MySocket));
    client->sd = sd;
    ...
}

Then you can create a new thread for that MySocket, and that thread can call select() to detect inbound data on that connection as needed.

Upvotes: 2

Related Questions