socket.c File Reference

a simple object-oriented socket wrapper object model inspired by Zed Shaw More...

#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "debug.h"
#include "socket.h"
#include "util.h"
#include "list.h"

Functions

co_obj_tco_fd_create (co_obj_t *parent, int fd)
 creates a file descriptor object More...
 
co_obj_tco_socket_create (size_t size, co_socket_t proto)
 creates a socket from specified values or initializes defaults More...
 
int co_socket_init (co_obj_t *self)
 creates a socket from specified values or initializes defaults More...
 
int co_socket_destroy (co_obj_t *self)
 closes a socket and removes it from memory More...
 
int co_socket_hangup (co_obj_t *self, co_obj_t *context)
 closes a socket and changes its state information More...
 
int co_socket_send (co_obj_t *self, char *outgoing, size_t length)
 sends a message on a specified socket More...
 
int co_socket_receive (co_obj_t *self, co_obj_t *fd, char *incoming, size_t length)
 receives a message on the listening socket More...
 
int co_socket_setopt (co_obj_t *self, int level, int option, void *optval, socklen_t optvallen)
 sets custom socket options, if specified by user More...
 
int co_socket_getopt (co_obj_t *self, int level, int option, void *optval, socklen_t optvallen)
 gets custom socket options specified from the user More...
 
int unix_socket_init (co_obj_t *self)
 initializes a unix socket More...
 
int unix_socket_bind (co_obj_t *self, const char *endpoint)
 binds a unix socket to a specified endpoint More...
 
int unix_socket_connect (co_obj_t *self, const char *endpoint)
 connects a socket to specified endpoint More...
 

Variables

co_socket_t unix_socket_proto
 

Detailed Description

a simple object-oriented socket wrapper object model inspired by Zed Shaw

Author
Josh King (jheretic), jking.nosp@m.@cha.nosp@m.mbana.nosp@m..net

Function Documentation

co_obj_t* co_fd_create ( co_obj_t parent,
int  fd 
)

creates a file descriptor object

Parameters
fdfile descriptor int

Referenced by _watch(), co_socket_init(), co_socket_receive(), and unix_socket_init().

47  {
48  CHECK(IS_SOCK(parent),"Parent is not a socket.");
49  co_fd_t *new_fd = h_calloc(1,sizeof(co_fd_t));
50  new_fd->_header._type = _ext8;
51  new_fd->_exttype = _fd;
52  new_fd->_len = sizeof(co_fd_t);
53  new_fd->socket = (co_socket_t*)parent;
54  new_fd->fd = fd;
55  return (co_obj_t*)new_fd;
56 error:
57  return NULL;
58 }
Definition: obj.h:131
Definition: socket.h:65
Definition: socket.h:48
co_obj_t* co_socket_create ( size_t  size,
co_socket_t  proto 
)

creates a socket from specified values or initializes defaults

Parameters
sizesize of socket struct
protosocket protocol

References co_socket_destroy(), co_socket_getopt(), co_socket_hangup(), co_socket_receive(), co_socket_send(), and co_socket_setopt().

66  {
67 
68  if(!proto.init) proto.init = NULL;
69  if(!proto.destroy) proto.destroy = co_socket_destroy;
70  if(!proto.hangup) proto.hangup = co_socket_hangup;
71  if(!proto.bind) proto.bind = NULL;
72  if(!proto.connect) proto.connect = NULL;
73  if(!proto.send) proto.send = co_socket_send;
74  if(!proto.receive) proto.receive = co_socket_receive;
75  if(!proto.setopt) proto.setopt = co_socket_setopt;
76  if(!proto.getopt) proto.getopt = co_socket_getopt;
77  co_socket_t *new_sock = h_calloc(1,size);
78  *new_sock = proto;
79  new_sock->_header._type = _ext8;
80  new_sock->_exttype = _sock;
81  new_sock->_len = size;
82 
83  if((proto.init != NULL) && (!new_sock->init((co_obj_t*)new_sock))) {
84  SENTINEL("Failed to initialize new socket.");
85  } else {
86  return (co_obj_t*)new_sock;
87  }
88 
89 error:
90  new_sock->destroy((co_obj_t*)new_sock);
91  return NULL;
92 }
int co_socket_getopt(co_obj_t *self, int level, int option, void *optval, socklen_t optvallen)
gets custom socket options specified from the user
Definition: socket.c:227
int co_socket_hangup(co_obj_t *self, co_obj_t *context)
closes a socket and changes its state information
Definition: socket.c:128
int co_socket_receive(co_obj_t *self, co_obj_t *fd, char *incoming, size_t length)
receives a message on the listening socket
Definition: socket.c:173
int co_socket_setopt(co_obj_t *self, int level, int option, void *optval, socklen_t optvallen)
sets custom socket options, if specified by user
Definition: socket.c:210
Definition: obj.h:131
Definition: socket.h:65
int co_socket_send(co_obj_t *self, char *outgoing, size_t length)
sends a message on a specified socket
Definition: socket.c:151
int co_socket_destroy(co_obj_t *self)
closes a socket and removes it from memory
Definition: socket.c:118
int co_socket_destroy ( co_obj_t self)

