1748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/*
2748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    This file is part of libmicrospdy
3748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    Copyright Copyright (C) 2013 Andrey Uzunov
4748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
5748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    This program is free software: you can redistribute it and/or modify
6748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    it under the terms of the GNU General Public License as published by
7748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    the Free Software Foundation, either version 3 of the License, or
8748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    (at your option) any later version.
9748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
10748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    This program is distributed in the hope that it will be useful,
11748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    but WITHOUT ANY WARRANTY; without even the implied warranty of
12748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    GNU General Public License for more details.
14748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
15748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    You should have received a copy of the GNU General Public License
16748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat*/
18748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
19748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat/**
20748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @file io_raw.c
21748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @brief  IO for SPDY without TLS.
22748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat * @author Andrey Uzunov
23748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat */
24748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
25748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "platform.h"
26748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "internal.h"
27748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "session.h"
28748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include "io_raw.h"
29748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat//TODO put in in the right place
30748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#include <netinet/tcp.h>
31748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
32748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
33748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid
34748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_global_init()
35748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
36748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
37748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
38748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
39748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid
40748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_global_deinit()
41748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
42748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
43748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
44748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
45748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
46748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_init(struct SPDY_Daemon *daemon)
47748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
48748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  (void)daemon;
49748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
50748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return SPDY_YES;
51748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
52748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
53748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
54748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid
55748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_deinit(struct SPDY_Daemon *daemon)
56748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
57748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  (void)daemon;
58748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
59748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
60748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
61748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
62748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_new_session(struct SPDY_Session *session)
63748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
64748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  int fd_flags;
65748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  int val = 1;
66748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  int ret;
67748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
68748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	//setting the socket to be non-blocking
69748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	fd_flags = fcntl (session->socket_fd, F_GETFL);
70748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	if ( -1 == fd_flags
71748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		|| 0 != fcntl (session->socket_fd, F_SETFL, fd_flags | O_NONBLOCK))
72748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		SPDYF_DEBUG("WARNING: Couldn't set the new connection to be non-blocking");
73748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
74748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if(SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags)
75748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  {
76748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
77748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    if(-1 == ret)
78748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_NODELAY");
79748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  }
80748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
81748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return SPDY_YES;
82748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
83748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
84748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
85748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratvoid
86748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_close_session(struct SPDY_Session *session)
87748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
88748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  (void)session;
89748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
90748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
91748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
92748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
93748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_recv(struct SPDY_Session *session,
94748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat				void * buffer,
95748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat				size_t size)
96748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
97748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	int n = read(session->socket_fd,
98748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat					buffer,
99748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat					size);
100748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	//if(n > 0) SPDYF_DEBUG("recvd: %i",n);
101748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	if (n < 0)
102748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	{
103748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		switch(errno)
104748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		{
105748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat			case EAGAIN:
106748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if EAGAIN != EWOULDBLOCK
107748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      case EWOULDBLOCK:
108748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
109748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat			case EINTR:
110748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        return SPDY_IO_ERROR_AGAIN;
111748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
112748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat			default:
113748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat				return SPDY_IO_ERROR_ERROR;
114748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		}
115748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	}
116748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
117748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return n;
118748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
119748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
120748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
121748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
122748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_send(struct SPDY_Session *session,
123748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat				const void * buffer,
124748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat				size_t size)
125748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
126748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	int n = write(session->socket_fd,
127748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat					buffer,
128748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat					size);
129748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	//if(n > 0) SPDYF_DEBUG("sent: %i",n);
130748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	if (n < 0)
131748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	{
132748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		switch(errno)
133748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		{
134748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat			case EAGAIN:
135748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if EAGAIN != EWOULDBLOCK
136748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      case EWOULDBLOCK:
137748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
138748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat			case EINTR:
139748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat        return SPDY_IO_ERROR_AGAIN;
140748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
141748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat			default:
142748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat				return SPDY_IO_ERROR_ERROR;
143748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat		}
144748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	}
145748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
146748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return n;
147748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
148748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
149748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
150748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
151748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_is_pending(struct SPDY_Session *session)
152748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
153748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  (void)session;
154748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
155748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return SPDY_NO;
156748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
157748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
158748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
159748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
160748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_before_write(struct SPDY_Session *session)
161748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
162748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if HAVE_DECL_TCP_CORK
163748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if(0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
164748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  {
165748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    int val = 1;
166748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    int ret;
167748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
168748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
169748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    if(-1 == ret)
170748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      SPDYF_DEBUG("WARNING: Couldn't set the new connection to TCP_CORK");
171748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  }
172748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
173748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
174748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return SPDY_YES;
175748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
176748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
177748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
178748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Eratint
179748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel EratSPDYF_raw_after_write(struct SPDY_Session *session, int was_written)
180748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat{
181748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#if HAVE_DECL_TCP_CORK
182748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  if(SPDY_YES == was_written && 0 == (SPDY_DAEMON_FLAG_NO_DELAY & session->daemon->flags))
183748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  {
184748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    int val = 0;
185748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    int ret;
186748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
187748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    ret = setsockopt(session->socket_fd, IPPROTO_TCP, TCP_CORK, &val, (socklen_t)sizeof(val));
188748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat    if(-1 == ret)
189748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat      SPDYF_DEBUG("WARNING: Couldn't unset the new connection to TCP_CORK");
190748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat  }
191748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat
192748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat#endif
193748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat	return was_written;
194748945ec6f1c67b7efc934ab0808e1d32f2fb98dDaniel Erat}
195