예제 #1
0
파일: wi-socket.c 프로젝트: asvitkine/phxd
static wi_integer_t _wi_socket_read_buffer(wi_socket_t *socket, wi_time_interval_t timeout, void *buffer, size_t length) {
	wi_socket_state_t	state;
	wi_integer_t		bytes;
	
#ifdef HAVE_OPENSSL_SSL_H
	if(socket->ssl) {
		if(timeout > 0.0 && SSL_pending(socket->ssl) == 0) {
			state = wi_socket_wait_descriptor(socket->sd, timeout, true, false);
			
			if(state != WI_SOCKET_READY) {
				if(state == WI_SOCKET_TIMEOUT)
					wi_error_set_errno(ETIMEDOUT);
				
				return -1;
			}
		}
		
		ERR_clear_error();
		
		bytes = SSL_read(socket->ssl, buffer, length);
		
		if(bytes <= 0) {
			wi_error_set_openssl_ssl_error_with_result(socket->ssl, bytes);
			
			ERR_clear_error();
		}
		
		return bytes;
	} else {
#endif
		if(timeout > 0.0) {
			state = wi_socket_wait_descriptor(socket->sd, timeout, true, false);
			
			if(state != WI_SOCKET_READY) {
				if(state == WI_SOCKET_TIMEOUT)
					wi_error_set_errno(ETIMEDOUT);
				
				return -1;
			}
		}
		
		bytes = read(socket->sd, buffer, length);
		
		if(bytes <= 0) {
			if(bytes < 0)
				wi_error_set_errno(errno);
			else
				wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF);
		}
		
		return bytes;
#ifdef HAVE_OPENSSL_SSL_H
	}
#endif
	
	return 0;
}
예제 #2
0
int32_t wi_socket_write_buffer(wi_socket_t *socket, wi_time_interval_t timeout, const void *buffer, size_t length) {
	int		bytes;
	
	if(timeout > 0.0) {
		if(wi_socket_wait_descriptor(socket->sd, timeout, false, true) <= 0)
			return -1;
	}

#ifdef WI_SSL
	if(socket->ssl) {
		bytes = SSL_write(socket->ssl, buffer, length);

		if(bytes < 0) {
			wi_error_set_ssl_error();

			socket->broken = true;
		}
	} else {
#endif
		bytes = write(socket->sd, buffer, length);
		
		if(bytes < 0)
			wi_error_set_errno(errno);
#ifdef WI_SSL
	}
#endif
	
	return bytes;
}
예제 #3
0
wi_socket_state_t wi_socket_wait(wi_socket_t *socket, wi_time_interval_t timeout) {
	if(wi_string_length(socket->buffer) > 0)
		return WI_SOCKET_READY;

	return wi_socket_wait_descriptor(socket->sd,
									 timeout,
									 (socket->direction & WI_SOCKET_READ),
									 (socket->direction & WI_SOCKET_WRITE));
}
예제 #4
0
int32_t wi_socket_read_buffer(wi_socket_t *socket, wi_time_interval_t timeout, void *buffer, size_t length) {
	int		bytes;
	
	if(timeout > 0.0) {
#ifdef WI_SSL
		if(socket->ssl && SSL_pending(socket->ssl) == 0) {
#endif
			if(wi_socket_wait_descriptor(socket->sd, timeout, true, false) <= 0)
				return -1;
#ifdef WI_SSL
		}
#endif
	}

#ifdef WI_SSL
	if(socket->ssl) {
		bytes = SSL_read(socket->ssl, buffer, length);
		
		if(bytes <= 0) {
			wi_error_set_ssl_error();

			socket->broken = true;
		}
	} else {
#endif
		bytes = read(socket->sd, buffer, length);
		
		if(bytes < 0)
			wi_error_set_errno(errno);
		else if(bytes == 0)
			wi_error_set_lib_error(WI_ERROR_SOCKET_EOF);
#ifdef WI_SSL
	}
#endif

	return bytes;
}
예제 #5
0
wi_boolean_t wi_socket_connect(wi_socket_t *socket, wi_time_interval_t timeout) {
	struct sockaddr		*sa;
	wi_socket_state_t	state;
	wi_uinteger_t		length;
	int					err;
	wi_boolean_t		blocking;
	
	sa		= wi_address_sa(socket->address);
	length	= wi_address_sa_length(socket->address);

	if(timeout > 0.0) {
		blocking = wi_socket_blocking(socket);

		if(blocking)
			wi_socket_set_blocking(socket, false);
		
		err = connect(socket->sd, sa, length);
		
		if(err < 0) {
			if(errno != EINPROGRESS) {
				wi_error_set_errno(errno);
				
				return false;
			}
			
			do {
				state = wi_socket_wait_descriptor(socket->sd, 1.0, true, true);
				timeout -= 1.0;
			} while(state == WI_SOCKET_TIMEOUT && timeout >= 0.0);
			
			if(state == WI_SOCKET_ERROR)
				return false;
			
			if(timeout <= 0.0) {
				wi_error_set_errno(ETIMEDOUT);
				
				return false;
			}
			
			err = wi_socket_error(socket);
			
			if(err != 0) {
				wi_error_set_errno(err);
				
				return false;
			}
		}

		if(blocking)
			wi_socket_set_blocking(socket, true);
	} else {
		if(connect(socket->sd, sa, length) < 0) {
			wi_error_set_errno(errno);
				
			return false;
		}
	}

	socket->direction = WI_SOCKET_READ;
	
	return true;
}
예제 #6
0
wi_integer_t wi_socket_read_buffer(wi_socket_t *socket, wi_time_interval_t timeout, void *buffer, size_t length) {
	wi_time_interval_t	interval;
	wi_socket_state_t	state;
	wi_uinteger_t		offset;
	wi_integer_t		bytes;
	
	WI_ASSERT(buffer != NULL, "buffer of length %u should not be NULL", length);

	if(timeout > 0.0) {
#ifdef HAVE_OPENSSL_SSL_H
		if(!socket->ssl || (socket->ssl && SSL_pending(socket->ssl) == 0)) {
#endif
			state = wi_socket_wait_descriptor(socket->sd, timeout, true, false);

			if(state != WI_SOCKET_READY) {
				if(state == WI_SOCKET_TIMEOUT)
					wi_error_set_errno(ETIMEDOUT);
				
				return -1;
			}
#ifdef HAVE_OPENSSL_SSL_H
		}
#endif
	}
	
	interval = 0.0;
		
#ifdef HAVE_OPENSSL_SSL_H
	if(socket->ssl) {
		do {
			bytes = SSL_read(socket->ssl, buffer, length);
			
			if(bytes <= 0) {
				if(bytes < 0 && SSL_get_error(socket->ssl, bytes) == SSL_ERROR_WANT_READ) {
					wi_thread_sleep(0.1);
					
					if(timeout > 0.0) {
						interval += 0.1;
						
						if(interval >= timeout) {
							wi_error_set_errno(ETIMEDOUT);
							
							break;
						}
					}
				} else {
					wi_error_set_openssl_ssl_error_with_result(socket->ssl, bytes);

					socket->broken = true;
					
					break;
				}
			}
		} while(bytes <= 0);
		
		return bytes;
	} else {
#endif
		offset = 0;
		
		do {
			bytes = read(socket->sd, buffer + offset, length - offset);
			
			if(bytes <= 0) {
				if(bytes < 0)
					wi_error_set_errno(errno);
				else
					wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF);
				
				return bytes;
			}
			
			offset += bytes;
			
			if(offset < length) {
				wi_thread_sleep(0.1);
				
				if(timeout > 0.0) {
					interval += 0.1;
					
					if(interval >= timeout) {
						wi_error_set_errno(ETIMEDOUT);
						
						return -1;
					}
				}
			}
		} while(offset < length);
		
		return offset;
#ifdef HAVE_OPENSSL_SSL_H
	}
