* use modern functions for downloads.
[citadel.git] / webcit / tcp_sockets.c
1 /*
2  * $Id$
3  */
4
5 /*
6  * Uncomment this to log all communications with the Citadel server
7 #define SERV_TRACE 1
8  */
9
10
11 #include "webcit.h"
12 #include "webserver.h"
13
14 /*
15  *  register the timeout
16  *  signum signalhandler number
17  * \return signals
18  */
19 RETSIGTYPE timeout(int signum)
20 {
21         lprintf(1, "Connection timed out; unable to reach citserver\n");
22         /* no exit here, since we need to server the connection unreachable thing. exit(3); */
23 }
24
25
26 /*
27  *  Connect a unix domain socket
28  *  sockpath where to open a unix domain socket
29  */
30 int uds_connectsock(char *sockpath)
31 {
32         struct sockaddr_un addr;
33         int s;
34
35         memset(&addr, 0, sizeof(addr));
36         addr.sun_family = AF_UNIX;
37         strncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
38
39         s = socket(AF_UNIX, SOCK_STREAM, 0);
40         if (s < 0) {
41                 lprintf(1, "Can't create socket[%s]: %s\n",
42                         sockpath,
43                         strerror(errno));
44                 return(-1);
45         }
46
47         if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
48                 lprintf(1, "Can't connect [%s]: %s\n",
49                         sockpath,
50                         strerror(errno));
51                 close(s);
52                 return(-1);
53         }
54
55         return s;
56 }
57
58
59 /*
60  *  Connect a TCP/IP socket
61  *  host the host to connect to
62  *  service the service on the host to call
63  */
64 int tcp_connectsock(char *host, char *service)
65 {
66         struct hostent *phe;
67         struct servent *pse;
68         struct protoent *ppe;
69         struct sockaddr_in sin;
70         int s;
71
72         memset(&sin, 0, sizeof(sin));
73         sin.sin_family = AF_INET;
74
75         pse = getservbyname(service, "tcp");
76         if (pse) {
77                 sin.sin_port = pse->s_port;
78         } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
79                 lprintf(1, "Can't get %s service entry\n", service);
80                 return (-1);
81         }
82         phe = gethostbyname(host);
83         if (phe) {
84                 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
85         } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
86                 lprintf(1, "Can't get %s host entry: %s\n",
87                         host, strerror(errno));
88                 return (-1);
89         }
90         if ((ppe = getprotobyname("tcp")) == 0) {
91                 lprintf(1, "Can't get TCP protocol entry: %s\n",
92                         strerror(errno));
93                 return (-1);
94         }
95
96         s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
97         if (s < 0) {
98                 lprintf(1, "Can't create socket: %s\n", strerror(errno));
99                 return (-1);
100         }
101         signal(SIGALRM, timeout);
102         alarm(30);
103
104         if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
105                 lprintf(1, "Can't connect to %s.%s: %s\n",
106                         host, service, strerror(errno));
107                 close(s);
108                 return (-1);
109         }
110         alarm(0);
111         signal(SIGALRM, SIG_IGN);
112
113         return (s);
114 }
115
116
117
118
119 /*
120  *  Input binary data from socket
121  *  buf the buffer to get the input to
122  *  bytes the maximal number of bytes to read
123  */
124 inline void _serv_read(char *buf, int bytes, wcsession *WCC)
125 {
126         int len, rlen;
127
128         len = 0;
129         while ((len < bytes) && (WCC->serv_sock != -1)){
130                 rlen = read(WCC->serv_sock, &buf[len], bytes - len);
131                 if (rlen < 1) {
132                         lprintf(1, "Server connection broken: %s\n",
133                                 strerror(errno));
134                         wc_backtrace();
135                         close(WCC->serv_sock);
136                         WCC->serv_sock = (-1);
137                         WCC->connected = 0;
138                         WCC->logged_in = 0;
139                         memset(buf, 0, bytes);
140                         return;
141                 }
142                 len = len + rlen;
143         }
144 }
145
146 void serv_read(char *buf, int bytes)
147 {
148         wcsession *WCC = WC;
149
150         WCC->ReadPos = NULL;
151
152         _serv_read(buf, bytes, WCC);
153 }
154
155 /*
156  *  input string from pipe
157  */
158 int serv_getln(char *strbuf, int bufsize)
159 {
160         wcsession *WCC = WC;
161         int ch, len;
162         char buf[2];
163
164         WCC->ReadPos = NULL;
165         len = 0;
166         strbuf[0] = 0;
167         do {
168                 _serv_read(&buf[0], 1, WCC);
169                 ch = buf[0];
170                 if ((ch != 13) && (ch != 10)) {
171                         strbuf[len++] = ch;
172                 }
173         } while ((ch != 10) && (ch != 0) && (len < (bufsize-1)) && (WCC->serv_sock != -1));
174         strbuf[len] = 0;
175 #ifdef SERV_TRACE
176         lprintf(9, "%3d>%s\n", WC->serv_sock, strbuf);
177 #endif
178         return len;
179 }
180
181 int StrBuf_ServGetln(StrBuf *buf)
182 {
183         wcsession *WCC = WC;
184         const char *ErrStr;
185         int rc;
186
187         WCC->ReadPos = NULL;
188         rc = StrBufTCP_read_line(buf, &WCC->serv_sock, 0, &ErrStr);
189         if (rc < 0)
190         {
191                 lprintf(1, "Server connection broken: %s\n",
192                         ErrStr);
193                 wc_backtrace();
194                 WCC->serv_sock = (-1);
195                 WCC->connected = 0;
196                 WCC->logged_in = 0;
197         }
198         return rc;
199 }
200
201 int StrBuf_ServGetlnBuffered(StrBuf *buf)
202 {
203         wcsession *WCC = WC;
204         const char *ErrStr;
205         int rc;
206
207         rc = StrBufTCP_read_buffered_line_fast(buf, 
208                                                WCC->ReadBuf, 
209                                                &WCC->ReadPos, 
210                                                &WCC->serv_sock, 
211                                                5, 1, 
212                                                &ErrStr);
213         if (rc < 0)
214         {
215                 lprintf(1, "Server connection broken: %s\n",
216                         ErrStr);
217                 wc_backtrace();
218                 WCC->serv_sock = (-1);
219                 WCC->connected = 0;
220                 WCC->logged_in = 0;
221         }
222         return rc;
223 }
224
225 int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize)
226 {
227         wcsession *WCC = WC;
228         const char *Err;
229         int rc;
230         
231         rc = StrBufReadBLOBBuffered(buf, 
232                                     WCC->ReadBuf, 
233                                     &WCC->ReadPos,
234                                     &WCC->serv_sock, 
235                                     1, 
236                                     BlobSize, 
237                                     NNN_TERM,
238                                     &Err);
239         if (rc < 0)
240         {
241                 lprintf(1, "Server connection broken: %s\n",
242                         Err);
243                 wc_backtrace();
244                 WCC->serv_sock = (-1);
245                 WCC->connected = 0;
246                 WCC->logged_in = 0;
247         }
248         return rc;
249 }
250
251 int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize)
252 {
253         wcsession *WCC = WC;
254         const char *Err;
255         int rc;
256         
257         WCC->ReadPos = NULL;
258         rc = StrBufReadBLOB(buf, &WCC->serv_sock, 1, BlobSize, &Err);
259         if (rc < 0)
260         {
261                 lprintf(1, "Server connection broken: %s\n",
262                         Err);
263                 wc_backtrace();
264                 WCC->serv_sock = (-1);
265                 WCC->connected = 0;
266                 WCC->logged_in = 0;
267         }
268         return rc;
269 }
270
271 /*
272  *  send binary to server
273  *  buf the buffer to write to citadel server
274  *  nbytes how many bytes to send to citadel server
275  */
276 void serv_write(const char *buf, int nbytes)
277 {
278         int bytes_written = 0;
279         int retval;
280         while (bytes_written < nbytes) {
281                 retval = write(WC->serv_sock, &buf[bytes_written],
282                                nbytes - bytes_written);
283                 if (retval < 1) {
284                         lprintf(1, "Server connection broken: %s\n",
285                                 strerror(errno));
286                         close(WC->serv_sock);
287                         WC->serv_sock = (-1);
288                         WC->connected = 0;
289                         WC->logged_in = 0;
290                         return;
291                 }
292                 bytes_written = bytes_written + retval;
293         }
294 }
295
296
297 /*
298  *  send line to server
299  *  string the line to send to the citadel server
300  */
301 void serv_puts(const char *string)
302 {
303         wcsession *WCC = WC;
304 #ifdef SERV_TRACE
305         lprintf(9, "%3d<%s\n", WC->serv_sock, string);
306 #endif
307         FlushStrBuf(WCC->ReadBuf);
308         WCC->ReadPos = NULL;
309
310         serv_write(string, strlen(string));
311         serv_write("\n", 1);
312 }
313
314 /*
315  *  send line to server
316  *  string the line to send to the citadel server
317  */
318 void serv_putbuf(const StrBuf *string)
319 {
320         wcsession *WCC = WC;
321 #ifdef SERV_TRACE
322         lprintf(9, "%3d<%s\n", WC->serv_sock, ChrPtr(string));
323 #endif
324         FlushStrBuf(WCC->ReadBuf);
325         WCC->ReadPos = NULL;
326
327         serv_write(ChrPtr(string), StrLength(string));
328         serv_write("\n", 1);
329 }
330
331
332 /*
333  *  convenience function to send stuff to the server
334  *  format the formatstring
335  *  ... the entities to insert into format 
336  */
337 void serv_printf(const char *format,...)
338 {
339         wcsession *WCC = WC;
340         va_list arg_ptr;
341         char buf[SIZ];
342         size_t len;
343
344         FlushStrBuf(WCC->ReadBuf);
345         WCC->ReadPos = NULL;
346
347         va_start(arg_ptr, format);
348         vsnprintf(buf, sizeof buf, format, arg_ptr);
349         va_end(arg_ptr);
350
351         len = strlen(buf);
352         buf[len++] = '\n';
353         buf[len] = '\0';
354         serv_write(buf, len);
355 #ifdef SERV_TRACE
356         lprintf(9, "<%s", buf);
357 #endif
358 }
359