/[libspopc]/session.c
ViewVC logotype

Annotation of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26