socket programming doubt

I am aware that TCP sockets are stream based and a single write may not send all the data. Is this the case with recv as well ?

I am in process of deciding a protocol to handle communication. I wanted some tips as to handle transactions. The data sent / received would be fixed length. Hence i am toying with the idea of discarding messages on receive do not conform to a length. The data sent is less then 100 bytes , so i am not sure how many times will i encounter a scenario where the send fails to fire it in one go or receive fails to read in one go.

Any other approaches to send /receive data ?

Since multiple receives are possible (via select call) I am not sure how to handle incomplete data from two more different clients. ( perhaps via some sort of buffer created per connection)

More importantly , if i have about 2-3 sockets from which i am receiving data , is the conventional approach to block till the complete packet(i.e. message) from one is received ?

PS : These are unix domain sockets for IPC , so no flow over n/w

Cheers!
Last edited on
I don't understand the PS. Either the sockets you are creating are TCP or they are Unix domain. They can't
be both at the same time.

recv() will receive any bytes that are in the TCP receive buffer at the time it is invoked. Since send() may
not write all the bytes at once, it follows that recv() may not receive the entire packet at once either.
Packetization over TCP is typically done by framing.

You have to have a receive buffer per connection. The conventional approach is NOT to block until a complete
packet is received unless you want to be vulnerable to a trivial DoS attack. (I send you an incomplete packet
and never send you the whole thing. You don't ever handle any other connections ever again.)

Thanks jmith! What i meant was old school IPC sockets. I got confused due to the following call.

socket(AF_UNIX, SOCK_STREAM, 0);

Does this use TCP stack to ??
No, that is a UNIX domain socket, in stream mode. So it works like a TCP socket, in that it
is stream-oriented, so everything I said above still applies, except that since UNIX domain
sockets are local only, you can't get DoS attacked unless the intruder has a shell on the
machine.
With TCP sockets, it's possible that recv can be delayed if you have a large TCP Window. That is, the packets have been received locally, but not confirmed.

If you're interested in understanding this aspect, you'll need to do a bit of reading about the Nagle algorithm and effect of different TCP Window sizes.
Thanks guys!

This particular section is going boom! Bad file descriptor on accept() , I am unable to figure out why?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
        while (1)
        {
                stat =0;
                execReturn=0;
                s2 = accept(s, (struct sockaddr *)&remote, &t);

                if(s2== -1)
                {
                         perror("accept");
                         outfile<<strerror(errno)<<endl;
                         exit(1);
                }

                pidc = fork();
                if(pidc == 0)
                {
                        close(s);
                        int retVal;
                        string xs;
                        retVal = RecieveAllData(s2,outfile,xs);
                        if(retVal !=SUCCESS)
                        {
                                close(s2);
                        }

                        ipMsg parsedValue;
                        TokenizeString(xs,parsedValue);
                        outfile<<"User----"<<parsedValue.user<<endl;
                        outfile<<"Pwd ----"<<parsedValue.pwd<<endl;
                        outfile<<"origin ----"<<parsedValue.origin<<endl;
                        outfile<<"cmd ----"<<parsedValue.command<<endl;


                        pidf = fork();
                        if (pidf == 0)
                        {
                                close(s2);
                                close(s);
                                sleep(5);
                                execReturn =execl("/root/test.sh","test.sh",NULL);
                                outfile<<"Errror"<<endl;
                                _exit(-1);
                        }
                        else if (pidf > 0)
                        {
                                int id = waitpid(pidf,&stat,0);
                                int sat = WEXITSTATUS(stat);
                                outfile<<"status is "<<sat<<"pid is "<<pidf<<endl;
                                char stg[32];
                                sprintf(stg,"%d",sat);
                                send(s2,stg,strlen(stg), 0);
                                close(s2);
                        }
                }
                sleep(5); /* wait 30 seconds */
        }

That means s is a bad file descriptor. Can you show what you've done with s?
Pretty much nothing.....


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
        int s, s2,  len;
        socklen_t t;
        struct sockaddr_un local, remote;

        if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
        {
                perror("socket");
                exit(1);
        }

        local.sun_family = AF_UNIX;
        strcpy(local.sun_path, SOCK_PATH);

        unlink(local.sun_path);
        len = strlen(local.sun_path) + sizeof(local.sun_family);

        if (bind(s, (struct sockaddr *)&local, len) == -1)
        {
                perror("bind");
                exit(1);
        }


        if (listen(s, 5) == -1)
        {
                perror("listen");
                exit(1);
        }



There is no close on s called any where in the source. Is it possible since child inherits and exits , it invaidates the same for parent?
Last edited on
It looks ok.

Is SOCK_PATH longer than local.sun_path?

Does it fail the first time around?
Last edited on
This is a strange problem. There were some logical inconsistencies with my close calls. I have fixed them... Here is the complete source. The problem still persists.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

int main(void)
{

        /* Our process ID and Session ID */
        pid_t pid, sid;

        /* Fork off the parent process */
        pid = fork();
        if (pid < 0)
        {
                exit(EXIT_FAILURE);
        }

        /* If we got a good PID, then
           we can exit the parent process. */
        if (pid > 0) {
                exit(EXIT_SUCCESS);
        }

        /* Change the file mode mask */
        umask(0);

        /* Open any logs here */
        ofstream outfile("/root/log.txt");


        /* Create a new SID for the child process */
        sid = setsid();
        if (sid < 0)
        {
                /* Log the failure */
                exit(EXIT_FAILURE);
        }

        /* Change the current working directory */
        if ((chdir("/")) < 0)
        {
                /* Log the failure */
                exit(EXIT_FAILURE);
        }

        /* Close out the standard file descriptors */
        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        close(STDERR_FILENO);

        /* Daemon-specific initialization goes here */

        int s, s2,  len;
        socklen_t t;
        struct sockaddr_un local, remote;

        if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
        {
                perror("socket");
                exit(1);
        }

        local.sun_family = AF_UNIX;
        strcpy(local.sun_path, SOCK_PATH);

        unlink(local.sun_path);
        len = strlen(local.sun_path) + sizeof(local.sun_family);

        if (bind(s, (struct sockaddr *)&local, len) == -1)
        {
                perror("bind");
                exit(1);
        }


        if (listen(s, 5) == -1)
        {
                perror("listen");
                exit(1);
        }


        pid_t  pidf,pidc;
        int stat=0;
        int execReturn =0;
        int n;
        char str[100];
        vector<int> pidV;

        while (1)
        {
                stat =0;
                execReturn=0;
                s2 = accept(s, (struct sockaddr *)&remote, &t);

                if(s2== -1)
                {
                         perror("accept");
                         outfile<<strerror(errno)<<endl;
                         exit(1);
                }

                pidc = fork();
                if(pidc!=0)
                        pidV.push_back(pidc);

                if(pidc == 0)
                {
                        close(s);
                        n = recv(s2, str, 100, 0);
                        str[n]='\0';
                        outfile<<"Message is "<<str;
                        pidf = fork();
                        if (pidf == 0)
                        {
                                close(s2);
                                execReturn =execl("/root/haresh/cpp/test.sh","test.sh",NULL);
                                outfile<<"Errror"<<endl;
                                _exit(-1);
                        }
                        else if (pidf > 0)
                        {
                                int id = waitpid(pidf,&stat,0);
                                int sat = WEXITSTATUS(stat);
                                outfile<<"status is "<<sat<<"pid is "<<pidf<<endl;
                                char stg[32];
                                sprintf(stg,"%d",sat);
                                send(s2,stg,strlen(stg), 0);
                                close(s2);
                                _exit(0);
                        }
                }
                else if(pidc > 0)
                {
                        close(s2);
                        //REAP ALL CHILDREN
                        /*
                        vector<int>::iterator beg = pidV.begin();
                        while(beg!=pidV.end())
                        {
                                int id = waitpid(*beg,&stat,WNOHANG);
                                if(id!=0)
                                {
                                        beg = pidV.erase(beg);
                                }
                                else
                                {
                                        ++beg;
                                }

                        }
                       */

                sleep(5); /* wait 30 seconds */
        }
        exit(EXIT_SUCCESS);
}





I have narrowed it down to the fact when child processes are waited upon, i get a bad file descriptor. I am not sure why since this segment of the code is not reachable. I.e. all based off REAP ALL CHILDREN comment. If uncommented, i get bad file descriptor.
Last edited on
Does it fail first time around? If not, when does it fail?

accept(s, (struct sockaddr *)&remote, &t); t is uninitialised.

Is there a reason you don't declare variables where they're used?

Does recv return -1?
Topic archived. No new replies allowed.