#endif

	return 0;
}
예제 #7
0
wi_boolean_t wi_socket_accept_tls(wi_socket_t *socket, wi_socket_tls_t *tls, wi_time_interval_t timeout) {
	wi_socket_state_t	state;
	int					err, result;
	wi_boolean_t		blocking;
	
	socket->ssl = SSL_new(tls->ssl_ctx);
	
	if(!socket->ssl) {
		wi_error_set_openssl_error();
		
		return false;
	}
	
	if(SSL_set_fd(socket->ssl, socket->sd) != 1) {
		wi_error_set_openssl_error();
		
		return false;
	}
	
	if(!tls->private_key && tls->dh) {
		if(SSL_set_tmp_dh(socket->ssl, tls->dh) != 1) {
			wi_error_set_openssl_error();
			
			return false;
		}
	}
	
	if(timeout > 0.0) {
		blocking = wi_socket_blocking(socket);
		
		if(blocking)
			wi_socket_set_blocking(socket, false);
		
		result = SSL_accept(socket->ssl);
		
		if(result != 1) {
			do {
				err = SSL_get_error(socket->ssl, result);
				
				if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
					wi_error_set_openssl_ssl_error_with_result(socket->ssl, result);
					
					return false;
				}

				state = wi_socket_wait_descriptor(socket->sd, 1.0, (err == SSL_ERROR_WANT_READ), (err == SSL_ERROR_WANT_WRITE));

				if(state == WI_SOCKET_ERROR)
					break;
				else if(state == WI_SOCKET_READY) {
					result = SSL_accept(socket->ssl);
					
					if(result == 1)
						break;
				}
				
				timeout -= 1.0;
			} while(timeout >= 0.0);

			if(state == WI_SOCKET_ERROR)
				return false;
			
			if(timeout <= 0.0) {
				wi_error_set_errno(ETIMEDOUT);
				
				return false;
			}
		}
		
		if(blocking)
			wi_socket_set_blocking(socket, true);
	} else {
		result = SSL_accept(socket->ssl);
		
		if(result != 1) {
			wi_error_set_openssl_ssl_error_with_result(socket->ssl, result);
			
			return false;
		}
	}
	
	return true;
}
예제 #8
0
static void wd_transfer_upload(wd_transfer_t *transfer) {
	wi_pool_t				*pool;
	wi_string_t				*path;
	wd_account_t			*account;
	char					buffer[WD_TRANSFER_BUFFER_SIZE];
	wi_time_interval_t		timeout, interval, speedinterval, statusinterval, accountinterval;
	wi_socket_state_t		state;
	ssize_t					result, speedbytes, statsbytes;
	int						sd, bytes;

	pool = wi_pool_init(wi_pool_alloc());

	/* start upload */
	wi_log_info(WI_STR("Receiving \"%@\" from %@"),
		transfer->path,
		wd_user_identifier(transfer->user));
	
	wi_socket_set_direction(transfer->socket, WI_SOCKET_READ);

//	if(!wi_socket_set_blocking(transfer->socket, false))
//		wi_log_warn(WI_STR("Could not set non-blocking for %@: %m"), wd_user_ip(transfer->user));

	sd = wi_socket_descriptor(transfer->socket);
	speedinterval = statusinterval = accountinterval = wi_time_interval();
	speedbytes = statsbytes = 0;
	account = wd_user_account(transfer->user);

	/* update status */
	wi_lock_lock(wd_status_lock);
	wd_current_uploads++;
	wd_total_uploads++;
	wd_write_status(true);
	wi_lock_unlock(wd_status_lock);

	while(wd_transfer_state(transfer) == WD_TRANSFER_RUNNING && transfer->transferred < transfer->size) {
		/* wait to read */
		timeout = 0.0;
		
		do {
			state = wi_socket_wait_descriptor(sd, 0.1, true, false);
			
			if(state == WI_SOCKET_TIMEOUT) {
				timeout += 0.1;
				
				if(timeout >= 30.0)
					break;
			}
		} while(state == WI_SOCKET_TIMEOUT && wd_transfer_state(transfer) == WD_TRANSFER_RUNNING);
		
		if(state == WI_SOCKET_ERROR) {
			wi_log_err(WI_STR("Could not wait for upload from %@: %m"),
				wd_user_ip(transfer->user));

			break;
		}
		
		if(timeout >= 30.0) {
			wi_log_err(WI_STR("Timed out waiting to read upload from %@"),
				wd_user_ip(transfer->user));
			
			break;
		}

		/* read data */
		bytes = wi_socket_read_buffer(transfer->socket, 30.0, buffer, sizeof(buffer));
		
		if(bytes <= 0) {
			if(bytes < 0) {
				wi_log_err(WI_STR("Could not read upload from %@: %m"),
					wd_user_ip(transfer->user));
			}
			
			break;
		}
		
		if((wi_file_offset_t) bytes > transfer->size - transfer->transferred)
			bytes = transfer->size - transfer->transferred;

		/* write data */
		result = write(transfer->fd, buffer, bytes);
		
		if(result <= 0) {
			if(result < 0) {
				wi_log_err(WI_STR("Could not write upload to %@: %s"),
					transfer->realpath, strerror(errno));
			}
			
			break;
		}

		/* update counters */
		interval = wi_time_interval();
		transfer->transferred += bytes;
		speedbytes += bytes;
		statsbytes += bytes;

		/* update speed */
		transfer->speed = speedbytes / (interval - speedinterval);

		wd_transfer_limit_upload_speed(transfer, account, speedbytes, interval, speedinterval);
		
		if(interval - speedinterval > 30.0) {
			speedbytes = 0;
			speedinterval = interval;
		}

		/* update status */
		if(interval - statusinterval > wd_current_uploads) {
			wi_lock_lock(wd_status_lock);
			wd_uploads_traffic += statsbytes;
			wd_write_status(false);
			wi_lock_unlock(wd_status_lock);

			statsbytes = 0;
			statusinterval = interval;
		}
		
		/* update account */
		if(interval - accountinterval > 15.0) {
			account = wd_user_account(transfer->user);
			accountinterval = interval;
		}
		
		wi_pool_drain(pool);
	}

	wi_log_info(WI_STR("Received %@/%@ (%llu/%llu bytes) of \"%@\" from %@"),
		wd_files_string_for_bytes(transfer->transferred - transfer->offset),
		wd_files_string_for_bytes(transfer->size - transfer->offset),
		transfer->transferred - transfer->offset,
		transfer->size - transfer->offset,
		transfer->path,
		wd_user_identifier(transfer->user));

	/* update status */
	wd_transfer_set_state(transfer, WD_TRANSFER_STOPPED);
	
	wi_lock_lock(wd_status_lock);
	wd_current_uploads--;
	wd_uploads_traffic += statsbytes;
	wd_write_status(true);
	wi_lock_unlock(wd_status_lock);

	if(transfer->transferred == transfer->size) {
		path = wi_string_by_deleting_path_extension(transfer->realpath);

		if(wi_fs_rename_path(transfer->realpath, path)) {
			path = wi_string_by_appending_path_extension(transfer->path, WI_STR(WD_TRANSFERS_PARTIAL_EXTENSION));

			wd_files_move_comment(path, transfer->path);
		} else {
			wi_log_warn(WI_STR("Could not move %@ to %@: %m"),
				transfer->realpath, path);
		}
	}

	wi_release(pool);
}
예제 #9
0
static wi_boolean_t wd_transfer_download(wd_transfer_t *transfer) {
	wi_pool_t				*pool;
	wi_socket_t				*socket;
	wi_p7_socket_t			*p7_socket;
	wd_account_t			*account;
	char					buffer[WD_TRANSFER_BUFFER_SIZE];
	wi_socket_state_t		state;
	wi_time_interval_t		timeout, interval, speedinterval, statusinterval, accountinterval;
	wi_file_offset_t		sendbytes, speedbytes, statsbytes;
	wi_uinteger_t			i, transfers;
	ssize_t					readbytes;
	int						sd;
	wi_boolean_t			data, result;
	wd_user_state_t			user_state;
	
	interval				= wi_time_interval();
	speedinterval			= interval;
	statusinterval			= interval;
	accountinterval			= interval;
	speedbytes				= 0;
	statsbytes				= 0;
	i						= 0;
	socket					= wd_user_socket(transfer->user);
	sd						= wi_socket_descriptor(socket);
	p7_socket				= wd_user_p7_socket(transfer->user);
	account					= wd_user_account(transfer->user);
	data					= true;
	result					= true;
	
	wd_transfers_note_statistics(WD_TRANSFER_DOWNLOAD, WD_TRANSFER_STATISTICS_ADD, 0);
	
	wi_dictionary_rdlock(wd_transfers_user_downloads);
	
	transfers = (wi_integer_t) wi_dictionary_data_for_key(wd_transfers_user_downloads, transfer->key);
	
	wi_dictionary_unlock(wd_transfers_user_downloads);

	pool = wi_pool_init(wi_pool_alloc());
	
	wd_user_lock_socket(transfer->user);
	
	while(wd_user_state(transfer->user) == WD_USER_LOGGED_IN) {
		if(data && transfer->remainingdatasize == 0)
			data = false;
			  
		if(!data && transfer->remainingrsrcsize == 0)
			break;
		
		readbytes = read(data ? transfer->datafd : transfer->rsrcfd, buffer, sizeof(buffer));
		
		if(readbytes <= 0) {
			if(readbytes < 0) {
				wi_log_error(WI_STR("Could not read download from \"%@\": %m"),
					data ? transfer->realdatapath : transfer->realrsrcpath, strerror(errno));
			}
			
			result = false;
			break;
		}

		timeout = wi_time_interval();
		
		do {
			user_state		= wd_user_state(transfer->user);
			state			= wi_socket_wait_descriptor(sd, 0.1, false, true);
			
			if(state == WI_SOCKET_TIMEOUT) {
				if(wi_time_interval() - timeout >= 30.0)
					break;
			}
		} while(state == WI_SOCKET_TIMEOUT && user_state == WD_USER_LOGGED_IN);

		if(state == WI_SOCKET_ERROR || wi_time_interval() - timeout >= 30.0) {
			wi_log_error(WI_STR("Could not wait for download to %@: %@"),
				wd_user_identifier(transfer->user),
				(state == WI_SOCKET_ERROR) ? wi_error_string() : WI_STR("Timed out"));
			
			result = false;
			break;
		}
		
		if(user_state != WD_USER_LOGGED_IN) {
			result = false;
			break;
		}

		if(data) {
			sendbytes = (transfer->remainingdatasize < (wi_file_offset_t) readbytes)
				? transfer->remainingdatasize
				: (wi_file_offset_t) readbytes;
		} else {
			sendbytes = (transfer->remainingrsrcsize < (wi_file_offset_t) readbytes)
				? transfer->remainingrsrcsize
				: (wi_file_offset_t) readbytes;
		}
		
		if(!wi_p7_socket_write_oobdata(p7_socket, 30.0, buffer, sendbytes)) {
			wi_log_error(WI_STR("Could not write download to %@: %m"),
				wd_user_identifier(transfer->user));
			
			result = false;
			break;
		}
		
		if(data)
			transfer->remainingdatasize		-= sendbytes;
		else
			transfer->remainingrsrcsize		-= sendbytes;
		
		interval							= wi_time_interval();
		transfer->transferred				+= sendbytes;
		transfer->actualtransferred			+= sendbytes;
		speedbytes							+= sendbytes;
		statsbytes							+= sendbytes;
		transfer->speed						= speedbytes / (interval - speedinterval);

		wd_transfer_limit_speed(transfer,
								wd_transfers_total_download_speed,
								wd_account_transfer_download_speed_limit(account),
								wd_current_downloads,
								transfers,
								speedbytes,
								interval,
								speedinterval);
		
		if(interval - speedinterval > 30.0) {
			speedbytes = 0;
			speedinterval = interval;
		}

		if(interval - statusinterval > wd_current_downloads) {
			wd_transfers_note_statistics(WD_TRANSFER_DOWNLOAD, WD_TRANSFER_STATISTICS_DATA, statsbytes);

			statsbytes = 0;
			statusinterval = interval;
		}
		
		if(interval - accountinterval > 15.0) {
			account = wd_user_account(transfer->user);
			accountinterval = interval;

			wi_dictionary_rdlock(wd_transfers_user_downloads);
			
			transfers = (wi_integer_t) wi_dictionary_data_for_key(wd_transfers_user_downloads, transfer->key);
			
			wi_dictionary_unlock(wd_transfers_user_downloads);
		}
		
		if(++i % 1000 == 0)
			wi_pool_drain(pool);
	}
	
	wd_user_unlock_socket(transfer->user);
	
	wi_release(pool);

	wd_transfers_note_statistics(WD_TRANSFER_DOWNLOAD, WD_TRANSFER_STATISTICS_REMOVE, statsbytes);
	
	return result;
}
예제 #10
0
wi_boolean_t wi_socket_connect(wi_socket_t *socket, wi_socket_context_t *context, wi_time_interval_t timeout) {
	struct sockaddr		*sa;
	uint32_t			length;
	int					state, err;
#ifdef WI_SSL
	int					ret;
#endif
	wi_boolean_t		blocking;
	
	blocking = wi_socket_blocking(socket);

	if(blocking)
		wi_socket_set_blocking(socket, false);
	
	sa		= wi_address_sa(socket->address);
	length	= wi_address_sa_length(socket->address);

	err		= connect(socket->sd, sa, length);
	
	if(err < 0) {
		if(errno != EINPROGRESS) {
			wi_error_set_errno(errno);
			
			return false;
		}
		
		do {
			state = wi_socket_wait_descriptor(socket->sd, 1.0, true, true);
			timeout -= 1.0;
		} while(state == 0 && timeout >= 0.0);
		
		if(state < 0)
			return false;
		
		if(timeout <= 0.0) {
			wi_error_set_errno(ETIMEDOUT);
			
			return false;
		}
		
		err = wi_socket_error(socket);
		
		if(err != 0) {
			wi_error_set_errno(err);
			
			return false;
		}
	}

#ifdef WI_SSL
	if(context && context->ssl_ctx) {
		socket->ssl = SSL_new(context->ssl_ctx);
		
		if(!socket->ssl) {
			wi_error_set_ssl_error();
			
			return false;
		}
		
		if(SSL_set_fd(socket->ssl, socket->sd) != 1) {
			wi_error_set_ssl_error();

			return false;
		}
		
		ret = SSL_connect(socket->ssl);
		
		if(ret != 1) {
			do {
				err = SSL_get_error(socket->ssl, ret);

				if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
					wi_error_set_ssl_error();
					
					return false;
				}
				
				state = wi_socket_wait_descriptor(socket->sd, 1.0, (err == SSL_ERROR_WANT_READ), (err == SSL_ERROR_WANT_WRITE));
				
				if(state < 0)
					break;
				
				if(state > 0) {
					ret = SSL_connect(socket->ssl);
					
					if(ret == 1)
						break;
				}
				
				timeout -= 1.0;
			} while(timeout >= 0.0);
			
			if(state < 0)
				return false;
			
			if(timeout <= 0.0) {
				wi_error_set_errno(ETIMEDOUT);
				
				return false;
			}
		}
	}
#endif

	if(blocking)
		wi_socket_set_blocking(socket, true);

	socket->direction = WI_SOCKET_READ;
	
	return true;
}
예제 #11
0
wi_boolean_t wi_socket_wait(wi_socket_t *socket, wi_time_interval_t timeout) {
	return wi_socket_wait_descriptor(socket->sd,
									 timeout,
									 (socket->direction & WI_SOCKET_READ),
									 (socket->direction & WI_SOCKET_WRITE));
}
예제 #12
0
wi_socket_t * wi_socket_accept(wi_socket_t *accept_socket, wi_socket_context_t *context, wi_time_interval_t timeout, wi_address_t **address) {
	wi_socket_t					*socket;
#ifdef WI_SSL
	SSL							*ssl = NULL;
#endif
	struct sockaddr_storage		ss;
	socklen_t					length;
	int							sd;
	
	length = sizeof(ss);
	sd = accept(accept_socket->sd, (struct sockaddr *) &ss, &length);
	
	*address = (length > 0) ? wi_autorelease(wi_address_init_with_sa(wi_address_alloc(), (struct sockaddr *) &ss)) : NULL;

	if(sd < 0) {
		wi_error_set_errno(errno);
		
		goto err;
	}
	
#ifdef WI_SSL
	if(context && context->ssl_ctx) {
		ssl = SSL_new(context->ssl_ctx);

		if(!ssl) {
			wi_error_set_ssl_error();
			
			goto err;
		}

		if(SSL_set_fd(ssl, sd) != 1) {
			wi_error_set_ssl_error();
			
			goto err;
		}

		if(!context->certificate && context->dh) {
			if(SSL_set_tmp_dh(ssl, context->dh) != 1) {
				wi_error_set_ssl_error();
				
				goto err;
			}
		}
		
		if(timeout > 0.0) {
			if(wi_socket_wait_descriptor(sd, timeout, true, false) <= 0)
				goto err;
		}

		if(SSL_accept(ssl) != 1) {
			wi_error_set_ssl_error();
			
			goto err;
		}
	}
#endif

	socket = wi_socket_init_with_descriptor(wi_socket_alloc(), sd);

	socket->close		= true;
	socket->address		= wi_retain(*address);
	socket->type		= accept_socket->type;
	socket->direction	= WI_SOCKET_READ;
	socket->interactive	= accept_socket->interactive;

#ifdef WI_SSL
	socket->ssl			= ssl;
#endif
	
	return wi_autorelease(socket);
	
err:
#ifdef WI_SSL
	if(ssl)
		SSL_free(ssl);
#endif

	if(sd >= 0)
		close(sd);

	return NULL;
}
예제 #13
0
wi_integer_t wi_socket_read_buffer(wi_socket_t *socket, wi_time_interval_t timeout, void *buffer, size_t length) {
#ifdef HAVE_OPENSSL_SSL_H
	wi_socket_state_t	state;
#endif
	wi_uinteger_t		offset;
	wi_integer_t		bytes;
	
	WI_ASSERT(buffer != NULL, "buffer of length %u should not be NULL", length);
	WI_ASSERT(socket->sd >= 0, "socket %@ should be valid", socket);
	
#ifdef HAVE_OPENSSL_SSL_H
	if(socket->ssl) {
		while(true) {
			if(timeout > 0.0 && SSL_pending(socket->ssl) == 0) {
				state = wi_socket_wait_descriptor(socket->sd, timeout, true, false);

				if(state != WI_SOCKET_READY) {
					if(state == WI_SOCKET_TIMEOUT)
						wi_error_set_errno(ETIMEDOUT);
					
					return -1;
				}
			}
			
			ERR_clear_error();
			
			bytes = SSL_read(socket->ssl, buffer, length);
			
			if(bytes > 0) {
				break;
			} else {
				if(bytes < 0 && SSL_get_error(socket->ssl, bytes) == SSL_ERROR_WANT_READ)
					continue;

				wi_error_set_openssl_ssl_error_with_result(socket->ssl, bytes);
				
				break;
			}
		}
		
		ERR_clear_error();
		
		return bytes;
	} else {
#endif
		offset = 0;
		
		while(offset < length) {
			bytes = _wi_socket_read_buffer(socket, timeout, buffer + offset, length - offset);
			
			if(bytes <= 0)
				return -1;
			
			offset += bytes;
		}
		
		return offset;
#ifdef HAVE_OPENSSL_SSL_H
	}
#endif

	return 0;
}