545 lines
15 KiB
C++
545 lines
15 KiB
C++
|
/*
|
||
|
GSport - an Apple //gs Emulator
|
||
|
Copyright (C) 2010 - 2012 by GSport contributors
|
||
|
|
||
|
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify it
|
||
|
under the terms of the GNU General Public License as published by the
|
||
|
Free Software Foundation; either version 2 of the License, or (at your
|
||
|
option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful, but
|
||
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
|
for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License along
|
||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
/* This file contains the socket calls */
|
||
|
|
||
|
#include "StdAfx.h"
|
||
|
#include "GenericSocketDriver.h"
|
||
|
#include "Log.h"
|
||
|
|
||
|
#ifndef MIN
|
||
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||
|
#endif
|
||
|
|
||
|
#define printf_ENABLED 1
|
||
|
|
||
|
#define fatal_printf(...)
|
||
|
|
||
|
#if !(defined _MSC_VER || defined __CYGWIN__)
|
||
|
extern int h_errno;
|
||
|
#if printf_ENABLED
|
||
|
#else
|
||
|
#define printf(...)
|
||
|
#endif
|
||
|
#else
|
||
|
#define socklen_t int
|
||
|
#if printf_ENABLED
|
||
|
#define printf LogOutput
|
||
|
#else
|
||
|
#define printf(...)
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
int g_wsastartup_called;
|
||
|
|
||
|
void
|
||
|
socket_init_connection(SocketInfo *parent_socket_info_ptr, SocketInfo *socket_info_ptr)
|
||
|
{
|
||
|
socket_info_ptr->host_handle = NULL;
|
||
|
socket_info_ptr->sockfd = -1; /* Indicate no socket open yet */
|
||
|
socket_info_ptr->rdwrfd = -1; /* Indicate no socket open yet */
|
||
|
socket_info_ptr->host_addrlen = sizeof(struct sockaddr_in);
|
||
|
socket_info_ptr->host_handle = malloc(socket_info_ptr->host_addrlen); /* Used in accept, freed in shutdown */
|
||
|
/* Real init will be done when bytes need to be read/write from skt */
|
||
|
|
||
|
socket_info_ptr->root_connection = parent_socket_info_ptr->root_connection;
|
||
|
socket_info_ptr->next_connection = NULL;
|
||
|
socket_info_ptr->connection_number = parent_socket_info_ptr->connection_number + 1;
|
||
|
|
||
|
socket_info_ptr->in_rdptr = 0;
|
||
|
socket_info_ptr->in_wrptr = 0;
|
||
|
socket_info_ptr->out_rdptr = 0;
|
||
|
socket_info_ptr->out_wrptr = 0;
|
||
|
}
|
||
|
|
||
|
/* Usage: socket_init() called to init socket mode */
|
||
|
/* At all times, we try to have a listen running on the incoming socket */
|
||
|
/* If we want to dial out, we close the incoming socket and create a new */
|
||
|
/* outgoing socket. Any hang-up causes the socket to be closed and it will */
|
||
|
/* then re-open on a subsequent call to scc_socket_open */
|
||
|
|
||
|
void
|
||
|
socket_init(SocketInfo *socket_info_ptr)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
WSADATA wsadata;
|
||
|
int ret;
|
||
|
|
||
|
if (g_wsastartup_called == 0) {
|
||
|
ret = WSAStartup(MAKEWORD(2, 0), &wsadata);
|
||
|
printf("WSAStartup ret: %d\n", ret);
|
||
|
g_wsastartup_called = 1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
socket_info_ptr->root_connection = socket_info_ptr;
|
||
|
socket_init_connection(socket_info_ptr, socket_info_ptr);
|
||
|
socket_info_ptr->connection_count = 0;
|
||
|
socket_info_ptr->connection_number = 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_shutdown(SocketInfo *socket_info_ptr)
|
||
|
{
|
||
|
if (socket_info_ptr->next_connection) {
|
||
|
socket_shutdown(socket_info_ptr->next_connection); // recursively clean up
|
||
|
free(socket_info_ptr->next_connection);
|
||
|
socket_info_ptr->next_connection = NULL;
|
||
|
}
|
||
|
|
||
|
socket_close(socket_info_ptr, 0);
|
||
|
free(socket_info_ptr->host_handle);
|
||
|
socket_info_ptr->host_handle = NULL;
|
||
|
}
|
||
|
|
||
|
SocketInfo *
|
||
|
socket_create_connection(SocketInfo *parent_socket_info_ptr)
|
||
|
{
|
||
|
SocketInfo *root_socket_info_ptr = parent_socket_info_ptr->root_connection;
|
||
|
SocketInfo *new_socket_info_ptr = root_socket_info_ptr;
|
||
|
|
||
|
if (root_socket_info_ptr->connection_count >= root_socket_info_ptr->max_connections)
|
||
|
return NULL;
|
||
|
|
||
|
new_socket_info_ptr = (SocketInfo *)malloc(sizeof(SocketInfo));
|
||
|
socket_init_connection(parent_socket_info_ptr, new_socket_info_ptr);
|
||
|
parent_socket_info_ptr->next_connection = new_socket_info_ptr;
|
||
|
return new_socket_info_ptr;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_add_new_inbound_connection(SocketInfo *socket_info_ptr, double dcycs, int rdwrfd)
|
||
|
{
|
||
|
SocketInfo *root_socket_info_ptr = socket_info_ptr->root_connection;
|
||
|
SocketInfo *new_socket_info_ptr = root_socket_info_ptr;
|
||
|
|
||
|
do {
|
||
|
if (new_socket_info_ptr->rdwrfd == -1) {
|
||
|
new_socket_info_ptr->rdwrfd = rdwrfd;
|
||
|
root_socket_info_ptr->connection_count += 1;
|
||
|
printf("%s #%d connected on rdwrfd=%d\n", root_socket_info_ptr->device_name, new_socket_info_ptr->connection_number, rdwrfd);
|
||
|
socket_recvd_char(socket_info_ptr, -1, dcycs); // reset buffer
|
||
|
return;
|
||
|
}
|
||
|
if (new_socket_info_ptr->next_connection)
|
||
|
new_socket_info_ptr = new_socket_info_ptr->next_connection;
|
||
|
else
|
||
|
new_socket_info_ptr = socket_create_connection(new_socket_info_ptr);
|
||
|
} while (new_socket_info_ptr);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
socket_close_handle(SOCKET sockfd)
|
||
|
{
|
||
|
if (sockfd != -1)
|
||
|
{
|
||
|
#if defined(_WIN32) || defined (__OS2__)
|
||
|
return closesocket(sockfd); // NW: a Windows socket handle is not a file descriptor
|
||
|
#else
|
||
|
return close(sockfd);
|
||
|
#endif
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_maybe_open_incoming(SocketInfo *socket_info_ptr, double dcycs)
|
||
|
{
|
||
|
struct sockaddr_in sa_in;
|
||
|
int on;
|
||
|
int ret;
|
||
|
SOCKET sockfd;
|
||
|
int inc;
|
||
|
|
||
|
inc = 0;
|
||
|
|
||
|
if(socket_info_ptr->sockfd != -1) {
|
||
|
/* it's already open, get out */
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (socket_info_ptr-> listen_tries == 0) {
|
||
|
return; // too many retries
|
||
|
}
|
||
|
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
memset(socket_info_ptr->host_handle, 0, socket_info_ptr->host_addrlen);
|
||
|
|
||
|
while(1) {
|
||
|
sockfd = socket(AF_INET, (socket_info_ptr->udp) ? SOCK_DGRAM : SOCK_STREAM, 0);
|
||
|
if(sockfd == -1) {
|
||
|
printf("socket ret: %d, errno: %d\n", sockfd, errno);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
printf("%s opened %s socket ret: %d\n", socket_info_ptr->device_name, (socket_info_ptr->udp) ? "UDP" : "TCP", sockfd);
|
||
|
|
||
|
on = 1;
|
||
|
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||
|
(char *)&on, sizeof(on));
|
||
|
if(ret < 0) {
|
||
|
printf("setsockopt REUSEADDR ret: %d, err:%d\n",
|
||
|
ret, errno);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
memset(&sa_in, 0, sizeof(sa_in));
|
||
|
sa_in.sin_family = AF_INET;
|
||
|
sa_in.sin_port = htons(socket_info_ptr->listen_port);
|
||
|
sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||
|
|
||
|
ret = bind(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in));
|
||
|
|
||
|
if(ret >= 0) {
|
||
|
if (!socket_info_ptr->udp) {
|
||
|
ret = listen(sockfd, 1);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
/* else ret to bind was < 0 */
|
||
|
printf("bind ret: %d, errno: %d\n", ret, errno);
|
||
|
printf("%s failed to listen on TCP port %d\n", socket_info_ptr->device_name, socket_info_ptr->listen_port);
|
||
|
//inc++;
|
||
|
socket_close_handle(sockfd);
|
||
|
// TODO: add port increment as an option?
|
||
|
//printf("Trying next port: %d\n", SCC_LISTEN_PORT + port);
|
||
|
//if(inc >= 10) {
|
||
|
//printf("Too many retries, quitting\n");
|
||
|
if (socket_info_ptr->listen_tries > 0)
|
||
|
--socket_info_ptr->listen_tries;
|
||
|
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
//}
|
||
|
}
|
||
|
|
||
|
printf("%s listening on port %d\n", socket_info_ptr->device_name, socket_info_ptr->listen_port);
|
||
|
socket_info_ptr->sockfd = sockfd;
|
||
|
socket_make_nonblock(socket_info_ptr, dcycs);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_open_outgoing(SocketInfo *socket_info_ptr, double dcycs)
|
||
|
{
|
||
|
struct sockaddr_in sa_in;
|
||
|
struct hostent *hostentptr;
|
||
|
int on;
|
||
|
int ret;
|
||
|
SOCKET sockfd;
|
||
|
|
||
|
//printf("socket_close being called from socket_open_outgoing\n");
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
|
||
|
memset(socket_info_ptr->host_handle, 0, socket_info_ptr->host_addrlen);
|
||
|
|
||
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||
|
if(sockfd == -1) {
|
||
|
printf("%s failed to open outgoing socket ret: %d, errno: %d\n", socket_info_ptr->device_name, sockfd, errno);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
printf("%s opened outgoing sockfd ret: %d\n", socket_info_ptr->device_name, sockfd);
|
||
|
|
||
|
on = 1;
|
||
|
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
||
|
(char *)&on, sizeof(on));
|
||
|
if(ret < 0) {
|
||
|
printf("setsockopt REUSEADDR ret: %d, err:%d\n",
|
||
|
ret, errno);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
memset(&sa_in, 0, sizeof(sa_in));
|
||
|
sa_in.sin_family = AF_INET;
|
||
|
sa_in.sin_port = htons(23);
|
||
|
hostentptr = gethostbyname((const char*)&socket_info_ptr->hostname[0]); // OG Added Cast
|
||
|
if(hostentptr == 0) {
|
||
|
#if defined(_WIN32) || defined (__OS2__)
|
||
|
fatal_printf("Lookup host %s failed\n",
|
||
|
&socket_info_ptr->hostname[0]);
|
||
|
#else
|
||
|
fatal_printf("Lookup host %s failed, herrno: %d\n",
|
||
|
&socket_info_ptr->hostname[0], h_errno);
|
||
|
#endif
|
||
|
socket_close_handle(sockfd);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
//x_show_alert(0, 0);
|
||
|
return;
|
||
|
}
|
||
|
memcpy(&sa_in.sin_addr.s_addr, hostentptr->h_addr,
|
||
|
hostentptr->h_length);
|
||
|
/* The above copies the 32-bit internet address into */
|
||
|
/* sin_addr.s_addr. It's in correct network format */
|
||
|
|
||
|
ret = connect(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in));
|
||
|
if(ret < 0) {
|
||
|
printf("connect ret: %d, errno: %d\n", ret, errno);
|
||
|
socket_close_handle(sockfd);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
printf("%s socket is now outgoing to %s\n", socket_info_ptr->device_name, &socket_info_ptr->hostname[0]);
|
||
|
socket_info_ptr->sockfd = sockfd;
|
||
|
socket_make_nonblock(socket_info_ptr, dcycs);
|
||
|
socket_info_ptr->rdwrfd = socket_info_ptr->sockfd;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_make_nonblock(SocketInfo *socket_info_ptr, double dcycs)
|
||
|
{
|
||
|
SOCKET sockfd;
|
||
|
int ret;
|
||
|
#if defined(_WIN32) || defined (__OS2__)
|
||
|
u_long flags;
|
||
|
#else
|
||
|
int flags;
|
||
|
#endif
|
||
|
|
||
|
sockfd = socket_info_ptr->sockfd;
|
||
|
|
||
|
#if defined(_WIN32) || defined (__OS2__)
|
||
|
flags = 1;
|
||
|
ret = ioctlsocket(sockfd, FIONBIO, &flags);
|
||
|
if(ret != 0) {
|
||
|
printf("ioctlsocket ret: %d\n", ret);
|
||
|
}
|
||
|
#else
|
||
|
flags = fcntl(sockfd, F_GETFL, 0);
|
||
|
if(flags == -1) {
|
||
|
printf("fcntl GETFL ret: %d, errno: %d\n", flags, errno);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
|
||
|
if(ret == -1) {
|
||
|
printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_close(SocketInfo *socket_info_ptr, double dcycs)
|
||
|
{
|
||
|
int rdwrfd;
|
||
|
SOCKET sockfd;
|
||
|
|
||
|
rdwrfd = socket_info_ptr->rdwrfd;
|
||
|
if(rdwrfd >= 0) {
|
||
|
printf("socket_close: rdwrfd=%d, closing\n", rdwrfd);
|
||
|
socket_close_handle(rdwrfd);
|
||
|
socket_recvd_char(socket_info_ptr, -1, dcycs); // reset buffer
|
||
|
socket_info_ptr->root_connection->connection_count -= 1;
|
||
|
}
|
||
|
sockfd = socket_info_ptr->sockfd;
|
||
|
if(sockfd != -1) {
|
||
|
printf("socket_close: sockfd=%d, closing\n", sockfd);
|
||
|
socket_close_handle(sockfd);
|
||
|
}
|
||
|
|
||
|
socket_info_ptr->rdwrfd = -1;
|
||
|
socket_info_ptr->sockfd = -1;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_accept(SocketInfo *socket_info_ptr, double dcycs)
|
||
|
{
|
||
|
#ifdef SOCKET_INFO
|
||
|
int flags;
|
||
|
int rdwrfd;
|
||
|
int ret;
|
||
|
|
||
|
if(socket_info_ptr->sockfd == -1) {
|
||
|
socket_maybe_open_incoming(socket_info_ptr, dcycs);
|
||
|
}
|
||
|
if(socket_info_ptr->sockfd == -1 || socket_info_ptr->udp) {
|
||
|
return; /* just give up */
|
||
|
}
|
||
|
if((socket_info_ptr->rdwrfd == -1) || (socket_info_ptr->connection_count < socket_info_ptr->max_connections)) {
|
||
|
rdwrfd = accept(socket_info_ptr->sockfd, (struct sockaddr*)socket_info_ptr->host_handle,
|
||
|
(socklen_t*)&(socket_info_ptr->host_addrlen));
|
||
|
if(rdwrfd < 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
flags = 0;
|
||
|
ret = 0;
|
||
|
#if !defined(_WIN32) && !defined(__OS2__)
|
||
|
/* For Linux, we need to set O_NONBLOCK on the rdwrfd */
|
||
|
flags = fcntl(rdwrfd, F_GETFL, 0);
|
||
|
if(flags == -1) {
|
||
|
printf("fcntl GETFL ret: %d, errno: %d\n", flags,errno);
|
||
|
return;
|
||
|
}
|
||
|
ret = fcntl(rdwrfd, F_SETFL, flags | O_NONBLOCK);
|
||
|
if(ret == -1) {
|
||
|
printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno);
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
socket_add_new_inbound_connection(socket_info_ptr, dcycs, rdwrfd);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static byte tmp_buf[256]; // used for receiving bytes in socket_fill_readbuf
|
||
|
|
||
|
void
|
||
|
socket_fill_readbuf(SocketInfo *socket_info_ptr, int space_left, double dcycs)
|
||
|
{
|
||
|
#ifdef SOCKET_INFO
|
||
|
int rdwrfd;
|
||
|
int ret;
|
||
|
int i;
|
||
|
|
||
|
socket_accept(socket_info_ptr, dcycs);
|
||
|
|
||
|
do
|
||
|
{
|
||
|
rdwrfd = (socket_info_ptr->udp) ? socket_info_ptr->sockfd : socket_info_ptr->rdwrfd;
|
||
|
if (rdwrfd >= 0) {
|
||
|
/* Try reading some bytes */
|
||
|
space_left = MIN(space_left, sizeof(tmp_buf));
|
||
|
if (socket_info_ptr->udp)
|
||
|
ret = recvfrom(rdwrfd, (char*)tmp_buf, space_left, 0, NULL, NULL);
|
||
|
else
|
||
|
ret = recv(rdwrfd, (char*)tmp_buf, space_left, 0); // OG Added cast
|
||
|
if (ret > 0) {
|
||
|
for (i = 0; i < ret; i++) {
|
||
|
byte c = tmp_buf[i];
|
||
|
socket_recvd_char(socket_info_ptr, c, dcycs);
|
||
|
}
|
||
|
}
|
||
|
else if (ret == 0) {
|
||
|
/* assume socket close */
|
||
|
printf("%s disconnecting from rdwrfd=%d (recv got 0)\n", socket_info_ptr->root_connection->device_name, rdwrfd);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
}
|
||
|
}
|
||
|
socket_info_ptr = socket_info_ptr->next_connection;
|
||
|
} while (socket_info_ptr);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_recvd_char(SocketInfo *socket_info_ptr, int c, double dcycs)
|
||
|
{
|
||
|
int handled_externally = 0; // TODO: would prefer bool or BOOL, but not sure about non-Windows builds
|
||
|
|
||
|
// NOTE: c might be -1 as a signal to clear the buffers (eg from socket_close)
|
||
|
// TODO: should we add if(socket_info_ptr->sockfd == -1) {
|
||
|
//socket_maybe_open_incoming(socket_info_ptr, dcycs); // TODO: would prefer not to do this for every character!
|
||
|
|
||
|
if (socket_info_ptr->root_connection->rx_handler != NULL) {
|
||
|
handled_externally = socket_info_ptr->root_connection->rx_handler(socket_info_ptr, c);
|
||
|
}
|
||
|
if (!handled_externally) {
|
||
|
// we handle this
|
||
|
// TODO: implement the read buffer
|
||
|
//scc_add_to_readbuf(port, c, dcycs);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
socket_empty_writebuf(SocketInfo *socket_info_ptr, double dcycs)
|
||
|
{
|
||
|
#ifdef SOCKET_INFO
|
||
|
# if !defined(_WIN32) && !defined(__OS2__)
|
||
|
struct sigaction newact, oldact;
|
||
|
# endif
|
||
|
int rdptr;
|
||
|
int wrptr;
|
||
|
int rdwrfd;
|
||
|
int done;
|
||
|
int ret;
|
||
|
int len;
|
||
|
|
||
|
/* Try writing some bytes */
|
||
|
done = 0;
|
||
|
while(!done) {
|
||
|
rdptr = socket_info_ptr->out_rdptr;
|
||
|
wrptr = socket_info_ptr->out_wrptr;
|
||
|
if(rdptr == wrptr) {
|
||
|
done = 1;
|
||
|
break;
|
||
|
}
|
||
|
rdwrfd = socket_info_ptr->rdwrfd;
|
||
|
len = wrptr - rdptr;
|
||
|
if(len < 0) {
|
||
|
len = SOCKET_OUTBUF_SIZE - rdptr;
|
||
|
}
|
||
|
if(len > 32) {
|
||
|
len = 32;
|
||
|
}
|
||
|
if(len <= 0) {
|
||
|
done = 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(rdwrfd == -1) {
|
||
|
socket_maybe_open_incoming(socket_info_ptr, dcycs);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if defined(_WIN32) || defined (__OS2__)
|
||
|
ret = send(rdwrfd, (const char*)&(socket_info_ptr->out_buf[rdptr]), len, 0); // OG Added Cast
|
||
|
# else
|
||
|
/* ignore SIGPIPE around writes to the socket, so we */
|
||
|
/* can catch a closed socket and prepare to accept */
|
||
|
/* a new connection. Otherwise, SIGPIPE kills GSport */
|
||
|
sigemptyset(&newact.sa_mask);
|
||
|
newact.sa_handler = SIG_IGN;
|
||
|
newact.sa_flags = 0;
|
||
|
sigaction(SIGPIPE, &newact, &oldact);
|
||
|
|
||
|
ret = send(rdwrfd, &(socket_info_ptr->out_buf[rdptr]), len, 0);
|
||
|
|
||
|
sigaction(SIGPIPE, &oldact, 0);
|
||
|
/* restore previous SIGPIPE behavior */
|
||
|
# endif /* WIN32 */
|
||
|
|
||
|
#if 0
|
||
|
printf("sock output: %02x\n", socket_info_ptr->out_buf[rdptr]);
|
||
|
#endif
|
||
|
if(ret == 0) {
|
||
|
done = 1; /* give up for now */
|
||
|
break;
|
||
|
} else if(ret < 0) {
|
||
|
/* assume socket is dead */
|
||
|
printf("socket write failed on rdwrfd=%d, closing\n", rdwrfd);
|
||
|
socket_close(socket_info_ptr, dcycs);
|
||
|
done = 1;
|
||
|
break;
|
||
|
} else {
|
||
|
rdptr = rdptr + ret;
|
||
|
if(rdptr >= SOCKET_OUTBUF_SIZE) {
|
||
|
rdptr = rdptr - SOCKET_OUTBUF_SIZE;
|
||
|
}
|
||
|
socket_info_ptr->out_rdptr = rdptr;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|