closes a socket and removes it from memory

Parameters
selfsocket name

References co_list_parse().

Referenced by co_socket_create().

118  {
119  if(self && IS_SOCK(self)) {
120  co_socket_t *this = (co_socket_t*)self;
121  if (this->fd->fd > 0) close(this->fd->fd);
122  co_list_parse(this->rfd_lst,_co_socket_close_fd_i,NULL);
123  co_obj_free(self);
124  return 1;
125  } else return 0;
126 }
Definition: socket.h:65
co_obj_t * co_list_parse(co_obj_t *list, co_iter_t iter, void *context)
process list with given iterator function
Definition: list.c:233
int co_socket_getopt ( co_obj_t self,
int  level,
int  option,
void *  optval,
socklen_t  optvallen 
)

gets custom socket options specified from the user

Parameters
selfsocket name
levelthe networking level to be customized
optionthe option to be changed
optvalthe value for the new option
optvallenthe length of the value for the new option

Referenced by co_socket_create().

227  {
228  CHECK(IS_SOCK(self),"Not a socket.");
229  co_socket_t *this = (co_socket_t*)self;
230 
231  //Check to see if this is a standard socket option, or needs custom handling.
232  if(level <= MAX_IPPROTO) {
233  CHECK(!getsockopt(this->fd->fd, level, option, optval, &optvallen), "Problem setting socket options.");
234  } else {
235  SENTINEL("No custom socket options defined!");
236  }
237 
238  return 1;
239 
240 error:
241  return 0;
242 }
Definition: socket.h:65
int co_socket_hangup ( co_obj_t self,
co_obj_t context 
)

closes a socket and changes its state information

Parameters
selfsocket name
contextco_obj_t context pointer (currently unused)

References co_list_contains(), and co_list_delete().

Referenced by co_socket_create().

128  {
129  CHECK_MEM(self);
130  CHECK(IS_SOCK(self),"Not a socket.");
131  CHECK(IS_FD(context),"Not a FD.");
132  co_socket_t *this = (co_socket_t*)self;
133  co_fd_t *fd = (co_fd_t*)context;
134  CHECK(fd->socket == this,"FD does not match socket");
135  if (fd == this->fd) {
136  CHECK(close(fd->fd) != -1,"Failed to close socket.");
137  this->fd_registered = false;
138  this->listen = false;
139  } else {
140  CHECK(co_list_contains(this->rfd_lst,(co_obj_t*)fd),"Socket does not contain FD");
141  fd = (co_fd_t*)co_list_delete(this->rfd_lst,(co_obj_t*)fd);
142  CHECK(close(fd->fd) != -1,"Failed to close socket.");
143  co_obj_free((co_obj_t*)fd);
144  }
145  return 1;
146 error:
147  ERROR("Failed to hangup any file descriptors for this socket.");
148  return 0;
149 }
co_obj_t * co_list_delete(co_obj_t *list, co_obj_t *item)
delete specified item from list
Definition: list.c:457
Definition: obj.h:131
Definition: socket.h:65
int co_list_contains(co_obj_t *list, co_obj_t *item)
determine if list contains specified item
Definition: list.c:258
Definition: socket.h:48
int co_socket_init ( co_obj_t self)

creates a socket from specified values or initializes defaults

Parameters
sizesize of socket struct
protosocket protocol

References co_fd_create().

94  {
95  if(self && IS_SOCK(self)) {
96  co_socket_t *this = (co_socket_t*)self;
97  this->local = h_calloc(1,sizeof(struct sockaddr_storage));
98  hattach(this->local,this);
99  this->remote = h_calloc(1,sizeof(struct sockaddr_storage));
100  hattach(this->remote,this);
101  this->fd = (co_fd_t*)co_fd_create((co_obj_t*)this,-1);
102  hattach(this->fd,this);
103  this->rfd_lst = co_list16_create();
104  hattach(this->rfd_lst,this);
105  this->fd_registered = false;
106  this->listen = false;
107  this->events = 0;
108  return 1;
109  } else return 0;
110 }
Definition: obj.h:131
Definition: socket.h:65
Definition: socket.h:48
co_obj_t * co_fd_create(co_obj_t *parent, int fd)
creates a file descriptor object
Definition: socket.c:47
int co_socket_receive ( co_obj_t self,
co_obj_t fd,
char *  incoming,
size_t  length 
)

receives a message on the listening socket

Parameters
selfsocket name
incomingmessage received
lengthlength of message

