Hello, I have found a few problems of AF_INET domain socket regarding out-of-band data.
1. recv() with MSG_OOB flag eats normal data if no OOB data is sent yet. 2. Calling recv() with MSG_OOB flag is blocked if no OOB data is sent yet. 3. Calling recv() without MSG_OOB flag after receiving OOB data is blocked even if received data exist in buffer. Regarding problem 1 and 2, POSIX states as follows about recv(). [EINVAL] The MSG_OOB flag is set and no out-of-band data is available. http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html Attached is a sample program to reproduce these problems. Argument to this program specifies the test mode. 0: cause problem 1 2: cause problem 2 3: cause problem 3 Expected results: debian:~/OOB> ./server_client 0 recv(OOB): Invalid argument OOB : (-1) NORMAL: 1234567890 (10) debian:~/OOB> ./server_client 1 OOB : A (1) NORMAL: 1234567890 (10) debian:~/OOB> ./server_client 2 recv(OOB): Invalid argument OOB : (-1) NORMAL: 1234567890 (10) debian:~/OOB> ./server_client 3 OOB : A (1) NORMAL: 1234567890 (10) debian:~/OOB> Result on cygwin: [yano@Express5800-S70 ~/OOB]$ ./server_client 0 OOB : 1234567890 (10) NORMAL: (0) [yano@Express5800-S70 ~/OOB]$ ./server_client 1 OOB : A (1) NORMAL: 1234567890 (10) [yano@Express5800-S70 ~/OOB]$ ./server_client 2 [yano@Express5800-S70 ~/OOB]$ ./server_client 3 OOB : A (1) [yano@Express5800-S70 ~/OOB]$ Only the result of test mode 1 is as expected. I have confirmed this occurs in both latest 32bit and 64 bit cygwin. -- Takashi Yano <takashi.y...@nifty.ne.jp>
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <signal.h> #include <sys/wait.h> #define PORT 12345 #define HOST "127.0.0.1" int server(int mode) { int sock0, sock1; struct sockaddr_in addr; struct sockaddr_in client; socklen_t len; /* Create a socket */ sock0 = socket(AF_INET, SOCK_STREAM, 0); if (sock0 < 0) { perror("socket"); return -1; } /* Bind */ addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = INADDR_ANY; if (bind(sock0, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return -1; } /* Wait for connection from client */ if (listen(sock0, 1) < 0) { perror("listen"); return -1; } /* Accept connection */ len = sizeof(client); sock1 = accept(sock0, (struct sockaddr *)&client, &len); if (sock1 < 0) { perror("accept"); return -1; } /* Send normal data */ if (send(sock1, "1234567890", 10, 0) < 0) { perror("send"); return -1; } if (mode & 1) { /* Send out-of-band data */ if (send(sock1, "A", 1, MSG_OOB) < 0) { perror("send(OOB)"); return -1; } } /* Wait for receiving all data at client side */ usleep(200000); if (mode & 2) { return -1; /* return -1 to kill client */ } /* Close client socket */ close(sock1); /* Close socket for listen */ close(sock0); return 0; } int client() { struct sockaddr_in server; int sock; char buf[256]; int n; /* Create a socket */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("sock"); return -1; } /* Setting for connection */ server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = inet_addr(HOST); /* Connect to server */ if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) { perror("connect"); return -1; } /* Wait for sending all data at server side */ usleep(100000); /* Receive out-of-band data from server */ memset(buf, 0, sizeof(buf)); n = recv(sock, buf, sizeof(buf), MSG_OOB); if (n<0) { perror("recv(OOB)"); } printf("OOB : %s (%d)\n", buf, n); /* Receive normal data from server */ memset(buf, 0, sizeof(buf)); n = recv(sock, buf, sizeof(buf), 0); if (n<0) { perror("recv"); } printf("NORMAL: %s (%d)\n", buf, n); /* Close socket */ close(sock); return 0; } int main(int argc, char *argv[]) { int mode = 0; pid_t pid; if (argc >= 2) { mode = atoi(argv[1]); } pid = fork(); if (pid) { if (server(mode) < 0) kill(pid, SIGTERM); wait(NULL); } else { return client(); } return 0; }
-- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple