1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2004 Evan Martin <martine@danga.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
7 /* network-fork.c: provide a net_post_mainloop that uses an
8 * external net_post_blocking via a fork. used by network-curl and
21 #include <sys/types.h>
22 #include <sys/wait.h> /* waitpid */
23 #include <signal.h> /* kill */
27 #include "network-internal.h"
39 NetStatusCallback user_cb
;
44 pipe_write(int pipe
, NetStatusType type
, int len
, void *data
) {
46 if (write(pipe
, &t
, 1) < 1)
48 if (write(pipe
, &len
, sizeof(int)) < sizeof(int))
51 if (write(pipe
, data
, len
) < len
)
58 fork_cb(NetStatusType status
, gpointer statusdata
, gpointer data
) {
59 ForkData
*forkdata
= data
;
60 if (status
== NET_STATUS_PROGRESS
)
61 pipe_write(forkdata
->pipefds
[1], NET_STATUS_PROGRESS
,
62 sizeof(NetStatusProgress
), statusdata
);
66 readall(int fd
, void *buf
, int len
) {
70 ret
= read(fd
, ((char*)buf
)+rlen
, len
-rlen
);
74 if (ret
== 0 && rlen
< len
)
81 pipe_cb(ForkData
*forkdata
, gint pipe
, GdkInputCondition cond
) {
85 NetStatusProgress progress
;
87 len
= read(pipe
, &t
, 1);
89 g_print("Pipe unexpectedly closed.\n");
93 if (!readall(pipe
, &len
, sizeof(int)))
97 case NET_STATUS_SUCCESS
:
98 buf
= g_new0(char, len
+1);
99 readall(pipe
, buf
, len
);
101 waitpid(forkdata
->pid
, NULL
, 0);
104 forkdata
->response
= g_string_new_len(buf
, len
);
108 case NET_STATUS_ERROR
:
109 buf
= g_new0(char, len
+1);
110 readall(pipe
, buf
, len
);
112 waitpid(forkdata
->pid
, NULL
, 0);
115 g_set_error(forkdata
->err
, NET_ERROR
, NET_ERROR_GENERIC
, "%s", buf
);
119 case NET_STATUS_PROGRESS
:
120 readall(pipe
, &progress
, sizeof(NetStatusProgress
));
121 if (forkdata
->user_cb
)
122 forkdata
->user_cb(NET_STATUS_PROGRESS
, &progress
, forkdata
->user_data
);
125 g_warning("pipe_cb: unhandled status %d.\n", t
);
130 net_mainloop_cancel(NetMainloopHandle handle
) {
131 ForkData
*forkdata
= (ForkData
*)handle
;
133 if (forkdata
->pid
> 0) {
134 kill(forkdata
->pid
, SIGKILL
);
135 gtk_input_remove(forkdata
->pipe_tag
);
136 forkdata
->pipe_tag
= 0;
137 waitpid(forkdata
->pid
, NULL
, 0);
140 close(forkdata
->pipefds
[0]);
141 close(forkdata
->pipefds
[1]);
142 g_set_error(forkdata
->err
, NET_ERROR
, NET_ERROR_CANCELLED
, "%s",
149 net_post_mainloop(const char *url
, GSList
*headers
, GString
*post
,
150 NetStatusCallback cb
, gpointer data
,
152 ForkData forkdata
= {0};
155 forkdata
.user_cb
= cb
;
156 forkdata
.user_data
= data
;
158 /* fork, run the request, then pipe the data back out of the fork. */
159 if (pipe(forkdata
.pipefds
) < 0) {
160 g_set_error(err
, NET_ERROR
, NET_ERROR_GENERIC
,
161 _("Error creating pipe (pipe(): %s)."), g_strerror(errno
));
164 forkdata
.pid
= fork();
165 if (forkdata
.pid
< 0) {
166 g_set_error(err
, 0, NET_ERROR_GENERIC
,
167 _("Error forking (fork(): %s)."), g_strerror(errno
));
169 } else if (forkdata
.pid
== 0) { /* child. */
173 response
= net_post_blocking(url
, headers
, post
, fork_cb
, &forkdata
, &err
);
174 if (response
== NULL
) {
175 int len
= strlen(err
->message
);
176 pipe_write(forkdata
.pipefds
[1], NET_STATUS_ERROR
, len
, err
->message
);
179 pipe_write(forkdata
.pipefds
[1], NET_STATUS_SUCCESS
, response
->len
, response
->str
);
180 g_string_free(response
, TRUE
);
183 close(forkdata
.pipefds
[0]);
184 close(forkdata
.pipefds
[1]);
188 /* otherwise, we're the parent. */
189 forkdata
.pipe_tag
= gtk_input_add_full(forkdata
.pipefds
[0], GDK_INPUT_READ
,
190 (GdkInputFunction
)pipe_cb
, NULL
, &forkdata
, NULL
);
192 cb(NET_STATUS_BEGIN
, &forkdata
, data
);
194 gtk_main(); /* wait for the response. */
195 if (forkdata
.pipe_tag
) {
196 gtk_input_remove(forkdata
.pipe_tag
);
197 forkdata
.pipe_tag
= 0;
201 close(forkdata
.pipefds
[0]);
202 close(forkdata
.pipefds
[1]);
205 cb(NET_STATUS_DONE
, &forkdata
, data
);
207 return forkdata
.response
;