aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-12-22 17:14:18 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2008-12-22 17:14:18 +0000
commit85f332e26795d8332807f092512f9a9d6596e526 (patch)
treec28a6c5c2b21a54af8050523911aeaeff17d6b19 /main
parent664e8fdabed38afdcb2dbe0992755c029d53bd54 (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.0@166283 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/manager.c25
-rw-r--r--main/utils.c114
2 files changed, 91 insertions, 48 deletions
diff --git a/main/manager.c b/main/manager.c
index f90adfc3d..2e130e562 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -859,30 +859,7 @@ struct ast_variable *astman_get_variables(const struct message *m)
*/
static int send_string(struct mansession *s, char *string)
{
- int len = strlen(string); /* residual length */
- char *src = string;
- struct timeval start = ast_tvnow();
- int n = 0;
-
- for (;;) {
- int elapsed;
- struct pollfd fd;
- n = fwrite(src, 1, len, s->f); /* try to write the string, non blocking */
- if (n == len /* ok */ || n < 0 /* error */)
- break;
- len -= n; /* skip already written data */
- src += n;
- fd.fd = s->fd;
- fd.events = POLLOUT;
- n = -1; /* error marker */
- elapsed = ast_tvdiff_ms(ast_tvnow(), start);
- if (elapsed > s->writetimeout)
- break;
- if (poll(&fd, 1, s->writetimeout - elapsed) < 1)
- break;
- }
- fflush(s->f);
- return n < 0 ? -1 : 0;
+ return ast_careful_fwrite(s->f, s->fd, string, strlen(string), s->writetimeout);
}
/*!
diff --git a/main/utils.c b/main/utils.c
index 45981b4d8..35efa6342 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -950,6 +950,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.
*
@@ -970,30 +1002,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);
@@ -1018,6 +1028,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;