From 9118c391a73093b2b3589e06d4a3f6c1b5124ccf Mon Sep 17 00:00:00 2001 From: "munkyu.im" Date: Tue, 27 Sep 2011 20:31:09 +0900 Subject: [PATCH] [Title] implement port redirection for sdb // Summary [Type] Feature [Module] // Module Name - (Main / Sub) [Priority] Critical [CQ#] // CQ Issue Number [Redmine#] // Redmine Isuue Number [Problem] // Problem Description [Cause] // Cause Description [Solution] // Solution Description [TestCase] // Executed the test-target --- vl.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- vl.h | 95 +++++++++++++++++++++++++ 2 files changed, 346 insertions(+), 3 deletions(-) diff --git a/vl.c b/vl.c index d9a2a99..2d57eda 100644 --- a/vl.c +++ b/vl.c @@ -28,7 +28,6 @@ #include #include #include - /* Needed early for CONFIG_BSD etc. */ #include "config-host.h" @@ -47,6 +46,7 @@ #include #include #include + #ifdef CONFIG_SIMPLE_TRACE #include "trace.h" #endif @@ -84,6 +84,8 @@ #endif #endif + + #if defined(__OpenBSD__) #include #endif @@ -94,6 +96,9 @@ #ifdef _WIN32 #include +#include +#include + #endif #ifdef CONFIG_SDL @@ -166,7 +171,7 @@ int main(int argc, char **argv) #include "arch_init.h" #include "vl.h" #include "ui/qemu-spice.h" - +#include "nbd.h" //#define DEBUG_NET //#define DEBUG_SLIRP @@ -174,6 +179,169 @@ int main(int argc, char **argv) #define MAX_VIRTIO_CONSOLES 1 +/* QSOCKET_CALL is used to deal with the fact that EINTR happens pretty + * easily in QEMU since we use SIGALRM to implement periodic timers + */ + +#ifdef _WIN32 +# define QSOCKET_CALL(_ret,_cmd) \ + do { _ret = (_cmd); } while ( _ret < 0 && WSAGetLastError() == WSAEINTR ) +#else +# define QSOCKET_CALL(_ret,_cmd) \ + do { \ + errno = 0; \ + do { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR ); \ + } while (0); +#endif + +#ifdef _WIN32 + +#include + +static int winsock_error; + +#define WINSOCK_ERRORS_LIST \ + EE(WSA_INVALID_HANDLE,EINVAL,"invalid handle") \ + EE(WSA_NOT_ENOUGH_MEMORY,ENOMEM,"not enough memory") \ + EE(WSA_INVALID_PARAMETER,EINVAL,"invalid parameter") \ + EE(WSAEINTR,EINTR,"interrupted function call") \ + EE(WSAEALREADY,EALREADY,"operation already in progress") \ + EE(WSAEBADF,EBADF,"bad file descriptor") \ + EE(WSAEACCES,EACCES,"permission denied") \ + EE(WSAEFAULT,EFAULT,"bad address") \ + EE(WSAEINVAL,EINVAL,"invalid argument") \ + EE(WSAEMFILE,EMFILE,"too many opened files") \ + EE(WSAEWOULDBLOCK,EWOULDBLOCK,"resource temporarily unavailable") \ + EE(WSAEINPROGRESS,EINPROGRESS,"operation now in progress") \ + EE(WSAEALREADY,EAGAIN,"operation already in progress") \ + EE(WSAENOTSOCK,EBADF,"socket operation not on socket") \ + EE(WSAEDESTADDRREQ,EDESTADDRREQ,"destination address required") \ + EE(WSAEMSGSIZE,EMSGSIZE,"message too long") \ + EE(WSAEPROTOTYPE,EPROTOTYPE,"wrong protocol type for socket") \ + EE(WSAENOPROTOOPT,ENOPROTOOPT,"bad protocol option") \ + EE(WSAEADDRINUSE,EADDRINUSE,"address already in use") \ + EE(WSAEADDRNOTAVAIL,EADDRNOTAVAIL,"cannot assign requested address") \ + EE(WSAENETDOWN,ENETDOWN,"network is down") \ + EE(WSAENETUNREACH,ENETUNREACH,"network unreachable") \ + EE(WSAENETRESET,ENETRESET,"network dropped connection on reset") \ + EE(WSAECONNABORTED,ECONNABORTED,"software caused connection abort") \ + EE(WSAECONNRESET,ECONNRESET,"connection reset by peer") \ + EE(WSAENOBUFS,ENOBUFS,"no buffer space available") \ + EE(WSAEISCONN,EISCONN,"socket is already connected") \ + EE(WSAENOTCONN,ENOTCONN,"socket is not connected") \ + EE(WSAESHUTDOWN,ESHUTDOWN,"cannot send after socket shutdown") \ + EE(WSAETOOMANYREFS,ETOOMANYREFS,"too many references") \ + EE(WSAETIMEDOUT,ETIMEDOUT,"connection timed out") \ + EE(WSAECONNREFUSED,ECONNREFUSED,"connection refused") \ + EE(WSAELOOP,ELOOP,"cannot translate name") \ + EE(WSAENAMETOOLONG,ENAMETOOLONG,"name too long") \ + EE(WSAEHOSTDOWN,EHOSTDOWN,"host is down") \ + EE(WSAEHOSTUNREACH,EHOSTUNREACH,"no route to host") \ + +typedef struct { + int winsock; + int unix; + const char* string; +} WinsockError; + +static const WinsockError _winsock_errors[] = { +#define EE(w,u,s) { w, u, s }, + WINSOCK_ERRORS_LIST +#undef EE + { -1, -1, NULL } +}; + +/* this function reads the latest winsock error code and updates + * errno to a matching value. It also returns the new value of + * errno. + */ +static int _fix_errno( void ) +{ + const WinsockError* werr = _winsock_errors; + int unix = EINVAL; /* generic error code */ + + winsock_error = WSAGetLastError(); + + for ( ; werr->string != NULL; werr++ ) { + if (werr->winsock == winsock_error) { + unix = werr->unix; + break; + } + } + errno = unix; + return -1; +} + +#else +static int _fix_errno( void ) +{ + return -1; +} + +#endif + +#define SOCKET_CALL(cmd) \ + int ret; \ + QSOCKET_CALL(ret, (cmd)); \ + if (ret < 0) \ + return _fix_errno(); \ + return ret; \ + +int socket_send(int fd, const void* buf, int buflen) +{ + SOCKET_CALL(send(fd, buf, buflen, 0)) +} + +#ifdef _WIN32 + +static void +socket_close_handler( void* _fd ) +{ + int fd = (int)_fd; + int ret; + char buff[64]; + + /* we want to drain the read side of the socket before closing it */ + do { + ret = recv( fd, buff, sizeof(buff), 0 ); + } while (ret < 0 && WSAGetLastError() == WSAEINTR); + + if (ret < 0 && WSAGetLastError() == EWOULDBLOCK) + return; + + qemu_set_fd_handler( fd, NULL, NULL, NULL ); + closesocket( fd ); +} + +void +socket_close( int fd ) +{ + int old_errno = errno; + + shutdown( fd, SD_BOTH ); + /* we want to drain the socket before closing it */ + qemu_set_fd_handler( fd, socket_close_handler, NULL, (void*)fd ); + + errno = old_errno; +} + +#else /* !_WIN32 */ + +#include + +void +socket_close( int fd ) +{ + int old_errno = errno; + + shutdown( fd, SHUT_RDWR ); + close( fd ); + + errno = old_errno; +} + +#endif /* !_WIN32 */ + static const char *data_dir; const char *bios_name = NULL; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; @@ -230,6 +398,7 @@ int ctrl_grab = 0; unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; int boot_menu; +int SLP_base_port; typedef struct FWBootEntry FWBootEntry; @@ -3146,6 +3315,8 @@ int qemu_main(int argc, char **argv, char **envp) * when bus is created by qdev.c */ qemu_register_reset(qbus_reset_all_fn, sysbus_get_default()); qemu_run_machine_init_done_notifiers(); + + sdb_setup(); qemu_system_reset(); if (loadvm) { @@ -3170,6 +3341,83 @@ int qemu_main(int argc, char **argv, char **envp) main_loop(); quit_timers(); net_cleanup(); - return 0; } + +int inet_strtoip(const char* str, uint32_t *ip) +{ + int comp[4]; + + if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4) + return -1; + + if ((unsigned)comp[0] >= 256 || + (unsigned)comp[1] >= 256 || + (unsigned)comp[2] >= 256 || + (unsigned)comp[3] >= 256) + return -1; + + *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) | + (comp[2] << 8) | comp[3]); + return 0; +} + +void sdb_setup(void) +{ + int tries = 10; + const char *base_port = "26100"; + int sdb_host_port = 26099; // sdb's default + int success = 0; + int s; + int port; + uint32_t guest_ip; + const char *p; + char buf[30] = {0,}; + + inet_strtoip("10.0.2.16", &guest_ip); + + port = strtol(base_port, (char **)&p, 0); + + for ( ; tries > 0; tries--, port += 10 ) { + // redir form [tcp:26100:10.0.2.16:26101] + sprintf(buf, "tcp:%d:10.0.2.16:26101", port+1); + if(net_slirp_redir((char*)buf) < 0) + continue; + + printf("SDB listening on port from %d to %d\n", port, port+9); + success = 1; + break; + } + if (!success) { + fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" ); + exit(1); + } + setenv( "SDB_PORT", (char*)buf, 1); + fflush(stdout); + + /* Save base port. */ + SLP_base_port = port; + + /* send a simple message to the SDB host server to tell it we just started. + * it should be listening on port 26099. if we can't reach it, don't bother + */ + do + { + char tmp[32]; + + if (s < 0) { + fprintf(stderr, "can't create socket to talk to the SDB server"); + break; + } + + sprintf(tmp,"0013host:emulator:%d",port+1); + socket_send(s, tmp, 30); + printf("sent '%s' to SDB server\n", tmp); + fflush(stdout); + + } + while (0); + + if (s >= 0) + socket_close(s); +} diff --git a/vl.h b/vl.h index f65c771..1ec8d12 100644 --- a/vl.h +++ b/vl.h @@ -1,3 +1,98 @@ +#include +#include +#include int qemu_main(int argc, char **argv, char **envp); +/* added for SDB(Samsung Development Bridge) */ + +#ifdef _WIN32 +# ifndef EINTR +# define EINTR 10004 +# endif +# ifndef EAGAIN +# define EAGAIN 10035 +# endif +# ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN +# endif +# ifndef EINPROGRESS +# define EINPROGRESS 10036 +# endif +# ifndef EALREADY +# define EALREADY 10037 +# endif +# ifndef EDESTADDRREQ +# define EDESTADDRREQ 10039 +# endif +# ifndef EMSGSIZE +# define EMSGSIZE 10040 +# endif +# ifndef EPROTOTYPE +# define EPROTOTYPE 10041 +# endif +# ifndef ENOPROTOOPT +# define ENOPROTOOPT 10042 +# endif +# ifndef EAFNOSUPPORT +# define EAFNOSUPPORT 10047 +# endif +# ifndef EADDRINUSE +# define EADDRINUSE 10048 +# endif +# ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL 10049 +# endif +# ifndef ENETDOWN +# define ENETDOWN 10050 +# endif +# ifndef ENETUNREACH +# define ENETUNREACH 10051 +# endif +# ifndef ENETRESET +# define ENETRESET 10052 +# endif +# ifndef ECONNABORTED +# define ECONNABORTED 10053 +# endif +# ifndef ECONNRESET +# define ECONNRESET 10054 +# endif +# ifndef ENOBUFS +# define ENOBUFS 10055 +# endif +# ifndef EISCONN +# define EISCONN 10056 +# endif +# ifndef ENOTCONN +# define ENOTCONN 10057 +# endif +# ifndef ESHUTDOWN +# define ESHUTDOWN 10058 +# endif +# ifndef ETOOMANYREFS +# define ETOOMANYREFS 10059 +# endif +# ifndef ETIMEDOUT +# define ETIMEDOUT 10060 +# endif +# ifndef ECONNREFUSED +# define ECONNREFUSED 10061 +# endif +# ifndef ELOOP +# define ELOOP 10062 +# endif +# ifndef EHOSTDOWN +# define EHOSTDOWN 10064 +# endif +# ifndef EHOSTUNREACH +# define EHOSTUNREACH 10065 +# endif +#endif /* _WIN32 */ + +void sdb_setup(void); +int inet_strtoip(const char* str, uint32_t *ip); +int socket_send(int fd, const void* buf, int buflen); +void socket_close(int fd); + + -- 2.7.4