/[libspopc]/session.c
ViewVC logotype

Contents of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Sun Apr 18 11:05:58 2010 UTC (10 years, 7 months ago) by ben
File MIME type: text/plain
File size: 9334 byte(s)
windows version revival (dev-cpp)
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 <stdio.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 DLLIMPORT void pop3_ssl_never(void)
70 {
71 SSL_USE = SSL_USE_NEVER;
72 }
73
74 /* let libspopc use SSL when connecting port 995 */
75 DLLIMPORT 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 DLLIMPORT void pop3_ssl_always(void)
82 {
83 SSL_USE = SSL_USE_ALWAYS;
84 }
85
86 /* set the filename of the certificate */
87 DLLIMPORT 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 DLLIMPORT 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 DLLIMPORT 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 DLLIMPORT 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 DLLIMPORT 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 #ifdef WIN32
212 perror("pop3_prepare.gethostbyname");
213 #else
214 herror("pop3_prepare.gethostbyname");
215 #endif
216 return BAD_SOCK;
217 }
218 /* begin hostent deep copy */
219 memmove(server,hostent_buf,sizeof(struct hostent));
220 server->h_name=strdup(hostent_buf->h_name);
221 server->h_aliases=NULL;
222 i=0;
223 while (hostent_buf->h_aliases[i])
224 {
225 server->h_aliases=realloc(server->h_aliases,(i+1)*sizeof(char*));
226 if(hostent_buf->h_aliases[i])
227 server->h_aliases[i]=strdup(hostent_buf->h_aliases[i]);
228 else server->h_aliases[i]=NULL;
229 i++;
230 }
231 server->h_addr_list=NULL;
232 i=0;
233 while (hostent_buf->h_addr_list[i])
234 { /* has at least one adress */
235 server->h_addr_list=realloc(server->h_addr_list,(i+1)*sizeof(char*));
236 server->h_addr_list[i]=malloc(server->h_length);
237 memmove(server->h_addr_list[i],hostent_buf->h_addr_list[i],server->h_length);
238 i++;
239 }
240 server->h_addr_list=realloc(server->h_addr_list, (i+1)*sizeof(char*));
241 #if 0
242 server->h_addr_list[i]=malloc(1);
243 server->h_addr_list[i]='\0';
244 #else
245 server->h_addr_list[i]=NULL;
246 #endif /* 0 */
247 /* end hostent deep copy */
248 mutex_out(&GETHOSTBYNAME);
249 /* end of critical section (name resolution) */
250
251 memmove((char*)&(connection->sin_addr.s_addr),server->h_addr,server->h_length);
252 connection->sin_family=AF_INET;
253 connection->sin_port=htons(port?(unsigned short int)port:(unsigned short int)110);
254 /* integral size mismatch in argument - htons(port)*/
255
256 #ifdef USE_SSL
257 sock = ssl_prepare(port);
258 #else
259 sock=socket(AF_INET,SOCK_STREAM,0);
260 if(BAD_SOCK == sock){
261 perror("pop3_prepare.socket");
262 }
263 #endif
264 #ifdef USE_SSL
265 socket_prepare(sock->sock);
266 #else
267 socket_prepare(sock);
268 #endif
269 return(sock);
270 }
271
272 /* connects to the server through the sock and returns server's welcome */
273 DLLIMPORT char* pop3_connect(pop3sock_t sock, struct sockaddr_in* connection){
274 int r;
275 char* buf;
276
277
278 #ifdef USE_SSL
279 r=connect(sock->sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
280 if ( r!=-1 && sock->ssl ) {
281 if (SSL_connect(sock->ssl) == -1) {
282 #ifdef WIN32
283 closesocket(sock->sock);
284 #else
285 close(sock->sock);
286 #endif
287 return(NULL);
288 }
289 if ( SSL_CERT ) {
290 if ( !SSL_get_peer_certificate(sock->ssl) ) {
291 #ifdef WIN32
292 closesocket(sock->sock);
293 #else
294 close(sock->sock);
295 #endif
296 return(NULL);
297 }
298 }
299 }
300 #else
301 r=connect(sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
302 #endif
303
304 if(r==-1){
305 perror("pop3_connect.connect");
306 return(NULL);
307 }
308
309
310 buf=(char*)malloc(POPBUF);
311 if(!buf){
312 perror("pop3_connect.malloc");
313 return(NULL);
314 }
315 r=pop3_recv(sock,buf,POPBUF); /* 512 is enough, as say RFC 1939 */
316 if(r==0 || r==-1){
317 /* -1: transport error (timeout?) */
318 /* 0: server error (busy?) */
319 perror("pop3_connect.pop3_recv");
320 free(buf);
321 return(NULL);
322 }
323 buf[r]='\0';
324 return buf;
325 }
326
327 DLLIMPORT void pop3_disconnect(pop3sock_t sock, struct hostent* server){
328 int i;
329 /* close socket */
330 #ifdef USE_SSL
331 if (sock->sock>0)
332 {
333 shutdown(sock->sock,SHUT_RDWR);
334 #ifdef WIN32
335 closesocket(sock->sock);
336 #else
337 close(sock->sock);
338 #endif
339 }
340 if (NULL != sock->ssl) {
341 /* a memory leak has been reported with: SSL_shutdown(sock->ssl);*/
342 SSL_free(sock->ssl);
343 }
344 if ( NULL != sock->ctx ) {
345 SSL_CTX_free(sock->ctx);
346 }
347
348 free(sock);
349 #else
350 if (sock>0) {
351 #ifndef WIN32
352 shutdown(sock,SHUT_RDWR);
353 #endif
354 #ifdef WIN32
355 closesocket(sock);
356 #else
357 close(sock);
358 #endif
359 }
360 #endif
361 /* free deep copy of struct hostent */
362 i=0;
363 while(NULL != server->h_addr_list[i]) {
364 /* has at least one adress */
365 free(server->h_addr_list[i]);
366 i++;
367 }
368 /* free(server->h_addr_list[i]); FIXME */
369 free(server->h_addr_list);
370 free(server->h_name);
371 #ifdef WIN32
372 WSACleanup();
373 #endif
374 }

  ViewVC Help
Powered by ViewVC 1.1.26