- if (!BIO_get_port(p,&port)) goto err;
-
- memset((char *)&server,0,sizeof(server));
- server.sa_in.sin_family=AF_INET;
- server.sa_in.sin_port=htons(port);
- addrlen = sizeof(server.sa_in);
-
- if (h == NULL || strcmp(h,"*") == 0)
- server.sa_in.sin_addr.s_addr=INADDR_ANY;
- else
- {
- if (!BIO_get_host_ip(h,&(ip[0]))) goto err;
- l=(unsigned long)
- ((unsigned long)ip[0]<<24L)|
- ((unsigned long)ip[1]<<16L)|
- ((unsigned long)ip[2]<< 8L)|
- ((unsigned long)ip[3]);
- server.sa_in.sin_addr.s_addr=htonl(l);
- }
-
-again:
- s=socket(server.sa.sa_family,SOCK_STREAM,SOCKET_PROTOCOL);
- if (s == INVALID_SOCKET)
- {
- SYSerr(SYS_F_SOCKET,get_last_socket_error());
- ERR_add_error_data(3,"port='",host,"'");
- BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_CREATE_SOCKET);
- goto err;
- }
-
-#ifdef SO_REUSEADDR
- if (bind_mode == BIO_BIND_REUSEADDR)
- {
- int i=1;
-
- ret=setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&i,sizeof(i));
- bind_mode=BIO_BIND_NORMAL;
- }
-#endif
- if (bind(s,&server.sa,addrlen) == -1)
- {
-#ifdef SO_REUSEADDR
- err_num=get_last_socket_error();
- if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) &&
-#ifdef OPENSSL_SYS_WINDOWS
- /* Some versions of Windows define EADDRINUSE to
- * a dummy value.
- */
- (err_num == WSAEADDRINUSE))
-#else
- (err_num == EADDRINUSE))
-#endif
- {
- client = server;
- if (h == NULL || strcmp(h,"*") == 0)
- {
-#if OPENSSL_USE_IPV6
- if (client.sa.sa_family == AF_INET6)
- {
- memset(&client.sa_in6.sin6_addr,0,sizeof(client.sa_in6.sin6_addr));
- client.sa_in6.sin6_addr.s6_addr[15]=1;
- }
- else
-#endif
- if (client.sa.sa_family == AF_INET)
- {
- client.sa_in.sin_addr.s_addr=htonl(0x7F000001);
- }
- else goto err;
- }
- cs=socket(client.sa.sa_family,SOCK_STREAM,SOCKET_PROTOCOL);
- if (cs != INVALID_SOCKET)
- {
- int ii;
- ii=connect(cs,&client.sa,addrlen);
- closesocket(cs);
- if (ii == INVALID_SOCKET)
- {
- bind_mode=BIO_BIND_REUSEADDR;
- closesocket(s);
- goto again;
- }
- /* else error */
- }
- /* else error */
- }
-#endif
- SYSerr(SYS_F_BIND,err_num);
- ERR_add_error_data(3,"port='",host,"'");
- BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
- goto err;
- }
- if (listen(s,MAX_LISTEN) == -1)
- {
- SYSerr(SYS_F_BIND,get_last_socket_error());
- ERR_add_error_data(3,"port='",host,"'");
- BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_LISTEN_SOCKET);
- goto err;
- }
- ret=1;
-err:
- if (str != NULL) OPENSSL_free(str);
- if ((ret == 0) && (s != INVALID_SOCKET))
- {
- closesocket(s);
- s= INVALID_SOCKET;
- }
- return(s);
- }
-
-int BIO_accept(int sock, char **addr)
- {
- int ret=INVALID_SOCKET;
- unsigned long l;
- unsigned short port;
- char *p;
-
- struct {
- /*
- * As for following union. Trouble is that there are platforms
- * that have socklen_t and there are platforms that don't, on
- * some platforms socklen_t is int and on some size_t. So what
- * one can do? One can cook #ifdef spaghetti, which is nothing
- * but masochistic. Or one can do union between int and size_t.
- * One naturally does it primarily for 64-bit platforms where
- * sizeof(int) != sizeof(size_t). But would it work? Note that
- * if size_t member is initialized to 0, then later int member
- * assignment naturally does the job on little-endian platforms
- * regardless accept's expectations! What about big-endians?
- * If accept expects int*, then it works, and if size_t*, then
- * length value would appear as unreasonably large. But this
- * won't prevent it from filling in the address structure. The
- * trouble of course would be if accept returns more data than
- * actual buffer can accomodate and overwrite stack... That's
- * where early OPENSSL_assert comes into picture. Besides, the
- * only 64-bit big-endian platform found so far that expects
- * size_t* is HP-UX, where stack grows towards higher address.
- * <appro>
- */
- union { size_t s; int i; } len;
- union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
-#if OPENSSL_USE_IPV6
- struct sockaddr_in6 sa_in6;
-#endif
- } from;
- } sa;
-
- sa.len.s=0;
- sa.len.i=sizeof(sa.from);
- memset(&sa.from,0,sizeof(sa.from));
- ret=accept(sock,&sa.from.sa,(void *)&sa.len);
- if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0)
- {
- OPENSSL_assert(sa.len.s<=sizeof(sa.from));
- sa.len.i = (int)sa.len.s;
- /* use sa.len.i from this point */
- }
- if (ret == INVALID_SOCKET)
- {
- if(BIO_sock_should_retry(ret)) return -2;
- SYSerr(SYS_F_ACCEPT,get_last_socket_error());
- BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR);
- goto end;
- }
-
- if (addr == NULL) goto end;
-
-#ifdef EAI_FAMILY
- do {
- char h[NI_MAXHOST],s[NI_MAXSERV];
- size_t nl;
- static union { void *p;
- int (WSAAPI *f)(const struct sockaddr *,size_t/*socklen_t*/,
- char *,size_t,char *,size_t,int);
- } p_getnameinfo = {NULL};
- /* 2nd argument to getnameinfo is specified to
- * be socklen_t. Unfortunately there is a number
- * of environments where socklen_t is not defined.
- * As it's passed by value, it's safe to pass it
- * as size_t... <appro> */
-
- if (p_getnameinfo.p==NULL)
- {
- if ((p_getnameinfo.p=DSO_global_lookup("getnameinfo"))==NULL)
- p_getnameinfo.p=(void*)-1;
- }
- if (p_getnameinfo.p==(void *)-1) break;
-
- if ((*p_getnameinfo.f)(&sa.from.sa,sa.len.i,h,sizeof(h),s,sizeof(s),
- NI_NUMERICHOST|NI_NUMERICSERV)) break;
- nl = strlen(h)+strlen(s)+2;
- p = *addr;
- if (p) { *p = '\0'; p = OPENSSL_realloc(p,nl); }
- else { p = OPENSSL_malloc(nl); }
- if (p==NULL)
- {
- BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
- goto end;
- }
- *addr = p;
- BIO_snprintf(*addr,nl,"%s:%s",h,s);
- goto end;
- } while(0);
-#endif
- if (sa.from.sa.sa_family != AF_INET) goto end;
- l=ntohl(sa.from.sa_in.sin_addr.s_addr);
- port=ntohs(sa.from.sa_in.sin_port);
- if (*addr == NULL)
- {
- if ((p=OPENSSL_malloc(24)) == NULL)
- {
- BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
- goto end;
- }
- *addr=p;
- }
- BIO_snprintf(*addr,24,"%d.%d.%d.%d:%d",
- (unsigned char)(l>>24L)&0xff,
- (unsigned char)(l>>16L)&0xff,
- (unsigned char)(l>> 8L)&0xff,
- (unsigned char)(l )&0xff,
- port);
-end:
- return(ret);
- }
+ if (!BIO_parse_hostserv(host, &h, &p, BIO_PARSE_PRIO_SERV))
+ return INVALID_SOCKET;
+
+ if (BIO_sock_init() != 1)
+ return INVALID_SOCKET;
+
+ if (BIO_lookup(h, p, BIO_LOOKUP_SERVER, AF_UNSPEC, SOCK_STREAM, &res) != 0)
+ goto err;
+
+ if ((s = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res),
+ BIO_ADDRINFO_protocol(res), 0)) == INVALID_SOCKET) {
+ s = INVALID_SOCKET;
+ goto err;
+ }
+
+ if (!BIO_listen(s, BIO_ADDRINFO_address(res),
+ bind_mode ? BIO_SOCK_REUSEADDR : 0)) {
+ BIO_closesocket(s);
+ s = INVALID_SOCKET;
+ }
+
+ err:
+ BIO_ADDRINFO_free(res);
+ OPENSSL_free(h);
+ OPENSSL_free(p);
+
+ return s;
+}
+
+int BIO_accept(int sock, char **ip_port)
+{
+ BIO_ADDR res;
+ int ret = -1;
+
+ ret = BIO_accept_ex(sock, &res, 0);
+ if (ret == (int)INVALID_SOCKET) {
+ if (BIO_sock_should_retry(ret)) {
+ ret = -2;
+ goto end;
+ }
+ SYSerr(SYS_F_ACCEPT, get_last_socket_error());
+ BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR);
+ goto end;
+ }
+
+ if (ip_port != NULL) {
+ char *host = BIO_ADDR_hostname_string(&res, 1);
+ char *port = BIO_ADDR_service_string(&res, 1);
+ if (host != NULL && port != NULL)
+ *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2);
+ else
+ *ip_port = NULL;
+
+ if (*ip_port == NULL) {
+ BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE);
+ BIO_closesocket(ret);
+ ret = (int)INVALID_SOCKET;
+ } else {
+ strcpy(*ip_port, host);
+ strcat(*ip_port, ":");
+ strcat(*ip_port, port);
+ }
+ OPENSSL_free(host);
+ OPENSSL_free(port);
+ }
+
+ end:
+ return ret;
+}
+# endif