/[libspopc]/session.c
ViewVC logotype

Annotation of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide annotations)
Sat Dec 4 14:24:49 2010 UTC (9 years, 5 months ago) by ben
File MIME type: text/plain
File size: 9794 byte(s)
added libspopc_settimeout(int)
1 ben 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 ben 2 * more information on http://herewe.servebeer.com/libspopc/
8 ben 1 *
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 ben 6 #include <stdio.h>
30 ben 1 #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 ben 20 extern int socket_timeout; /* from libscpopc.c */
49    
50 ben 1 /* needs from queries.c */
51     extern int pop3_recv (pop3sock_t sock, char* buf, int len);
52    
53     /* mutex locks for this object (must be declared in libspopc.c) */
54     extern mutex GETHOSTBYNAME;
55     /* end mutex locks */
56    
57     #ifdef USE_SSL
58    
59     #define SSL_USE_NEVER -1 /* never use SSL even on port 995 */
60     #define SSL_USE_AUTO 0 /* use SSL only on port 995 (default) */
61     #define SSL_USE_ALWAYS 1 /* force SSL whatever the port is */
62    
63     static int SSL_UP = 0; /* prevent SSL_library_init() to be called twice */
64     static char* SSL_CERT = NULL; /* whole application on-disk certfile */
65    
66     /* set default behaviour as SSL_USE_AUTO for backward compatibility */
67     static int SSL_USE = SSL_USE_AUTO;
68    
69    
70     /* let libspopc never use SSL even connecting on port 995 */
71 ben 6 DLLIMPORT void pop3_ssl_never(void)
72 ben 1 {
73     SSL_USE = SSL_USE_NEVER;
74     }
75    
76     /* let libspopc use SSL when connecting port 995 */
77 ben 6 DLLIMPORT void pop3_ssl_auto(void)
78 ben 1 {
79     SSL_USE = SSL_USE_AUTO;
80     }
81    
82     /* let libspopc use SSL connecting on any port, even 110 */
83 ben 6 DLLIMPORT void pop3_ssl_always(void)
84 ben 1 {
85     SSL_USE = SSL_USE_ALWAYS;
86     }
87    
88     /* set the filename of the certificate */
89 ben 6 DLLIMPORT void pop3_cert_setup(const char *certfile)
90 ben 1 {
91     if (SSL_CERT) free(SSL_CERT);
92     SSL_CERT=NULL;
93     if (certfile) SSL_CERT=strdup(certfile);
94     }
95    
96     /* callback for error reporting on ssl verification
97     * just return 0 on error, 1 else
98     */
99 ben 6 DLLIMPORT int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) {
100 ben 1 if (!ok) { /* bad identification */
101     int err;
102     err = X509_STORE_CTX_get_error(ctx);
103     return 0;
104     }
105     return 1;
106     }
107    
108     /* init ssl library and context
109     * depending on port and SSL_USE_*
110     */
111 ben 6 DLLIMPORT pop3sock_t ssl_prepare(const int port){
112 ben 1 pop3sock_t sock;
113    
114     sock =(pop3sock_t)malloc(sizeof(pop3sock));
115     sock->sock=socket(AF_INET,SOCK_STREAM,0);
116     if(-1==sock->sock){
117     perror("ssl_prepare.socket");
118     free(sock);
119     return(NULL);
120     }
121     if (( (995 == port) && (SSL_USE == SSL_USE_AUTO))
122     || (SSL_USE == SSL_USE_ALWAYS) ) {
123     if (0 == SSL_UP) SSL_UP=SSL_library_init();
124    
125     if (1 != SSL_UP) {
126 ben 5 #ifdef WIN32
127     closesocket(sock->sock);
128     #else
129 ben 1 close(sock->sock);
130 ben 5 #endif
131 ben 1 free(sock);
132     perror("ssl_prepare.SSL_library_init");
133     return(NULL);
134     }
135     SSL_load_error_strings();
136     sock->ctx = SSL_CTX_new(SSLv23_client_method());
137     if (NULL == sock->ctx) {
138 ben 5 #ifdef WIN32
139     closesocket(sock->sock);
140     #else
141 ben 1 close(sock->sock);
142 ben 5 #endif
143 ben 1 free(sock);
144     perror("ssl_prepare.SSLv23_client_method");
145     return(NULL);
146     }
147     if ( SSL_CERT != NULL ) {
148     SSL_CTX_load_verify_locations(sock->ctx, SSL_CERT, 0);
149     SSL_CTX_set_verify(sock->ctx, SSL_VERIFY_PEER, &ssl_verify_callback);
150     }
151     sock->ssl = SSL_new(sock->ctx);
152     if (NULL == sock->ssl) {
153 ben 5 #ifdef WIN32
154     closesocket(sock->sock);
155     #else
156 ben 1 close(sock->sock);
157 ben 5 #endif
158 ben 1 SSL_CTX_free(sock->ctx);
159     free(sock);
160     perror("ssl_prepare.SSL_new");
161     return(NULL);
162     }
163     SSL_set_fd(sock->ssl, sock->sock);
164     } else { /* port != 995 or SSL_USE_NEVER */
165     sock->ssl=NULL;
166     sock->ctx=NULL;
167     }
168     return sock;
169     }
170    
171     #endif
172    
173     /* prepares the socket options
174     * mainly set read an write timeouts
175     * this way may be either ignored
176     * or refused on some platform
177     */
178 ben 6 DLLIMPORT int socket_prepare(int sock){
179 ben 17 int ret=0;
180     #ifdef WIN32
181 ben 20 int timeout = socket_timeout * 1000;
182 ben 17 if (ret += setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof timeout))
183     perror("socket_prepare.setsockopt");
184     if (ret += setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&timeout, sizeof timeout))
185     perror("socket_prepare.setsockopt");
186     #else
187 ben 1 struct timeval tv;
188 ben 20 tv.tv_sec = socket_timeout;
189 ben 1 tv.tv_usec = 0 ;
190    
191     if (ret += setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, sizeof tv))
192     perror("socket_prepare.setsockopt");
193     if (ret += setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&tv, sizeof tv))
194     perror("socket_prepare.setsockopt");
195 ben 17 #endif
196     return ret;
197 ben 1 }
198    
199     /* prepares the pop session and returns a socket descriptor */
200 ben 6 DLLIMPORT pop3sock_t pop3_prepare(const char* servername, const int port, struct sockaddr_in* connection, struct hostent* server){
201 ben 1 pop3sock_t sock;
202     struct hostent* hostent_buf;
203     int i;
204     #ifdef WIN32
205    
206     WSADATA wsaData;
207    
208     if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
209     {
210     exit(1);
211     }
212    
213     #endif
214    
215     memset((char*)connection,0,sizeof(struct sockaddr_in));
216    
217     /* here, enter a critical section to perform atomic name resolution */
218     mutex_in(&GETHOSTBYNAME);
219     hostent_buf=gethostbyname(servername);
220     if(!hostent_buf){
221 ben 6 #ifdef WIN32
222     perror("pop3_prepare.gethostbyname");
223     #else
224 ben 1 herror("pop3_prepare.gethostbyname");
225 ben 6 #endif
226 ben 1 return BAD_SOCK;
227     }
228     /* begin hostent deep copy */
229     memmove(server,hostent_buf,sizeof(struct hostent));
230     server->h_name=strdup(hostent_buf->h_name);
231     server->h_aliases=NULL;
232     i=0;
233     while (hostent_buf->h_aliases[i])
234     {
235     server->h_aliases=realloc(server->h_aliases,(i+1)*sizeof(char*));
236 ben 16 server->h_aliases[i]=strdup(hostent_buf->h_aliases[i]);
237 ben 1 i++;
238     }
239 ben 16 if (i>0) {
240     server->h_aliases=realloc(server->h_aliases,(i+1)*sizeof(char*));
241     server->h_aliases[i]=NULL;
242     }
243    
244 ben 1 server->h_addr_list=NULL;
245     i=0;
246     while (hostent_buf->h_addr_list[i])
247     { /* has at least one adress */
248     server->h_addr_list=realloc(server->h_addr_list,(i+1)*sizeof(char*));
249     server->h_addr_list[i]=malloc(server->h_length);
250     memmove(server->h_addr_list[i],hostent_buf->h_addr_list[i],server->h_length);
251     i++;
252 ben 16 }
253     if (i>0) {
254     server->h_addr_list=realloc(server->h_addr_list, (i+1)*sizeof(char*));
255     server->h_addr_list[i]=NULL;
256     }
257    
258 ben 1 /* end hostent deep copy */
259     mutex_out(&GETHOSTBYNAME);
260     /* end of critical section (name resolution) */
261    
262     memmove((char*)&(connection->sin_addr.s_addr),server->h_addr,server->h_length);
263     connection->sin_family=AF_INET;
264     connection->sin_port=htons(port?(unsigned short int)port:(unsigned short int)110);
265     /* integral size mismatch in argument - htons(port)*/
266    
267     #ifdef USE_SSL
268     sock = ssl_prepare(port);
269     #else
270     sock=socket(AF_INET,SOCK_STREAM,0);
271     if(BAD_SOCK == sock){
272     perror("pop3_prepare.socket");
273     }
274     #endif
275     #ifdef USE_SSL
276     socket_prepare(sock->sock);
277     #else
278     socket_prepare(sock);
279     #endif
280     return(sock);
281     }
282    
283     /* connects to the server through the sock and returns server's welcome */
284 ben 6 DLLIMPORT char* pop3_connect(pop3sock_t sock, struct sockaddr_in* connection){
285 ben 1 int r;
286     char* buf;
287    
288    
289     #ifdef USE_SSL
290     r=connect(sock->sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
291     if ( r!=-1 && sock->ssl ) {
292     if (SSL_connect(sock->ssl) == -1) {
293 ben 5 #ifdef WIN32
294     closesocket(sock->sock);
295     #else
296 ben 1 close(sock->sock);
297 ben 5 #endif
298 ben 1 return(NULL);
299     }
300     if ( SSL_CERT ) {
301     if ( !SSL_get_peer_certificate(sock->ssl) ) {
302 ben 5 #ifdef WIN32
303     closesocket(sock->sock);
304     #else
305 ben 1 close(sock->sock);
306 ben 5 #endif
307 ben 1 return(NULL);
308     }
309     }
310     }
311     #else
312     r=connect(sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
313     #endif
314    
315     if(r==-1){
316     perror("pop3_connect.connect");
317     return(NULL);
318     }
319    
320    
321     buf=(char*)malloc(POPBUF);
322     if(!buf){
323     perror("pop3_connect.malloc");
324     return(NULL);
325     }
326     r=pop3_recv(sock,buf,POPBUF); /* 512 is enough, as say RFC 1939 */
327     if(r==0 || r==-1){
328     /* -1: transport error (timeout?) */
329     /* 0: server error (busy?) */
330     perror("pop3_connect.pop3_recv");
331     free(buf);
332     return(NULL);
333     }
334     buf[r]='\0';
335     return buf;
336     }
337    
338 ben 6 DLLIMPORT void pop3_disconnect(pop3sock_t sock, struct hostent* server){
339 ben 1 int i;
340     /* close socket */
341     #ifdef USE_SSL
342     if (sock->sock>0)
343     {
344 ben 5 #ifdef WIN32
345     closesocket(sock->sock);
346     #else
347 ben 8 shutdown(sock->sock,SHUT_RDWR);
348 ben 1 close(sock->sock);
349 ben 5 #endif
350 ben 1 }
351     if (NULL != sock->ssl) {
352 ben 3 /* a memory leak has been reported with: SSL_shutdown(sock->ssl);*/
353 ben 1 SSL_free(sock->ssl);
354     }
355     if ( NULL != sock->ctx ) {
356     SSL_CTX_free(sock->ctx);
357     }
358    
359     free(sock);
360     #else
361     if (sock>0) {
362 ben 5 #ifdef WIN32
363     closesocket(sock);
364     #else
365 ben 8 shutdown(sock,SHUT_RDWR);
366 ben 1 close(sock);
367 ben 5 #endif
368 ben 1 }
369     #endif
370     /* free deep copy of struct hostent */
371 ben 16 if (server->h_addr_list) {
372     i=0;
373     while(NULL != server->h_addr_list[i]) {
374     /* has at least one adress */
375     free(server->h_addr_list[i]);
376     i++;
377     }
378     free(server->h_addr_list);
379 ben 1 }
380 ben 16 if (server->h_aliases) {
381     i=0;
382     while (NULL != server->h_aliases[i]) {
383     free(server->h_aliases[i]);
384     i++;
385     }
386     free(server->h_aliases);
387     }
388 ben 1 free(server->h_name);
389     #ifdef WIN32
390     WSACleanup();
391     #endif
392     }

  ViewVC Help
Powered by ViewVC 1.1.26