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