views:

123

answers:

3

I have a problem with a little C script which should run as a server and launch a popup for every message arriving. The execl syntax is correct because if I try a little script with

main() { execl(...); }

it works.

When I put it in a while(1) loop it doesn't work. Everything else is working, like printf or string operation, but not the execl. Even if I fork it doesn't work. How can I make it work?

And I've tried with the fork(), but it doesn't work either.

Here's the complete server C code.

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>

#define BUFLEN 512
#define PORT 9930

void diep(char *s) {
     perror(s);
     exit(1);
}

int main() {
    struct sockaddr_in si_me, si_other;
    int s, i, slen=sizeof(si_other), broadcastPermission;
    char buf[100], zeni[BUFLEN];

    if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
       diep("socket");

    broadcastPermission = 1;
    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission, sizeof(broadcastPermission)) < 0)
        diep("setsockopt() failed");

    memset((char *) &si_me, 0, sizeof(si_me));
    si_me.sin_family = AF_INET;
    si_me.sin_port = htons(PORT);
    si_me.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(s, &si_me, sizeof(si_me))==-1)
       diep("bind");

    while (1) {
        if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1) diep("recvfrom()");
        //printf("Received packet from %s:%d\nData: %s\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);

 strcpy(zeni, "");
 strcat(zeni, "zenity --warning --title Hack!! --text ");
 strcat(zeni, buf);
 printf("cmd: %s\n", zeni);
 //system (zeni);
 execl("/usr/bin/zenity", "/usr/bin/zenity", "--warning", "--title", "Warn!", "--text", buf, (char *) NULL);
    }

    close(s);
    return 0;

}
+2  A: 

There's a stack overflow in your call to recvfrom.

recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)

I believe you mixed the 2 buffers. You're using buf, which has size 100, but telling its size is BUFLEN, which is 512. Whenever someone sends more than 100 bytes, it's very likely your program is going to crash.

Besides that, it's possible that the recvfrom is not returning because it isn't receiving anything. Is your printf being executed?


UPDATE: as pointed by @Daniel and @Dale, execl won't return unless an error occurs. Quoting from the man-page:

The exec family of functions replaces the current process image with a new process image.

As alternative, you can use system.

jweyrich
True for the overflow error, my bad.But the recvfrom works great because the incoming message is very short; and yes, the printf works perfectly.
Possa
Oh, thanks, it was that!! :DGreat for you!
Possa
+1  A: 

Please read exec(3) man page.

In your case execl system call will replace current processes image with the image of /usr/bin/zenity".

You have two solutions: use system(3) as you tried there or do a fork and inside the child run execlp.

Daniel Băluţă
Yes, I solved with system().
Possa
+3  A: 

@jweyrich has already pointed out some problems with your use of recvfrom, however there is a more fundamental problem. The code

while (1) {
    recvfrom(...);
    execl(...);
}

will only ever execute at most once. This because the exec family of system calls (including execl) replace the the program currently executing with the one given in the call to execl. In effect, execl never returns, except with an error.

To create a new child process in unix, you must first call fork, which clones the existing process, and then within the child call execl (or some related system call) to replace child process with the program you actually want to run. Doing this correctly manually is somewhat tricky, so the system function wraps this up for you, however it has it's own drawbacks.

Dale Hagglund
Very valid point. Since he put it in a loop, I should've supposed he plans to run more than once. +1 from me.
jweyrich