📄 sockctl.c
字号:
/* ---------------------------------------------------------------------------- CFL - A C Foundation Library Copyright (C) 1994-2003 Mark A Lindner This file is part of CFL. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ---------------------------------------------------------------------------- $Log: sockctl.c,v $ Revision 1.2 2003/03/14 09:02:30 markl Code cleanup & bug fixes. Revision 1.1 2003/03/03 08:20:08 markl Initial checkin (clean compile on Solaris & OS X) ----------------------------------------------------------------------------*//* Feature test switches */#include "config.h"/* System headers */#include <fcntl.h>#include <netinet/in.h>#include <ctype.h>#include <string.h>/* Local headers */#include "cfl/defs.h"#include "cfl/net.h"#include "cfl/cerrno.h"#include "cfl/system.h"#include "netcommon.h"#include "getXXbyYY_r.h"/* File scope variables */const int __C_net_socktypes[C_NET_NTYPES] = { SOCK_STREAM, SOCK_DGRAM, -1 };const char *__C_net_protocols[C_NET_NTYPES] = { "tcp", "udp", NULL };/* External functions */c_bool_t __C_socket_addr2sock(struct sockaddr_in *sa, const char *addr) { struct hostent he, *rhe; c_buffer_t *rbuf = __C_net_get_buffer(); int herr; if(!sa || !addr) return(FALSE); if(isdigit((int)*addr)) { if((sa->sin_addr.s_addr = inet_addr(addr)) == -1) return(FALSE); sa->sin_family = AF_INET; } else {GETHOSTBYNAME: if(! C_gethostbyname_r(addr, &he, rbuf->buf, rbuf->bufsz, &rhe, &herr)) { if(herr == ERANGE) { C_buffer_resize(rbuf, rbuf->bufsz + C_NET_BUFSZ); goto GETHOSTBYNAME; } else { C_error_set_errno(C_EADDRINFO); return(FALSE); } } memcpy((void *)&(sa->sin_addr), (void *)he.h_addr, (size_t)he.h_length); sa->sin_family = he.h_addrtype; } return(TRUE); }/* */c_bool_t __C_socket_sock2addr(struct sockaddr_in *sa, char *addr, size_t addrsz) { struct hostent he, *rhe; c_buffer_t *rbuf = __C_net_get_buffer(); int herr; if(!sa || !addr || !addrsz) return(FALSE);GETHOSTBYADDR: if(! C_gethostbyaddr_r((char *)&(sa->sin_addr.s_addr), sizeof(in_addr_t), AF_INET, &he, rbuf->buf, rbuf->bufsz, &rhe, &herr)) { if(herr == ERANGE) { C_buffer_resize(rbuf, rbuf->bufsz + C_NET_BUFSZ); goto GETHOSTBYADDR; } else { C_error_set_errno(C_EADDRINFO); return(FALSE); } } strncpy(addr, he.h_name, --addrsz); *(addr + addrsz) = NUL; return(TRUE); }/* */static c_bool_t __C_socket_create(c_socket_t *s, int type) { int sd; if((type < 0) || (type >= C_NET_MAXTYPE)) { C_error_set_errno(C_EINVAL); return(FALSE); } if((sd = socket(AF_INET, __C_net_socktypes[type], 0)) < 0) { C_error_set_errno(C_ESOCKET); return(FALSE); } s->sd = sd; s->sfp = NULL; s->flags = 0; s->state = C_NET_CREATED; s->type = type; return(TRUE); }/* */c_bool_t C_socket_create_s(c_socket_t *s, int type) { if(!s) return(FALSE); C_zero(s, c_socket_t); return(__C_socket_create(s, type)); }/* */c_socket_t * C_socket_create(int type) { c_socket_t *s = C_new(c_socket_t); if(! __C_socket_create(s, type)) return(C_free(s)); return(s); }/* */c_bool_t C_socket_listen(c_socket_t *s, in_port_t port) { struct hostent he, *rhe; c_buffer_t *rbuf = __C_net_get_buffer(); int herr, x = 1; char *myname; if(!s) { C_error_set_errno(C_EINVAL); return(FALSE); } if(s->state != C_NET_CREATED) { C_error_set_errno(C_EBADSTATE); return(FALSE); } myname = C_system_get_hostname();GETHOSTBYNAME2: if(! C_gethostbyname_r(myname, &he, rbuf->buf, rbuf->bufsz, &rhe, &herr)) { if(herr == ERANGE) { C_buffer_resize(rbuf, rbuf->bufsz + C_NET_BUFSZ); goto GETHOSTBYNAME2; } else { C_error_set_errno(C_EADDRINFO); return(FALSE); } } s->laddr.sin_addr.s_addr = htonl(INADDR_ANY); s->laddr.sin_family = he.h_addrtype; s->laddr.sin_port = htons(port); if(setsockopt(s->sd, SOL_SOCKET, SO_REUSEADDR, (void *)&x, sizeof(int)) < 0) { C_error_set_errno(C_ESOCKINFO); return(FALSE); } if(bind(s->sd, (struct sockaddr *)&(s->laddr), sizeof(struct sockaddr_in)) < 0) { C_error_set_errno(C_EBIND); return(FALSE); } if(s->type == C_NET_TCP) { if(listen(s->sd, C_NET_BACKLOG) < 0) { C_error_set_errno(C_ELISTEN); return(FALSE); } s->state = C_NET_LISTENING; } return(TRUE); }/* */static c_bool_t __C_socket_accept(c_socket_t *s, c_socket_t *ms) { int sz = sizeof(struct sockaddr_in); if(!ms) { C_error_set_errno(C_EINVAL); return(FALSE); } if(ms->state != C_NET_LISTENING) { C_error_set_errno(C_EBADSTATE); return(FALSE); } if(ms->type != C_NET_TCP) { C_error_set_errno(C_EBADTYPE); return(FALSE); }ACCEPT: if((s->sd = accept(ms->sd, (struct sockaddr *)&(s->raddr), &sz)) < 0) { switch(errno) { case EWOULDBLOCK: C_error_set_errno(C_EBLOCKED); return(FALSE); case EINTR: case ECONNABORTED: goto ACCEPT; default: C_error_set_errno(C_EACCEPT); return(FALSE); } } s->type = ms->type; s->state = C_NET_CONNECTED; s->flags = ms->flags; s->sfp = NULL; s->flags &= ~(C_NET_MUNBLOCK); memcpy((void *)&(s->laddr), (void *)&(ms->laddr), sizeof(struct sockaddr_in)); return(TRUE); }/* */c_socket_t *C_socket_accept(c_socket_t *ms) { c_socket_t *s = C_new(c_socket_t); if(!__C_socket_accept(s, ms)) return(C_free(s)); return(s); }/* */c_bool_t C_socket_accept_s(c_socket_t *s, c_socket_t *ms) { if(!ms || !s) { C_error_set_errno(C_EINVAL); return(FALSE); } C_zero(s, c_socket_t); return(__C_socket_accept(s, ms)); }/* */c_bool_t C_socket_connect(c_socket_t *s, const char *host, in_port_t port) { int sz = (int)sizeof(struct sockaddr_in); if(!s || !host) { C_error_set_errno(C_EINVAL); return(FALSE); } if(! *host) { C_error_set_errno(C_EINVAL); return(FALSE); } if(s->state != C_NET_CREATED) { C_error_set_errno(C_EBADSTATE); return(FALSE); } if(!__C_socket_addr2sock(&(s->raddr), host)) { C_error_set_errno(C_EADDRINFO); return(FALSE); } s->raddr.sin_port = htons(port);CONNECT: if(connect(s->sd, (struct sockaddr *)&(s->raddr), sz) < 0) { switch(errno) { case ECONNREFUSED: C_error_set_errno(C_ENOCONN); break; case EINTR: goto CONNECT; default: C_error_set_errno(C_ECONNECT); } return(FALSE); } s->state = C_NET_CONNECTED; sz = (int)sizeof(struct sockaddr_in); getsockname(s->sd, (struct sockaddr *)&(s->laddr), &sz); return(TRUE); }/* */c_bool_t C_socket_shutdown(c_socket_t *s, uint_t how) { if(!s || (how < C_NET_SHUTRD) || (how > C_NET_SHUTALL)) { C_error_set_errno(C_EINVAL); return(FALSE); } if(s->state != C_NET_CONNECTED) { C_error_set_errno(C_EBADSTATE); return(FALSE); } s->state = C_NET_SHUTDOWN; s->flags |= (how << C_NET_OSHUT); shutdown(s->sd, --how); return(TRUE); }/* */static c_bool_t __C_socket_destroy(c_socket_t *s) { if(!s) { C_error_set_errno(C_EINVAL); return(FALSE); } if(!((s->state == C_NET_CREATED) || ((s->state == C_NET_SHUTDOWN) && (s->flags & C_NET_MSHUT)))) { C_error_set_errno(C_EBADSTATE); return(FALSE); } if(s->sfp) fclose(s->sfp); close(s->sd); return(TRUE); }/* */c_bool_t C_socket_destroy(c_socket_t *s) { c_bool_t ok; ok = __C_socket_destroy(s); if(ok) C_free(s); return(ok); }/* */c_bool_t C_socket_destroy_s(c_socket_t *s) { return(__C_socket_destroy(s)); }/* */c_bool_t C_socket_fopen(c_socket_t *s, int buffering) { if(!s) { C_error_set_errno(C_EINVAL); return(FALSE); } if(s->state != C_NET_CONNECTED) { C_error_set_errno(C_EBADSTATE); return(FALSE); } if(s->type != C_NET_TCP) { C_error_set_errno(C_EBADTYPE); return(FALSE); } if(!(s->sfp = fdopen(s->sd, "r+"))) { C_error_set_errno(C_EFDOPEN); return(FALSE); } if(setvbuf(s->sfp, NULL, buffering, 0)) { C_error_set_errno(C_EINVAL); return(FALSE); } return(TRUE); }/* */c_bool_t C_socket_get_peeraddr(c_socket_t *s, char *buf, size_t bufsz) { if(!s || !buf || !bufsz) { C_error_set_errno(C_EINVAL); return(FALSE); } if(s->state != C_NET_CONNECTED) { C_error_set_errno(C_EBADSTATE); return(FALSE); } if(!__C_socket_sock2addr(&(s->raddr), buf, bufsz)) { C_error_set_errno(C_EADDRINFO); return(FALSE); } return(TRUE); }/* */c_bool_t C_socket_fclose(c_socket_t *s) { if(!s)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -