/[libspopc]/session.c
ViewVC logotype

Contents of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5 - (show annotations)
Thu Dec 10 11:54:10 2009 UTC (11 years, 1 month ago) by ben
File MIME type: text/plain
File size: 9165 byte(s)
WIN32: use closesocket()
1 /* this is session.c file, part of the libspopc library sources
2 * copyright © 2002- Benoit Rouits <brouits@free.fr>
3 * released under the terms of the GNU Lesser General Public Licence.
4 *
5 * libspopc offers simple API for a pop3 client.
6 * See RFC 1725 for pop3 specifications.
7 * more information on http://herewe.servebeer.com/libspopc/
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 /*I casted 'port' to true unsigned, now, tell me if warning continues */
25 /*; #pragma warning(disable: 4761)*/ /* disable "integral size mismatch in argument" -warning */
26
27 #ifdef WIN32
28 #include <winsock.h>
29 #include <io.h>
30 #else
31 #include <netdb.h>
32 #include <unistd.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #endif
36
37
38 #include <stdlib.h>
39 #include <string.h> /* strdup */
40 #include <stdio.h> /* perror */
41 #include <sys/types.h>
42
43 #include "libspopc.h"
44 #include "mutex.h"
45
46 #define socklen_t int /* actually true on most systems */
47
48 /* needs from queries.c */
49 extern int pop3_recv (pop3sock_t sock, char* buf, int len);
50
51 /* mutex locks for this object (must be declared in libspopc.c) */
52 extern mutex GETHOSTBYNAME;
53 /* end mutex locks */
54
55 #ifdef USE_SSL
56
57 #define SSL_USE_NEVER -1 /* never use SSL even on port 995 */
58 #define SSL_USE_AUTO 0 /* use SSL only on port 995 (default) */
59 #define SSL_USE_ALWAYS 1 /* force SSL whatever the port is */
60
61 static int SSL_UP = 0; /* prevent SSL_library_init() to be called twice */
62 static char* SSL_CERT = NULL; /* whole application on-disk certfile */
63
64 /* set default behaviour as SSL_USE_AUTO for backward compatibility */
65 static int SSL_USE = SSL_USE_AUTO;
66
67
68 /* let libspopc never use SSL even connecting on port 995 */
69 void pop3_ssl_never(void)
70 {
71 SSL_USE = SSL_USE_NEVER;
72 }
73
74 /* let libspopc use SSL when connecting port 995 */
75 void pop3_ssl_auto(void)
76 {
77 SSL_USE = SSL_USE_AUTO;
78 }
79
80 /* let libspopc use SSL connecting on any port, even 110 */
81 void pop3_ssl_always(void)
82 {
83 SSL_USE = SSL_USE_ALWAYS;
84 }
85
86 /* set the filename of the certificate */
87 void pop3_cert_setup(const char *certfile)
88 {
89 if (SSL_CERT) free(SSL_CERT);
90 SSL_CERT=NULL;
91 if (certfile) SSL_CERT=strdup(certfile);
92 }
93
94 /* callback for error reporting on ssl verification
95 * just return 0 on error, 1 else
96 */
97 int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) {
98 if (!ok) { /* bad identification */
99 int err;
100 err = X509_STORE_CTX_get_error(ctx);
101 return 0;
102 }
103 return 1;
104 }
105
106 /* init ssl library and context
107 * depending on port and SSL_USE_*
108 */
109 pop3sock_t ssl_prepare(const int port){
110 pop3sock_t sock;
111
112 sock =(pop3sock_t)malloc(sizeof(pop3sock));
113 sock->sock=socket(AF_INET,SOCK_STREAM,0);
114 if(-1==sock->sock){
115 perror("ssl_prepare.socket");
116 free(sock);
117 return(NULL);
118 }
119 if (( (995 == port) && (SSL_USE == SSL_USE_AUTO))
120 || (SSL_USE == SSL_USE_ALWAYS) ) {
121 if (0 == SSL_UP) SSL_UP=SSL_library_init();
122
123 if (1 != SSL_UP) {
124 #ifdef WIN32
125 closesocket(sock->sock);
126 #else
127 close(sock->sock);
128 #endif
129 free(sock);
130 perror("ssl_prepare.SSL_library_init");
131 return(NULL);
132 }
133 SSL_load_error_strings();
134 sock->ctx = SSL_CTX_new(SSLv23_client_method());
135 if (NULL == sock->ctx) {
136 #ifdef WIN32
137 closesocket(sock->sock);
138 #else
139 close(sock->sock);
140 #endif
141 free(sock);
142 perror("ssl_prepare.SSLv23_client_method");
143 return(NULL);
144 }
145 if ( SSL_CERT != NULL ) {
146 SSL_CTX_load_verify_locations(sock->ctx, SSL_CERT, 0);
147 SSL_CTX_set_verify(sock->ctx, SSL_VERIFY_PEER, &ssl_verify_callback);
148 }
149 sock->ssl = SSL_new(sock->ctx);
150 if (NULL == sock->ssl) {
151 #ifdef WIN32
152 closesocket(sock->sock);
153 #else
154 close(sock->sock);
155 #endif
156 SSL_CTX_free(sock->ctx);
157 free(sock);
158 perror("ssl_prepare.SSL_new");
159 return(NULL);
160 }
161 SSL_set_fd(sock->ssl, sock->sock);
162 } else { /* port != 995 or SSL_USE_NEVER */
163 sock->ssl=NULL;
164 sock->ctx=NULL;
165 }
166 return sock;
167 }
168
169 #endif
170
171 /* prepares the socket options
172 * mainly set read an write timeouts
173 * this way may be either ignored
174 * or refused on some platform
175 */
176 int socket_prepare(int sock){
177 struct timeval tv;
178 int ret=0;
179 tv.tv_sec = SOCKET_TIMEOUT;
180 tv.tv_usec = 0 ;
181
182 if (ret += setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, sizeof tv))
183 perror("socket_prepare.setsockopt");
184 if (ret += setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&tv, sizeof tv))
185 perror("socket_prepare.setsockopt");
186 return ret;
187 }
188
189 /* prepares the pop session and returns a socket descriptor */
190 pop3sock_t pop3_prepare(const char* servername, const int port, struct sockaddr_in* connection, struct hostent* server){
191 pop3sock_t sock;
192 struct hostent* hostent_buf;
193 int i;
194 #ifdef WIN32
195
196 WSADATA wsaData;
197
198 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
199 {
200 exit(1);
201 }
202
203 #endif
204
205 memset((char*)connection,0,sizeof(struct sockaddr_in));
206
207 /* here, enter a critical section to perform atomic name resolution */
208 mutex_in(&GETHOSTBYNAME);
209 hostent_buf=gethostbyname(servername);
210 if(!hostent_buf){
211 herror("pop3_prepare.gethostbyname");
212 return BAD_SOCK;
213 }
214 /* begin hostent deep copy */
215 memmove(server,hostent_buf,sizeof(struct hostent));
216 server->h_name=strdup(hostent_buf->h_name);
217 server->h_aliases=NULL;
218 i=0;
219 while (hostent_buf->h_aliases[i])
220 {
221 server->h_aliases=realloc(server->h_aliases,(i+1)*sizeof(char*));
222 if(hostent_buf->h_aliases[i])
223 server->h_aliases[i]=strdup(hostent_buf->h_aliases[i]);
224 else server->h_aliases[i]=NULL;
225 i++;
226 }
227 server->h_addr_list=NULL;
228 i=0;
229 while (hostent_buf->h_addr_list[i])
230 { /* has at least one adress */
231 server->h_addr_list=realloc(server->h_addr_list,(i+1)*sizeof(char*));
232 server->h_addr_list[i]=malloc(server->h_length);
233 memmove(server->h_addr_list[i],hostent_buf->h_addr_list[i],server->h_length);
234 i++;
235 }
236 server->h_addr_list=realloc(server->h_addr_list, (i+1)*sizeof(char*));
237 #if 0
238 server->h_addr_list[i]=malloc(1);
239 server->h_addr_list[i]='\0';
240 #else
241 server->h_addr_list[i]=NULL;
242 #endif /* 0 */
243 /* end hostent deep copy */
244 mutex_out(&GETHOSTBYNAME);
245 /* end of critical section (name resolution) */
246
247 memmove((char*)&(connection->sin_addr.s_addr),server->h_addr,server->h_length);
248 connection->sin_family=AF_INET;
249 connection->sin_port=htons(port?(unsigned short int)port:(unsigned short int)110);
250 /* integral size mismatch in argument - htons(port)*/
251
252 #ifdef USE_SSL
253 sock = ssl_prepare(port);
254 #else
255 sock=socket(AF_INET,SOCK_STREAM,0);
256 if(BAD_SOCK == sock){
257 perror("pop3_prepare.socket");
258 }
259 #endif
260 #ifdef USE_SSL
261 socket_prepare(sock->sock);
262 #else
263 socket_prepare(sock);
264 #endif
265 return(sock);
266 }
267
268 /* connects to the server through the sock and returns server's welcome */
269 char* pop3_connect(pop3sock_t sock, struct sockaddr_in* connection){
270 int r;
271 char* buf;
272
273
274 #ifdef USE_SSL
275 r=connect(sock->sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
276 if ( r!=-1 && sock->ssl ) {
277 if (SSL_connect(sock->ssl) == -1) {
278 #ifdef WIN32
279 closesocket(sock->sock);
280 #else
281 close(sock->sock);
282 #endif
283 return(NULL);
284 }
285 if ( SSL_CERT ) {
286 if ( !SSL_get_peer_certificate(sock->ssl) ) {
287 #ifdef WIN32
288 closesocket(sock->sock);
289 #else
290 close(sock->sock);
291 #endif
292 return(NULL);
293 }
294 }
295 }
296 #else
297 r=connect(sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
298 #endif
299
300 if(r==-1){
301 perror("pop3_connect.connect");
302 return(NULL);
303 }
304
305
306 buf=(char*)malloc(POPBUF);
307 if(!buf){
308 perror("pop3_connect.malloc");
309 return(NULL);
310 }
311 r=pop3_recv(sock,buf,POPBUF); /* 512 is enough, as say RFC 1939 */
312 if(r==0 || r==-1){
313 /* -1: transport error (timeout?) */
314 /* 0: server error (busy?) */
315 perror("pop3_connect.pop3_recv");
316 free(buf);
317 return(NULL);
318 }
319 buf[r]='\0';
320 return buf;
321 }
322
323 void pop3_disconnect(pop3sock_t sock, struct hostent* server){
324 int i;
325 /* close socket */
326 #ifdef USE_SSL
327 if (sock->sock>0)
328 {
329 shutdown(sock->sock,SHUT_RDWR);
330 #ifdef WIN32
331 closesocket(sock->sock);
332 #else
333 close(sock->sock);
334 #endif
335 }
336 if (NULL != sock->ssl) {
337 /* a memory leak has been reported with: SSL_shutdown(sock->ssl);*/
338 SSL_free(sock->ssl);
339 }
340 if ( NULL != sock->ctx ) {
341 SSL_CTX_free(sock->ctx);
342 }
343
344 free(sock);
345 #else
346 if (sock>0) {
347 #ifndef WIN32
348 shutdown(sock,SHUT_RDWR);
349 #endif
350 #ifdef WIN32
351 closesocket(sock);
352 #else
353 close(sock);
354 #endif
355 }
356 #endif
357 /* free deep copy of struct hostent */
358 i=0;
359 while(NULL != server->h_addr_list[i]) {
360 /* has at least one adress */
361 free(server->h_addr_list[i]);
362 i++;
363 }
364 /* free(server->h_addr_list[i]); FIXME */
365 free(server->h_addr_list);
366 free(server->h_name);
367 #ifdef WIN32
368 WSACleanup();
369 #endif
370 }

  ViewVC Help
Powered by ViewVC 1.1.26