Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » U++ Core » SIGPIPE problem
SIGPIPE problem [message #57108] Wed, 26 May 2021 05:19 Go to next message
zsolt is currently offline  zsolt
Messages: 693
Registered: December 2005
Location: Budapest, Hungary
Contributor
I'm writing an HTTP App server currently and I'm using some libraries, such as libpq.
My problem is, that some of the libraries are switching SIGPIPE signal handler on and off, and I have no control over that.
So when a client disconnects while my server is sending the HTTP response, sometimes it gets a SIGPIPE and my app stops at that point in debugger.
I'm running tons of unit tests so this is not very convenient, as some tests are doing this.

I fixed this by changing the flags argument of send() from 0 to MSG_NOSIGNAL in TcpSocket::RawSend() method.

Do you have any better idea?

 int TcpSocket::RawSend(const void *buf, int amount)
 {
+#ifdef PLATFORM_POSIX
+	int res = send(socket, (const char *)buf, amount, MSG_NOSIGNAL);
+#else
 	int res = send(socket, (const char *)buf, amount, 0);
+#endif
 	if(res < 0 && WouldBlock())
 		res = 0;
 	else
 	if(res == 0 || res < 0)
 		SetSockError("send");
 	return res;
 }
Re: SIGPIPE problem [message #57120 is a reply to message #57108] Thu, 27 May 2021 09:14 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
zsolt wrote on Wed, 26 May 2021 05:19
I'm writing an HTTP App server currently and I'm using some libraries, such as libpq.
My problem is, that some of the libraries are switching SIGPIPE signal handler on and off, and I have no control over that.
So when a client disconnects while my server is sending the HTTP response, sometimes it gets a SIGPIPE and my app stops at that point in debugger.
I'm running tons of unit tests so this is not very convenient, as some tests are doing this.

I fixed this by changing the flags argument of send() from 0 to MSG_NOSIGNAL in TcpSocket::RawSend() method.

Do you have any better idea?

 int TcpSocket::RawSend(const void *buf, int amount)
 {
+#ifdef PLATFORM_POSIX
+	int res = send(socket, (const char *)buf, amount, MSG_NOSIGNAL);
+#else
 	int res = send(socket, (const char *)buf, amount, 0);
+#endif
 	if(res < 0 && WouldBlock())
 		res = 0;
 	else
 	if(res == 0 || res < 0)
 		SetSockError("send");
 	return res;
 }


Sounds good, applied, thank you.

Mirek
Re: SIGPIPE problem [message #57124 is a reply to message #57120] Thu, 27 May 2021 16:41 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 693
Registered: December 2005
Location: Budapest, Hungary
Contributor
Thank you!
Re: SIGPIPE problem [message #57132 is a reply to message #57120] Fri, 28 May 2021 20:41 Go to previous messageGo to next message
Novo is currently offline  Novo
Messages: 1358
Registered: December 2006
Ultimate Contributor
mirek wrote on Thu, 27 May 2021 03:14


Sounds good, applied, thank you.

Mirek

MacOS 10.15: ./umk uppsrc ide CLANG -bus
/Users/ssg/worker0/m-upp/build/uppsrc/Core/Socket.cpp:565:52: error: use of undeclared identifier 'MSG_NOSIGNAL'
        int res = send(socket, (const char *)buf, amount, MSG_NOSIGNAL);
                                                          ^
1 error generated.


Regards,
Novo
Re: SIGPIPE problem [message #57139 is a reply to message #57132] Mon, 31 May 2021 09:44 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Ok, needs to be PLATFORM_LINUX instead... (commited).

Mirek

EDIT: "That said, question for zsolt: What about using signal(SIGPIPE, SIG_IGN) instead?" - already answered in the first post...

[Updated on: Mon, 31 May 2021 09:45]

Report message to a moderator

Re: SIGPIPE problem [message #57140 is a reply to message #57139] Mon, 31 May 2021 11:01 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 693
Registered: December 2005
Location: Budapest, Hungary
Contributor
Thank you! signal(SIGPIPE, SIG_IGN) is not working well.
But BSD (FreeBsd at least) also supports MSG_NOSIGNAL.
Re: SIGPIPE problem [message #57142 is a reply to message #57140] Mon, 31 May 2021 11:21 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
OK, can I get a verified list for that conditional compilation? Smile

Mirek
Re: SIGPIPE problem [message #57143 is a reply to message #57142] Mon, 31 May 2021 13:11 Go to previous messageGo to next message
Oblivion is currently offline  Oblivion
Messages: 1091
Registered: August 2007
Senior Contributor
Hi,

On BSD-based systems there is a socket option called SO_NOSIGPIPE, instead:

FreeBSD >= 9.0: https://www.freebsd.org/cgi/man.cgi?query=getsockopt&sek tion=2&manpath=FreeBSD+9.0-RELEASE
MacOS X: https://developer.apple.com/library/archive/documentation/Sy stem/Conceptual/ManPages_iPhoneOS/man2/getsockopt.2.html


Note: Apparently neither MSG_NOSIGNAL nor SO_NOSIGPIPE is supported on Solaris (if we support that OS at all...).

Best regards,
Oblivion




[Updated on: Mon, 31 May 2021 13:16]

Report message to a moderator

Re: SIGPIPE problem [message #57144 is a reply to message #57143] Mon, 31 May 2021 17:05 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 693
Registered: December 2005
Location: Budapest, Hungary
Contributor
Is this OK?
@@ -557,16 +557,22 @@ bool TcpSocket::WouldBlock()
 	}
 	return c == SOCKERR(EWOULDBLOCK);	       
 #endif
 }
 
 int TcpSocket::RawSend(const void *buf, int amount)
 {
-#ifdef PLATFORM_POSIX
-	int res = send(socket, (const char *)buf, amount, MSG_NOSIGNAL);
+#ifdef MSG_NOSIGNAL
+#define UPP_NOSIGPIPE_OPTION MSG_NOSIGNAL
+#endif
+#ifdef SO_NOSIGPIPE
+#define UPP_NOSIGPIPE_OPTION SO_NOSIGPIPE
+# endif
+#ifdef UPP_NOSIGPIPE_OPTION
+	int res = send(socket, (const char *)buf, amount, UPP_NOSIGPIPE_OPTION);
 #else
 	int res = send(socket, (const char *)buf, amount, 0);
 #endif
 	if(res < 0 && WouldBlock())
 		res = 0;
 	else
 	if(res == 0 || res < 0)
Re: SIGPIPE problem [message #57145 is a reply to message #57144] Mon, 31 May 2021 17:06 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 693
Registered: December 2005
Location: Budapest, Hungary
Contributor
The complete method:
int TcpSocket::RawSend(const void *buf, int amount)
{
#ifdef MSG_NOSIGNAL
#define UPP_NOSIGPIPE_OPTION MSG_NOSIGNAL
#endif
#ifdef SO_NOSIGPIPE
#define UPP_NOSIGPIPE_OPTION SO_NOSIGPIPE
# endif
#ifdef UPP_NOSIGPIPE_OPTION
	int res = send(socket, (const char *)buf, amount, UPP_NOSIGPIPE_OPTION);
#else
	int res = send(socket, (const char *)buf, amount, 0);
#endif
	if(res < 0 && WouldBlock())
		res = 0;
	else
	if(res == 0 || res < 0)
		SetSockError("send");
	return res;
}
Re: SIGPIPE problem [message #57146 is a reply to message #57145] Mon, 31 May 2021 17:10 Go to previous messageGo to next message
zsolt is currently offline  zsolt
Messages: 693
Registered: December 2005
Location: Budapest, Hungary
Contributor
Or this one is better:
int TcpSocket::RawSend(const void *buf, int amount)
{
#ifdef MSG_NOSIGNAL
#define UPP_NOSIGPIPE_OPTION MSG_NOSIGNAL
#endif
#ifdef SO_NOSIGPIPE
#define UPP_NOSIGPIPE_OPTION SO_NOSIGPIPE
#endif
#ifndef UPP_NOSIGPIPE_OPTION
#define UPP_NOSIGPIPE_OPTION 0
#endif
	int res = send(socket, (const char *)buf, amount, UPP_NOSIGPIPE_OPTION);
	if(res < 0 && WouldBlock())
		res = 0;
	else
	if(res == 0 || res < 0)
		SetSockError("send");
	return res;
}
Re: SIGPIPE problem [message #57147 is a reply to message #57146] Mon, 31 May 2021 17:18 Go to previous messageGo to next message
Novo is currently offline  Novo
Messages: 1358
Registered: December 2006
Ultimate Contributor
I checked against the latest revision.
Everything compiles fine now, including FreeBSD 12.


Regards,
Novo
Re: SIGPIPE problem [message #57148 is a reply to message #57146] Mon, 31 May 2021 17:23 Go to previous messageGo to next message
Oblivion is currently offline  Oblivion
Messages: 1091
Registered: August 2007
Senior Contributor
Hello zsolt,


It looks nice but I'm afraid that won't work. SO_NOSIGPIPE should be set using the setsockopt() function, preferably at socket initialization.

E.g.

#ifdef SO_NOSIGPIPE
   const int val = 1;
   setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
#endif



Best regards,
Oblivion


Re: SIGPIPE problem [message #57152 is a reply to message #57148] Tue, 01 June 2021 09:19 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Yeah, great, getting complicated pretty fast... Smile

Oblivion wrote on Mon, 31 May 2021 17:23
Hello zsolt,

It looks nice but I'm afraid that won't work. SO_NOSIGPIPE should be set using the setsockopt() function, preferably at socket initialization.

E.g.

#ifdef SO_NOSIGPIPE
   const int val = 1;
   setsockopt(socket, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
#endif



Best regards,
Oblivion


Is it guaranteed to be #define though?

But perhaps even if it is not, it would be worth it...

Mirek
Re: SIGPIPE problem [message #57154 is a reply to message #57152] Tue, 01 June 2021 13:15 Go to previous message
Oblivion is currently offline  Oblivion
Messages: 1091
Registered: August 2007
Senior Contributor
Well, the SIGPIPE issue is a relic network/socket programmers have to deal with, dating back to the implementation of TCP sockets in unix in early 80s.

AFAIK, there is no perfect solution. While the posix manual seems to define MSG_NOSIGNAL from some point on, it is not adopted by every camp yet.

Another workaround seems to be this, which I didn't know either:


Quote:

The most general solution, for when you are not in full control of the program's signal handling and want to write data to an actual pipe or use write(2) on a socket, is to first mask the signal for the current thread with pthread_sigmask(3), write the data, drain any pending signal with sigtimedwait(2) and a zero timeout, and then finally unmask SIGPIPE. This technique is described in more detail here. Note that some systems such as OpenBSD do not have sigtimedwait(2) in which case you need to use sigpending(2) to check for pending signals and then call the blocking sigwait(2).


Read the full blog, here:

https://www.doof.me.uk/2020/09/23/sigpipe-and-how-to-ignore- it/

Workaround (explained):
https://web.archive.org/web/20200126153413/http://www.microh owto.info:80/howto/ignore_sigpipe_without_affecting_other_th reads_in_a_process.html

Best regards,
Oblivion


[Updated on: Tue, 01 June 2021 13:23]

Report message to a moderator

Previous Topic: Small optimization
Next Topic: MSVS15x64: Compile Error C3256 C3259 C3250 in Fn.h findarg
Goto Forum:
  


Current Time: Thu Mar 28 12:54:33 CET 2024

Total time taken to generate the page: 0.01431 seconds