views:

386

answers:

3

I have a fairly basic TCP server keeping track of a couple connections and recv'ing data when it's available. However, I'd like to artificially trigger an event from within the program itself, so I can send my TCP server data as if it came from sock1 or sock2, but in reality came from somewhere else. Is this possible, or at all clear?

struct pollfd fds[2];
fds[0].fd = sock1;
fds[1].fd = sock2;

while (true) {
  int res = poll(fds, 2, timeout);

  if ((fds[0].revents & POLLIN)){
    //ready to recv data from sock1
  }
  if ((fds[1].revents & POLLIN)){
    //ready to recv data from sock2
  }
}
+4  A: 

Create a pair of connected sockets (see socketpair(2)), and wait for events on one of the sockets in your poll loop. When you want to wake up the poll thread, write a single byte to the other socket. When the polling loop wakes up, read the byte, do whatever was required and continue.

janm
Do you mean use the write() function to write to its buffer, then make an if-statement saying "if you receive a 1-byte message with this value, do this"? Why is the socketpair necessary -- is there a reason I can't write directly to a socket's buffer that I'm waiting on?
oskar
As you suspect, you need socketpair() because you cannot write to the socket buffer you are waiting on. So you need the pair of sockets to give other parts of your program a way to wake up the poll loop. The poll loop needs to notice that it has been woken up in this way and then do whatever it is you want to do. The next question is how you tell it what to do: you wither need an internal data structure, or you could write a complete message to the write end of the socket pair. If you write complete messages and you have multiple writers be careful about non-atomic writes corrupting messages.
janm
"wither" -> "either"
janm
Yay self-pipe trick :)
ephemient
A: 

This is more like a design question -- your polling loop should probably abstract the poll method to allow trapping on other external signals, like from kill -USR1.

If you really want to trigger port traffic, you'll likely want to use netcat to send data to the socket.

memnoch_proxy
+1  A: 

I would consider something like this:

struct pollfd fds[2];
fds[0].fd = sock1;
fds[0].events = POLLIN;
fds[1].fd = sock2;
fds[1].events = POLLIN;

for (;;) {
  int result = poll(fds, 2, timeout);

  if (result) {
    if ((fds[0].revents & POLLIN)){
      /* Process data from sock1. */
    }
    if ((fds[1].revents & POLLIN)){
      /* Process data from sock2. */
    }
  } else {
    /* Do anything else you like, including
       processing data that wasn't from a
       real socket. */
  }
}

Notes:

  • don't forget to initialise your events field
  • for(;;) is more idiomatic C than while(true) and doesn't require true to be defined
Tim
How it answers the question?
qrdl
I was hoping for a way to externally trigger the poll() function, whereas I think your code simply waits for it to time out and then provides a way to so something else.
oskar