Back to index

im-sdk  12.3.91
stream-tls.c
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif /* HAVE_CONFIG_H */
00004 
00005 #ifndef HAVE_TLS
00006 
00007 #include <iiimp.h>
00008 
00009 IIIMF_status
00010 iiimf_tls_set_certificate(
00011     IIIMF_stream *stream,
00012     const char *certfile,
00013     const char *keyfile,
00014     const char *cafile,
00015     const char *capath
00016 )
00017 {
00018     return IIIMF_STATUS_FAIL;
00019 }
00020 
00021 IIIMF_status
00022 iiimf_tls_supported(void)
00023 {
00024     return IIIMF_STATUS_FAIL;
00025 }
00026 
00027 IIIMF_status
00028 iiimf_accept_tls_stream(
00029     IIIMF_stream *stream,
00030     IIIMF_stream **stream_ret
00031 )
00032 {
00033     return IIIMF_STATUS_FAIL;
00034 }
00035 
00036 IIIMF_status
00037 iiimf_listen_tls_stream(
00038     const char *node,
00039     const char *service,
00040     int timeout,
00041     IIIMF_stream **ret    
00042 )
00043 {
00044     return IIIMF_STATUS_FAIL;
00045 }
00046 
00047 IIIMF_status
00048 iiimf_connect_tls_stream(
00049     const char *node,
00050     const char *service,
00051     int timeout,
00052     IIIMF_stream **ret
00053 )
00054 {
00055     return IIIMF_STATUS_FAIL;
00056 }
00057 
00058 IIIMF_status
00059 iiimf_delete_tls_stream(
00060     IIIMF_stream *stream
00061 )
00062 {
00063     return IIIMF_STATUS_FAIL;
00064 }
00065 
00066 #else
00067 #include <unistd.h>
00068 #include <sys/types.h>
00069 #include <sys/socket.h>
00070 #include <netdb.h>
00071 #include <netinet/in.h>
00072 #include <stdlib.h>
00073 #include <string.h>
00074 #include <fcntl.h>
00075 #include <errno.h>
00076 #if defined(HAVE_UNIX_SOCKET)
00077 #if defined(HAVE_STDDEF_H)
00078 #include <stddef.h>
00079 #endif
00080 #include <sys/un.h>
00081 #endif
00082 #if defined(HAVE_POLL)
00083 #include <poll.h>
00084 #else /* !HAVE_POLL */
00085 #include <sys/time.h>
00086 #endif /* !HAVE_POLL */
00087 #if defined(WIN32)
00088 #include <winsock.h>
00089 #endif /* WIN32 */
00090 
00091 #include <iiimp.h>
00092 
00093 #include "stream.h"
00094 
00095 #include <openssl/ssl.h>
00096 #include <openssl/err.h>
00097 
00098 static int ssl_initialized = 0;
00099 
00100 /* function declarations */
00101 
00102 static IIIMF_status
00103 tls_socket_read(
00104     IIIMF_stream_private private,
00105     void *buf,
00106     size_t nbyte
00107 );
00108 
00109 static IIIMF_status
00110 tls_stream_write(
00111     IIIMF_stream_private private,
00112     const void* buf,
00113     size_t nbyte
00114 );
00115 
00116 /* enum and structure */
00117 
00118 enum IIIMF_STREAM_TLS_FLAGS {
00119        IIIMF_STREAM_TLS_LISTEN,
00120        IIIMF_STREAM_TLS_OPEN
00121 };
00122 
00123 typedef struct IIIMF_stream_tls_private IIIMF_stream_tls_private;
00124 struct IIIMF_stream_tls_private {
00125     SSL_CTX *ctx;
00126     SSL *ssl;
00127     int handshake;
00128     int flags;
00129     int fd;
00130     int timeout;
00131 };
00132 
00133 static IIIMF_status
00134 do_handshake(
00135     IIIMF_stream_tls_private *ptlspriv
00136 )
00137 {
00138     X509 *cert;
00139 
00140     /* create SSL */
00141     if (!ptlspriv->ssl) {
00142         ptlspriv->ssl = SSL_new(ptlspriv->ctx);
00143         SSL_set_fd(ptlspriv->ssl, ptlspriv->fd);
00144     }
00145 
00146     /* now handshake with peer */
00147     switch (ptlspriv->flags) {
00148         case IIIMF_STREAM_TLS_OPEN:
00149             SSL_connect(ptlspriv->ssl);
00150             break;
00151         case IIIMF_STREAM_TLS_LISTEN:
00152             SSL_accept(ptlspriv->ssl);
00153             break;
00154         default:
00155             break;
00156     }
00157 
00158     /* get peer certificate */    
00159     cert = SSL_get_peer_certificate(ptlspriv->ssl);
00160     if (cert) {
00161         /* verify peer's certificate */
00162         if (SSL_get_verify_result(ptlspriv->ssl)) {
00163 #if 0
00164             fprintf (stderr, "%s\n", X509_NAME_oneline(X509_get_subject_name(cert), 0, 0));
00165             fprintf (stderr, "%s\n", X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0));
00166 #endif
00167             X509_free(cert);
00168         }
00169     }
00170     ptlspriv->handshake = 1;
00171     return IIIMF_STATUS_SUCCESS;
00172 }
00173 
00174 static int
00175 verify_callback(
00176     int ok,
00177     X509_STORE_CTX *ctx
00178 )
00179 {
00180     return ok;
00181 }
00182 
00183 static IIIMF_stream_tls_private*
00184 create_tlspriv(
00185     int flags,
00186     int fd,
00187     int timeout
00188 )
00189 {
00190     IIIMF_stream_tls_private *p;
00191 
00192     if (!ssl_initialized) {
00193         SSL_load_error_strings();
00194         SSL_library_init();
00195         ssl_initialized = 1;
00196     }
00197     p = (IIIMF_stream_tls_private*) malloc(sizeof(*p));
00198     if (!p) return NULL;
00199 
00200     /* create ssl context */
00201     switch (flags) {
00202             case IIIMF_STREAM_TLS_OPEN:
00203                 p->ctx = SSL_CTX_new(SSLv23_client_method());
00204                 break;
00205             case IIIMF_STREAM_TLS_LISTEN:
00206                 p->ctx = SSL_CTX_new(SSLv23_server_method());
00207                 break;
00208             default: /* TODO */
00209                 break;
00210     }
00211     /* set timeout */
00212     SSL_CTX_set_timeout(p->ctx, (long) timeout / 1000);
00213 
00214     /* 
00215      * we shouldn't create SSL at now.
00216      * user may or not set certificate by calling iiimp_tls_set_certificate,
00217      * so deley until do_handshake is called.
00218      */
00219     p->ssl = NULL;
00220 
00221     p->timeout = timeout;
00222     p->flags = flags;
00223     p->fd = fd;
00224     p->handshake = 0;
00225 
00226     return p;
00227 }
00228 
00229 static void
00230 delete_tlspriv(
00231     IIIMF_stream_tls_private *ptlspriv
00232 )
00233 {
00234     if (ptlspriv->ssl) {
00235         SSL_shutdown(ptlspriv->ssl);
00236         SSL_free(ptlspriv->ssl);
00237     }
00238     if (ptlspriv->ctx) SSL_CTX_free(ptlspriv->ctx);
00239     close(ptlspriv->fd);
00240     free(ptlspriv);
00241 }
00242 
00243 #if defined(HAVE_UNIX_SOCKET)
00244 static IIIMF_status
00245 create_tls_stream_unix(
00246     const char *node,
00247     const char *service,
00248     int timeout,
00249     IIIMF_stream ** stream_ret
00250 )
00251 {
00252     int fd;
00253     int fd_flag;
00254     int r;
00255     size_t size;
00256     struct sockaddr_un sun_addr;
00257 
00258     fd = -1;
00259 
00260     fd = socket(AF_UNIX, SOCK_STREAM, 0);
00261     if (fd == -1) {
00262        return IIIMF_STATUS_STREAM;
00263     }
00264 
00265     sun_addr.sun_family = AF_UNIX;
00266     if ((NULL == service) || ('\0' == (*service))) {
00267        strncpy(sun_addr.sun_path, node, sizeof(sun_addr.sun_path));
00268     } else {
00269        snprintf(sun_addr.sun_path, sizeof(sun_addr.sun_path), "%s/%s",
00270                node, service);
00271     }
00272 
00273     size = (offsetof(struct sockaddr_un, sun_path)
00274              + strlen (sun_addr.sun_path) + 1);
00275 
00276     r = connect(fd, (struct sockaddr *)(&sun_addr), size);
00277 
00278     if (r < 0) {
00279        (void)close(fd);
00280        return IIIMF_STATUS_STREAM;
00281     }
00282 
00283     fd_flag = fcntl(fd, F_GETFD);
00284     fd_flag |= FD_CLOEXEC;
00285     (void)fcntl(fd, F_SETFD, fd_flag);
00286     {
00287        IIIMF_status st;
00288        IIIMF_stream *stream;
00289        IIIMF_stream_tls_private *tlspriv;
00290 
00291        tlspriv = create_tlspriv(IIIMF_STREAM_TLS_OPEN, fd,
00292                                timeout);
00293 
00294        if (!tlspriv) {
00295            close(fd);
00296            return IIIMF_STATUS_MALLOC;
00297        }
00298 
00299        st = iiimf_create_stream(tls_socket_read, tls_stream_write,
00300                              tlspriv, timeout, &stream);
00301        if (st != IIIMF_STATUS_SUCCESS) return st;
00302        *stream_ret = stream;
00303     }
00304 
00305     return IIIMF_STATUS_SUCCESS;
00306 
00307 }
00308 #endif
00309 
00310 IIIMF_status
00311 iiimf_connect_tls_stream(
00312     const char *     node,
00313     const char *     service,
00314     int                 timeout,
00315     IIIMF_stream ** stream_ret
00316 )
00317 {
00318     int                     fd;
00319     int                     fd_flag;
00320 
00321 #if defined(HAVE_GETADDRINFO)
00322     int                     e;
00323     struct addrinfo *       res;
00324     struct addrinfo *       aip;
00325     struct addrinfo  hints;
00326 
00327 #if defined(HAVE_UNIX_SOCKET)
00328     if (*node == '/') {
00329        return create_tls_stream_unix(node, service, timeout, stream_ret);
00330     }
00331 #endif
00332     fd = -1;
00333 
00334     (void)memset(&hints, 0, sizeof (hints));
00335     hints.ai_flags = AI_CANONNAME;
00336     hints.ai_socktype = SOCK_STREAM;
00337 
00338     e = getaddrinfo(node, service, &hints, &res);
00339     if (0 != e) {
00340        return -1;
00341     }
00342 
00343     for (aip = res; NULL != aip; aip = aip->ai_next) {
00344        fd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
00345        if (-1 == fd) {
00346            break;
00347        }
00348 
00349        if (-1 == connect(fd, aip->ai_addr, aip->ai_addrlen)) {
00350            (void)close(fd);
00351            fd = -1;
00352            continue;
00353        } else {
00354            break;
00355        }
00356     }
00357 
00358     freeaddrinfo(res);
00359 
00360     if (-1 == fd) return IIIMF_STATUS_STREAM;
00361 
00362 #else /* !HAVE_GETADDRINFO */
00363 
00364 #if defined(WIN32)
00365     unsigned short int      port_number;
00366 #else /* !WIN32 */
00367     int                     port_number;
00368 #endif /* !WIN32 */
00369     int                     r;
00370     int                     optval;
00371     unsigned long    in_addr;
00372     struct hostent * hostp;
00373     struct sockaddr_in      addr;
00374     struct servent * srvp;
00375 
00376 #if defined(HAVE_UNIX_SOCKET)
00377     if (*node == '/') {
00378        return create_tls_stream_unix(node, service, timeout, stream_ret);
00379     }
00380 #endif
00381 #if defined(WIN32)
00382     start_winsock(1, 1);
00383 #endif
00384 
00385     fd = socket(PF_INET, SOCK_STREAM, 0);
00386     if (fd < 0 ) return IIIMF_STATUS_STREAM;
00387 
00388     port_number = 0;
00389 
00390     (void)memset((char *)(&addr), 0, sizeof (addr));
00391     addr.sin_family = PF_INET;
00392 
00393     if (0 < strlen(service)) {
00394        srvp = getservbyname(service, "tcp");
00395        if (NULL != srvp) {
00396            port_number = srvp->s_port;
00397        }
00398        (void)endservent();
00399        if (0 == port_number) {
00400            port_number = atoi(service);
00401        }
00402     }
00403     if (0 == port_number) {
00404        port_number = 9010;
00405     }
00406     addr.sin_port = htons(port_number);
00407     in_addr = inet_addr(node);
00408     if ((unsigned long)(-1) != in_addr) {
00409        (void)memcpy(&addr.sin_addr, &in_addr, sizeof (in_addr));
00410     } else {
00411        hostp = gethostbyname(node);
00412        if (NULL == hostp) {
00413 #if defined(WIN32)
00414            (void)sock_close(fd);
00415 #else /* !WIN32 */
00416            (void)close(fd);
00417 #endif /* !WIN32 */
00418            return IIIMF_STATUS_STREAM;
00419        }
00420 
00421        if (0 < hostp->h_length) {
00422            (void)memcpy(&addr.sin_addr, hostp->h_addr,
00423                       hostp->h_length);
00424        } else {
00425 #if defined(WIN32)
00426            sock_close(fd);
00427 #else /* !WIN32 */
00428            (void)close(fd);
00429 #endif /* !WIN32 */
00430            return IIIMF_STATUS_STREAM;
00431        }
00432     }
00433 
00434     r = connect(fd, (struct sockaddr *)(&addr), sizeof (addr));
00435 #if defined(WIN32)
00436     if (SOCKET_ERROR == r) {
00437        sock_close(fd);
00438        return IIIMF_STATUS_STREAM;
00439     }
00440 #else /* !WIN32 */
00441     if (r < 0) {
00442        (void)close(fd);
00443        return IIIMF_STATUS_STREAM;
00444     }
00445 #endif /* !WIN32 */
00446 #endif /* !HAVE_GETADDRINFO */
00447 
00448     fd_flag = fcntl(fd, F_GETFD);
00449     fd_flag |= FD_CLOEXEC;
00450     (void)fcntl(fd, F_SETFD, fd_flag);
00451 
00452     {
00453        IIIMF_status st;
00454        IIIMF_stream *stream;
00455        IIIMF_stream_tls_private *tlspriv;
00456 
00457        tlspriv = create_tlspriv(IIIMF_STREAM_TLS_OPEN, fd,
00458                                timeout);
00459        if (!tlspriv) {
00460            close(fd);
00461            return IIIMF_STATUS_MALLOC;
00462        }
00463 
00464        st = iiimf_create_stream(tls_socket_read, tls_stream_write,
00465                              tlspriv, timeout, &stream);
00466        if (st != IIIMF_STATUS_SUCCESS) return st;
00467        *stream_ret = stream;
00468     }
00469 
00470     return IIIMF_STATUS_SUCCESS;
00471 }
00472 
00473 IIIMF_status
00474 iiimf_listen_tls_stream(
00475     const char *     node,
00476     const char *     service,
00477     int                 timeout,
00478     IIIMF_stream ** stream_ret
00479 )
00480 {
00481     int                     fd;
00482     int                     fd_flag;
00483     int                     optval;
00484     int                     r = 0;
00485 
00486 #if defined(HAVE_GETADDRINFO)
00487     int                     e;
00488     struct addrinfo *       a;
00489     struct addrinfo *       aip;
00490     struct addrinfo  hints;
00491 
00492     fd = -1;
00493 
00494     (void)memset(&hints, 0, sizeof (hints));
00495     hints.ai_flags = AI_PASSIVE;
00496     hints.ai_socktype = SOCK_STREAM;
00497 
00498     e = getaddrinfo(NULL, service, &hints, &aip);
00499     if (0 != e) return IIIMF_STATUS_STREAM;
00500 
00501     for (a = aip; NULL != a; a = a->ai_next) {
00502        fd = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
00503        if (-1 != fd) {
00504            r = bind(fd, aip->ai_addr, sizeof (struct sockaddr));
00505            if (-1 != r) break;
00506            (void)close(fd);
00507            fd = -1;
00508        }
00509     }
00510     freeaddrinfo(aip);
00511     if ((-1 == fd) || (-1 == r)) return IIIMF_STATUS_STREAM;
00512     r = listen(fd, 5);
00513     if (-1 == r) return IIIMF_STATUS_STREAM;
00514 #else /* !HAVE_GETADDRINFO */
00515 
00516 #if defined(WIN32)
00517     unsigned short int      port_number;
00518 #else /* !WIN32 */
00519     int                     port_number;
00520 #endif /* !WIN32 */
00521 #if defined(PF_INET6) && defined(ENABLE_IPV6)
00522     struct sockaddr_in6     addr;
00523 #else /* !PF_INET6 && ENABLE_IPV6 */
00524     struct sockaddr_in      addr;
00525 #endif /* !PF_INET6 && ENABLE_IPV6 */
00526     struct servent * srvp;
00527 
00528 #if defined(WIN32)
00529     start_winsock(1, 1);
00530 #endif
00531 
00532 #if defined(PF_INET6) && defined(ENABLE_IPV6)
00533     fd = socket(PF_INET6, SOCK_STREAM, 0);
00534 #else /* !PF_INET6 && ENABLE_IPV6 */
00535     fd = socket(PF_INET, SOCK_STREAM, 0);
00536 #endif /* !PF_INET6 && ENABLE_IPV6 */
00537 
00538     if (fd < 0 ) return IIIMF_STATUS_STREAM;
00539 
00540     port_number = 0;
00541 
00542     if (0 < strlen(service)) {
00543        srvp = getservbyname(service, "tcp");
00544        if (NULL != srvp) {
00545            port_number = srvp->s_port;
00546        }
00547        (void)endservent();
00548        if (0 == port_number) {
00549            port_number = atoi(service);
00550        }
00551     }
00552     if (0 == port_number) {
00553        port_number = 9010;
00554     }
00555 
00556     (void)memset((char *)(&addr), 0, sizeof (addr));
00557 #if defined(PF_INET6) && defined(ENABLE_IPV6)
00558     addr.sin6_family = PF_INET6;
00559     addr.sin6_flowinfo = 0;
00560     addr.sin6_port = htons(port_number);
00561     addr.sin6_addr = in6addr_any;
00562 #else /* !PF_INET6 && ENABLE_IPV6 */
00563     addr.sin_family = PF_INET;
00564     addr.sin_port = htons(port_number);
00565 #endif /* !PF_INET6 && ENABLE_IPV6 */
00566 
00567     if ((bind(fd, (struct sockaddr *)(&addr), sizeof (addr)) < 0) ||
00568        (listen(fd, 5) < 0) ) {
00569 #if defined(WIN32)
00570        sock_close(fd);
00571 #else /* !WIN32 */
00572        (void)close(fd);
00573 #endif /* !WIN32 */
00574        return IIIMF_STATUS_STREAM;
00575     }
00576 #endif /* !HAVE_GETADDRINFO */
00577 
00578     optval = 1;
00579     r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (int));
00580     if (-1 == r) {
00581 #if defined(WIN32)
00582        sock_close(fd);
00583 #else /* !WIN32 */
00584        (void)close(fd);
00585 #endif /* !WIN32 */
00586        return IIIMF_STATUS_STREAM;
00587     }
00588 
00589     fd_flag = fcntl(fd, F_GETFD);
00590     fd_flag |= FD_CLOEXEC;
00591     (void)fcntl(fd, F_SETFD, fd_flag);
00592 
00593     {
00594        IIIMF_status st;
00595        IIIMF_stream *stream;
00596        IIIMF_stream_tls_private *tlspriv;
00597 
00598        tlspriv = create_tlspriv(IIIMF_STREAM_TLS_LISTEN, fd, timeout);
00599        if (!tlspriv) {
00600            close(fd);
00601            return IIIMF_STATUS_MALLOC;
00602        }
00603 
00604        st = iiimf_create_stream(NULL, NULL, tlspriv, timeout, &stream);
00605        if (st != IIIMF_STATUS_SUCCESS) return st;
00606        *stream_ret = stream;
00607     }
00608 
00609     return IIIMF_STATUS_SUCCESS;
00610 }
00611 
00612 IIIMF_status
00613 iiimf_accept_tls_stream(
00614     IIIMF_stream *  stream,
00615     IIIMF_stream ** stream_ret
00616 )
00617 {
00618     IIIMF_stream_tls_private *tlspriv = (IIIMF_stream_tls_private*) stream->private_data;
00619     IIIMF_status     status;
00620     struct sockaddr  address;
00621     socklen_t        address_len;
00622     int                     fd;
00623 #if defined(HAVE_POLL)
00624     struct pollfd    fds[1];
00625     int                     poll_ret;
00626 #else /* !HAVE_POLL */
00627     fd_set           fdvar;
00628     struct timeval   timeout;
00629     int                     select_ret;
00630 
00631     timeout.tv_sec = tlspriv->timeout / 1000;
00632     timeout.tv_usec = tlspriv->timeout % 1000;
00633 #endif /* !HAVE_POLL */
00634 
00635     if (tlspriv->flags != IIIMF_STREAM_TLS_LISTEN)
00636        return IIIMF_STATUS_ARGUMENT;
00637 
00638     if (0 <= tlspriv->timeout) {
00639 #if defined(HAVE_POLL)
00640        fds[0].fd = tlspriv->fd;
00641        fds[0].events = POLLIN;
00642        poll_ret = poll(fds, 1, tlspriv->timeout);
00643        if (0 == poll_ret) {
00644            return IIIMF_STATUS_TIMEOUT;
00645        } else if (-1 == poll_ret) {
00646            return IIIMF_STATUS_STREAM;
00647        }
00648 #else /* !HAVE_POLL */
00649        do {
00650            FD_ZERO(&fdvar);
00651            FD_SET(tlspriv->fd, &fdvar);
00652            select_ret = select(tlspriv->fd + 1, NULL,
00653                             &fdvar, NULL, &timeout);
00654        } while ((-1 == select_ret) && (EINTR == errno));
00655        if (-1 == select_ret) return IIIMF_STATUS_TIMEOUT;
00656 #endif /* !HAVE_POLL */
00657     }
00658     address_len = (sizeof (address));
00659     fd = accept(tlspriv->fd, &address, &address_len);
00660     if (-1 == fd) return IIIMF_STATUS_STREAM;
00661 
00662     {
00663        IIIMF_stream *stream_new;
00664        IIIMF_stream_tls_private *tlspriv_new;
00665 
00666         /* we need a special handling for accepted socket */
00667         tlspriv_new = malloc(sizeof(*tlspriv_new));
00668        if (!tlspriv_new) {
00669            close(fd);
00670            return IIIMF_STATUS_MALLOC;
00671        }
00672         tlspriv_new->ctx = NULL;
00673         tlspriv_new->ssl = SSL_new(tlspriv->ctx);
00674         SSL_set_fd(tlspriv_new->ssl, fd);
00675         tlspriv_new->timeout = tlspriv->timeout;
00676         tlspriv_new->flags = IIIMF_STREAM_TLS_OPEN;
00677         tlspriv_new->fd = fd;
00678         tlspriv_new->handshake = 0;
00679         do_handshake(tlspriv_new);
00680        status = iiimf_create_stream(tls_socket_read, tls_stream_write,
00681                                  tlspriv_new, tlspriv->timeout, &stream_new);
00682        if (status != IIIMF_STATUS_SUCCESS) return status;
00683        *stream_ret = stream_new;
00684     }
00685 
00686     return IIIMF_STATUS_SUCCESS;
00687 }
00688 
00689 IIIMF_status
00690 iiimf_delete_tls_stream(
00691     IIIMF_stream *  stream
00692 )
00693 {
00694     IIIMF_stream_tls_private *tlspriv = (IIIMF_stream_tls_private*) stream->private_data;
00695    
00696     delete_tlspriv(tlspriv);
00697     iiimf_stream_delete(stream);
00698     return IIIMF_STATUS_SUCCESS;
00699 }
00700 
00701 IIIMF_status
00702 iiimf_tls_supported(void)
00703 {
00704     return IIIMF_STATUS_SUCCESS;
00705 }
00706 
00707 IIIMF_status
00708 iiimf_tls_set_certificate(
00709     IIIMF_stream *stream,
00710     const char *certfile,
00711     const char *keyfile,
00712     const char *cafile,
00713     const char *capath
00714 )
00715 {
00716     IIIMF_stream_tls_private *tlspriv = (IIIMF_stream_tls_private*) stream->private_data;
00717 
00718     if (tlspriv->handshake) return IIIMF_STATUS_FAIL; /* stream already handshaked with peer */
00719 
00720     if (!certfile && !keyfile) return IIIMF_STATUS_FAIL;
00721 
00722     /* set certificate */
00723     if (certfile) {
00724         if (!SSL_CTX_use_certificate_file(tlspriv->ctx, certfile, SSL_FILETYPE_PEM)) {
00725         }
00726     }
00727     /* set private key */
00728     if (!SSL_CTX_use_PrivateKey_file(tlspriv->ctx, keyfile ? keyfile : certfile, SSL_FILETYPE_PEM)) {
00729     }
00730 
00731     /* check private key */
00732     if (!SSL_CTX_check_private_key(tlspriv->ctx)) {
00733     }
00734 
00735     SSL_CTX_set_verify(tlspriv->ctx, SSL_VERIFY_PEER, verify_callback);
00736     // SSL_CTX_set_verify_depth(tlspriv->ctx, 1);
00737     /* set ca */
00738     if (cafile || capath) {
00739 
00740         if (!SSL_CTX_load_verify_locations(tlspriv->ctx, cafile, capath) ||
00741             !SSL_CTX_set_default_verify_paths(tlspriv->ctx)) {
00742         }
00743 
00744         if (tlspriv->flags == IIIMF_STREAM_TLS_LISTEN) {
00745             /* if the stream is server mode */
00746             STACK_OF(X509_NAME) *ca_list = NULL;
00747             if (cafile) {
00748                 ca_list = SSL_load_client_CA_file(cafile);
00749             }
00750             if (capath) {
00751                 if (!ca_list) ca_list = sk_X509_NAME_new_null();
00752                 if (!SSL_add_dir_cert_subjects_to_stack (ca_list, capath)) {
00753                 }
00754             }
00755             if (ca_list) SSL_CTX_set_client_CA_list(tlspriv->ctx, ca_list);
00756         }
00757     }
00758 
00759     return IIIMF_STATUS_SUCCESS;
00760 }
00761 
00762 static IIIMF_status
00763 tls_socket_read(
00764     IIIMF_stream_private        private,
00765     void *                  buf,
00766     size_t                  nbyte)
00767 {
00768     IIIMF_stream_tls_private *tlspriv = (IIIMF_stream_tls_private*) private;
00769     char *           p;
00770     ssize_t          n;
00771     ssize_t          r;
00772 #if 0
00773 #if defined(HAVE_POLL)
00774     struct pollfd    fds[1];
00775     int                     poll_ret;
00776 #else /* !HAVE_POLL */
00777     fd_set           fdvar;
00778     struct timeval   timeout;
00779     int                     select_ret;
00780 
00781     timeout.tv_sec = tlspriv->timeout / 1000;
00782     timeout.tv_usec = tlspriv->timeout % 1000;
00783 
00784 #endif /* !HAVE_POLL */
00785 #endif
00786 
00787     if (!tlspriv->handshake)
00788         do_handshake(tlspriv);
00789     for (p = buf, n = nbyte; 0 < n; p += r, n -= r) {
00790 #if 0
00791        if (0 <= tlspriv->timeout) {
00792 #if defined(HAVE_POLL)
00793            fds[0].fd = SSL_get_fd(tlspriv->ssl);
00794            fds[0].events = POLLIN;
00795            fprintf (stderr, "poll\n");
00796            poll_ret = poll(fds, 1, tlspriv->timeout);
00797            if (0 == poll_ret) {
00798               return IIIMF_STATUS_TIMEOUT;
00799            } else if (-1 == poll_ret) {
00800               return IIIMF_STATUS_STREAM;
00801            }
00802 #else /* !HAVE_POLL */
00803            do {
00804               FD_ZERO(&fdvar);
00805               FD_SET(tlspriv->fd, &fdvar);
00806               select_ret = select(tlspriv->fd + 1, NULL,
00807                                 &fdvar, NULL, &timeout);
00808            } while ((-1 == select_ret) && (EINTR == errno));
00809 #endif /* !HAVE_POLL */
00810        }
00811 #endif
00812 
00813        r = SSL_read(tlspriv->ssl, p, n);
00814        if (r == 0) {
00815            return IIIMF_STATUS_CONNECTION_CLOSED;
00816        }
00817        if (r < 0) {
00818            if (EINTR == errno) {
00819               continue;
00820            } else {
00821               return IIIMF_STATUS_STREAM_RECEIVE;
00822            }
00823        }
00824     }
00825 
00826     return IIIMF_STATUS_SUCCESS;
00827 }
00828 
00829 static IIIMF_status
00830 tls_stream_write(
00831     IIIMF_stream_private        private,
00832     const void *            buf,
00833     size_t                  nbyte)
00834 {
00835     IIIMF_stream_tls_private *tlspriv = (IIIMF_stream_tls_private*) private;
00836     const char *     p;
00837     ssize_t          n;
00838     ssize_t          r;
00839 
00840     if (!tlspriv->handshake)
00841         do_handshake(tlspriv);
00842     for (p = buf, n = nbyte; 0 < n; p += r, n -= r) {
00843        r = SSL_write(tlspriv->ssl, p, n);
00844        if (r < 0) return IIIMF_STATUS_STREAM_SEND;
00845     }
00846 
00847     return IIIMF_STATUS_SUCCESS;
00848 }
00849 
00850 #if defined(WIN32)
00851 static int
00852 start_winsock(int major, int minor)
00853 {
00854     WORD      wVersionRequested;
00855     WSADATA   wsaData;
00856     int       r;
00857 
00858     wVersionRequested = MAKEWORD(major, minor);
00859 
00860     r = WSAStartup(wVersionRequested, &wsaData);
00861 
00862     if (0 != r) return -1;
00863 
00864 #ifdef CHK_WSOCK_VERSION
00865     if ((1 != LOBYTE(wnsaData.wVersion)) ||
00866        (1 != HIBYTE(wsaData.wVersion))) {
00867        /* wrong version */
00868        return 1;
00869     }
00870 #endif /* CHK_WSOCK_VERSION */
00871 
00872        return 0;
00873 }
00874 
00875 
00876 static int
00877 end_winsock()
00878 {
00879     return WSACleanup();
00880 }
00881 
00882 
00883 static int
00884 sock_close(int fd)
00885 {
00886     int r;
00887     if (INVALID_SOCKET != fd) {
00888        r = closesocket(fd);
00889        end_winsock();
00890        fd = INVALID_SOCKET;
00891        return r;
00892     }
00893     return 0;
00894 }
00895 #endif /* WIN32 */
00896 #endif /* HAVE_TLS */
00897 
00898 /* Local Variables: */
00899 /* c-file-style: "iiim-project" */
00900 /* End: */