References co_fd_create(), and co_list_append().

Referenced by co_socket_create().

173  {
174  CHECK_MEM(self);
175  CHECK(IS_SOCK(self),"Not a socket.");
176  co_socket_t *this = (co_socket_t*)self;
177  CHECK(((co_fd_t*)fd)->socket == this,"FD does not match socket");
178  int received = 0;
179  int rfd = 0;
180  if(this->listen) {
181  DEBUG("Receiving on listening socket.");
182  if((co_fd_t*)fd == this->fd) {
183  socklen_t size = sizeof(*(this->remote));
184  DEBUG("Accepting connection (fd=%d).", this->fd->fd);
185  CHECK((rfd = accept(this->fd->fd, (struct sockaddr *) this->remote, &size)) != -1, "Failed to accept connection.");
186  DEBUG("Accepted connection (fd=%d).", rfd);
187  co_obj_t *new_rfd = co_fd_create((co_obj_t*)this,rfd);
188  CHECK(co_list_append(this->rfd_lst,new_rfd),"Failed to append rfd");
189  int flags = fcntl(rfd, F_GETFL, 0);
190  fcntl(rfd, F_SETFL, flags | O_NONBLOCK); //Set non-blocking.
191  if(this->register_cb) this->register_cb((co_obj_t*)this, new_rfd);
192  return 0;
193  } else {
194  rfd = ((co_fd_t*)fd)->fd;
195  DEBUG("Setting receiving file descriptor %d.", rfd);
196  }
197  } else if(this->fd->fd >= 0) {
198  DEBUG("Setting listening file descriptor %d.", this->fd->fd);
199  rfd = this->fd->fd;
200  } else ERROR("No valid file descriptor found in socket!");
201 
202  DEBUG("Attempting to receive data on FD %d.", rfd);
203  CHECK((received = recv(rfd, incoming, length, 0)) >= 0, "Error receiving data from socket.");
204  return received;
205 
206 error:
207  return -1;
208 }
int co_list_append(co_obj_t *list, co_obj_t *new_obj)
insert new item at end of list
Definition: list.c:425
Definition: obj.h:131
Definition: socket.h:65
Definition: socket.h:48
co_obj_t * co_fd_create(co_obj_t *parent, int fd)
creates a file descriptor object
Definition: socket.c:47
int co_socket_send ( co_obj_t self,
char *  outgoing,
size_t  length 
)

sends a message on a specified socket

Parameters
selfsocket name
outgoingmessage to be sent
lengthlength of message

Referenced by co_socket_create().

151  {
152  CHECK_MEM(self);
153  CHECK(IS_FD(self),"Not a FD.");
154  co_fd_t *this = (co_fd_t*)self;
155  unsigned int sent = 0;
156  unsigned int remaining = length;
157  int n;
158 
159  while(sent < length) {
160  n = send(this->fd, outgoing+sent, remaining, 0);
161  if(n < 0) break;
162  sent += n;
163  remaining -= n;
164  }
165 
166  DEBUG("Sent %d bytes.", sent);
167  return sent;
168 
169 error:
170  return -1;
171 }
Definition: socket.h:48
int co_socket_setopt ( co_obj_t self,
int  level,
int  option,
void *  optval,
socklen_t  optvallen 
)

sets custom socket options, if specified by user

Parameters
selfsocket name
levelthe networking level to be customized
optionthe option to be changed
optvalthe value for the new option
optvallenthe length of the value for the new option

Referenced by co_socket_create().

210  {
211  CHECK(IS_SOCK(self),"Not a socket.");
212  co_socket_t *this = (co_socket_t*)self;
213 
214  //Check to see if this is a standard socket option, or needs custom handling.
215  if(level <= MAX_IPPROTO) {
216  CHECK(!setsockopt(this->fd->fd, level, option, optval, optvallen), "Problem setting socket options.");
217  } else {
218  SENTINEL("No custom socket options defined!");
219  }
220 
221  return 1;
222 
223 error:
224  return 0;
225 }
Definition: socket.h:65
int unix_socket_bind ( co_obj_t self,
const char *  endpoint 
)

binds a unix socket to a specified endpoint

