/[libspopc]/session.c
ViewVC logotype

Contents of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Wed Oct 14 03:13:57 2009 UTC (10 years, 11 months ago) by ben
File MIME type: text/plain
File size: 8960 byte(s)
updated manual to conform to t2t format
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
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 /* a memory leak has been reported with: SSL_shutdown(sock->ssl);*/
329 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