citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

clientsocket.c
Go to the documentation of this file.
1// This module handles client-side sockets opened by the Citadel server (for
2// the client side of Internet protocols, etc.) It does _not_ handle client
3// sockets for the Citadel client; for that you must look in ipc_c_tcp.c
4// (which, uncoincidentally, bears a striking similarity to this file).
5//
6// Copyright (c) 1987-2017 by the citadel.org team
7//
8// This program is open source software. Use, duplication, or disclosure
9// is subject to the terms of the GNU General Public License, version 3.
10// The program is distributed without any warranty, expressed or implied.
11
12#include <stdlib.h>
13#include <unistd.h>
14#include <netdb.h>
15#include <stdio.h>
16#ifdef __FreeBSD__
17#include <sys/socket.h>
18#endif
19#include <libcitadel.h>
20#include "ctdl_module.h"
21#include "clientsocket.h"
22
23int sock_connect(char *host, char *service) {
24 struct in6_addr serveraddr;
25 struct addrinfo hints;
26 struct addrinfo *res = NULL;
27 struct addrinfo *ai = NULL;
28 int rc = (-1);
29 int sock = (-1);
30
31 if ((host == NULL) || IsEmptyStr(host))
32 return (-1);
33 if ((service == NULL) || IsEmptyStr(service))
34 return (-1);
35
36 memset(&hints, 0x00, sizeof(hints));
37 hints.ai_flags = AI_NUMERICSERV;
38 hints.ai_family = AF_UNSPEC;
39 hints.ai_socktype = SOCK_STREAM;
40
41 // Handle numeric IPv4 and IPv6 addresses
42 rc = inet_pton(AF_INET, host, &serveraddr);
43 if (rc == 1) { // dotted quad
44 hints.ai_family = AF_INET;
45 hints.ai_flags |= AI_NUMERICHOST;
46 }
47 else {
48 rc = inet_pton(AF_INET6, host, &serveraddr);
49 if (rc == 1) { // IPv6 address
50 hints.ai_family = AF_INET6;
51 hints.ai_flags |= AI_NUMERICHOST;
52 }
53 }
54
55 // Begin the connection process
56 rc = getaddrinfo(host, service, &hints, &res);
57 if (rc != 0) {
58 syslog(LOG_ERR, "%s: %s", host, gai_strerror(rc));
59 return(-1);
60 }
61
62 // Try all available addresses until we connect to one or until we run out.
63 for (ai = res; ai != NULL; ai = ai->ai_next) {
64 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
65 if (sock < 0) {
66 syslog(LOG_ERR, "%s: %m", host);
67 freeaddrinfo(res);
68 return(-1);
69 }
70 rc = connect(sock, ai->ai_addr, ai->ai_addrlen);
71 if (rc >= 0) {
72 freeaddrinfo(res);
73 return(sock);
74 }
75 else {
76 syslog(LOG_ERR, "%s: %m", host);
77 close(sock);
78 }
79 }
80 freeaddrinfo(res);
81 return(-1);
82}
83
84
85// Read data from the client socket.
86//
87// sock socket fd to read from
88// buf buffer to read into
89// bytes number of bytes to read
90// timeout Number of seconds to wait before timing out
91//
92// Possible return values:
93// 1 Requested number of bytes has been read.
94// 0 Request timed out.
95// -1 Connection is broken, or other error.
96int socket_read_blob(int *Socket, StrBuf *Target, int bytes, int timeout) {
97 const char *Error;
98 int retval = 0;
99
100 retval = StrBufReadBLOBBuffered(Target, CC->SBuf.Buf, &CC->SBuf.ReadWritePointer, Socket, 1, bytes, O_TERM, &Error);
101 if (retval < 0) {
102 syslog(LOG_ERR, "clientsocket: socket_read_blob() failed: %s", Error);
103 }
104 return retval;
105}
106
107
108int CtdlSockGetLine(int *sock, StrBuf *Target, int nSec) {
109 const char *Error;
110 int rc;
111
112 FlushStrBuf(Target);
113 rc = StrBufTCP_read_buffered_line_fast(Target,
114 CC->SBuf.Buf,
115 &CC->SBuf.ReadWritePointer,
116 sock, nSec, 1, &Error);
117 if ((rc < 0) && (Error != NULL)) {
118 syslog(LOG_ERR, "clientsocket: CtdlSockGetLine() failed: %s", Error);
119 }
120 return rc;
121}
122
123
124// client_getln() ... Get a LF-terminated line of text from the client.
125int sock_getln(int *sock, char *buf, int bufsize) {
126 int i, retval;
127 const char *pCh;
128
129 FlushStrBuf(CC->sMigrateBuf);
130 retval = CtdlSockGetLine(sock, CC->sMigrateBuf, 5);
131
132 i = StrLength(CC->sMigrateBuf);
133 pCh = ChrPtr(CC->sMigrateBuf);
134
135 memcpy(buf, pCh, i + 1);
136
137 FlushStrBuf(CC->sMigrateBuf);
138 if (retval < 0) {
139 safestrncpy(&buf[i], "000", bufsize - i);
140 i += 3;
141 }
142 return i;
143}
144
145
146// sock_write() - send binary to server.
147// Returns the number of bytes written, or -1 for error.
148int sock_write(int *sock, const char *buf, int nbytes) {
149 return sock_write_timeout(sock, buf, nbytes, 50);
150}
151
152
153int sock_write_timeout(int *sock, const char *buf, int nbytes, int timeout) {
154 int nSuccessLess = 0;
155 int bytes_written = 0;
156 int retval;
157 fd_set rfds;
158 int fdflags;
159 int IsNonBlock;
160 struct timeval tv;
161 int selectresolution = 100;
162
163 fdflags = fcntl(*sock, F_GETFL);
164 IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
165
166 while ((nSuccessLess < timeout) && (*sock != -1) && (bytes_written < nbytes)) {
167 if (IsNonBlock) {
168 tv.tv_sec = selectresolution;
169 tv.tv_usec = 0;
170
171 FD_ZERO(&rfds);
172 FD_SET(*sock, &rfds);
173 if (select(*sock + 1, NULL, &rfds, NULL, &tv) == -1) {
174 close (*sock);
175 *sock = -1;
176 return -1;
177 }
178 }
179 if (IsNonBlock && ! FD_ISSET(*sock, &rfds)) {
180 nSuccessLess ++;
181 continue;
182 }
183 retval = write(*sock, &buf[bytes_written],
184 nbytes - bytes_written);
185 if (retval < 1) {
186 sock_close(*sock);
187 *sock = -1;
188 return (-1);
189 }
190 bytes_written = bytes_written + retval;
191 if (IsNonBlock && (bytes_written == nbytes)){
192 tv.tv_sec = selectresolution;
193 tv.tv_usec = 0;
194
195 FD_ZERO(&rfds);
196 FD_SET(*sock, &rfds);
197 if (select(*sock + 1, NULL, &rfds, NULL, &tv) == -1) {
198 close (*sock);
199 *sock = -1;
200 return -1;
201 }
202 }
203 }
204 return (bytes_written);
205}
206
207
208// client_getln() ... Get a LF-terminated line of text from the client.
209int sock_getln_err(int *sock, char *buf, int bufsize, int *rc, int nSec) {
210 int i, retval;
211 const char *pCh;
212
213 FlushStrBuf(CC->sMigrateBuf);
214 *rc = retval = CtdlSockGetLine(sock, CC->sMigrateBuf, nSec);
215
216 i = StrLength(CC->sMigrateBuf);
217 pCh = ChrPtr(CC->sMigrateBuf);
218
219 memcpy(buf, pCh, i + 1);
220
221 FlushStrBuf(CC->sMigrateBuf);
222 if (retval < 0) {
223 safestrncpy(&buf[i], "000", bufsize - i);
224 i += 3;
225 }
226 return i;
227}
228
229
230// Multiline version of sock_gets() ... this is a convenience function for
231// client side protocol implementations. It only returns the first line of
232// a multiline response, discarding the rest.
233int ml_sock_gets(int *sock, char *buf, int nSec) {
234 int rc = 0;
235 char bigbuf[1024];
236 int g;
237
238 g = sock_getln_err(sock, buf, SIZ, &rc, nSec);
239 if (rc < 0)
240 return rc;
241 if (g < 4)
242 return (g);
243 if (buf[3] != '-')
244 return (g);
245
246 do {
247 g = sock_getln_err(sock, bigbuf, SIZ, &rc, nSec);
248 if (rc < 0)
249 return rc;
250 if (g < 0)
251 return (g);
252 } while ((g >= 4) && (bigbuf[3] == '-'));
253
254 return (strlen(buf));
255}
256
257
258// sock_puts() - send line to server - implemented in terms of serv_write()
259// Returns the number of bytes written, or -1 for error.
260int sock_puts(int *sock, char *buf) {
261 int i, j;
262
263 i = sock_write(sock, buf, strlen(buf));
264 if (i < 0)
265 return (i);
266 j = sock_write(sock, "\n", 1);
267 if (j < 0)
268 return (j);
269 return (i + j);
270}
void timeout(int signum)
Definition: citmail.c:41
int sock_getln(int *sock, char *buf, int bufsize)
Definition: clientsocket.c:125
int sock_puts(int *sock, char *buf)
Definition: clientsocket.c:260
int sock_getln_err(int *sock, char *buf, int bufsize, int *rc, int nSec)
Definition: clientsocket.c:209
int CtdlSockGetLine(int *sock, StrBuf *Target, int nSec)
Definition: clientsocket.c:108
int socket_read_blob(int *Socket, StrBuf *Target, int bytes, int timeout)
Definition: clientsocket.c:96
int ml_sock_gets(int *sock, char *buf, int nSec)
Definition: clientsocket.c:233
int sock_write(int *sock, const char *buf, int nbytes)
Definition: clientsocket.c:148
int sock_write_timeout(int *sock, const char *buf, int nbytes, int timeout)
Definition: clientsocket.c:153
int sock_connect(char *host, char *service)
Definition: clientsocket.c:23
#define sock_close(sock)
Definition: clientsocket.h:26
#define CC
Definition: context.h:140
#define SIZ
Definition: sysconfig.h:33