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