static void dgram_reset_rcv_timeout(BIO *b) { #if defined(SO_RCVTIMEO) bio_dgram_data *data = (bio_dgram_data *)b->ptr; /* Is a timer active? */ if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { #ifdef OPENSSL_SYS_WINDOWS int timeout = data->socket_timeout.tv_sec * 1000 + data->socket_timeout.tv_usec / 1000; if (TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); } #else if ( TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), sizeof(struct TINYCLR_SSL_TIMEVAL)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); } #endif } #endif }
static int conn_state(BIO *b, BIO_CONNECT *c) { int ret= -1,i; unsigned long l; char *p,*q; int (*cb)(const BIO *,int,int)=NULL; if (c->info_callback != NULL) cb=c->info_callback; for (;;) { switch (c->state) { case BIO_CONN_S_BEFORE: p=c->param_hostname; if (p == NULL) { BIOerr(BIO_F_CONN_STATE,BIO_R_NO_HOSTNAME_SPECIFIED); goto exit_loop; } for ( ; *p != '\0'; p++) { if ((*p == ':') || (*p == '/')) break; } i= *p; if ((i == ':') || (i == '/')) { *(p++)='\0'; if (i == ':') { for (q=p; *q; q++) if (*q == '/') { *q='\0'; break; } if (c->param_port != NULL) OPENSSL_free(c->param_port); c->param_port=BUF_strdup(p); } } if (c->param_port == NULL) { BIOerr(BIO_F_CONN_STATE,BIO_R_NO_PORT_SPECIFIED); ERR_add_error_data(2,"host=",c->param_hostname); goto exit_loop; } c->state=BIO_CONN_S_GET_IP; break; case BIO_CONN_S_GET_IP: if (BIO_get_host_ip(c->param_hostname,&(c->ip[0])) <= 0) goto exit_loop; c->state=BIO_CONN_S_GET_PORT; break; case BIO_CONN_S_GET_PORT: if (c->param_port == NULL) { /* abort(); */ goto exit_loop; } else if (BIO_get_port(c->param_port,&c->port) <= 0) goto exit_loop; c->state=BIO_CONN_S_CREATE_SOCKET; break; case BIO_CONN_S_CREATE_SOCKET: /* now setup address */ TINYCLR_SSL_MEMSET((char *)&c->them,0,sizeof(c->them)); c->them.sin_family=AF_INET; c->them.sin_port=TINYCLR_SSL_HTONS((unsigned short)c->port); l=(unsigned long) ((unsigned long)c->ip[0]<<24L)| ((unsigned long)c->ip[1]<<16L)| ((unsigned long)c->ip[2]<< 8L)| ((unsigned long)c->ip[3]); c->them.sin_addr.S_un.S_addr=TINYCLR_SSL_HTONL(l); c->state=BIO_CONN_S_CREATE_SOCKET; ret=TINYCLR_SSL_SOCKET(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL); if (ret == INVALID_SOCKET) { SYSerr(SYS_F_SOCKET,get_last_socket_error()); ERR_add_error_data(4,"host=",c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_UNABLE_TO_CREATE_SOCKET); goto exit_loop; } b->num=ret; c->state=BIO_CONN_S_NBIO; break; case BIO_CONN_S_NBIO: if (c->nbio) { if (!BIO_socket_nbio(b->num,1)) { BIOerr(BIO_F_CONN_STATE,BIO_R_ERROR_SETTING_NBIO); ERR_add_error_data(4,"host=", c->param_hostname, ":",c->param_port); goto exit_loop; } } c->state=BIO_CONN_S_CONNECT; #if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) i=1; i=TINYCLR_SSL_SETSOCKOPT(b->num,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); if (i < 0) { SYSerr(SYS_F_SOCKET,get_last_socket_error()); ERR_add_error_data(4,"host=",c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_KEEPALIVE); goto exit_loop; } #endif break; case BIO_CONN_S_CONNECT: BIO_clear_retry_flags(b); ret=TINYCLR_SSL_CONNECT(b->num, (struct TINYCLR_SSL_SOCKADDR *)&c->them, sizeof(c->them)); b->retry_reason=0; if (ret < 0) { if (BIO_sock_should_retry(ret)) { BIO_set_retry_special(b); c->state=BIO_CONN_S_BLOCKED_CONNECT; b->retry_reason=BIO_RR_CONNECT; } else { SYSerr(SYS_F_CONNECT,get_last_socket_error()); ERR_add_error_data(4,"host=", c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_CONNECT_ERROR); } goto exit_loop; } else c->state=BIO_CONN_S_OK; break; case BIO_CONN_S_BLOCKED_CONNECT: i=BIO_sock_error(b->num); if (i) { BIO_clear_retry_flags(b); SYSerr(SYS_F_CONNECT,i); ERR_add_error_data(4,"host=", c->param_hostname, ":",c->param_port); BIOerr(BIO_F_CONN_STATE,BIO_R_NBIO_CONNECT_ERROR); ret=0; goto exit_loop; } else c->state=BIO_CONN_S_OK; break; case BIO_CONN_S_OK: ret=1; goto exit_loop; default: /* TINYCLR_SSL_ABORT(); */ goto exit_loop; } if (cb != NULL) { if (!(ret=cb((BIO *)b,c->state,ret))) goto end; } } /* Loop does not exit */ exit_loop: if (cb != NULL) ret=cb((BIO *)b,c->state,ret); end: return(ret); }
static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) { long ret=1; int *ip; struct TINYCLR_SSL_SOCKADDR *to = NULL; bio_dgram_data *data = NULL; #if defined(IP_MTU_DISCOVER) || defined(IP_MTU) long sockopt_val = 0; unsigned int sockopt_len = 0; #endif #ifdef OPENSSL_SYS_LINUX socklen_t addr_len; union { struct TINYCLR_SSL_SOCKADDR sa; struct TINYCLR_SSL_SOCKADDR_IN s4; #if OPENSSL_USE_IPV6 struct sockaddr_in6 s6; #endif } addr; #endif data = (bio_dgram_data *)b->ptr; switch (cmd) { case BIO_CTRL_RESET: num=0; case BIO_C_FILE_SEEK: ret=0; break; case BIO_C_FILE_TELL: case BIO_CTRL_INFO: ret=0; break; case BIO_C_SET_FD: dgram_clear(b); b->num= *((int *)ptr); b->shutdown=(int)num; b->init=1; break; case BIO_C_GET_FD: if (b->init) { ip=(int *)ptr; if (ip != NULL) *ip=b->num; ret=b->num; } else ret= -1; break; case BIO_CTRL_GET_CLOSE: ret=b->shutdown; break; case BIO_CTRL_SET_CLOSE: b->shutdown=(int)num; break; case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: ret=0; break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret=1; break; case BIO_CTRL_DGRAM_CONNECT: to = (struct TINYCLR_SSL_SOCKADDR *)ptr; #if 0 if (TINYCLR_SSL_CONNECT(b->num, to, sizeof(struct TINYCLR_SSL_SOCKADDR)) < 0) { TINYCLR_SSL_PERROR("connect"); ret = 0; } else { #endif switch (to->sa_family) { case AF_INET: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in)); break; #if OPENSSL_USE_IPV6 case AF_INET6: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in6)); break; #endif default: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa)); break; } #if 0 } #endif break; /* (Linux)kernel sets DF bit on outgoing IP packets */ case BIO_CTRL_DGRAM_MTU_DISCOVER: #ifdef OPENSSL_SYS_LINUX addr_len = (socklen_t)sizeof(addr); TINYCLR_SSL_MEMSET((void *)&addr, 0, sizeof(addr)); if (getsockname(b->num, &addr.sa, &addr_len) < 0) { ret = 0; break; } sockopt_len = sizeof(sockopt_val); switch (addr.sa.sa_family) { case AF_INET: sockopt_val = IP_PMTUDISC_DO; if ((ret = TINYCLR_SSL_SETSOCKOPT(b->num, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt_val, sizeof(sockopt_val))) < 0) TINYCLR_SSL_PERROR("setsockopt"); break; #if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) case AF_INET6: sockopt_val = IPV6_PMTUDISC_DO; if ((ret = TINYCLR_SSL_SETSOCKOPT(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &sockopt_val, sizeof(sockopt_val))) < 0) TINYCLR_SSL_PERROR("setsockopt"); break; #endif default: ret = -1; break; } ret = -1; #else break; #endif case BIO_CTRL_DGRAM_QUERY_MTU: #ifdef OPENSSL_SYS_LINUX addr_len = (socklen_t)sizeof(addr); TINYCLR_SSL_MEMSET((void *)&addr, 0, sizeof(addr)); if (getsockname(b->num, &addr.sa, &addr_len) < 0) { ret = 0; break; } sockopt_len = sizeof(sockopt_val); switch (addr.sa.sa_family) { case AF_INET: if ((ret = TINYCLR_SSL_GETSOCKOPT(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, &sockopt_len)) < 0 || sockopt_val < 0) { ret = 0; } else { /* we assume that the transport protocol is UDP and no * IP options are used. */ data->mtu = sockopt_val - 8 - 20; ret = data->mtu; } break; #if OPENSSL_USE_IPV6 && defined(IPV6_MTU) case AF_INET6: if ((ret = TINYCLR_SSL_GETSOCKOPT(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val, &sockopt_len)) < 0 || sockopt_val < 0) { ret = 0; } else { /* we assume that the transport protocol is UDP and no * IPV6 options are used. */ data->mtu = sockopt_val - 8 - 40; ret = data->mtu; } break; #endif default: ret = 0; break; } #else ret = 0; #endif break; case BIO_CTRL_DGRAM_GET_MTU: return data->mtu; break; case BIO_CTRL_DGRAM_SET_MTU: data->mtu = num; ret = num; break; case BIO_CTRL_DGRAM_SET_CONNECTED: to = (struct TINYCLR_SSL_SOCKADDR *)ptr; if ( to != NULL) { data->connected = 1; switch (to->sa_family) { case AF_INET: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in)); break; #if OPENSSL_USE_IPV6 case AF_INET6: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in6)); break; #endif default: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa)); break; } } else { data->connected = 0; TINYCLR_SSL_MEMSET(&(data->peer), 0x00, sizeof(data->peer)); } break; case BIO_CTRL_DGRAM_GET_PEER: switch (data->peer.sa.sa_family) { case AF_INET: ret=sizeof(data->peer.sa_in); break; #if OPENSSL_USE_IPV6 case AF_INET6: ret=sizeof(data->peer.sa_in6); break; #endif default: ret=sizeof(data->peer.sa); break; } if (num==0 || num>ret) num=ret; TINYCLR_SSL_MEMCPY(ptr,&data->peer,(ret=num)); break; case BIO_CTRL_DGRAM_SET_PEER: to = (struct TINYCLR_SSL_SOCKADDR *) ptr; switch (to->sa_family) { case AF_INET: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in)); break; #if OPENSSL_USE_IPV6 case AF_INET6: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa_in6)); break; #endif default: TINYCLR_SSL_MEMCPY(&data->peer,to,sizeof(data->peer.sa)); break; } break; case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: TINYCLR_SSL_MEMCPY(&(data->next_timeout), ptr, sizeof(struct TINYCLR_SSL_TIMEVAL)); break; #if defined(SO_RCVTIMEO) case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: #ifdef OPENSSL_SYS_WINDOWS { struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr; int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; if (TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); ret = -1; } } #else if ( TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, sizeof(struct TINYCLR_SSL_TIMEVAL)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); ret = -1; } #endif break; case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: #ifdef OPENSSL_SYS_WINDOWS { int timeout, sz = sizeof(timeout); struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr; if (TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, &sz) < 0) { TINYCLR_SSL_PERROR("getsockopt"); ret = -1; } else { tv->tv_sec = timeout / 1000; tv->tv_usec = (timeout % 1000) * 1000; ret = sizeof(*tv); } } #elif defined(OPENSSL_SYS_ARM) || defined(OPENSSL_SYS_SH) if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, (u32_t *)&ret) < 0) { TINYCLR_SSL_PERROR("getsockopt"); ret = -1; } #else if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, (void *)&ret) < 0) { TINYCLR_SSL_PERROR("getsockopt"); ret = -1; } #endif break; #endif #if defined(SO_SNDTIMEO) case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: #ifdef OPENSSL_SYS_WINDOWS { struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr; int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; if (TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); ret = -1; } } #else if ( TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, sizeof(struct TINYCLR_SSL_TIMEVAL)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); ret = -1; } #endif break; case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: #ifdef OPENSSL_SYS_WINDOWS { int timeout, sz = sizeof(timeout); struct TINYCLR_SSL_TIMEVAL *tv = (struct TINYCLR_SSL_TIMEVAL *)ptr; if (TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, &sz) < 0) { TINYCLR_SSL_PERROR("getsockopt"); ret = -1; } else { tv->tv_sec = timeout / 1000; tv->tv_usec = (timeout % 1000) * 1000; ret = sizeof(*tv); } } #elif defined(OPENSSL_SYS_ARM) || defined(OPENSSL_SYS_SH) if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, (u32_t *)&ret) < 0) { TINYCLR_SSL_PERROR("getsockopt"); ret = -1; } #else if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, (void *)&ret) < 0) { TINYCLR_SSL_PERROR("getsockopt"); ret = -1; } #endif break; #endif case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: /* fall-through */ case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: #ifdef OPENSSL_SYS_WINDOWS if ( data->_errno == WSAETIMEDOUT) #else if ( data->_errno == EAGAIN) #endif { ret = 1; data->_errno = 0; } else ret = 0; break; #ifdef EMSGSIZE case BIO_CTRL_DGRAM_MTU_EXCEEDED: if ( data->_errno == EMSGSIZE) { ret = 1; data->_errno = 0; } else ret = 0; break; #endif default: ret=0; break; } return(ret); }
static void dgram_adjust_rcv_timeout(BIO *b) { #if defined(SO_RCVTIMEO) bio_dgram_data *data = (bio_dgram_data *)b->ptr; int sz = sizeof(int); /* Is a timer active? */ if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { struct TINYCLR_SSL_TIMEVAL timenow, timeleft; /* Read current socket timeout */ #ifdef OPENSSL_SYS_WINDOWS int timeout; if (TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, &sz) < 0) { TINYCLR_SSL_PERROR("getsockopt"); } else { data->socket_timeout.tv_sec = timeout / 1000; data->socket_timeout.tv_usec = (timeout % 1000) * 1000; } #elif defined(OPENSSL_SYS_ARM) || defined(OPENSSL_SYS_SH) if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), (u32_t *)&sz) < 0) { TINYCLR_SSL_PERROR("getsockopt"); } #else if ( TINYCLR_SSL_GETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), (void *)&sz) < 0) { TINYCLR_SSL_PERROR("getsockopt"); } #endif /* Get current time */ get_current_time(&timenow); /* Calculate time left until timer expires */ TINYCLR_SSL_MEMCPY(&timeleft, &(data->next_timeout), sizeof(struct TINYCLR_SSL_TIMEVAL)); timeleft.tv_sec -= timenow.tv_sec; timeleft.tv_usec -= timenow.tv_usec; if (timeleft.tv_usec < 0) { timeleft.tv_sec--; timeleft.tv_usec += 1000000; } if (timeleft.tv_sec < 0) { timeleft.tv_sec = 0; timeleft.tv_usec = 1; } /* Adjust socket timeout if next handhake message timer * will expire earlier. */ if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) || (data->socket_timeout.tv_sec > timeleft.tv_sec) || (data->socket_timeout.tv_sec == timeleft.tv_sec && data->socket_timeout.tv_usec >= timeleft.tv_usec)) { #ifdef OPENSSL_SYS_WINDOWS timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; if (TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); } #else if ( TINYCLR_SSL_SETSOCKOPT(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, sizeof(struct TINYCLR_SSL_TIMEVAL)) < 0) { TINYCLR_SSL_PERROR("setsockopt"); } #endif } } #endif }