diff --git a/examples/example_bass.cpp b/examples/example_bass.cpp index b7f91352..ffb95d89 100644 --- a/examples/example_bass.cpp +++ b/examples/example_bass.cpp @@ -188,7 +188,7 @@ int main(int argc, char *argv[]) double row = bass_get_row(stream); #ifndef SYNC_PLAYER if (sync_update(rocket, (int)floor(row), &bass_cb, (void *)&stream)) - sync_tcp_connect(rocket, "localhost", SYNC_DEFAULT_PORT); + sync_tcp_reconnect(rocket); #endif /* draw */ diff --git a/lib/device.c b/lib/device.c index 605e88ab..ce8e4514 100644 --- a/lib/device.c +++ b/lib/device.c @@ -142,7 +142,41 @@ static inline int xrecv(SOCKET s, void *buf, size_t len, int flags) static struct Library *socket_base = NULL; #endif -static SOCKET server_connect(const char *host, unsigned short nport) +static SOCKET sock_connect(struct sockaddr *sa, int sa_len) +{ + char greet[128]; + + SOCKET sock = socket(sa->sa_family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + return INVALID_SOCKET; + + if (connect(sock, sa, sa_len) < 0) { + closesocket(sock); + return INVALID_SOCKET; + } + +#ifdef USE_NODELAY + int yes = 1; + + /* Try disabling Nagle since we're latency-sensitive, UDP would + * really be more appropriate but that's a much bigger change. + */ + (void) setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&yes, sizeof(yes)); +#endif + + if (xsend(sock, CLIENT_GREET, strlen(CLIENT_GREET), 0) || + xrecv(sock, greet, strlen(SERVER_GREET), 0) || + strncmp(SERVER_GREET, greet, strlen(SERVER_GREET))) { + closesocket(sock); + return INVALID_SOCKET; + } + + return sock; +} + +static SOCKET server_connect(struct sync_device *d, + const char *host, + unsigned short nport) { SOCKET sock = INVALID_SOCKET; #ifdef USE_GETADDRINFO @@ -176,9 +210,13 @@ static SOCKET server_connect(const char *host, unsigned short nport) return INVALID_SOCKET; for (curr = addr; curr; curr = curr->ai_next) { - int family = curr->ai_family; - struct sockaddr *sa = curr->ai_addr; - int sa_len = (int)curr->ai_addrlen; + sock = sock_connect(curr->ai_addr, (int)curr->ai_addrlen); + if (sock != INVALID_SOCKET) { + memcpy(&d->server.addr, curr->ai_addr, curr->ai_addrlen); + d->server.addrlen = curr->ai_addrlen; + break; + } + } #else @@ -187,49 +225,19 @@ static SOCKET server_connect(const char *host, unsigned short nport) return INVALID_SOCKET; for (ap = he->h_addr_list; *ap; ++ap) { - int family = he->h_addrtype; - struct sockaddr_in sin; - struct sockaddr *sa = (struct sockaddr *)&sin; - int sa_len = sizeof(*sa); - - sin.sin_family = he->h_addrtype; - sin.sin_port = htons(nport); - memcpy(&sin.sin_addr, *ap, he->h_length); - memset(&sin.sin_zero, 0, sizeof(sin.sin_zero)); - -#endif - - sock = socket(family, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) - continue; - - if (connect(sock, sa, sa_len) >= 0) { - char greet[128]; - -#ifdef USE_NODELAY - int yes = 1; + d->server.sin.sin_family = he->h_addrtype; + d->server.sin.sin_port = htons(nport); + memcpy(&d->server.sin.sin_addr, *ap, he->h_length); + memset(&d->server.sin.sin_zero, 0, sizeof(d->server.sin.sin_zero)); + + sock = sock_connect((struct sockaddr *)&d->server.sin, + sizeof(struct sockaddr)); + if (sock != INVALID_SOCKET) + break; + } - /* Try disabling Nagle since we're latency-sensitive, UDP would - * really be more appropriate but that's a much bigger change. - */ - (void) setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&yes, sizeof(yes)); #endif - if (xsend(sock, CLIENT_GREET, strlen(CLIENT_GREET), 0) || - xrecv(sock, greet, strlen(SERVER_GREET), 0)) { - closesocket(sock); - sock = INVALID_SOCKET; - continue; - } - - if (!strncmp(SERVER_GREET, greet, strlen(SERVER_GREET))) - break; - } - - closesocket(sock); - sock = INVALID_SOCKET; - } - #ifdef USE_GETADDRINFO freeaddrinfo(addr); #endif @@ -475,16 +483,9 @@ static int handle_del_key_cmd(SOCKET sock, struct sync_device *data) return sync_del_key(data->tracks[track], row); } -int sync_tcp_connect(struct sync_device *d, const char *host, unsigned short port) +int update_tracks(struct sync_device *d) { int i; - if (d->sock != INVALID_SOCKET) - closesocket(d->sock); - - d->sock = server_connect(host, port); - if (d->sock == INVALID_SOCKET) - return -1; - for (i = 0; i < (int)d->num_tracks; ++i) { free(d->tracks[i]->keys); d->tracks[i]->keys = NULL; @@ -501,6 +502,38 @@ int sync_tcp_connect(struct sync_device *d, const char *host, unsigned short por return 0; } +int sync_tcp_connect(struct sync_device *d, const char *host, unsigned short port) +{ + if (d->sock != INVALID_SOCKET) + closesocket(d->sock); + + d->sock = server_connect(d, host, port); + if (d->sock == INVALID_SOCKET) + return -1; + + return update_tracks(d); +} + +int sync_tcp_reconnect(struct sync_device *d) +{ + if (d->sock != INVALID_SOCKET) + closesocket(d->sock); + + +#ifdef USE_GETADDRINFO + d->sock = sock_connect((struct sockaddr *)&d->server.addr, + d->server.addrlen); +#else + d->sock = sock_connect((struct sockaddr *)&d->server.sin, + sizeof(struct sockaddr)); +#endif + + if (d->sock == INVALID_SOCKET) + return -1; + + return update_tracks(d); +} + int sync_connect(struct sync_device *d, const char *host, unsigned short port) { return sync_tcp_connect(d, host, port); diff --git a/lib/device.h b/lib/device.h index d26194e7..f0842e82 100644 --- a/lib/device.h +++ b/lib/device.h @@ -69,6 +69,14 @@ struct sync_device { #ifndef SYNC_PLAYER int row; SOCKET sock; + struct { +#ifdef USE_GETADDRINFO + struct sockaddr_storage addr; + int addrlen; +#else + struct sockaddr_in sin; +#endif + } server; #endif struct sync_io_cb io_cb; }; diff --git a/lib/sync.h b/lib/sync.h index e4e68a76..5c68cc81 100644 --- a/lib/sync.h +++ b/lib/sync.h @@ -33,6 +33,7 @@ struct sync_cb { }; #define SYNC_DEFAULT_PORT 1338 int sync_tcp_connect(struct sync_device *, const char *, unsigned short); +int sync_tcp_reconnect(struct sync_device *); int SYNC_DEPRECATED("use sync_tcp_connect instead") sync_connect(struct sync_device *, const char *, unsigned short); int sync_update(struct sync_device *, int, struct sync_cb *, void *); int sync_save_tracks(const struct sync_device *);