aboutsummaryrefslogtreecommitdiffstats
path: root/main/utils.c
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-12-22 17:19:05 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-12-22 17:19:05 +0000
commit00bba5642e9285bd209b83dfcea655b4910cd785 (patch)
treeb7c642fe2d86c7bfff53be5ad3e2174288ffb856 /main/utils.c
parent76b42f9e4caff653e0dab5cd1a051bebf5acde93 (diff)
Merged revisions 166282 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk ........ r166282 | russell | 2008-12-22 11:09:36 -0600 (Mon, 22 Dec 2008) | 12 lines Introduce ast_careful_fwrite() and use in AMI to prevent partial writes. This patch introduces a function to do careful writes on a file stream which will handle timeouts and partial writes. It is currently used in AMI to address the issue that has been reported. However, there are probably a few other places where this could be used. (closes issue #13546) Reported by: srt Tested by: russell http://reviewboard.digium.com/r/104/ ........ git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.6.1@166284 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/utils.c')
-rw-r--r--main/utils.c114
1 files changed, 90 insertions, 24 deletions
diff --git a/main/utils.c b/main/utils.c
index 8a5d8a611..b027cdf03 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1057,6 +1057,38 @@ int ast_wait_for_input(int fd, int ms)
return poll(pfd, 1, ms);
}
+static int ast_wait_for_output(int fd, int timeoutms)
+{
+ struct pollfd pfd = {
+ .fd = fd,
+ .events = POLLOUT,
+ };
+ int res;
+
+ /* poll() until the fd is writable without blocking */
+ while ((res = poll(&pfd, 1, timeoutms)) <= 0) {
+ if (res == 0) {
+ /* timed out. */
+ ast_log(LOG_NOTICE, "Timed out trying to write\n");
+ return -1;
+ } else if (res == -1) {
+ /* poll() returned an error, check to see if it was fatal */
+
+ if (errno == EINTR || errno == EAGAIN) {
+ /* This was an acceptable error, go back into poll() */
+ continue;
+ }
+
+ /* Fatal error, bail. */
+ ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
/*!
* Try to write string, but wait no more than ms milliseconds before timing out.
*
@@ -1077,30 +1109,8 @@ int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
int res = 0;
while (len) {
- struct pollfd pfd = {
- .fd = fd,
- .events = POLLOUT,
- };
-
- /* poll() until the fd is writable without blocking */
- while ((res = poll(&pfd, 1, timeoutms)) <= 0) {
- if (res == 0) {
- /* timed out. */
- ast_log(LOG_NOTICE, "Timed out trying to write\n");
- return -1;
- } else if (res == -1) {
- /* poll() returned an error, check to see if it was fatal */
-
- if (errno == EINTR || errno == EAGAIN) {
- /* This was an acceptable error, go back into poll() */
- continue;
- }
-
- /* Fatal error, bail. */
- ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
-
- return -1;
- }
+ if (ast_wait_for_output(fd, timeoutms)) {
+ return -1;
}
res = write(fd, s, len);
@@ -1125,6 +1135,62 @@ int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
return res;
}
+int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms)
+{
+ struct timeval start = ast_tvnow();
+ int n = 0;
+
+ while (len) {
+ int elapsed;
+
+ if (ast_wait_for_output(fd, timeoutms)) {
+ /* poll returned a fatal error, so bail out immediately. */
+ return -1;
+ }
+
+ /* Clear any errors from a previous write */
+ clearerr(f);
+
+ n = fwrite(src, 1, len, f);
+
+ if (ferror(f) && errno != EINTR && errno != EAGAIN) {
+ /* fatal error from fwrite() */
+ if (!feof(f)) {
+ /* Don't spam the logs if it was just that the connection is closed. */
+ ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
+ }
+ n = -1;
+ break;
+ }
+
+ /* Update for data already written to the socket */
+ len -= n;
+ src += n;
+
+ elapsed = ast_tvdiff_ms(ast_tvnow(), start);
+ if (elapsed > timeoutms) {
+ /* We've taken too long to write
+ * This is only an error condition if we haven't finished writing. */
+ n = len ? -1 : 0;
+ break;
+ }
+ }
+
+ while (fflush(f)) {
+ if (errno == EAGAIN || errno == EINTR) {
+ continue;
+ }
+ if (!feof(f)) {
+ /* Don't spam the logs if it was just that the connection is closed. */
+ ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
+ }
+ n = -1;
+ break;
+ }
+
+ return n < 0 ? -1 : 0;
+}
+
char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
{
char *e;