1 /*
2 * Some code in this file is derived from the public domain code in
3 * WWW/Library/Implementation/HTTCP.c distributed with lynx-2.2,
4 * whose original author is Tim Berners-lee <timbl@info.cern.ch>.
5 *
6 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
7 *
8 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
9 *
10 * This file may be distributed under the terms of the Q Public License
11 * as defined by Trolltech AS of Norway and appearing in the file
12 * LICENSE.QPL included in the packaging of this file.
13 *
14 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
15 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
17 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
18 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
19 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
20 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/tcp.c,v 1.6 2011/05/16 16:21:59 william Exp $
23 */
24
25 #define _INCLUDE_FROM_TCP_C_
26
27 #include "tgifdefs.h"
28
29 #include "msg.e"
30 #include "remote.e"
31 #include "strtbl.e"
32 #include "tcp.e"
33 #include "util.e"
34
SetSocketBlockingState(pn_socket,n_blocking)35 void SetSocketBlockingState(pn_socket, n_blocking)
36 int *pn_socket, n_blocking;
37 {
38 int rc;
39 #ifdef O_NONBLOCK
40 int flags = fcntl(*pn_socket, F_GETFL);
41
42 rc = fcntl(*pn_socket, F_SETFL,
43 n_blocking ? (flags & (~O_NONBLOCK)) : (flags | O_NONBLOCK));
44 #else /* ~O_NONBLOCK */
45 int val=(!n_blocking);
46
47 rc = ioctl(*pn_socket, FIONBIO, &val);
48 #endif /* O_NONBLOCK */
49 if (rc == (-1)) {
50 fprintf(stderr, "%s\n",
51 TgLoadString(n_blocking ? STID_FAIL_TO_MAKE_SOCKET_BLOCK :
52 STID_FAIL_TO_MAKE_SOCKET_NON_BLOCK));
53 }
54 }
55
TcpFreeBuf(buf)56 void TcpFreeBuf(buf)
57 char *buf;
58 {
59 free(buf);
60 }
61
62 static int gnPipeBroken=FALSE;
63
64 static
BrokenPipe(nSig)65 void BrokenPipe(nSig)
66 int nSig;
67 {
68 if (nSig == SIGPIPE) {
69 gnPipeBroken = TRUE;
70 signal(SIGPIPE, SIG_DFL);
71 }
72 }
73
TcpDoConnect(psz_host,us_port,pn_socket)74 int TcpDoConnect(psz_host, us_port, pn_socket)
75 char *psz_host;
76 int us_port, *pn_socket;
77 {
78 static int not_initialized=TRUE;
79 struct sockaddr_in soc_address;
80 struct sockaddr_in *sin=(&soc_address);
81 struct hostent *p_hostent=NULL;
82 int status=TG_REMOTE_STATUS_OK;
83
84 if (not_initialized) {
85 not_initialized = FALSE;
86 signal(SIGPIPE, BrokenPipe);
87 }
88 if (*psz_host >= '0' && *psz_host <= '9') {
89 sin->sin_addr.s_addr = inet_addr(psz_host);
90 } else {
91 p_hostent = gethostbyname(psz_host);
92 if (p_hostent == NULL) {
93 return TG_REMOTE_STATUS_HOST;
94 }
95 memcpy(&sin->sin_addr, p_hostent->h_addr, p_hostent->h_length);
96 }
97 sin->sin_family = AF_INET;
98 sin->sin_port = htons((unsigned short)us_port);
99 *pn_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
100
101 SetSocketBlockingState(pn_socket, FALSE);
102
103 status = connect(*pn_socket, (struct sockaddr*)&soc_address,
104 sizeof(soc_address));
105 #ifdef EAGAIN
106 if ((status < 0) && (errno==EINPROGRESS || errno==EAGAIN)) {
107 #else /* ~EAGAIN */
108 if ((status < 0) && (errno == EINPROGRESS)) {
109 #endif /* EAGAIN */
110 struct timeval timeout;
111 int rc=0;
112
113 timeout.tv_sec = 0;
114 timeout.tv_usec = 100000;
115 while (rc <= 0) {
116 fd_set writefds;
117
118 FD_ZERO(&writefds);
119 FD_SET(*pn_socket, &writefds);
120 #ifdef __hpux
121 rc = select(FD_SETSIZE, NULL, (int*)&writefds, NULL, &timeout);
122 #else /* ~__hpux */
123 rc = select(FD_SETSIZE, NULL, &writefds, NULL, &timeout);
124 #endif /* __hpux */
125 if ((rc < 0)&&(errno != EALREADY)) {
126 status = rc;
127 break;
128 } else if (rc > 0) {
129 gnPipeBroken = FALSE;
130 status = connect(*pn_socket, (struct sockaddr*)&soc_address,
131 sizeof(soc_address));
132 if (gnPipeBroken) {
133 fprintf(stderr, TgLoadString(STID_BROKEN_PIPE_CONTACT_HOST),
134 psz_host);
135 fprintf(stderr, "\n");
136 }
137 if ((status < 0)&&(errno == EISCONN)) status = TG_REMOTE_STATUS_OK;
138 if (errno == EALREADY) {
139 rc = 0;
140 } else {
141 break;
142 }
143 } else {
144 status = connect(*pn_socket, (struct sockaddr*)&soc_address,
145 sizeof(soc_address));
146 #ifdef EAGAIN
147 if ((status < 0) && (errno != EALREADY) && (errno != EISCONN) &&
148 (errno != EAGAIN))
149 #else /* ~EAGAIN */
150 if ((status < 0) && (errno != EALREADY) && (errno != EISCONN))
151 #endif /* EAGAIN */
152 break;
153 }
154 if (UserAbortComm()) {
155 status = TG_REMOTE_STATUS_INTR;
156 errno = EINTR;
157 break;
158 }
159 }
160 }
161 if (status >= 0) {
162 SetSocketBlockingState(pn_socket, TRUE);
163 } else {
164 close(*pn_socket);
165 }
166 return status;
167 }
168
TcpDoWrite(n_socket,buf,buf_sz)169 int TcpDoWrite(n_socket, buf, buf_sz)
170 int n_socket, buf_sz;
171 char *buf;
172 {
173 int status=0;
174
175 if (buf == NULL) return TG_REMOTE_STATUS_OK;
176
177 status = write(n_socket, buf, (int)buf_sz);
178 if (status <= 0) {
179 if (status == 0) {
180 fprintf(stderr, "%s\n", TgLoadString(STID_WRITE_TO_SOCKET_FAILED));
181 } else if ((errno == ENOTCONN || errno == ECONNRESET || errno == EPIPE)) {
182 fprintf(stderr, "%s\n",
183 TgLoadString(STID_UNEXP_NETWORK_ERR_WRITE_SOCK));
184 return TG_REMOTE_STATUS_WRITE;
185 }
186 }
187 return TG_REMOTE_STATUS_OK;
188 }
189
190 #define MIN_READ_SIZE 0x100
191
TcpDoRead(n_socket,ppsz_buf,pn_buf_sz)192 int TcpDoRead(n_socket, ppsz_buf, pn_buf_sz)
193 int n_socket, *pn_buf_sz;
194 char **ppsz_buf;
195 {
196 int buf_sz=0x400, len=0, end_of_file=FALSE;
197 char *buf=(char*)malloc(buf_sz*sizeof(char));
198
199 if (pn_buf_sz != NULL) *pn_buf_sz = 0;
200 *ppsz_buf = NULL;
201 if (buf == NULL) {
202 FailAllocMessage();
203 return TG_REMOTE_STATUS_MEM;
204 }
205 do {
206 int bytes_read;
207
208 if (buf_sz - len < MIN_READ_SIZE) {
209 buf_sz += 0x400;
210 if ((buf=(char*)realloc(buf, buf_sz)) == NULL) {
211 FailAllocMessage();
212 return TG_REMOTE_STATUS_MEM;
213 }
214 }
215 bytes_read = read(n_socket, &buf[len], buf_sz-len-1);
216 if (bytes_read <= 0) {
217 if (bytes_read < 0 && (errno == ENOTCONN || errno == ECONNRESET ||
218 errno == EPIPE)) {
219 free(buf);
220 fprintf(stderr, "%s\n",
221 TgLoadString(STID_READ_FROM_SOCKET_FAILED));
222 return TG_REMOTE_STATUS_READ;
223 } else if (bytes_read < 0) {
224 free(buf);
225 fprintf(stderr, "%s\n",
226 TgLoadString(STID_UNEXP_NETWORK_ERR_READ_SOCK));
227 return TG_REMOTE_STATUS_NET;
228 }
229 end_of_file = TRUE;
230 } else {
231 len += bytes_read;
232 }
233 } while (!end_of_file);
234 buf[len] = '\0';
235 *ppsz_buf = buf;
236 if (pn_buf_sz != NULL) *pn_buf_sz = len;
237 return TG_REMOTE_STATUS_OK;
238 }
239
240