static int timeout_connect( int fd, const struct sockaddr *serv_addr, socklen_t addrlen ) { if( socket_connect( fd, serv_addr, addrlen) < 0 ) { if( errno != EINPROGRESS ) { return -1; } } if( wait_socket( fd, WAIT_WRITE ) <= 0 ) { if( errno == 0 ) { errno = ETIMEDOUT; } return -1; } /* Completed or failed */ int optval = 0; socklen_t optlen = sizeof(optval); /* casting &optval to char* is required for win32 */ if( getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen) == -1 ) { return -1; } if (optval != 0) { errno = optval; return -1; } return 0; }
static int send_header(tcp_con_t *con,const char *response){ int rc; size_t soc_remains; ssize_t send_len; char *wp; int buff_len; const char *peer_addr=NULL; struct sigaction saved_act; gchar *send_buffer = NULL; if ( (!con) || (!response) ) return -EINVAL; peer_addr = tcp_get_peeraddr(con); rc = ipmsg_convert_string_external(peer_addr, response, (const char **)&send_buffer); if (rc != 0) { ipmsg_err_dialog("%s\n", _("Can not convert header into external representation")); goto no_free_out; } soc_remains = strlen(send_buffer); if (wait_socket(con->soc, WAIT_FOR_WRITE, TCP_SELECT_SEC) < 0) { err_out("Can not send socket\n"); goto error_out; } wp=(char *)send_buffer; dbg_out("Send:%s(%d, %x)\n",wp,soc_remains,soc_remains); while(soc_remains>0) { disable_pipe_signal(&saved_act); send_len=send(con->soc,wp,soc_remains,0); enable_pipe_signal(&saved_act); if (send_len<0) { if (errno == EINTR) continue; rc=-errno; err_out("Error:%s (%d)\n",strerror(errno),errno); goto error_out; } wp += send_len; soc_remains -= send_len; dbg_out("soc remains:%d\n",soc_remains); } rc=0; error_out: if (send_buffer != NULL) g_free(send_buffer); no_free_out: return rc; }
static int tcp_ipmsg_finalize_connection(tcp_con_t *con){ int rc=0; char dummy[1]; g_assert(con); sock_set_buffer(con->soc, _TCP_BUF_MIN_SIZE, _TCP_BUF_SIZE); dbg_out("Wait for closing by peer.\n"); sock_set_recv_timeout(con->soc,TCP_CLOSE_WAIT_SEC); rc=wait_socket(con->soc,WAIT_FOR_READ,TCP_SELECT_SEC); if (rc<0) { dbg_out("OK timeout select :%s(%d)\n",strerror(errno),errno); return -errno; } memset(dummy, 0, sizeof(dummy)); rc=recv(con->soc, dummy,sizeof(dummy),0); /* 相手のクローズ検出 */ if (rc<0) dbg_out("OK timeout:%s(%d)\n",strerror(errno),errno); else rc=0; return rc; }
gpointer ipmsg_tcp_recv_thread(gpointer data){ ssize_t recv_len; size_t addr_len; int rc; tcp_con_t *con; char *recv_buf=NULL; int count=200; struct addrinfo *info; con=(tcp_con_t *)data; if (!con) { err_out("No connection recived\n"); g_assert(con); return NULL; } if (!(con->peer_info)) { err_out("Invalid connection recived\n"); g_assert(con->peer_info); return NULL; } rc=tcp_enable_keepalive(con); if (rc<0) return NULL; recv_buf=g_malloc(_MSG_BUF_SIZE); if (!recv_buf) return NULL; memset(recv_buf,0,_MSG_BUF_SIZE); while(1) { if (wait_socket(con->soc,WAIT_FOR_READ,TCP_SELECT_SEC)<0) { err_out("Can not send socket\n"); destroy_tcp_connection(con); goto error_out; }else{ read_retry: errno=0; memset(recv_buf, 0, sizeof(recv_buf)); info=con->peer_info; recv_len=recv(con->soc, recv_buf, _MSG_BUF_SIZE, MSG_PEEK); if (recv_len<=0) { if (errno==EINTR) goto read_retry; if (errno) err_out("Can not peek message %s(errno:%d)\n",strerror(errno),errno); destroy_tcp_connection(con); goto error_out; } dbg_out("tcp peek read:%d %s\n",recv_len,recv_buf); recv_len=recv(con->soc, recv_buf, recv_len, MSG_PEEK); dbg_out("tcp read:%d %s\n",recv_len,recv_buf); if (recv_len>0) { msg_data_t msg; request_msg_t req; char *path; off_t size; unsigned long ipmsg_fattr; recv_buf[recv_len-1]='\0'; memset(&req,0,sizeof(request_msg_t)); init_message_data(&msg); parse_message(NULL,&msg,recv_buf,recv_len); parse_request(&req,msg.message); rc=refer_attach_file(req.pkt_no,req.fileid,&ipmsg_fattr,(const char **)&path,&size); if (rc<0) { err_out("Can not find message:pktno %ld id : %d\n", req.pkt_no, req.fileid); close(con->soc); /* エラーとしてクローズする */ }else{ dbg_out("transfer:%s (%d)\n",path,size); switch(ipmsg_fattr) { case IPMSG_FILE_REGULAR: if (!tcp_transfer_file(con,path,size,0)) { tcp_ipmsg_finalize_connection(con); download_monitor_release_file(req.pkt_no,req.fileid); } break; case IPMSG_FILE_DIR: if (!tcp_transfer_dir(con,path)){ download_monitor_release_file(req.pkt_no,req.fileid); tcp_ipmsg_finalize_connection(con); } break; default: break; } release_message_data(&msg); g_free(path); break; } release_message_data(&msg); break; } } --count; if (!count) break; } if (con->peer_info) /* closeは相手側で行うので, destroy_tcp_connectionは呼び出せない * (Win版ipmsgの仕様). */ freeaddrinfo(con->peer_info); error_out: g_free(con); if (recv_buf) g_free(recv_buf); return NULL; }
static int tcp_transfer_file(tcp_con_t *con,const char *path,const off_t size, off_t offset){ int fd; int rc; char *buff = NULL; off_t read_len; off_t file_remains; off_t soc_remains; off_t write_len; off_t total_write; char *wp; struct sigaction saved_act; if ( (!con) || (!path) ) return -EINVAL; buff = g_malloc(TCP_FILE_BUFSIZ); if (buff == NULL) return -ENOMEM; fd=open(path,O_RDONLY); if (fd<0) return -errno; rc=lseek(fd, offset, SEEK_SET); if (rc<0) { rc=-errno; goto close_out; } total_write=0; file_remains=size; while(file_remains>0) { read_len=read(fd,buff,TCP_FILE_BUFSIZ); if (read_len<0) { rc=-errno; err_out("Can not read file %s %d\n",strerror(errno),errno); goto close_out; } file_remains -= read_len; soc_remains = read_len; wp = buff; if (wait_socket(con->soc,WAIT_FOR_WRITE,TCP_SELECT_SEC)<0) { err_out("Can not send socket\n"); goto close_out; } dbg_out("sock remains:%d\n",soc_remains); disable_pipe_signal(&saved_act); while(soc_remains > 0) { write_len = write(con->soc, wp, soc_remains); if (write_len<0) { if (errno==EINTR) continue; err_out("Can not send %s %d\n",strerror(errno),errno); enable_pipe_signal(&saved_act); goto close_out; } dbg_out("write len :%d\n",write_len); wp += write_len; total_write += write_len; soc_remains -= write_len; } enable_pipe_signal(&saved_act); dbg_out("transfer %s %d/%d(%d)\n",path,total_write,size,file_remains); } rc=0; close_out: close(fd); if (rc<0) dbg_out("Can not send file:%s %s %d\n",path,strerror(errno),errno); if (buff != NULL) g_free(buff); return rc; }
/** * Same as eConnect() except you may the specify address family here (default is * AF_UNSPEC). * We couldn't just add the new family arg to eConnect because the original one * is pure virtual declared in EClientSocketBase. Thanks C++ design crap ... */ bool EPosixClientSocket::eConnect2( const char *host, unsigned int port, int clientId, int family ) { // already connected? if( m_fd >= 0) { assert(false); // for now we don't allow that return true; } // initialize Winsock DLL (only for Windows) if ( !SocketsInit()) { // Does this set errno? getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), "Initializing Winsock DLL failed."); return false; } // use local machine if no host passed in if ( !( host && *host)) { host = "127.0.0.1"; } // starting to connect to server struct addrinfo *aitop; int s = resolveHost( host, port, family, &aitop ); if( s != 0 ) { SocketsDestroy(); const char *err; #ifdef HAVE_GETADDRINFO err = gai_strerror(s); #else err = "Invalid address, hostname resolving not supported."; #endif getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err ); return false; } int con_errno = 0; for( struct addrinfo *ai = aitop; ai != NULL; ai = ai->ai_next ) { // create socket m_fd = socket(ai->ai_family, ai->ai_socktype, 0); if( m_fd < 0) { con_errno = errno; continue; } /* Set socket O_NONBLOCK. If wanted we could handle errors (portability!) We could even make O_NONBLOCK optional. */ int sn = set_socket_nonblock( m_fd ); assert( sn == 0 ); // try to connect if( timeout_connect( m_fd, ai->ai_addr, ai->ai_addrlen ) < 0 ) { con_errno = errno; SocketClose(m_fd); m_fd = -1; continue; } /* successfully connected */ break; } freeaddrinfo(aitop); /* connection failed, tell the error which happened in our last try */ if( m_fd < 0 ) { const char *err = strerror(con_errno); SocketsDestroy(); getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err ); return false; } // set client id setClientId( clientId); errno = 0; onConnectBase(); if( !isOutBufferEmpty() ) { /* For now we consider it as error if it's not possible to send an integer string within a single tcp packet. Here we don't know weather ::send() really failed or not. If so then we hopefully still have it's errno set.*/ const char *err = (errno != 0) ? strerror(errno) : "Sending client id failed."; eDisconnect(); getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err ); return false; } if( wait_socket( m_fd, WAIT_READ ) <= 0 ) { const char *err = (errno != 0) ? strerror(errno) : strerror(ENODATA); eDisconnect(); getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err ); return false; } while( !isConnected() ) { assert( isSocketOK() ); // need to be handled if send() would destroy it if ( !checkMessagesConnect()) { const char *err = (errno != 0) ? strerror(errno) : "The remote host closed the connection."; eDisconnect(); getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err ); return false; } } // successfully connected return true; }
int as_tls_connect(as_socket* sock, uint64_t deadline) { int rv; #if defined(_MSC_VER) // Windows SSL_connect() will fail with SSL_ERROR_SYSCALL if non-blocking // socket has not completed TCP connect. Wait on socket before calling // SSL_connect() when on Windows. rv = wait_socket(sock->fd, 0, deadline, false); if (rv != 0) { as_log_warn("wait_writable failed: %d", rv); return rv; } #endif while (true) { rv = SSL_connect(sock->ssl); if (rv == 1) { log_session_info(sock); return 0; } int sslerr = SSL_get_error(sock->ssl, rv); unsigned long errcode; char errbuf[1024]; switch (sslerr) { case SSL_ERROR_WANT_READ: rv = wait_socket(sock->fd, 0, deadline, true); if (rv != 0) { as_log_warn("wait_readable failed: %d", rv); return rv; } // loop back around and retry break; case SSL_ERROR_WANT_WRITE: rv = wait_socket(sock->fd, 0, deadline, false); if (rv != 0) { as_log_warn("wait_writable failed: %d", rv); return rv; } // loop back around and retry break; case SSL_ERROR_SSL: log_verify_details(sock); errcode = ERR_get_error(); ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_log_warn("SSL_connect failed: %s", errbuf); return -1; case SSL_ERROR_SYSCALL: errcode = ERR_get_error(); if (errcode != 0) { ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_log_warn("SSL_connect I/O error: %s", errbuf); } else { if (rv == 0) { as_log_warn("SSL_connect I/O error: unexpected EOF"); } else { as_log_warn("SSL_connect I/O error: %d", as_last_error()); } } return -2; default: as_log_warn("SSL_connect: unexpected ssl error: %d", sslerr); return -3; break; } } }
int as_tls_write(as_socket* sock, void* bufp, size_t len, uint32_t socket_timeout, uint64_t deadline) { uint8_t* buf = (uint8_t *) bufp; size_t pos = 0; while (true) { int rv = SSL_write(sock->ssl, buf + pos, (int)(len - pos)); if (rv > 0) { pos += rv; if (pos >= len) { return 0; } } else /* if (rv <= 0) */ { int sslerr = SSL_get_error(sock->ssl, rv); unsigned long errcode; char errbuf[1024]; switch (sslerr) { case SSL_ERROR_WANT_READ: rv = wait_socket(sock->fd, socket_timeout, deadline, true); if (rv != 0) { return rv; } // loop back around and retry break; case SSL_ERROR_WANT_WRITE: rv = wait_socket(sock->fd, socket_timeout, deadline, false); if (rv != 0) { return rv; } // loop back around and retry break; case SSL_ERROR_SSL: log_verify_details(sock); errcode = ERR_get_error(); ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_log_warn("SSL_write failed: %s", errbuf); return -1; case SSL_ERROR_SYSCALL: errcode = ERR_get_error(); if (errcode != 0) { ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_log_warn("SSL_write I/O error: %s", errbuf); } else { if (rv == 0) { as_log_warn("SSL_write I/O error: unexpected EOF"); } else { as_log_warn("SSL_write I/O error: %d", as_last_error()); } } return -1; default: as_log_warn("SSL_write: unexpected ssl error: %d", sslerr); return -1; break; } } } }
int main( int argc, char ** argv ) { /* getopt_long stores the option index here. */ int option_index = 0; int port = 9999; const char * config_file = NULL; const char * startup_message = ""; int timeout = 60; unsigned width = 512; unsigned height = 64; int no_init = 0; while (1) { const int c = getopt_long( argc, argv, "vp:c:t:W:H:m:n", long_options, &option_index ); if (c == -1) break; switch (c) { case 'v': verbose++; break; case 'n': no_init++; break; case 'c': config_file = optarg; break; case 't': timeout = atoi(optarg); break; case 'W': width = atoi(optarg); break; case 'H': height = atoi(optarg); break; case 'm': startup_message = optarg; break; default: usage(); return -1; } } const int sock = udp_socket(port); if (sock < 0) die("socket port %d failed: %s\n", port, strerror(errno)); const size_t image_size = width * height * 3; const size_t buf_size = (width*height*4)/packets_per_frame + 1; // largest possible UDP packet uint8_t *buf = malloc(buf_size); #if 0 if (sizeof(buf) < image_size + 1) die("%u x %u too large for UDP\n", width, height); #endif fprintf(stderr, "%u x %u, UDP port %u\n", width, height, port); ledscape_config_t * config = &ledscape_matrix_default; if (config_file) { config = ledscape_config(config_file); if (!config) return EXIT_FAILURE; } if (config->type == LEDSCAPE_MATRIX) { config->matrix_config.width = width; config->matrix_config.height = height; } ledscape_t * const leds = ledscape_init(config, no_init); if (!leds) return EXIT_FAILURE; const unsigned report_interval = 10; unsigned last_report = 0; unsigned long delta_sum = 0; unsigned frames = 0; uint32_t * const fb = calloc(width*height,4); ledscape_printf(fb, width, 0xFF0000, "%s", startup_message); ledscape_printf(fb+16*width, width, 0x00FF00, "%dx%d UDP port %d", width, height, port); ledscape_draw(leds, fb); while (1) { int rc = wait_socket(sock, timeout*1000); if (rc < 0) { // something failed memset(fb, 0, width*height*4); ledscape_printf(fb, width, 0xFF0000, "read failed?"); ledscape_draw(leds, fb); exit(EXIT_FAILURE); } if (rc == 0) { // go into timeout mode memset(fb, 0, width*height*4); ledscape_printf(fb, width, 0xFF0000, "timeout"); ledscape_draw(leds, fb); continue; } const ssize_t rlen = recv(sock, buf, buf_size, 0); if (rlen < 0) die("recv failed: %s\n", strerror(errno)); warn_once("received %zu bytes\n", rlen); /* if (buf[0] == 2) { // image type printf("image type: %.*s\n", (int) rlen - 1, &buf[1] ); continue; } if (buf[0] != 1) { // What is it? warn_once("Unknown image type '%c' (%02x)\n", buf[0], buf[0] ); continue; } */ const unsigned frame_part = buf[0]; if (frame_part != 0 && frame_part != 1) { printf("bad type %d\n", frame_part); continue; } if ((size_t) rlen != image_size + 1) { warn_once("WARNING: Received packet %zu bytes, expected %zu\n", rlen, image_size + 1 ); } struct timeval start_tv, stop_tv, delta_tv; gettimeofday(&start_tv, NULL); const unsigned frame_num = 0; // copy the 3-byte values into the 4-byte framebuffer // and turn onto the side for (unsigned x = 0 ; x < width ; x++) // 256 { for (unsigned y = 0 ; y < 32 ; y++) // 64 { uint32_t * out = (void*) &fb[(y+32*frame_part)*width + x]; const uint8_t * const in = &buf[1 + 3*(y*width + x)]; uint32_t r = in[0]; uint32_t g = in[1]; uint32_t b = in[2]; *out = (r << 16) | (g << 8) | (b << 0); } } // only draw after the second frame if (frame_part == 1) ledscape_draw(leds, fb); gettimeofday(&stop_tv, NULL); timersub(&stop_tv, &start_tv, &delta_tv); frames++; delta_sum += delta_tv.tv_usec; if (stop_tv.tv_sec - last_report < report_interval) continue; last_report = stop_tv.tv_sec; const unsigned delta_avg = delta_sum / frames; printf("%6u usec avg, max %.2f fps, actual %.2f fps (over %u frames)\n", delta_avg, report_interval * 1.0e6 / delta_avg, frames * 1.0 / report_interval, frames ); frames = delta_sum = 0; } return 0; }