Parameters
selfsocket name
endpointspecified endpoint for socket (file path)
264  {
265  DEBUG("Binding unix_socket %s.", endpoint);
266  CHECK(IS_SOCK(self),"Not a socket.");
267  unix_socket_t *this = (unix_socket_t*)self;
268  struct sockaddr_un *address = (struct sockaddr_un *)this->_(local);
269  CHECK_MEM(address);
270  address->sun_family = AF_UNIX;
271  CHECK((sizeof(endpoint) <= sizeof(address->sun_path)), "Endpoint %s is too large for socket path.", endpoint);
272  strcpy(address->sun_path, endpoint);
273  unlink(address->sun_path);
274 
275  //Initialize socket.
276  CHECK((this->_(fd)->fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1, "Failed to grab Unix socket file descriptor.");
277 
278  //Set some default socket options.
279  const int optval = 1;
280  setsockopt(this->_(fd)->fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
281  //int flags = fcntl(this->_(fd)->fd, F_GETFL, 0);
282  //fcntl(this->_(fd)->fd, F_SETFL, flags | O_NONBLOCK); //Set non-blocking.
283  //Set default timeout
284  struct timeval timeout;
285  timeout.tv_sec = 5;
286  timeout.tv_usec = 0;
287  setsockopt(this->_(fd)->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
288  setsockopt(this->_(fd)->fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
289 
290  //Bind socket to file descriptor.
291  socklen_t size = offsetof(struct sockaddr_un, sun_path) + sizeof(address->sun_path);
292  CHECK(!bind(this->_(fd)->fd, (struct sockaddr *) address, size), "Failed to bind Unix socket %s.", address->sun_path);
293  CHECK(!listen(this->_(fd)->fd, SOMAXCONN), "Failed to listen on Unix socket %s.", address->sun_path);
294  this->_(listen) = true;
295  if(this->_(register_cb)) this->_(register_cb)((co_obj_t*)this, (co_obj_t*)this->_(fd));
296  return 1;
297 
298 error:
299  close(this->_(fd)->fd);
300  return 0;
301 }
Definition: obj.h:131
Definition: socket.h:158
int unix_socket_connect ( co_obj_t self,
const char *  endpoint 
)

connects a socket to specified endpoint

Parameters
selfsocket name
endpointspecified endpoint for socket (file path)
303  {
304  DEBUG("Connecting unix_socket %s.", endpoint);
305  CHECK(IS_SOCK(self),"Not a socket.");
306  unix_socket_t *this = (unix_socket_t*)self;
307  struct sockaddr_un address = { .sun_family = AF_UNIX };
308  FILE *f = NULL;
309 
310  CHECK((sizeof(endpoint) <= sizeof(address.sun_path)), "Endpoint %s is too large for socket path.", endpoint);
311  CHECK(!(f = fopen(endpoint, "r")), "Invalid socket file path.");
312  strcpy(address.sun_path, endpoint);
313 
314  //Initialize socket.
315  CHECK((this->_(fd)->fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1, "Failed to grab Unix socket file descriptor.");
316 
317  //Set some default socket options.
318  const int optval = 1;
319  setsockopt(this->_(fd)->fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
320  //Set default timeout
321  struct timeval timeout;
322  timeout.tv_sec = 5;
323  timeout.tv_usec = 0;
324  setsockopt(this->_(fd)->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
325  setsockopt(this->_(fd)->fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
326  //int flags = fcntl(this->_(fd)->fd, F_GETFL, 0);
327  //fcntl(this->_(fd)->fd, F_SETFL, flags | O_NONBLOCK); //Set non-blocking.
328 
329  //Bind socket to file descriptor.
330  CHECK(!connect(this->_(fd)->fd, (struct sockaddr *) &address, sizeof(address)) || errno == EINPROGRESS, "Failed to bind Unix socket.");
331  return 1;
332 
333 error:
334  close(this->_(fd)->fd);
335  return 0;
336 }
Definition: socket.h:158
int unix_socket_init ( co_obj_t self)

initializes a unix socket

Parameters
selfsocket name

References co_fd_create().

244  {
245  if(self && IS_SOCK(self)) {
246  co_socket_t *this = (co_socket_t*)self;
247  this->fd = (co_fd_t*)co_fd_create((co_obj_t*)this,-1);
248  hattach(this->fd,this);
249  this->rfd_lst = co_list16_create();
250  hattach(this->rfd_lst,this);
251  this->local = h_calloc(1,sizeof(struct sockaddr_un));
252  hattach(this->local,this);
253  this->remote = h_calloc(1,sizeof(struct sockaddr_un));
254  hattach(this->remote,this);
255  this->fd_registered = false;
256  this->listen = false;
257  this->uri = h_strdup("unix://");
258  hattach(this->uri,this);
259  this->events = 0;
260  return 1;
261  } else return 0;
262 }
Definition: obj.h:131
Definition: socket.h:65
Definition: socket.h:48
co_obj_t * co_fd_create(co_obj_t *parent, int fd)
creates a file descriptor object
Definition: socket.c:47

Variable Documentation

co_socket_t unix_socket_proto
Initial value:
= {
}
int unix_socket_init(co_obj_t *self)
initializes a unix socket
Definition: socket.c:244
int unix_socket_bind(co_obj_t *self, const char *endpoint)
binds a unix socket to a specified endpoint
Definition: socket.c:264
int unix_socket_connect(co_obj_t *self, const char *endpoint)
connects a socket to specified endpoint
Definition: socket.c:303