MultiTech / CyaSSL

Dependents:   HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers io.c Source File

io.c

00001 /* io.c
00002  *
00003  * Copyright (C) 2006-2014 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ctaocrypt/settings.h>
00027 
00028 #ifdef _WIN32_WCE
00029     /* On WinCE winsock2.h must be included before windows.h for socket stuff */
00030     #include <winsock2.h>
00031 #endif
00032 
00033 #include <cyassl/internal.h>
00034 #include <cyassl/error-ssl.h>
00035 
00036 /* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
00037    automatic setting of default I/O functions EmbedSend() and EmbedReceive()
00038    but they'll still need SetCallback xxx() at end of file 
00039 */
00040 #ifndef CYASSL_USER_IO
00041 
00042 #ifdef HAVE_LIBZ
00043     #include "zlib.h"
00044 #endif
00045 
00046 #ifndef USE_WINDOWS_API
00047     #ifdef CYASSL_LWIP
00048         /* lwIP needs to be configured to use sockets API in this mode */
00049         /* LWIP_SOCKET 1 in lwip/opt.h or in build */
00050         #include "lwip/sockets.h"
00051         #include <errno.h>
00052         #ifndef LWIP_PROVIDE_ERRNO
00053             #define LWIP_PROVIDE_ERRNO 1
00054         #endif
00055     #elif defined(FREESCALE_MQX)
00056         #include <posix.h>
00057         #include <rtcs.h>
00058     #elif defined(CYASSL_MDK_ARM)
00059         #if defined(CYASSL_MDK5)
00060             #include "cmsis_os.h"
00061             #include "rl_fs.h" 
00062             #include "rl_net.h" 
00063         #else
00064             #include <rtl.h>
00065         #endif
00066         #undef RNG
00067         #include "CYASSL_MDK_ARM.h"
00068         #undef RNG
00069         #define RNG CyaSSL_RNG 
00070         /* for avoiding name conflict in "stm32f2xx.h" */
00071         static int errno;
00072     #elif defined(CYASSL_TIRTOS)
00073         #include <sys/socket.h>
00074     #elif defined(CYASSL_IAR_ARM)
00075         /* nothing */
00076     #else
00077         #include <sys/types.h>
00078         #include <errno.h>
00079         #ifndef EBSNET
00080             #include <unistd.h>
00081         #endif
00082         #include <fcntl.h>
00083         #if !(defined(DEVKITPRO) || defined(HAVE_RTP_SYS) || defined(EBSNET)) \
00084             || defined(CYASSL_PICOTCP)
00085             #include <sys/socket.h>
00086             #include <arpa/inet.h>
00087             #include <netinet/in.h>
00088             #include <netdb.h>
00089             #ifdef __PPU
00090                 #include <netex/errno.h>
00091             #else
00092                 #include <sys/ioctl.h>
00093             #endif
00094         #endif
00095         #ifdef HAVE_RTP_SYS
00096             #include <socket.h>
00097         #endif
00098         #ifdef EBSNET
00099             #include "rtipapi.h"  /* errno */
00100             #include "socket.h"
00101         #endif
00102     #endif
00103 #endif /* USE_WINDOWS_API */
00104 
00105 #ifdef __sun
00106     #include <sys/filio.h>
00107 #endif
00108 
00109 #ifdef USE_WINDOWS_API 
00110     /* no epipe yet */
00111     #ifndef WSAEPIPE
00112         #define WSAEPIPE       -12345
00113     #endif
00114     #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
00115     #define SOCKET_EAGAIN      WSAETIMEDOUT
00116     #define SOCKET_ECONNRESET  WSAECONNRESET
00117     #define SOCKET_EINTR       WSAEINTR
00118     #define SOCKET_EPIPE       WSAEPIPE
00119     #define SOCKET_ECONNREFUSED WSAENOTCONN
00120     #define SOCKET_ECONNABORTED WSAECONNABORTED
00121     #define close(s) closesocket(s)
00122 #elif defined(__PPU)
00123     #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
00124     #define SOCKET_EAGAIN      SYS_NET_EAGAIN
00125     #define SOCKET_ECONNRESET  SYS_NET_ECONNRESET
00126     #define SOCKET_EINTR       SYS_NET_EINTR
00127     #define SOCKET_EPIPE       SYS_NET_EPIPE
00128     #define SOCKET_ECONNREFUSED SYS_NET_ECONNREFUSED
00129     #define SOCKET_ECONNABORTED SYS_NET_ECONNABORTED
00130 #elif defined(FREESCALE_MQX)
00131     /* RTCS doesn't have an EWOULDBLOCK error */
00132     #define SOCKET_EWOULDBLOCK EAGAIN
00133     #define SOCKET_EAGAIN      EAGAIN
00134     #define SOCKET_ECONNRESET  RTCSERR_TCP_CONN_RESET
00135     #define SOCKET_EINTR       EINTR
00136     #define SOCKET_EPIPE       EPIPE
00137     #define SOCKET_ECONNREFUSED RTCSERR_TCP_CONN_REFUSED
00138     #define SOCKET_ECONNABORTED RTCSERR_TCP_CONN_ABORTED
00139 #elif defined(CYASSL_MDK_ARM)
00140     #if defined(CYASSL_MDK5)
00141         #define SOCKET_EWOULDBLOCK BSD_ERROR_WOULDBLOCK
00142         #define SOCKET_EAGAIN      BSD_ERROR_LOCKED
00143         #define SOCKET_ECONNRESET  BSD_ERROR_CLOSED
00144         #define SOCKET_EINTR       BSD_ERROR
00145         #define SOCKET_EPIPE       BSD_ERROR
00146         #define SOCKET_ECONNREFUSED BSD_ERROR
00147         #define SOCKET_ECONNABORTED BSD_ERROR
00148     #else
00149         #define SOCKET_EWOULDBLOCK SCK_EWOULDBLOCK
00150         #define SOCKET_EAGAIN      SCK_ELOCKED
00151         #define SOCKET_ECONNRESET  SCK_ECLOSED
00152         #define SOCKET_EINTR       SCK_ERROR
00153         #define SOCKET_EPIPE       SCK_ERROR
00154         #define SOCKET_ECONNREFUSED SCK_ERROR
00155         #define SOCKET_ECONNABORTED SCK_ERROR
00156     #endif
00157 #elif defined(CYASSL_PICOTCP)
00158     #define SOCKET_EWOULDBLOCK  PICO_ERR_EAGAIN
00159     #define SOCKET_EAGAIN       PICO_ERR_EAGAIN
00160     #define SOCKET_ECONNRESET   PICO_ERR_ECONNRESET
00161     #define SOCKET_EINTR        PICO_ERR_EINTR
00162     #define SOCKET_EPIPE        PICO_ERR_EIO
00163     #define SOCKET_ECONNREFUSED PICO_ERR_ECONNREFUSED
00164     #define SOCKET_ECONNABORTED PICO_ERR_ESHUTDOWN
00165 #else
00166     #define SOCKET_EWOULDBLOCK EWOULDBLOCK
00167     #define SOCKET_EAGAIN      EAGAIN
00168     #define SOCKET_ECONNRESET  ECONNRESET
00169     #define SOCKET_EINTR       EINTR
00170     #define SOCKET_EPIPE       EPIPE
00171     #define SOCKET_ECONNREFUSED ECONNREFUSED
00172     #define SOCKET_ECONNABORTED ECONNABORTED
00173 #endif /* USE_WINDOWS_API */
00174 
00175 
00176 #ifdef DEVKITPRO
00177     /* from network.h */
00178     int net_send(int, const void*, int, unsigned int);
00179     int net_recv(int, void*, int, unsigned int);
00180     #define SEND_FUNCTION net_send
00181     #define RECV_FUNCTION net_recv
00182 #elif defined(CYASSL_LWIP)
00183     #define SEND_FUNCTION lwip_send
00184     #define RECV_FUNCTION lwip_recv
00185 #elif defined(CYASSL_PICOTCP)
00186     #define SEND_FUNCTION pico_send
00187     #define RECV_FUNCTION pico_recv
00188 #else
00189     #define SEND_FUNCTION send
00190     #define RECV_FUNCTION recv
00191 #endif
00192 
00193 
00194 /* Translates return codes returned from 
00195  * send() and recv() if need be. 
00196  */
00197 static INLINE int TranslateReturnCode(int old, int sd)
00198 {
00199     (void)sd;
00200 
00201 #ifdef FREESCALE_MQX
00202     if (old == 0) {
00203         errno = SOCKET_EWOULDBLOCK;
00204         return -1;  /* convert to BSD style wouldblock as error */
00205     }
00206 
00207     if (old < 0) {
00208         errno = RTCS_geterror(sd);
00209         if (errno == RTCSERR_TCP_CONN_CLOSING)
00210             return 0;   /* convert to BSD style closing */
00211     }
00212 #endif
00213 
00214     return old;
00215 }
00216 
00217 static INLINE int LastError(void)
00218 {
00219 #ifdef USE_WINDOWS_API 
00220     return WSAGetLastError();
00221 #elif defined(EBSNET)
00222     return xn_getlasterror();
00223 #else
00224     return errno;
00225 #endif
00226 }
00227 
00228 /* The receive embedded callback
00229  *  return : nb bytes read, or error
00230  */
00231 int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx)
00232 {
00233     int recvd;
00234     int err;
00235     int sd = *(int*)ctx;
00236 
00237 #ifdef CYASSL_DTLS
00238     {
00239         int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
00240         if (CyaSSL_dtls(ssl)
00241                      && !CyaSSL_get_using_nonblock(ssl)
00242                      && dtls_timeout != 0) {
00243             #ifdef USE_WINDOWS_API
00244                 DWORD timeout = dtls_timeout * 1000;
00245             #else
00246                 struct timeval timeout;
00247                 XMEMSET(&timeout, 0, sizeof(timeout));
00248                 timeout.tv_sec = dtls_timeout;
00249             #endif
00250             if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
00251                            sizeof(timeout)) != 0) {
00252                 CYASSL_MSG("setsockopt rcvtimeo failed");
00253             }
00254         }
00255     }
00256 #endif
00257 
00258     recvd = (int)RECV_FUNCTION(sd, buf, sz, ssl->rflags);
00259 
00260     recvd = TranslateReturnCode(recvd, sd);
00261 
00262     if (recvd < 0) {
00263         err = LastError();
00264         CYASSL_MSG("Embed Receive error");
00265 
00266         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00267             if (!CyaSSL_dtls(ssl) || CyaSSL_get_using_nonblock(ssl)) {
00268                 CYASSL_MSG("    Would block");
00269                 return CYASSL_CBIO_ERR_WANT_READ;
00270             }
00271             else {
00272                 CYASSL_MSG("    Socket timeout");
00273                 return CYASSL_CBIO_ERR_TIMEOUT;
00274             }
00275         }
00276         else if (err == SOCKET_ECONNRESET) {
00277             CYASSL_MSG("    Connection reset");
00278             return CYASSL_CBIO_ERR_CONN_RST;
00279         }
00280         else if (err == SOCKET_EINTR) {
00281             CYASSL_MSG("    Socket interrupted");
00282             return CYASSL_CBIO_ERR_ISR;
00283         }
00284         else if (err == SOCKET_ECONNREFUSED) {
00285             CYASSL_MSG("    Connection refused");
00286             return CYASSL_CBIO_ERR_WANT_READ;
00287         }
00288         else if (err == SOCKET_ECONNABORTED) {
00289             CYASSL_MSG("    Connection aborted");
00290             return CYASSL_CBIO_ERR_CONN_CLOSE;
00291         }
00292         else {
00293             CYASSL_MSG("    General error");
00294             return CYASSL_CBIO_ERR_GENERAL;
00295         }
00296     }
00297     else if (recvd == 0) {
00298         CYASSL_MSG("Embed receive connection closed");
00299         return CYASSL_CBIO_ERR_CONN_CLOSE;
00300     }
00301 
00302     return recvd;
00303 }
00304 
00305 /* The send embedded callback
00306  *  return : nb bytes sent, or error
00307  */
00308 int EmbedSend(CYASSL* ssl, char *buf, int sz, void *ctx)
00309 {
00310     int sd = *(int*)ctx;
00311     int sent;
00312     int len = sz;
00313     int err;
00314 
00315     sent = (int)SEND_FUNCTION(sd, &buf[sz - len], len, ssl->wflags);
00316 
00317     if (sent < 0) {
00318         err = LastError();
00319         CYASSL_MSG("Embed Send error");
00320 
00321         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00322             CYASSL_MSG("    Would Block");
00323             return CYASSL_CBIO_ERR_WANT_WRITE;
00324         }
00325         else if (err == SOCKET_ECONNRESET) {
00326             CYASSL_MSG("    Connection reset");
00327             return CYASSL_CBIO_ERR_CONN_RST;
00328         }
00329         else if (err == SOCKET_EINTR) {
00330             CYASSL_MSG("    Socket interrupted");
00331             return CYASSL_CBIO_ERR_ISR;
00332         }
00333         else if (err == SOCKET_EPIPE) {
00334             CYASSL_MSG("    Socket EPIPE");
00335             return CYASSL_CBIO_ERR_CONN_CLOSE;
00336         }
00337         else {
00338             CYASSL_MSG("    General error");
00339             return CYASSL_CBIO_ERR_GENERAL;
00340         }
00341     }
00342  
00343     return sent;
00344 }
00345 
00346 
00347 #ifdef CYASSL_DTLS
00348 
00349 #include <cyassl/ctaocrypt/sha.h>
00350 
00351 #ifdef USE_WINDOWS_API
00352    #define XSOCKLENT int
00353 #else
00354    #define XSOCKLENT socklen_t
00355 #endif
00356 
00357 #define SENDTO_FUNCTION sendto
00358 #define RECVFROM_FUNCTION recvfrom
00359 
00360 
00361 /* The receive embedded callback
00362  *  return : nb bytes read, or error
00363  */
00364 int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx)
00365 {
00366     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
00367     int recvd;
00368     int err;
00369     int sd = dtlsCtx->fd;
00370     int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
00371     struct sockaddr_storage peer;
00372     XSOCKLENT peerSz = sizeof(peer);
00373 
00374     CYASSL_ENTER("EmbedReceiveFrom()");
00375 
00376     if (!CyaSSL_get_using_nonblock(ssl) && dtls_timeout != 0) {
00377         #ifdef USE_WINDOWS_API
00378             DWORD timeout = dtls_timeout * 1000;
00379         #else
00380             struct timeval timeout;
00381             XMEMSET(&timeout, 0, sizeof(timeout));
00382             timeout.tv_sec = dtls_timeout;
00383         #endif
00384         if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
00385                        sizeof(timeout)) != 0) {
00386                 CYASSL_MSG("setsockopt rcvtimeo failed");
00387         }
00388     }
00389 
00390     recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
00391                                   (struct sockaddr*)&peer, &peerSz);
00392 
00393     recvd = TranslateReturnCode(recvd, sd);
00394 
00395     if (recvd < 0) {
00396         err = LastError();
00397         CYASSL_MSG("Embed Receive From error");
00398 
00399         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00400             if (CyaSSL_get_using_nonblock(ssl)) {
00401                 CYASSL_MSG("    Would block");
00402                 return CYASSL_CBIO_ERR_WANT_READ;
00403             }
00404             else {
00405                 CYASSL_MSG("    Socket timeout");
00406                 return CYASSL_CBIO_ERR_TIMEOUT;
00407             }
00408         }
00409         else if (err == SOCKET_ECONNRESET) {
00410             CYASSL_MSG("    Connection reset");
00411             return CYASSL_CBIO_ERR_CONN_RST;
00412         }
00413         else if (err == SOCKET_EINTR) {
00414             CYASSL_MSG("    Socket interrupted");
00415             return CYASSL_CBIO_ERR_ISR;
00416         }
00417         else if (err == SOCKET_ECONNREFUSED) {
00418             CYASSL_MSG("    Connection refused");
00419             return CYASSL_CBIO_ERR_WANT_READ;
00420         }
00421         else {
00422             CYASSL_MSG("    General error");
00423             return CYASSL_CBIO_ERR_GENERAL;
00424         }
00425     }
00426     else {
00427         if (dtlsCtx->peer.sz > 0
00428                 && peerSz != (XSOCKLENT)dtlsCtx->peer.sz
00429                 && memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
00430             CYASSL_MSG("    Ignored packet from invalid peer");
00431             return CYASSL_CBIO_ERR_WANT_READ;
00432         }
00433     }
00434 
00435     return recvd;
00436 }
00437 
00438 
00439 /* The send embedded callback
00440  *  return : nb bytes sent, or error
00441  */
00442 int EmbedSendTo(CYASSL* ssl, char *buf, int sz, void *ctx)
00443 {
00444     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
00445     int sd = dtlsCtx->fd;
00446     int sent;
00447     int len = sz;
00448     int err;
00449 
00450     CYASSL_ENTER("EmbedSendTo()");
00451 
00452     sent = (int)SENDTO_FUNCTION(sd, &buf[sz - len], len, ssl->wflags,
00453                                 (const struct sockaddr*)dtlsCtx->peer.sa,
00454                                 dtlsCtx->peer.sz);
00455     if (sent < 0) {
00456         err = LastError();
00457         CYASSL_MSG("Embed Send To error");
00458 
00459         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00460             CYASSL_MSG("    Would Block");
00461             return CYASSL_CBIO_ERR_WANT_WRITE;
00462         }
00463         else if (err == SOCKET_ECONNRESET) {
00464             CYASSL_MSG("    Connection reset");
00465             return CYASSL_CBIO_ERR_CONN_RST;
00466         }
00467         else if (err == SOCKET_EINTR) {
00468             CYASSL_MSG("    Socket interrupted");
00469             return CYASSL_CBIO_ERR_ISR;
00470         }
00471         else if (err == SOCKET_EPIPE) {
00472             CYASSL_MSG("    Socket EPIPE");
00473             return CYASSL_CBIO_ERR_CONN_CLOSE;
00474         }
00475         else {
00476             CYASSL_MSG("    General error");
00477             return CYASSL_CBIO_ERR_GENERAL;
00478         }
00479     }
00480  
00481     return sent;
00482 }
00483 
00484 
00485 /* The DTLS Generate Cookie callback
00486  *  return : number of bytes copied into buf, or error
00487  */
00488 int EmbedGenerateCookie(CYASSL* ssl, byte *buf, int sz, void *ctx)
00489 {
00490     int sd = ssl->wfd;
00491     struct sockaddr_storage peer;
00492     XSOCKLENT peerSz = sizeof(peer);
00493     byte digest[SHA_DIGEST_SIZE];
00494     int  ret = 0;
00495 
00496     (void)ctx;
00497 
00498     XMEMSET(&peer, 0, sizeof(peer));
00499     if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
00500         CYASSL_MSG("getpeername failed in EmbedGenerateCookie");
00501         return GEN_COOKIE_E;
00502     }
00503 
00504     ret = ShaHash((byte*)&peer, peerSz, digest);
00505     if (ret != 0)
00506         return ret;
00507 
00508     if (sz > SHA_DIGEST_SIZE)
00509         sz = SHA_DIGEST_SIZE;
00510     XMEMCPY(buf, digest, sz);
00511 
00512     return sz;
00513 }
00514 
00515 #endif /* CYASSL_DTLS */
00516 
00517 #ifdef HAVE_OCSP
00518 
00519 
00520 static int Word16ToString(char* d, word16 number)
00521 {
00522     int i = 0;
00523 
00524     if (d != NULL) {
00525         word16 order = 10000;
00526         word16 digit;
00527 
00528         if (number == 0) {
00529             d[i++] = '0';
00530         }
00531         else {
00532             while (order) {
00533                 digit = number / order;
00534                 if (i > 0 || digit != 0) {
00535                     d[i++] = (char)digit + '0';
00536                 }
00537                 if (digit != 0)
00538                     number %= digit * order;
00539                 if (order > 1)
00540                     order /= 10;
00541                 else
00542                     order = 0;
00543             }
00544         }
00545         d[i] = 0;
00546     }
00547 
00548     return i;
00549 }
00550 
00551 
00552 static int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
00553 {
00554     struct sockaddr_storage addr;
00555     int sockaddr_len = sizeof(struct sockaddr_in);
00556     XMEMSET(&addr, 0, sizeof(addr));
00557 
00558     #ifdef HAVE_GETADDRINFO
00559     {
00560         struct addrinfo hints;
00561         struct addrinfo* answer = NULL;
00562         char strPort[6];
00563 
00564         XMEMSET(&hints, 0, sizeof(hints));
00565         hints.ai_family = AF_UNSPEC;
00566         hints.ai_socktype = SOCK_STREAM;
00567         hints.ai_protocol = IPPROTO_TCP;
00568 
00569         if (Word16ToString(strPort, port) == 0) {
00570             CYASSL_MSG("invalid port number for OCSP responder");
00571             return -1;
00572         }
00573 
00574         if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) {
00575             CYASSL_MSG("no addr info for OCSP responder");
00576             return -1;
00577         }
00578 
00579         sockaddr_len = answer->ai_addrlen;
00580         XMEMCPY(&addr, answer->ai_addr, sockaddr_len);
00581         freeaddrinfo(answer);
00582 
00583     }
00584     #else /* HAVE_GETADDRINFO */
00585     {
00586         struct hostent* entry = gethostbyname(ip);
00587         struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
00588 
00589         if (entry) {
00590             sin->sin_family = AF_INET;
00591             sin->sin_port = htons(port);
00592             XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0],
00593                                                                entry->h_length);
00594         }
00595         else {
00596             CYASSL_MSG("no addr info for OCSP responder");
00597             return -1;
00598         }
00599     }
00600     #endif /* HAVE_GETADDRINFO */
00601 
00602     *sockfd = socket(addr.ss_family, SOCK_STREAM, 0);
00603 
00604 #ifdef USE_WINDOWS_API
00605     if (*sockfd == INVALID_SOCKET) {
00606         CYASSL_MSG("bad socket fd, out of fds?");
00607         return -1;
00608     }
00609 #else
00610      if (*sockfd < 0) {
00611          CYASSL_MSG("bad socket fd, out of fds?");
00612          return -1;
00613      }
00614 #endif
00615 
00616     if (connect(*sockfd, (struct sockaddr *)&addr, sockaddr_len) != 0) {
00617         CYASSL_MSG("OCSP responder tcp connect failed");
00618         return -1;
00619     }
00620 
00621     return 0;
00622 }
00623 
00624 
00625 static int build_http_request(const char* domainName, const char* path,
00626                                     int ocspReqSz, byte* buf, int bufSize)
00627 {
00628     word32 domainNameLen, pathLen, ocspReqSzStrLen, completeLen;
00629     char ocspReqSzStr[6];
00630 
00631     domainNameLen = (word32)XSTRLEN(domainName);
00632     pathLen = (word32)XSTRLEN(path);
00633     ocspReqSzStrLen = Word16ToString(ocspReqSzStr, (word16)ocspReqSz);
00634 
00635     completeLen = domainNameLen + pathLen + ocspReqSzStrLen + 84;
00636     if (completeLen > (word32)bufSize)
00637         return 0;
00638 
00639     XSTRNCPY((char*)buf, "POST ", 5);
00640     buf += 5;
00641     XSTRNCPY((char*)buf, path, pathLen);
00642     buf += pathLen;
00643     XSTRNCPY((char*)buf, " HTTP/1.1\r\nHost: ", 17);
00644     buf += 17;
00645     XSTRNCPY((char*)buf, domainName, domainNameLen);
00646     buf += domainNameLen;
00647     XSTRNCPY((char*)buf, "\r\nContent-Length: ", 18);
00648     buf += 18;
00649     XSTRNCPY((char*)buf, ocspReqSzStr, ocspReqSzStrLen);
00650     buf += ocspReqSzStrLen;
00651     XSTRNCPY((char*)buf,
00652                       "\r\nContent-Type: application/ocsp-request\r\n\r\n", 44);
00653 
00654     return completeLen;
00655 }
00656 
00657 
00658 static int decode_url(const char* url, int urlSz,
00659     char* outName, char* outPath, word16* outPort)
00660 {
00661     int result = -1;
00662 
00663     if (outName != NULL && outPath != NULL && outPort != NULL)
00664     {
00665         if (url == NULL || urlSz == 0)
00666         {
00667             *outName = 0;
00668             *outPath = 0;
00669             *outPort = 0;
00670         }
00671         else
00672         {
00673             int i, cur;
00674     
00675             /* need to break the url down into scheme, address, and port */
00676             /*     "http://example.com:8080/" */
00677             /*     "http://[::1]:443/"        */
00678             if (XSTRNCMP(url, "http://", 7) == 0) {
00679                 cur = 7;
00680             } else cur = 0;
00681     
00682             i = 0;
00683             if (url[cur] == '[') {
00684                 cur++;
00685                 /* copy until ']' */
00686                 while (url[cur] != 0 && url[cur] != ']' && cur < urlSz) {
00687                     outName[i++] = url[cur++];
00688                 }
00689                 cur++; /* skip ']' */
00690             }
00691             else {
00692                 while (url[cur] != 0 && url[cur] != ':' &&
00693                                                url[cur] != '/' && cur < urlSz) {
00694                     outName[i++] = url[cur++];
00695                 }
00696             }
00697             outName[i] = 0;
00698             /* Need to pick out the path after the domain name */
00699     
00700             if (cur < urlSz && url[cur] == ':') {
00701                 char port[6];
00702                 int j;
00703                 word32 bigPort = 0;
00704                 i = 0;
00705                 cur++;
00706                 while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
00707                         i < 6) {
00708                     port[i++] = url[cur++];
00709                 }
00710     
00711                 for (j = 0; j < i; j++) {
00712                     if (port[j] < '0' || port[j] > '9') return -1;
00713                     bigPort = (bigPort * 10) + (port[j] - '0');
00714                 }
00715                 *outPort = (word16)bigPort;
00716             }
00717             else
00718                 *outPort = 80;
00719     
00720             if (cur < urlSz && url[cur] == '/') {
00721                 i = 0;
00722                 while (cur < urlSz && url[cur] != 0 && i < 80) {
00723                     outPath[i++] = url[cur++];
00724                 }
00725                 outPath[i] = 0;
00726             }
00727             else {
00728                 outPath[0] = '/';
00729                 outPath[1] = 0;
00730             }
00731             result = 0;
00732         }
00733     }
00734 
00735     return result;
00736 }
00737 
00738 
00739 /* return: >0 OCSP Response Size
00740  *         -1 error */
00741 static int process_http_response(int sfd, byte** respBuf,
00742                                                   byte* httpBuf, int httpBufSz)
00743 {
00744     int result;
00745     int len = 0;
00746     char *start, *end;
00747     byte *recvBuf = NULL;
00748     int recvBufSz = 0;
00749     enum phr_state { phr_init, phr_http_start, phr_have_length,
00750                      phr_have_type, phr_wait_end, phr_http_end
00751     } state = phr_init;
00752 
00753     start = end = NULL;
00754     do {
00755         if (end == NULL) {
00756             result = (int)recv(sfd, (char*)httpBuf+len, httpBufSz-len-1, 0);
00757             if (result > 0) {
00758                 len += result;
00759                 start = (char*)httpBuf;
00760                 start[len] = 0;
00761             }
00762             else {
00763                 CYASSL_MSG("process_http_response recv http from peer failed");
00764                 return -1;
00765             }
00766         }
00767         end = XSTRSTR(start, "\r\n");
00768 
00769         if (end == NULL) {
00770             if (len != 0)
00771                 XMEMMOVE(httpBuf, start, len);
00772             start = end = NULL;
00773         }
00774         else if (end == start) {
00775             if (state == phr_wait_end) {
00776                 state = phr_http_end;
00777                 len -= 2;
00778                 start += 2;
00779              }
00780              else {
00781                 CYASSL_MSG("process_http_response header ended early");
00782                 return -1;
00783              }
00784         }
00785         else {
00786             *end = 0;
00787             len -= (int)(end - start) + 2;
00788                 /* adjust len to remove the first line including the /r/n */
00789 
00790             if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) {
00791                 start += 9;
00792                 if (XSTRNCASECMP(start, "200 OK", 6) != 0 ||
00793                                                            state != phr_init) {
00794                     CYASSL_MSG("process_http_response not OK");
00795                     return -1;
00796                 }
00797                 state = phr_http_start;
00798             }
00799             else if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
00800                 start += 13;
00801                 while (*start == ' ' && *start != '\0') start++;
00802                 if (XSTRNCASECMP(start, "application/ocsp-response", 25) != 0) {
00803                     CYASSL_MSG("process_http_response not ocsp-response");
00804                     return -1;
00805                 }
00806                 
00807                 if (state == phr_http_start) state = phr_have_type;
00808                 else if (state == phr_have_length) state = phr_wait_end;
00809                 else {
00810                     CYASSL_MSG("process_http_response type invalid state");
00811                     return -1;
00812                 }
00813             }
00814             else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
00815                 start += 15;
00816                 while (*start == ' ' && *start != '\0') start++;
00817                 recvBufSz = atoi(start);
00818 
00819                 if (state == phr_http_start) state = phr_have_length;
00820                 else if (state == phr_have_type) state = phr_wait_end;
00821                 else {
00822                     CYASSL_MSG("process_http_response length invalid state");
00823                     return -1;
00824                 }
00825             }
00826             
00827             start = end + 2;
00828         }
00829     } while (state != phr_http_end);
00830 
00831     recvBuf = (byte*)XMALLOC(recvBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
00832     if (recvBuf == NULL) {
00833         CYASSL_MSG("process_http_response couldn't create response buffer");
00834         return -1;
00835     }
00836 
00837     /* copy the remainder of the httpBuf into the respBuf */
00838     if (len != 0)
00839         XMEMCPY(recvBuf, start, len);
00840 
00841     /* receive the OCSP response data */
00842     do {
00843         result = (int)recv(sfd, (char*)recvBuf+len, recvBufSz-len, 0);
00844         if (result > 0)
00845             len += result;
00846         else {
00847             CYASSL_MSG("process_http_response recv ocsp from peer failed");
00848             return -1;
00849         }
00850     } while (len != recvBufSz);
00851 
00852     *respBuf = recvBuf;
00853     return recvBufSz;
00854 }
00855 
00856 
00857 #define SCRATCH_BUFFER_SIZE 512
00858 
00859 int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
00860                         byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
00861 {
00862     SOCKET_T sfd = 0;
00863     word16   port;
00864     int      ret = -1;
00865 #ifdef CYASSL_SMALL_STACK
00866     char*    path;
00867     char*    domainName;
00868 #else
00869     char     path[80];
00870     char     domainName[80];
00871 #endif
00872 
00873 #ifdef CYASSL_SMALL_STACK
00874     path = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00875     if (path == NULL)
00876         return -1;
00877     
00878     domainName = (char*)XMALLOC(80, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00879     if (domainName == NULL) {
00880         XFREE(path, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00881         return -1;
00882     }
00883 #endif
00884 
00885     (void)ctx;
00886 
00887     if (ocspReqBuf == NULL || ocspReqSz == 0) {
00888         CYASSL_MSG("OCSP request is required for lookup");
00889     }
00890     else if (ocspRespBuf == NULL) {
00891         CYASSL_MSG("Cannot save OCSP response");
00892     }
00893     else if (decode_url(url, urlSz, domainName, path, &port) < 0) {
00894         CYASSL_MSG("Unable to decode OCSP URL");
00895     }
00896     else {
00897         /* Note, the library uses the EmbedOcspRespFree() callback to
00898          * free this buffer. */
00899         int   httpBufSz = SCRATCH_BUFFER_SIZE;
00900         byte* httpBuf   = (byte*)XMALLOC(httpBufSz, NULL, 
00901                                                         DYNAMIC_TYPE_IN_BUFFER);
00902 
00903         if (httpBuf == NULL) {
00904             CYASSL_MSG("Unable to create OCSP response buffer");
00905         }
00906         else {
00907             httpBufSz = build_http_request(domainName, path, ocspReqSz,
00908                                                             httpBuf, httpBufSz);
00909 
00910             if ((tcp_connect(&sfd, domainName, port) != 0) || (sfd <= 0)) {
00911                 CYASSL_MSG("OCSP Responder connection failed");
00912             }
00913             else if ((int)send(sfd, (char*)httpBuf, httpBufSz, 0) !=
00914                                                                     httpBufSz) {
00915                 CYASSL_MSG("OCSP http request failed");
00916             }
00917             else if ((int)send(sfd, (char*)ocspReqBuf, ocspReqSz, 0) !=
00918                                                                     ocspReqSz) {
00919                 CYASSL_MSG("OCSP ocsp request failed");
00920             }
00921             else {
00922                 ret = process_http_response(sfd, ocspRespBuf, httpBuf,
00923                                                            SCRATCH_BUFFER_SIZE);
00924             }
00925 
00926             close(sfd);
00927             XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
00928         }
00929     }
00930 
00931 #ifdef CYASSL_SMALL_STACK
00932     XFREE(path,       NULL, DYNAMIC_TYPE_TMP_BUFFER);
00933     XFREE(domainName, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00934 #endif
00935 
00936     return ret;
00937 }
00938 
00939 
00940 void EmbedOcspRespFree(void* ctx, byte *resp)
00941 {
00942     (void)ctx;
00943 
00944     if (resp)
00945         XFREE(resp, NULL, DYNAMIC_TYPE_IN_BUFFER);
00946 }
00947 
00948 
00949 #endif
00950 
00951 #endif /* CYASSL_USER_IO */
00952 
00953 CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)
00954 {
00955     ctx->CBIORecv = CBIORecv;
00956 }
00957 
00958 
00959 CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX *ctx, CallbackIOSend CBIOSend)
00960 {
00961     ctx->CBIOSend = CBIOSend;
00962 }
00963 
00964 
00965 CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *rctx)
00966 {
00967     ssl->IOCB_ReadCtx = rctx;
00968 }
00969 
00970 
00971 CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *wctx)
00972 {
00973     ssl->IOCB_WriteCtx = wctx;
00974 }
00975 
00976 
00977 CYASSL_API void* CyaSSL_GetIOReadCtx(CYASSL* ssl)
00978 {
00979     if (ssl)
00980         return ssl->IOCB_ReadCtx;
00981 
00982     return NULL;
00983 }
00984 
00985 
00986 CYASSL_API void* CyaSSL_GetIOWriteCtx(CYASSL* ssl)
00987 {
00988     if (ssl)
00989         return ssl->IOCB_WriteCtx;
00990 
00991     return NULL;
00992 }
00993 
00994 
00995 CYASSL_API void CyaSSL_SetIOReadFlags(CYASSL* ssl, int flags)
00996 {
00997     ssl->rflags = flags; 
00998 }
00999 
01000 
01001 CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags)
01002 {
01003     ssl->wflags = flags;
01004 }
01005 
01006 
01007 #ifdef CYASSL_DTLS
01008 
01009 CYASSL_API void CyaSSL_CTX_SetGenCookie(CYASSL_CTX* ctx, CallbackGenCookie cb)
01010 {
01011     ctx->CBIOCookie = cb;
01012 }
01013 
01014 
01015 CYASSL_API void CyaSSL_SetCookieCtx(CYASSL* ssl, void *ctx)
01016 {
01017     ssl->IOCB_CookieCtx = ctx;
01018 }
01019 
01020 
01021 CYASSL_API void* CyaSSL_GetCookieCtx(CYASSL* ssl)
01022 {
01023     if (ssl)
01024         return ssl->IOCB_CookieCtx;
01025 
01026     return NULL;
01027 }
01028 
01029 #endif /* CYASSL_DTLS */
01030 
01031 
01032 #ifdef HAVE_NETX
01033 
01034 /* The NetX receive callback
01035  *  return :  bytes read, or error
01036  */
01037 int NetX_Receive(CYASSL *ssl, char *buf, int sz, void *ctx)
01038 {
01039     NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
01040     ULONG left;
01041     ULONG total;
01042     ULONG copied = 0;
01043     UINT  status;
01044 
01045     if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
01046         CYASSL_MSG("NetX Recv NULL parameters");
01047         return CYASSL_CBIO_ERR_GENERAL;
01048     }
01049 
01050     if (nxCtx->nxPacket == NULL) {
01051         status = nx_tcp_socket_receive(nxCtx->nxSocket, &nxCtx->nxPacket,
01052                                        nxCtx->nxWait);
01053         if (status != NX_SUCCESS) {
01054             CYASSL_MSG("NetX Recv receive error");
01055             return CYASSL_CBIO_ERR_GENERAL;
01056         }
01057     }
01058 
01059     if (nxCtx->nxPacket) {
01060         status = nx_packet_length_get(nxCtx->nxPacket, &total);
01061         if (status != NX_SUCCESS) {
01062             CYASSL_MSG("NetX Recv length get error");
01063             return CYASSL_CBIO_ERR_GENERAL;
01064         }
01065 
01066         left = total - nxCtx->nxOffset;
01067         status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
01068                                                buf, sz, &copied);
01069         if (status != NX_SUCCESS) {
01070             CYASSL_MSG("NetX Recv data extract offset error");
01071             return CYASSL_CBIO_ERR_GENERAL;
01072         }
01073 
01074         nxCtx->nxOffset += copied;
01075 
01076         if (copied == left) {
01077             CYASSL_MSG("NetX Recv Drained packet");
01078             nx_packet_release(nxCtx->nxPacket);
01079             nxCtx->nxPacket = NULL;
01080             nxCtx->nxOffset = 0;
01081         }
01082     }
01083 
01084     return copied;
01085 }
01086 
01087 
01088 /* The NetX send callback
01089  *  return : bytes sent, or error
01090  */
01091 int NetX_Send(CYASSL* ssl, char *buf, int sz, void *ctx)
01092 {
01093     NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
01094     NX_PACKET*      packet;
01095     NX_PACKET_POOL* pool;   /* shorthand */
01096     UINT            status;
01097 
01098     if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
01099         CYASSL_MSG("NetX Send NULL parameters");
01100         return CYASSL_CBIO_ERR_GENERAL;
01101     }
01102 
01103     pool = nxCtx->nxSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool;
01104     status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET,
01105                                 nxCtx->nxWait);
01106     if (status != NX_SUCCESS) {
01107         CYASSL_MSG("NetX Send packet alloc error");
01108         return CYASSL_CBIO_ERR_GENERAL;
01109     }
01110 
01111     status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
01112     if (status != NX_SUCCESS) {
01113         nx_packet_release(packet);
01114         CYASSL_MSG("NetX Send data append error");
01115         return CYASSL_CBIO_ERR_GENERAL;
01116     }
01117 
01118     status = nx_tcp_socket_send(nxCtx->nxSocket, packet, nxCtx->nxWait);
01119     if (status != NX_SUCCESS) {
01120         nx_packet_release(packet);
01121         CYASSL_MSG("NetX Send socket send error");
01122         return CYASSL_CBIO_ERR_GENERAL;
01123     }
01124 
01125     return sz;
01126 }
01127 
01128 
01129 /* like set_fd, but for default NetX context */
01130 void CyaSSL_SetIO_NetX(CYASSL* ssl, NX_TCP_SOCKET* nxSocket, ULONG waitOption)
01131 {
01132     if (ssl) {
01133         ssl->nxCtx.nxSocket = nxSocket;
01134         ssl->nxCtx.nxWait   = waitOption;
01135     }
01136 }
01137 
01138 #endif /* HAVE_NETX */
01139