[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [openss7] Getting through
Chuck,
Yes, recv and send system calls block unless O_NONBLOCK is set
on the socket, however, as with other sockets, recv only blocks
if there is nothing to receive in the read queue (so it waits),
but that blocking, as usual, can be interrupted by a signal
and return EAGAIN or ERESTART. write only blocks if the write
buffer is full, otherwise it queues up the send data and returns
immediately. Send may also be interrupted by a signal with
EAGAIN and ERESTART.
I have a few suggestions on your socket code below. Maybe
they are just a bit stylistic, but ...
Chuck Winters wrote: Tue, 12 Jun 2001 15:28:35
> Brian,
> Thanks for the patch. Things are coming along much better now. I have
> one question though, is the recv and send system calls blocking? I have
> a test program which seems to show that they are not blocking, and
> something else is going wrong. I am a little confused.
>
> Thanks,
> Chuck
> --
> Chuck Winters | Email: cwinters@atl.lmco.com
> Distributed Processing Laboratory | Phone: 856-338-3987
> Lockheed Martin Advanced Technology Labs |
> 1 Federal St - A&E-3W |
> Camden, NJ 08102 |
> #include <sys/socket.h>
> #include <sys/types.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <netinet/in.h>
> #include <arpa/inet.h>
> #include <sys/uio.h>
> #include <errno.h>
>
> int main(void)
> {
> int listen_sock;
> int connect_sock;
> int ct = 0;
> struct sockaddr_in server_addr;
> struct sockaddr_in client_addr;
> int sockaddr_len = 0;
> char buff[1024];
> int on = 1;
>
> memset(&server_addr, 0, sizeof(struct sockaddr_in));
> memset(&client_addr, 0, sizeof(struct sockaddr_in));
> memset(buff, 0, 1024);
>
> /** Create a socket **/
> if((listen_sock = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
> {
> perror("Creating Socket");
> exit(1);
> }
> fprintf(stderr, "Created socket with fd of %d\n", listen_sock);
>
> setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
Why are you setting SO_REUSEADDR on the socket you intend to listen on?
> /** Fill address in **/
> server_addr.sin_family = AF_INET;
> server_addr.sin_port = htons(33822);
> server_addr.sin_addr.s_addr = inet_addr("192.168.1.33");
>
> /** Bind address to the socket **/
> if(bind(listen_sock, (struct sockaddr* ) &server_addr, sizeof(struct sockaddr_in)) < 0)
> {
> perror("Binding to socket");
> exit(2);
> }
>
> /** Now listen and accept a connection **/
> if(listen(listen_sock, 1) < 0)
> {
> perror("Listening");
> exit(3);
> }
> fprintf(stderr, "After listen\n");
>
> if((connect_sock = accept(listen_sock, (struct sockaddr* ) &client_addr, &sockaddr_len)) < 0)
> {
> perror("Accepting\n");
> exit(4);
> }
> if(sockaddr_len == sizeof(struct sockaddr_in))
> fprintf(stderr, "Client Address is %s\n", inet_ntoa(client_addr.sin_addr));
For SCTP, accept can return multiple address
(i.e., n * sizeof(struct sockaddr_in) ), but
of course this depends on what addresses you
use to connect.
But, if your INIT message on the other machine
winds up going out a different interface than
you think, this might be multiple addresses
even though you have only specified one to bind
or connect.
>
> /** Now read from the socket **/
> for(ct = 0; ct < 100; ct++)
> {
> if(recv(connect_sock, buff, 1024, MSG_WAITALL | MSG_NOSIGNAL) < 0)
> {
> if(errno == EAGAIN)
> ct--;
> else
> perror("Reading from fd");
> }
> else
> {
> fprintf(stderr, "%d) Data received is %s\n", ct, buff);
> }
> memset(buff, 0, 1024);
> }
MSG_WAITALL is not necessarily going to have the
effect that it appears that you are looking for
here. As you will see from the note at about
line 2710 in sctp_ipv4.c, SCTP delivers partially
received frames, unlike UDP. If SCTP has fragmented
DATA chunks sent from the other side, recvmsg will
return MSG_TRUNC in the receive flags. recv has
no mechanism to return this, however, it does return
the number of bytes read. (Which may be less than
the 1024 you are expecting.) A subsequent read,
recv, or recvmsg will pick up where it left off.
RECV will block only if there is no data in the
receive queue. If these is less than your target
data in the receive queue, MSG_WAITALL will still
return with less than the target data. This is
proper POSIX behavior I believe. (See recv(2)).
>
> /** Close the fd **/
> close(listen_sock);
> close(connect_sock);
> exit(0);
> }
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <arpa/inet.h>
> #include <stdio.h>
> #include <string.h>
> #include <netinet/in.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <sys/uio.h>
> #include <signal.h>
> #include <unistd.h>
> #include <errno.h>
>
> int main(void)
> {
> int listen_sock;
> int ct = 0;
> struct sockaddr_in server_addr;
> struct sockaddr_in my_addr;
> char buff[12] = "Hello World";
>
> memset(&my_addr, 0, sizeof(struct sockaddr_in));
> memset(&server_addr, 0, sizeof(struct sockaddr_in));
> signal(SIGPIPE, SIG_IGN);
>
> /** Create a socket **/
> if((listen_sock = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0)
> {
> perror("Creating Socket");
> exit(1);
> }
> fprintf(stderr, "Created socket with fd of %d\n", listen_sock);
>
> /** Fill in addr **/
> server_addr.sin_family = AF_INET;
> server_addr.sin_port = htons(33822);
> server_addr.sin_addr.s_addr = inet_addr("192.168.1.33");
>
> my_addr.sin_family = AF_INET;
> my_addr.sin_port = htons(1024);
> my_addr.sin_addr.s_addr = inet_addr("192.168.1.34");
>
> if(bind(listen_sock, (struct sockaddr* ) &my_addr, sizeof(struct sockaddr_in)) < 0)
> {
> perror("Binding");
> exit(1);
> }
> fprintf(stderr, "Bound to my_addr to socket %d\n", listen_sock);
>
> /** Connect to the Server **/
> if(connect(listen_sock, (struct sockaddr* ) &server_addr, sizeof(struct sockaddr_in)) < 0)
> {
> perror("Connecting");
> exit(2);
> }
> fprintf(stderr, "Connected to socket %d\n", listen_sock);
>
> /** Write to the socket **/
> for(ct = 0; ct < 10; ct++)
> {
> if(send(listen_sock, buff, sizeof(buff), 0) == EPIPE)
> {
> signal(SIGPIPE, SIG_IGN);
> }
You have a problem here. send(2) returns -1 on error and will
never return EPIPE. EPIPE just happens to be integer value 32,
so if you wind up sending 32 bytes, you will reinstall the
signal handler.
A better way to avoid getting SIGPIPEs is to give send(2) the
MSG_NOSIGNAL flag, which will suppress EPIPE signals. At any rate,
I think what you wanted to say here was:
if ( send(listen_sock, buff, sizeof(buff), 0) < 0 )
{
if ( errno == EPIPE )
signal(SIGPIPE, SIG_IGN);
}
Nevertheless, I think this should work better:
if ( send(listen_sock, buff, sizeof(buff), MSG_NOSIGNAL) < 0 )
perror("Sending");
> fprintf(stderr, "Sent %s to bert for the %d time\n", buff, ct);
> }
>
> /** close **/
> close(listen_sock);
> exit(0);
> }
>
>
In searching about, I think I may have found a bug in recvmsg not
returning the MSG_EOR flag properly if the target length exactly
matches the messages length.... But it doesn't look like you are
using recvmsg anyway...
--
Brian F. G. Bidulock ¦ The reasonable man adapts himself to the ¦
bidulock@openss7.org ¦ world; the unreasonable one persists in ¦
http://www.openss7.org/ ¦ trying to adapt the world to himself. ¦
¦ Therefore all progress depends on the ¦
¦ unreasonable man. -- George Bernard Shaw ¦