* buybuy serv_read
[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 /*
147  *  input string from pipe
148  */
149 int serv_getln(char *strbuf, int bufsize)
150 {
151         wcsession *WCC = WC;
152         int ch, len;
153         char buf[2];
154
155         WCC->ReadPos = NULL;
156         len = 0;
157         strbuf[0] = 0;
158         do {
159                 _serv_read(&buf[0], 1, WCC);
160                 ch = buf[0];
161                 if ((ch != 13) && (ch != 10)) {
162                         strbuf[len++] = ch;
163                 }
164         } while ((ch != 10) && (ch != 0) && (len < (bufsize-1)) && (WCC->serv_sock != -1));
165         strbuf[len] = 0;
166 #ifdef SERV_TRACE
167         lprintf(9, "%3d>%s\n", WC->serv_sock, strbuf);
168 #endif
169         return len;
170 }
171
172 int StrBuf_ServGetln(StrBuf *buf)
173 {
174         wcsession *WCC = WC;
175         const char *ErrStr;
176         int rc;
177
178         WCC->ReadPos = NULL;
179         rc = StrBufTCP_read_line(buf, &WCC->serv_sock, 0, &ErrStr);
180         if (rc < 0)
181         {
182                 lprintf(1, "Server connection broken: %s\n",
183                         ErrStr);
184                 wc_backtrace();
185                 WCC->serv_sock = (-1);
186                 WCC->connected = 0;
187                 WCC->logged_in = 0;
188         }
189         return rc;
190 }
191
192 int StrBuf_ServGetlnBuffered(StrBuf *buf)
193 {
194         wcsession *WCC = WC;
195         const char *ErrStr;
196         int rc;
197
198         rc = StrBufTCP_read_buffered_line_fast(buf, 
199                                                WCC->ReadBuf, 
200                                                &WCC->ReadPos, 
201                                                &WCC->serv_sock, 
202                                                5, 1, 
203                                                &ErrStr);
204         if (rc < 0)
205         {
206                 lprintf(1, "Server connection broken: %s\n",
207                         ErrStr);
208                 wc_backtrace();
209                 WCC->serv_sock = (-1);
210                 WCC->connected = 0;
211                 WCC->logged_in = 0;
212         }
213         return rc;
214 }
215
216 int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize)
217 {
218         wcsession *WCC = WC;
219         const char *Err;
220         int rc;
221         
222         rc = StrBufReadBLOBBuffered(buf, 
223                                     WCC->ReadBuf, 
224                                     &WCC->ReadPos,
225                                     &WCC->serv_sock, 
226                                     1, 
227                                     BlobSize, 
228                                     NNN_TERM,
229                                     &Err);
230         if (rc < 0)
231         {
232                 lprintf(1, "Server connection broken: %s\n",
233                         Err);
234                 wc_backtrace();
235                 WCC->serv_sock = (-1);
236                 WCC->connected = 0;
237                 WCC->logged_in = 0;
238         }
239         return rc;
240 }
241
242 int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize)
243 {
244         wcsession *WCC = WC;
245         const char *Err;
246         int rc;
247         
248         WCC->ReadPos = NULL;
249         rc = StrBufReadBLOB(buf, &WCC->serv_sock, 1, BlobSize, &Err);
250         if (rc < 0)
251         {
252                 lprintf(1, "Server connection broken: %s\n",
253                         Err);
254                 wc_backtrace();
255                 WCC->serv_sock = (-1);
256                 WCC->connected = 0;
257                 WCC->logged_in = 0;
258         }
259         return rc;
260 }
261
262 /*
263  *  send binary to server
264  *  buf the buffer to write to citadel server
265  *  nbytes how many bytes to send to citadel server
266  */
267 void serv_write(const char *buf, int nbytes)
268 {
269         int bytes_written = 0;
270         int retval;
271         while (bytes_written < nbytes) {
272                 retval = write(WC->serv_sock, &buf[bytes_written],
273                                nbytes - bytes_written);
274                 if (retval < 1) {
275                         lprintf(1, "Server connection broken: %s\n",
276                                 strerror(errno));
277                         close(WC->serv_sock);
278                         WC->serv_sock = (-1);
279                         WC->connected = 0;
280                         WC->logged_in = 0;
281                         return;
282                 }
283                 bytes_written = bytes_written + retval;
284         }
285 }
286
287
288 /*
289  *  send line to server
290  *  string the line to send to the citadel server
291  */
292 void serv_puts(const char *string)
293 {
294         wcsession *WCC = WC;
295 #ifdef SERV_TRACE
296         lprintf(9, "%3d<%s\n", WC->serv_sock, string);
297 #endif
298         FlushStrBuf(WCC->ReadBuf);
299         WCC->ReadPos = NULL;
300
301         serv_write(string, strlen(string));
302         serv_write("\n", 1);
303 }
304
305 /*
306  *  send line to server
307  *  string the line to send to the citadel server
308  */
309 void serv_putbuf(const StrBuf *string)
310 {
311         wcsession *WCC = WC;
312 #ifdef SERV_TRACE
313         lprintf(9, "%3d<%s\n", WC->serv_sock, ChrPtr(string));
314 #endif
315         FlushStrBuf(WCC->ReadBuf);
316         WCC->ReadPos = NULL;
317
318         serv_write(ChrPtr(string), StrLength(string));
319         serv_write("\n", 1);
320 }
321
322
323 /*
324  *  convenience function to send stuff to the server
325  *  format the formatstring
326  *  ... the entities to insert into format 
327  */
328 void serv_printf(const char *format,...)
329 {
330         wcsession *WCC = WC;
331         va_list arg_ptr;
332         char buf[SIZ];
333         size_t len;
334
335         FlushStrBuf(WCC->ReadBuf);
336         WCC->ReadPos = NULL;
337
338         va_start(arg_ptr, format);
339         vsnprintf(buf, sizeof buf, format, arg_ptr);
340         va_end(arg_ptr);
341
342         len = strlen(buf);
343         buf[len++] = '\n';
344         buf[len] = '\0';
345         serv_write(buf, len);
346 #ifdef SERV_TRACE
347         lprintf(9, "<%s", buf);
348 #endif
349 }
350